diff --git a/crypto/src/crypto/BufferedAeadBlockCipher.cs b/crypto/src/crypto/BufferedAeadBlockCipher.cs
index bf453feea..b10cd25fe 100644
--- a/crypto/src/crypto/BufferedAeadBlockCipher.cs
+++ b/crypto/src/crypto/BufferedAeadBlockCipher.cs
@@ -14,14 +14,10 @@ namespace Org.BouncyCastle.Crypto
{
private readonly IAeadBlockCipher cipher;
- public BufferedAeadBlockCipher(
- IAeadBlockCipher cipher)
+ public BufferedAeadBlockCipher(IAeadBlockCipher cipher)
{
- if (cipher == null)
- throw new ArgumentNullException("cipher");
-
- this.cipher = cipher;
- }
+ this.cipher = cipher ?? throw new ArgumentNullException(nameof(cipher));
+ }
public override string AlgorithmName
{
@@ -37,13 +33,11 @@ namespace Org.BouncyCastle.Crypto
* @exception ArgumentException if the parameters argument is
* inappropriate.
*/
- public override void Init(
- bool forEncryption,
- ICipherParameters parameters)
+ public override void Init(bool forEncryption, ICipherParameters parameters)
{
- if (parameters is ParametersWithRandom)
+ if (parameters is ParametersWithRandom withRandom)
{
- parameters = ((ParametersWithRandom) parameters).Parameters;
+ parameters = withRandom.Parameters;
}
cipher.Init(forEncryption, parameters);
diff --git a/crypto/src/crypto/BufferedAeadCipher.cs b/crypto/src/crypto/BufferedAeadCipher.cs
index fb3408e12..22f65c628 100644
--- a/crypto/src/crypto/BufferedAeadCipher.cs
+++ b/crypto/src/crypto/BufferedAeadCipher.cs
@@ -16,10 +16,7 @@ namespace Org.BouncyCastle.Crypto
public BufferedAeadCipher(IAeadCipher cipher)
{
- if (cipher == null)
- throw new ArgumentNullException("cipher");
-
- this.cipher = cipher;
+ this.cipher = cipher ?? throw new ArgumentNullException(nameof(cipher));
}
public override string AlgorithmName
@@ -36,13 +33,11 @@ namespace Org.BouncyCastle.Crypto
* @exception ArgumentException if the parameters argument is
* inappropriate.
*/
- public override void Init(
- bool forEncryption,
- ICipherParameters parameters)
+ public override void Init(bool forEncryption, ICipherParameters parameters)
{
- if (parameters is ParametersWithRandom)
+ if (parameters is ParametersWithRandom withRandom)
{
- parameters = ((ParametersWithRandom)parameters).Parameters;
+ parameters = withRandom.Parameters;
}
cipher.Init(forEncryption, parameters);
diff --git a/crypto/src/crypto/BufferedStreamCipher.cs b/crypto/src/crypto/BufferedStreamCipher.cs
index 8ee41c1e5..6ae51f47d 100644
--- a/crypto/src/crypto/BufferedStreamCipher.cs
+++ b/crypto/src/crypto/BufferedStreamCipher.cs
@@ -11,10 +11,7 @@ namespace Org.BouncyCastle.Crypto
public BufferedStreamCipher(IStreamCipher cipher)
{
- if (cipher == null)
- throw new ArgumentNullException("cipher");
-
- this.m_cipher = cipher;
+ m_cipher = cipher ?? throw new ArgumentNullException(nameof(cipher));
}
public override string AlgorithmName
diff --git a/crypto/src/crypto/CryptoServicesRegistrar.cs b/crypto/src/crypto/CryptoServicesRegistrar.cs
index 33bf47386..a2784108e 100644
--- a/crypto/src/crypto/CryptoServicesRegistrar.cs
+++ b/crypto/src/crypto/CryptoServicesRegistrar.cs
@@ -11,7 +11,7 @@ namespace Org.BouncyCastle.Crypto
public static SecureRandom GetSecureRandom(SecureRandom secureRandom)
{
- return secureRandom ?? new SecureRandom();
+ return secureRandom ?? GetSecureRandom();
}
}
}
diff --git a/crypto/src/crypto/IBlockResult.cs b/crypto/src/crypto/IBlockResult.cs
index f3b73e59f..2a62e26de 100644
--- a/crypto/src/crypto/IBlockResult.cs
+++ b/crypto/src/crypto/IBlockResult.cs
@@ -31,6 +31,7 @@ namespace Org.BouncyCastle.Crypto
int Collect(Span<byte> output);
#endif
+ /// <summary>Return an upper limit for the size of the result.</summary>
int GetMaxResultLength();
}
}
diff --git a/crypto/src/crypto/IDerivationFunction.cs b/crypto/src/crypto/IDerivationFunction.cs
index 9c0228ab0..35dea0a2e 100644
--- a/crypto/src/crypto/IDerivationFunction.cs
+++ b/crypto/src/crypto/IDerivationFunction.cs
@@ -2,16 +2,12 @@ using System;
namespace Org.BouncyCastle.Crypto
{
- /**
- * base interface for general purpose byte derivation functions.
- */
+ /// <summary>Base interface for general purpose byte derivation functions.</summary>
public interface IDerivationFunction
{
void Init(IDerivationParameters parameters);
- /**
- * return the message digest used as the basis for the function
- */
+ /// <summary>The message digest used as the basis for the function.</summary>
IDigest Digest { get; }
int GenerateBytes(byte[] output, int outOff, int length);
diff --git a/crypto/src/crypto/agreement/DHBasicAgreement.cs b/crypto/src/crypto/agreement/DHBasicAgreement.cs
index 6c3fe6595..a27d8c534 100644
--- a/crypto/src/crypto/agreement/DHBasicAgreement.cs
+++ b/crypto/src/crypto/agreement/DHBasicAgreement.cs
@@ -19,20 +19,17 @@ namespace Org.BouncyCastle.Crypto.Agreement
private DHPrivateKeyParameters key;
private DHParameters dhParams;
- public virtual void Init(
- ICipherParameters parameters)
+ public virtual void Init(ICipherParameters parameters)
{
- if (parameters is ParametersWithRandom)
+ if (parameters is ParametersWithRandom withRandom)
{
- parameters = ((ParametersWithRandom) parameters).Parameters;
+ parameters = withRandom.Parameters;
}
- if (!(parameters is DHPrivateKeyParameters))
- {
- throw new ArgumentException("DHEngine expects DHPrivateKeyParameters");
- }
+ if (!(parameters is DHPrivateKeyParameters dhPrivateKeyParameters))
+ throw new ArgumentException("DHBasicAgreement expects DHPrivateKeyParameters");
- this.key = (DHPrivateKeyParameters) parameters;
+ this.key = dhPrivateKeyParameters;
this.dhParams = key.Parameters;
}
diff --git a/crypto/src/crypto/agreement/ECDHBasicAgreement.cs b/crypto/src/crypto/agreement/ECDHBasicAgreement.cs
index 1358db0cf..4555cdde4 100644
--- a/crypto/src/crypto/agreement/ECDHBasicAgreement.cs
+++ b/crypto/src/crypto/agreement/ECDHBasicAgreement.cs
@@ -26,15 +26,17 @@ namespace Org.BouncyCastle.Crypto.Agreement
{
protected internal ECPrivateKeyParameters privKey;
- public virtual void Init(
- ICipherParameters parameters)
+ public virtual void Init(ICipherParameters parameters)
{
- if (parameters is ParametersWithRandom)
+ if (parameters is ParametersWithRandom withRandom)
{
- parameters = ((ParametersWithRandom)parameters).Parameters;
+ parameters = withRandom.Parameters;
}
- this.privKey = (ECPrivateKeyParameters)parameters;
+ if (!(parameters is ECPrivateKeyParameters ecPrivateKeyParameters))
+ throw new ArgumentException("ECDHBasicAgreement expects ECPrivateKeyParameters");
+
+ this.privKey = ecPrivateKeyParameters;
}
public virtual int GetFieldSize()
diff --git a/crypto/src/crypto/agreement/ECDHCBasicAgreement.cs b/crypto/src/crypto/agreement/ECDHCBasicAgreement.cs
index f0b5d1e02..bb4c185df 100644
--- a/crypto/src/crypto/agreement/ECDHCBasicAgreement.cs
+++ b/crypto/src/crypto/agreement/ECDHCBasicAgreement.cs
@@ -31,15 +31,17 @@ namespace Org.BouncyCastle.Crypto.Agreement
{
private ECPrivateKeyParameters privKey;
- public virtual void Init(
- ICipherParameters parameters)
+ public virtual void Init(ICipherParameters parameters)
{
- if (parameters is ParametersWithRandom)
+ if (parameters is ParametersWithRandom withRandom)
{
- parameters = ((ParametersWithRandom) parameters).Parameters;
+ parameters = withRandom.Parameters;
}
- this.privKey = (ECPrivateKeyParameters)parameters;
+ if (!(parameters is ECPrivateKeyParameters ecPrivateKeyParameters))
+ throw new ArgumentException("ECDHCBasicAgreement expects ECPrivateKeyParameters");
+
+ this.privKey = ecPrivateKeyParameters;
}
public virtual int GetFieldSize()
diff --git a/crypto/src/crypto/agreement/ECMqvBasicAgreement.cs b/crypto/src/crypto/agreement/ECMqvBasicAgreement.cs
index b71f5a7d2..984d66587 100644
--- a/crypto/src/crypto/agreement/ECMqvBasicAgreement.cs
+++ b/crypto/src/crypto/agreement/ECMqvBasicAgreement.cs
@@ -12,12 +12,11 @@ namespace Org.BouncyCastle.Crypto.Agreement
{
protected internal MqvPrivateParameters privParams;
- public virtual void Init(
- ICipherParameters parameters)
+ public virtual void Init(ICipherParameters parameters)
{
- if (parameters is ParametersWithRandom)
+ if (parameters is ParametersWithRandom withRandom)
{
- parameters = ((ParametersWithRandom)parameters).Parameters;
+ parameters = withRandom.Parameters;
}
this.privParams = (MqvPrivateParameters)parameters;
diff --git a/crypto/src/crypto/agreement/kdf/ConcatenationKdfGenerator.cs b/crypto/src/crypto/agreement/kdf/ConcatenationKdfGenerator.cs
index 207c795da..8467460b4 100644
--- a/crypto/src/crypto/agreement/kdf/ConcatenationKdfGenerator.cs
+++ b/crypto/src/crypto/agreement/kdf/ConcatenationKdfGenerator.cs
@@ -29,9 +29,12 @@ namespace Org.BouncyCastle.Crypto.Agreement.Kdf
byte[] sharedSecret = kdfParameters.GetSharedSecret();
byte[] otherInfo = kdfParameters.GetIV();
- m_buffer = new byte[4 + sharedSecret.Length + otherInfo.Length + m_hLen];
+ m_buffer = new byte[4 + sharedSecret.Length + (otherInfo == null ? 0 : otherInfo.Length) + m_hLen];
sharedSecret.CopyTo(m_buffer, 4);
- otherInfo.CopyTo(m_buffer, 4 + sharedSecret.Length);
+ if (otherInfo != null)
+ {
+ otherInfo.CopyTo(m_buffer, 4 + sharedSecret.Length);
+ }
}
/// <summary>the underlying digest.</summary>
diff --git a/crypto/src/crypto/digests/ISAPDigest.cs b/crypto/src/crypto/digests/ISAPDigest.cs
new file mode 100644
index 000000000..3be28e4e2
--- /dev/null
+++ b/crypto/src/crypto/digests/ISAPDigest.cs
@@ -0,0 +1,149 @@
+using System;
+using System.IO;
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+ public class ISAPDigest : IDigest
+ {
+ private ulong x0, x1, x2, x3, x4;
+ private ulong t0, t1, t2, t3, t4;
+ private MemoryStream buffer = new MemoryStream();
+
+ private void ROUND(ulong C)
+ {
+ t0 = x0 ^ x1 ^ x2 ^ x3 ^ C ^ (x1 & (x0 ^ x2 ^ x4 ^ C));
+ t1 = x0 ^ x2 ^ x3 ^ x4 ^ C ^ ((x1 ^ x2 ^ C) & (x1 ^ x3));
+ t2 = x1 ^ x2 ^ x4 ^ C ^ (x3 & x4);
+ t3 = x0 ^ x1 ^ x2 ^ C ^ ((~x0) & (x3 ^ x4));
+ t4 = x1 ^ x3 ^ x4 ^ ((x0 ^ x4) & x1);
+ x0 = t0 ^ ROTR(t0, 19) ^ ROTR(t0, 28);
+ x1 = t1 ^ ROTR(t1, 39) ^ ROTR(t1, 61);
+ x2 = ~(t2 ^ ROTR(t2, 1) ^ ROTR(t2, 6));
+ x3 = t3 ^ ROTR(t3, 10) ^ ROTR(t3, 17);
+ x4 = t4 ^ ROTR(t4, 7) ^ ROTR(t4, 41);
+ }
+
+ private void P12()
+ {
+ ROUND(0xf0);
+ ROUND(0xe1);
+ ROUND(0xd2);
+ ROUND(0xc3);
+ ROUND(0xb4);
+ ROUND(0xa5);
+ ROUND(0x96);
+ ROUND(0x87);
+ ROUND(0x78);
+ ROUND(0x69);
+ ROUND(0x5a);
+ ROUND(0x4b);
+ }
+
+ private ulong ROTR(ulong x, int n)
+ {
+ return (x >> n) | (x << (64 - n));
+ }
+
+ protected ulong U64BIG(ulong x)
+ {
+ return ((ROTR(x, 8) & (0xFF000000FF000000UL)) | (ROTR(x, 24) & (0x00FF000000FF0000UL)) |
+ (ROTR(x, 40) & (0x0000FF000000FF00UL)) | (ROTR(x, 56) & (0x000000FF000000FFUL)));
+ }
+
+ public string AlgorithmName
+ {
+ get { return "ISAP Hash"; }
+ }
+
+ public void BlockUpdate(byte[] input, int inOff, int inLen)
+ {
+ if (inOff + inLen > input.Length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+ buffer.Write(input, inOff, inLen);
+ }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public void BlockUpdate(ReadOnlySpan<byte> input)
+ {
+ buffer.Write(input.ToArray(), 0, input.Length);
+ }
+
+ public int DoFinal(Span<byte> output)
+ {
+ byte[] rv = new byte[32];
+ int rlt = DoFinal(rv, 0);
+ rv.AsSpan(0, 32).CopyTo(output);
+ return rlt;
+ }
+
+#endif
+
+ public int DoFinal(byte[] output, int outOff)
+ {
+ if (32 + outOff > output.Length)
+ {
+ throw new OutputLengthException("output buffer is too short");
+ }
+ t0 = t1 = t2 = t3 = t4 = 0;
+ /* init state */
+ x0 = 17191252062196199485UL;
+ x1 = 10066134719181819906UL;
+ x2 = 13009371945472744034UL;
+ x3 = 4834782570098516968UL;
+ x4 = 3787428097924915520UL;
+ /* absorb */
+ byte[] input = buffer.GetBuffer();
+ int len = (int)buffer.Length;
+ ulong[] in64 = new ulong[len >> 3];
+ Pack.LE_To_UInt64(input, 0, in64, 0, in64.Length);
+ int idx = 0;
+ while (len >= 8)
+ {
+ x0 ^= U64BIG(in64[idx++]);
+ P12();
+ len -= 8;
+ }
+ /* absorb final input block */
+ x0 ^= 0x80UL << ((7 - len) << 3);
+ while (len > 0)
+ {
+ x0 ^= (input[(idx << 3) + --len] & 0xFFUL) << ((7 - len) << 3);
+ }
+ P12();
+ // squeeze
+ ulong[] out64 = new ulong[4];
+ for (idx = 0; idx < 3; ++idx)
+ {
+ out64[idx] = U64BIG(x0);
+ P12();
+ }
+ /* squeeze final output block */
+ out64[idx] = U64BIG(x0);
+ Pack.UInt64_To_LE(out64, output, outOff);
+ return 32;
+ }
+
+ public int GetByteLength()
+ {
+ throw new NotImplementedException();
+ }
+
+ public int GetDigestSize()
+ {
+ return 32;
+ }
+
+ public void Reset()
+ {
+ buffer.SetLength(0);
+ }
+
+ public void Update(byte input)
+ {
+ buffer.Write(new byte[] { input }, 0, 1);
+ }
+ }
+}
diff --git a/crypto/src/crypto/digests/LongDigest.cs b/crypto/src/crypto/digests/LongDigest.cs
index 6a2f94ece..df48c4889 100644
--- a/crypto/src/crypto/digests/LongDigest.cs
+++ b/crypto/src/crypto/digests/LongDigest.cs
@@ -12,7 +12,7 @@ namespace Org.BouncyCastle.Crypto.Digests
public abstract class LongDigest
: IDigest, IMemoable
{
- private int MyByteLength = 128;
+ private const int MyByteLength = 128;
private byte[] xBuf;
private int xBufOff;
diff --git a/crypto/src/crypto/digests/MD5Digest.cs b/crypto/src/crypto/digests/MD5Digest.cs
index 062d7bb46..3a0967bc3 100644
--- a/crypto/src/crypto/digests/MD5Digest.cs
+++ b/crypto/src/crypto/digests/MD5Digest.cs
@@ -182,16 +182,6 @@ namespace Org.BouncyCastle.Crypto.Digests
private static readonly int S44 = 21;
/*
- * rotate int x left n bits.
- */
- private static uint RotateLeft(
- uint x,
- int n)
- {
- return (x << n) | (x >> (32 - n));
- }
-
- /*
* F, G, H and I are the basic MD5 functions.
*/
private static uint F(
@@ -236,82 +226,82 @@ namespace Org.BouncyCastle.Crypto.Digests
//
// Round 1 - F cycle, 16 times.
//
- a = RotateLeft((a + F(b, c, d) + X[0] + 0xd76aa478), S11) + b;
- d = RotateLeft((d + F(a, b, c) + X[1] + 0xe8c7b756), S12) + a;
- c = RotateLeft((c + F(d, a, b) + X[2] + 0x242070db), S13) + d;
- b = RotateLeft((b + F(c, d, a) + X[3] + 0xc1bdceee), S14) + c;
- a = RotateLeft((a + F(b, c, d) + X[4] + 0xf57c0faf), S11) + b;
- d = RotateLeft((d + F(a, b, c) + X[5] + 0x4787c62a), S12) + a;
- c = RotateLeft((c + F(d, a, b) + X[6] + 0xa8304613), S13) + d;
- b = RotateLeft((b + F(c, d, a) + X[7] + 0xfd469501), S14) + c;
- a = RotateLeft((a + F(b, c, d) + X[8] + 0x698098d8), S11) + b;
- d = RotateLeft((d + F(a, b, c) + X[9] + 0x8b44f7af), S12) + a;
- c = RotateLeft((c + F(d, a, b) + X[10] + 0xffff5bb1), S13) + d;
- b = RotateLeft((b + F(c, d, a) + X[11] + 0x895cd7be), S14) + c;
- a = RotateLeft((a + F(b, c, d) + X[12] + 0x6b901122), S11) + b;
- d = RotateLeft((d + F(a, b, c) + X[13] + 0xfd987193), S12) + a;
- c = RotateLeft((c + F(d, a, b) + X[14] + 0xa679438e), S13) + d;
- b = RotateLeft((b + F(c, d, a) + X[15] + 0x49b40821), S14) + c;
+ a = Integers.RotateLeft((a + F(b, c, d) + X[0] + 0xd76aa478), S11) + b;
+ d = Integers.RotateLeft((d + F(a, b, c) + X[1] + 0xe8c7b756), S12) + a;
+ c = Integers.RotateLeft((c + F(d, a, b) + X[2] + 0x242070db), S13) + d;
+ b = Integers.RotateLeft((b + F(c, d, a) + X[3] + 0xc1bdceee), S14) + c;
+ a = Integers.RotateLeft((a + F(b, c, d) + X[4] + 0xf57c0faf), S11) + b;
+ d = Integers.RotateLeft((d + F(a, b, c) + X[5] + 0x4787c62a), S12) + a;
+ c = Integers.RotateLeft((c + F(d, a, b) + X[6] + 0xa8304613), S13) + d;
+ b = Integers.RotateLeft((b + F(c, d, a) + X[7] + 0xfd469501), S14) + c;
+ a = Integers.RotateLeft((a + F(b, c, d) + X[8] + 0x698098d8), S11) + b;
+ d = Integers.RotateLeft((d + F(a, b, c) + X[9] + 0x8b44f7af), S12) + a;
+ c = Integers.RotateLeft((c + F(d, a, b) + X[10] + 0xffff5bb1), S13) + d;
+ b = Integers.RotateLeft((b + F(c, d, a) + X[11] + 0x895cd7be), S14) + c;
+ a = Integers.RotateLeft((a + F(b, c, d) + X[12] + 0x6b901122), S11) + b;
+ d = Integers.RotateLeft((d + F(a, b, c) + X[13] + 0xfd987193), S12) + a;
+ c = Integers.RotateLeft((c + F(d, a, b) + X[14] + 0xa679438e), S13) + d;
+ b = Integers.RotateLeft((b + F(c, d, a) + X[15] + 0x49b40821), S14) + c;
//
// Round 2 - G cycle, 16 times.
//
- a = RotateLeft((a + G(b, c, d) + X[1] + 0xf61e2562), S21) + b;
- d = RotateLeft((d + G(a, b, c) + X[6] + 0xc040b340), S22) + a;
- c = RotateLeft((c + G(d, a, b) + X[11] + 0x265e5a51), S23) + d;
- b = RotateLeft((b + G(c, d, a) + X[0] + 0xe9b6c7aa), S24) + c;
- a = RotateLeft((a + G(b, c, d) + X[5] + 0xd62f105d), S21) + b;
- d = RotateLeft((d + G(a, b, c) + X[10] + 0x02441453), S22) + a;
- c = RotateLeft((c + G(d, a, b) + X[15] + 0xd8a1e681), S23) + d;
- b = RotateLeft((b + G(c, d, a) + X[4] + 0xe7d3fbc8), S24) + c;
- a = RotateLeft((a + G(b, c, d) + X[9] + 0x21e1cde6), S21) + b;
- d = RotateLeft((d + G(a, b, c) + X[14] + 0xc33707d6), S22) + a;
- c = RotateLeft((c + G(d, a, b) + X[3] + 0xf4d50d87), S23) + d;
- b = RotateLeft((b + G(c, d, a) + X[8] + 0x455a14ed), S24) + c;
- a = RotateLeft((a + G(b, c, d) + X[13] + 0xa9e3e905), S21) + b;
- d = RotateLeft((d + G(a, b, c) + X[2] + 0xfcefa3f8), S22) + a;
- c = RotateLeft((c + G(d, a, b) + X[7] + 0x676f02d9), S23) + d;
- b = RotateLeft((b + G(c, d, a) + X[12] + 0x8d2a4c8a), S24) + c;
+ a = Integers.RotateLeft((a + G(b, c, d) + X[1] + 0xf61e2562), S21) + b;
+ d = Integers.RotateLeft((d + G(a, b, c) + X[6] + 0xc040b340), S22) + a;
+ c = Integers.RotateLeft((c + G(d, a, b) + X[11] + 0x265e5a51), S23) + d;
+ b = Integers.RotateLeft((b + G(c, d, a) + X[0] + 0xe9b6c7aa), S24) + c;
+ a = Integers.RotateLeft((a + G(b, c, d) + X[5] + 0xd62f105d), S21) + b;
+ d = Integers.RotateLeft((d + G(a, b, c) + X[10] + 0x02441453), S22) + a;
+ c = Integers.RotateLeft((c + G(d, a, b) + X[15] + 0xd8a1e681), S23) + d;
+ b = Integers.RotateLeft((b + G(c, d, a) + X[4] + 0xe7d3fbc8), S24) + c;
+ a = Integers.RotateLeft((a + G(b, c, d) + X[9] + 0x21e1cde6), S21) + b;
+ d = Integers.RotateLeft((d + G(a, b, c) + X[14] + 0xc33707d6), S22) + a;
+ c = Integers.RotateLeft((c + G(d, a, b) + X[3] + 0xf4d50d87), S23) + d;
+ b = Integers.RotateLeft((b + G(c, d, a) + X[8] + 0x455a14ed), S24) + c;
+ a = Integers.RotateLeft((a + G(b, c, d) + X[13] + 0xa9e3e905), S21) + b;
+ d = Integers.RotateLeft((d + G(a, b, c) + X[2] + 0xfcefa3f8), S22) + a;
+ c = Integers.RotateLeft((c + G(d, a, b) + X[7] + 0x676f02d9), S23) + d;
+ b = Integers.RotateLeft((b + G(c, d, a) + X[12] + 0x8d2a4c8a), S24) + c;
//
// Round 3 - H cycle, 16 times.
//
- a = RotateLeft((a + H(b, c, d) + X[5] + 0xfffa3942), S31) + b;
- d = RotateLeft((d + H(a, b, c) + X[8] + 0x8771f681), S32) + a;
- c = RotateLeft((c + H(d, a, b) + X[11] + 0x6d9d6122), S33) + d;
- b = RotateLeft((b + H(c, d, a) + X[14] + 0xfde5380c), S34) + c;
- a = RotateLeft((a + H(b, c, d) + X[1] + 0xa4beea44), S31) + b;
- d = RotateLeft((d + H(a, b, c) + X[4] + 0x4bdecfa9), S32) + a;
- c = RotateLeft((c + H(d, a, b) + X[7] + 0xf6bb4b60), S33) + d;
- b = RotateLeft((b + H(c, d, a) + X[10] + 0xbebfbc70), S34) + c;
- a = RotateLeft((a + H(b, c, d) + X[13] + 0x289b7ec6), S31) + b;
- d = RotateLeft((d + H(a, b, c) + X[0] + 0xeaa127fa), S32) + a;
- c = RotateLeft((c + H(d, a, b) + X[3] + 0xd4ef3085), S33) + d;
- b = RotateLeft((b + H(c, d, a) + X[6] + 0x04881d05), S34) + c;
- a = RotateLeft((a + H(b, c, d) + X[9] + 0xd9d4d039), S31) + b;
- d = RotateLeft((d + H(a, b, c) + X[12] + 0xe6db99e5), S32) + a;
- c = RotateLeft((c + H(d, a, b) + X[15] + 0x1fa27cf8), S33) + d;
- b = RotateLeft((b + H(c, d, a) + X[2] + 0xc4ac5665), S34) + c;
+ a = Integers.RotateLeft((a + H(b, c, d) + X[5] + 0xfffa3942), S31) + b;
+ d = Integers.RotateLeft((d + H(a, b, c) + X[8] + 0x8771f681), S32) + a;
+ c = Integers.RotateLeft((c + H(d, a, b) + X[11] + 0x6d9d6122), S33) + d;
+ b = Integers.RotateLeft((b + H(c, d, a) + X[14] + 0xfde5380c), S34) + c;
+ a = Integers.RotateLeft((a + H(b, c, d) + X[1] + 0xa4beea44), S31) + b;
+ d = Integers.RotateLeft((d + H(a, b, c) + X[4] + 0x4bdecfa9), S32) + a;
+ c = Integers.RotateLeft((c + H(d, a, b) + X[7] + 0xf6bb4b60), S33) + d;
+ b = Integers.RotateLeft((b + H(c, d, a) + X[10] + 0xbebfbc70), S34) + c;
+ a = Integers.RotateLeft((a + H(b, c, d) + X[13] + 0x289b7ec6), S31) + b;
+ d = Integers.RotateLeft((d + H(a, b, c) + X[0] + 0xeaa127fa), S32) + a;
+ c = Integers.RotateLeft((c + H(d, a, b) + X[3] + 0xd4ef3085), S33) + d;
+ b = Integers.RotateLeft((b + H(c, d, a) + X[6] + 0x04881d05), S34) + c;
+ a = Integers.RotateLeft((a + H(b, c, d) + X[9] + 0xd9d4d039), S31) + b;
+ d = Integers.RotateLeft((d + H(a, b, c) + X[12] + 0xe6db99e5), S32) + a;
+ c = Integers.RotateLeft((c + H(d, a, b) + X[15] + 0x1fa27cf8), S33) + d;
+ b = Integers.RotateLeft((b + H(c, d, a) + X[2] + 0xc4ac5665), S34) + c;
//
// Round 4 - K cycle, 16 times.
//
- a = RotateLeft((a + K(b, c, d) + X[0] + 0xf4292244), S41) + b;
- d = RotateLeft((d + K(a, b, c) + X[7] + 0x432aff97), S42) + a;
- c = RotateLeft((c + K(d, a, b) + X[14] + 0xab9423a7), S43) + d;
- b = RotateLeft((b + K(c, d, a) + X[5] + 0xfc93a039), S44) + c;
- a = RotateLeft((a + K(b, c, d) + X[12] + 0x655b59c3), S41) + b;
- d = RotateLeft((d + K(a, b, c) + X[3] + 0x8f0ccc92), S42) + a;
- c = RotateLeft((c + K(d, a, b) + X[10] + 0xffeff47d), S43) + d;
- b = RotateLeft((b + K(c, d, a) + X[1] + 0x85845dd1), S44) + c;
- a = RotateLeft((a + K(b, c, d) + X[8] + 0x6fa87e4f), S41) + b;
- d = RotateLeft((d + K(a, b, c) + X[15] + 0xfe2ce6e0), S42) + a;
- c = RotateLeft((c + K(d, a, b) + X[6] + 0xa3014314), S43) + d;
- b = RotateLeft((b + K(c, d, a) + X[13] + 0x4e0811a1), S44) + c;
- a = RotateLeft((a + K(b, c, d) + X[4] + 0xf7537e82), S41) + b;
- d = RotateLeft((d + K(a, b, c) + X[11] + 0xbd3af235), S42) + a;
- c = RotateLeft((c + K(d, a, b) + X[2] + 0x2ad7d2bb), S43) + d;
- b = RotateLeft((b + K(c, d, a) + X[9] + 0xeb86d391), S44) + c;
+ a = Integers.RotateLeft((a + K(b, c, d) + X[0] + 0xf4292244), S41) + b;
+ d = Integers.RotateLeft((d + K(a, b, c) + X[7] + 0x432aff97), S42) + a;
+ c = Integers.RotateLeft((c + K(d, a, b) + X[14] + 0xab9423a7), S43) + d;
+ b = Integers.RotateLeft((b + K(c, d, a) + X[5] + 0xfc93a039), S44) + c;
+ a = Integers.RotateLeft((a + K(b, c, d) + X[12] + 0x655b59c3), S41) + b;
+ d = Integers.RotateLeft((d + K(a, b, c) + X[3] + 0x8f0ccc92), S42) + a;
+ c = Integers.RotateLeft((c + K(d, a, b) + X[10] + 0xffeff47d), S43) + d;
+ b = Integers.RotateLeft((b + K(c, d, a) + X[1] + 0x85845dd1), S44) + c;
+ a = Integers.RotateLeft((a + K(b, c, d) + X[8] + 0x6fa87e4f), S41) + b;
+ d = Integers.RotateLeft((d + K(a, b, c) + X[15] + 0xfe2ce6e0), S42) + a;
+ c = Integers.RotateLeft((c + K(d, a, b) + X[6] + 0xa3014314), S43) + d;
+ b = Integers.RotateLeft((b + K(c, d, a) + X[13] + 0x4e0811a1), S44) + c;
+ a = Integers.RotateLeft((a + K(b, c, d) + X[4] + 0xf7537e82), S41) + b;
+ d = Integers.RotateLeft((d + K(a, b, c) + X[11] + 0xbd3af235), S42) + a;
+ c = Integers.RotateLeft((c + K(d, a, b) + X[2] + 0x2ad7d2bb), S43) + d;
+ b = Integers.RotateLeft((b + K(c, d, a) + X[9] + 0xeb86d391), S44) + c;
H1 += a;
H2 += b;
@@ -332,8 +322,5 @@ namespace Org.BouncyCastle.Crypto.Digests
CopyIn(d);
}
-
}
-
}
-
diff --git a/crypto/src/crypto/digests/PhotonBeetleDigest.cs b/crypto/src/crypto/digests/PhotonBeetleDigest.cs
new file mode 100644
index 000000000..13b30e025
--- /dev/null
+++ b/crypto/src/crypto/digests/PhotonBeetleDigest.cs
@@ -0,0 +1,247 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+ /**
+ * Photon-Beetle, https://www.isical.ac.in/~lightweight/beetle/
+ * https://csrc.nist.gov/CSRC/media/Projects/lightweight-cryptography/documents/readonlyist-round/updated-spec-doc/photon-beetle-spec-readonly.pdf
+ * <p>
+ * Photon-Beetle with reference to C Reference Impl from: https://github.com/PHOTON-Beetle/Software
+ * </p>
+ */
+ public class PhotonBeetleDigest
+ : IDigest
+ {
+ private byte[] state;
+ private byte[][] state_2d;
+ private MemoryStream buffer = new MemoryStream();
+ private const int INITIAL_RATE_INBYTES = 16;
+ private int RATE_INBYTES = 4;
+ private int SQUEEZE_RATE_INBYTES = 16;
+ private int STATE_INBYTES = 32;
+ private int TAG_INBYTES = 32;
+ private int LAST_THREE_BITS_OFFSET = 5;
+ private int ROUND = 12;
+ private int D = 8;
+ private int Dq = 3;
+ private int Dr = 7;
+ private int DSquare = 64;
+ private int S = 4;
+ private int S_1 = 3;
+ private byte[][] RC = {//[D][12]
+ new byte[]{1, 3, 7, 14, 13, 11, 6, 12, 9, 2, 5, 10},
+ new byte[]{0, 2, 6, 15, 12, 10, 7, 13, 8, 3, 4, 11},
+ new byte[]{2, 0, 4, 13, 14, 8, 5, 15, 10, 1, 6, 9},
+ new byte[]{6, 4, 0, 9, 10, 12, 1, 11, 14, 5, 2, 13},
+ new byte[]{14, 12, 8, 1, 2, 4, 9, 3, 6, 13, 10, 5},
+ new byte[]{15, 13, 9, 0, 3, 5, 8, 2, 7, 12, 11, 4},
+ new byte[]{13, 15, 11, 2, 1, 7, 10, 0, 5, 14, 9, 6},
+ new byte[]{9, 11, 15, 6, 5, 3, 14, 4, 1, 10, 13, 2}
+ };
+ private byte[][] MixColMatrix = { //[D][D]
+ new byte[]{2, 4, 2, 11, 2, 8, 5, 6},
+ new byte[]{12, 9, 8, 13, 7, 7, 5, 2},
+ new byte[]{4, 4, 13, 13, 9, 4, 13, 9},
+ new byte[] {1, 6, 5, 1, 12, 13, 15, 14},
+ new byte[]{15, 12, 9, 13, 14, 5, 14, 13},
+ new byte[]{9, 14, 5, 15, 4, 12, 9, 6},
+ new byte[]{12, 2, 2, 10, 3, 1, 1, 14},
+ new byte[]{15, 1, 13, 10, 5, 10, 2, 3}
+ };
+
+ private byte[] sbox = { 12, 5, 6, 11, 9, 0, 10, 13, 3, 14, 15, 8, 4, 7, 1, 2 };
+
+ public PhotonBeetleDigest()
+ {
+ state = new byte[STATE_INBYTES];
+ state_2d = new byte[D][];
+ for (int i = 0; i < D; ++i)
+ {
+ state_2d[i] = new byte[D];
+ }
+ }
+
+
+ public String AlgorithmName => "Photon-Beetle Hash";
+
+
+ public int GetDigestSize()
+ {
+ return TAG_INBYTES;
+ }
+
+
+ public void Update(byte input)
+ {
+ buffer.Write(new byte[] { input }, 0, 1);
+ }
+
+
+ public void BlockUpdate(byte[] input, int inOff, int len)
+ {
+ if ((inOff + len) > input.Length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+ buffer.Write(input, inOff, len);
+ }
+
+
+ public int DoFinal(byte[] output, int outOff)
+ {
+ if (32 + outOff > output.Length)
+ {
+ throw new OutputLengthException("output buffer is too short");
+ }
+ byte[] input = buffer.GetBuffer();
+ int inlen = (int)buffer.Length;
+ if (inlen == 0)
+ {
+ state[STATE_INBYTES - 1] ^= (byte)(1 << LAST_THREE_BITS_OFFSET);
+ }
+ else if (inlen <= INITIAL_RATE_INBYTES)
+ {
+ Array.Copy(input, 0, state, 0, inlen);
+ if (inlen < INITIAL_RATE_INBYTES)
+ {
+ state[inlen] ^= 0x01; // ozs
+ }
+ state[STATE_INBYTES - 1] ^= (byte)((inlen < INITIAL_RATE_INBYTES ? 1 : 2) << LAST_THREE_BITS_OFFSET);
+ }
+ else
+ {
+ Array.Copy(input, 0, state, 0, INITIAL_RATE_INBYTES);
+ inlen -= INITIAL_RATE_INBYTES;
+ int Dlen_inblocks = (inlen + RATE_INBYTES - 1) / RATE_INBYTES;
+ int i, LastDBlocklen;
+ for (i = 0; i < Dlen_inblocks - 1; i++)
+ {
+ PHOTON_Permutation();
+ XOR(input, INITIAL_RATE_INBYTES + i * RATE_INBYTES, RATE_INBYTES);
+ }
+ PHOTON_Permutation();
+ LastDBlocklen = inlen - i * RATE_INBYTES;
+ XOR(input, INITIAL_RATE_INBYTES + i * RATE_INBYTES, LastDBlocklen);
+ if (LastDBlocklen < RATE_INBYTES)
+ {
+ state[LastDBlocklen] ^= 0x01; // ozs
+ }
+ state[STATE_INBYTES - 1] ^= (byte)((inlen % RATE_INBYTES == 0 ? 1 : 2) << LAST_THREE_BITS_OFFSET);
+ }
+ PHOTON_Permutation();
+ Array.Copy(state, 0, output, outOff, SQUEEZE_RATE_INBYTES);
+ PHOTON_Permutation();
+ Array.Copy(state, 0, output, outOff + SQUEEZE_RATE_INBYTES, TAG_INBYTES - SQUEEZE_RATE_INBYTES);
+ return TAG_INBYTES;
+ }
+
+ void XOR(byte[] in_right, int rOff, int iolen_inbytes)
+ {
+ for (int i = 0; i < iolen_inbytes; i++)
+ {
+ state[i] ^= in_right[i + rOff];
+ }
+ }
+
+
+ public void Reset()
+ {
+ buffer.SetLength(0);
+ Arrays.Fill(state, (byte)0);
+ }
+
+ void PHOTON_Permutation()
+ {
+ int i, j, k, l;
+ for (i = 0; i < DSquare; i++)
+ {
+ state_2d[i >> Dq][i & Dr] = (byte)(((state[i >> 1] & 0xFF) >> (4 * (i & 1))) & 0xf);
+ }
+ for (int round = 0; round < ROUND; round++)
+ {
+ //AddKey
+ for (i = 0; i < D; i++)
+ {
+ state_2d[i][0] ^= RC[i][round];
+ }
+ //SubCell
+ for (i = 0; i < D; i++)
+ {
+ for (j = 0; j < D; j++)
+ {
+ state_2d[i][j] = sbox[state_2d[i][j]];
+ }
+ }
+ //ShiftRow
+ for (i = 1; i < D; i++)
+ {
+ Array.Copy(state_2d[i], 0, state, 0, D);
+ Array.Copy(state, i, state_2d[i], 0, D - i);
+ Array.Copy(state, 0, state_2d[i], D - i, i);
+ }
+ //MixColumn
+ for (j = 0; j < D; j++)
+ {
+ for (i = 0; i < D; i++)
+ {
+ byte sum = 0;
+ for (k = 0; k < D; k++)
+ {
+ int x = MixColMatrix[i][k], ret = 0, b = state_2d[k][j];
+ for (l = 0; l < S; l++)
+ {
+ if (((b >> l) & 1) != 0)
+ {
+ ret ^= x;
+ }
+ if (((x >> S_1) & 1) != 0)
+ {
+ x <<= 1;
+ x ^= 0x3;
+ }
+ else
+ {
+ x <<= 1;
+ }
+ }
+ sum ^= (byte)(ret & 15);
+ }
+ state[i] = sum;
+ }
+ for (i = 0; i < D; i++)
+ {
+ state_2d[i][j] = state[i];
+ }
+ }
+ }
+ for (i = 0; i < DSquare; i += 2)
+ {
+ state[i >> 1] = (byte)(((state_2d[i >> Dq][i & Dr] & 0xf)) | ((state_2d[i >> Dq][(i + 1) & Dr] & 0xf) << 4));
+ }
+ }
+
+ public int GetByteLength()
+ {
+ throw new NotImplementedException();
+ }
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+
+ public int DoFinal(Span<byte> output)
+ {
+ byte[] rv = new byte[32];
+ int rlt = DoFinal(rv, 0);
+ rv.AsSpan(0, 32).CopyTo(output);
+ return rlt;
+ }
+
+ public void BlockUpdate(ReadOnlySpan<byte> input)
+ {
+ buffer.Write(input.ToArray(), 0, input.Length);
+ }
+
+#endif
+ }
+}
diff --git a/crypto/src/crypto/digests/XoodyakDigest.cs b/crypto/src/crypto/digests/XoodyakDigest.cs
new file mode 100644
index 000000000..cf1afcc10
--- /dev/null
+++ b/crypto/src/crypto/digests/XoodyakDigest.cs
@@ -0,0 +1,207 @@
+using System;
+using System.IO;
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+ public class XoodyakDigest : IDigest
+ {
+ private byte[] state;
+ private int phase;
+ private MODE mode;
+ private int Rabsorb;
+ private const int f_bPrime = 48;
+ private const int Rkout = 24;
+ private const int PhaseDown = 1;
+ private const int PhaseUp = 2;
+ private const int NLANES = 12;
+ private const int NROWS = 3;
+ private const int NCOLUMS = 4;
+ private const int MAXROUNDS = 12;
+ private const int TAGLEN = 16;
+ private const int Rhash = 16;
+ const int Rkin = 44;
+ private readonly uint[] RC = {0x00000058, 0x00000038, 0x000003C0, 0x000000D0, 0x00000120, 0x00000014, 0x00000060,
+ 0x0000002C, 0x00000380, 0x000000F0, 0x000001A0, 0x00000012};
+ private MemoryStream buffer = new MemoryStream();
+ enum MODE
+ {
+ ModeHash,
+ ModeKeyed
+ }
+
+ public XoodyakDigest()
+ {
+ state = new byte[48];
+ Reset();
+ }
+
+ public string AlgorithmName => "Xoodyak Hash";
+
+ private void Up(byte[] Yi, int YiOff, int YiLen, uint Cu)
+ {
+ if (mode != MODE.ModeHash)
+ {
+ state[f_bPrime - 1] ^= (byte)Cu;
+ }
+ uint[] a = new uint[NLANES];
+ Pack.LE_To_UInt32(state, 0, a, 0, a.Length);
+ uint x, y;
+ uint[] b = new uint[NLANES];
+ uint[] p = new uint[NCOLUMS];
+ uint[] e = new uint[NCOLUMS];
+ for (int i = 0; i < MAXROUNDS; ++i)
+ {
+ /* Theta: Column Parity Mixer */
+ for (x = 0; x < NCOLUMS; ++x)
+ {
+ p[x] = a[index(x, 0)] ^ a[index(x, 1)] ^ a[index(x, 2)];
+ }
+ for (x = 0; x < NCOLUMS; ++x)
+ {
+ y = p[(x + 3) & 3];
+ e[x] = ROTL32(y, 5) ^ ROTL32(y, 14);
+ }
+ for (x = 0; x < NCOLUMS; ++x)
+ {
+ for (y = 0; y < NROWS; ++y)
+ {
+ a[index(x, y)] ^= e[x];
+ }
+ }
+ /* Rho-west: plane shift */
+ for (x = 0; x < NCOLUMS; ++x)
+ {
+ b[index(x, 0)] = a[index(x, 0)];
+ b[index(x, 1)] = a[index(x + 3, 1)];
+ b[index(x, 2)] = ROTL32(a[index(x, 2)], 11);
+ }
+ /* Iota: round ant */
+ b[0] ^= RC[i];
+ /* Chi: non linear layer */
+ for (x = 0; x < NCOLUMS; ++x)
+ {
+ for (y = 0; y < NROWS; ++y)
+ {
+ a[index(x, y)] = b[index(x, y)] ^ (~b[index(x, y + 1)] & b[index(x, y + 2)]);
+ }
+ }
+ /* Rho-east: plane shift */
+ for (x = 0; x < NCOLUMS; ++x)
+ {
+ b[index(x, 0)] = a[index(x, 0)];
+ b[index(x, 1)] = ROTL32(a[index(x, 1)], 1);
+ b[index(x, 2)] = ROTL32(a[index(x + 2, 2)], 8);
+ }
+ Array.Copy(b, 0, a, 0, NLANES);
+ }
+ Pack.UInt32_To_LE(a, 0, a.Length, state, 0);
+ phase = PhaseUp;
+ if (Yi != null)
+ {
+ Array.Copy(state, 0, Yi, YiOff, YiLen);
+ }
+ }
+
+ void Down(byte[] Xi, int XiOff, int XiLen, uint Cd)
+ {
+ for (int i = 0; i < XiLen; i++)
+ {
+ state[i] ^= Xi[XiOff++];
+ }
+ state[XiLen] ^= 0x01;
+ state[f_bPrime - 1] ^= (byte)((mode == MODE.ModeHash) ? (Cd & 0x01) : Cd);
+ phase = PhaseDown;
+ }
+
+ private uint index(uint x, uint y)
+ {
+ return (((y % NROWS) * NCOLUMS) + ((x) % NCOLUMS));
+ }
+
+ private uint ROTL32(uint a, int offset)
+ {
+ return (a << (offset & 31)) ^ (a >> ((32 - (offset)) & 31));
+ }
+
+ public void BlockUpdate(byte[] input, int inOff, int inLen)
+ {
+ if (inOff + inLen > input.Length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+ buffer.Write(input, inOff, inLen);
+ }
+
+ public int DoFinal(byte[] output, int outOff)
+ {
+ if (32 + outOff > output.Length)
+ {
+ throw new OutputLengthException("output buffer is too short");
+ }
+ byte[] input = buffer.GetBuffer();
+ int inLen = (int)buffer.Length;
+ int inOff = 0;
+ uint Cd = 0x03;
+ int splitLen;
+ do
+ {
+ if (phase != PhaseUp)
+ {
+ Up(null, 0, 0, 0);
+ }
+ splitLen = System.Math.Min(inLen, Rabsorb);
+ Down(input, inOff, splitLen, Cd);
+ Cd = 0;
+ inOff += splitLen;
+ inLen -= splitLen;
+ }
+ while (inLen != 0);
+ Up(output, outOff, TAGLEN, 0x40);
+ Down(null, 0, 0, 0);
+ Up(output, outOff + TAGLEN, TAGLEN, 0);
+ return 32;
+ }
+
+ public int GetByteLength()
+ {
+ throw new NotImplementedException();
+ }
+
+ public int GetDigestSize()
+ {
+ return 32;
+ }
+
+ public void Reset()
+ {
+ for (int i = 0; i < state.Length; ++i)
+ {
+ state[i] = 0;
+ }
+ phase = PhaseUp;
+ mode = MODE.ModeHash;
+ Rabsorb = Rhash;
+ buffer.SetLength(0);
+ }
+
+ public void Update(byte input)
+ {
+ buffer.Write(new byte[] { input }, 0, 1);
+ }
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public int DoFinal(Span<byte> output)
+ {
+ byte[] rv = new byte[32];
+ int rlt = DoFinal(rv, 0);
+ rv.AsSpan(0, 32).CopyTo(output);
+ return rlt;
+ }
+
+ public void BlockUpdate(ReadOnlySpan<byte> input)
+ {
+ buffer.Write(input.ToArray(), 0, input.Length);
+ }
+#endif
+ }
+}
diff --git a/crypto/src/crypto/encodings/OaepEncoding.cs b/crypto/src/crypto/encodings/OaepEncoding.cs
index 6871a039a..9ddaec779 100644
--- a/crypto/src/crypto/encodings/OaepEncoding.cs
+++ b/crypto/src/crypto/encodings/OaepEncoding.cs
@@ -74,7 +74,7 @@ namespace Org.BouncyCastle.Crypto.Encodings
}
else
{
- this.random = CryptoServicesRegistrar.GetSecureRandom();
+ this.random = forEncryption ? CryptoServicesRegistrar.GetSecureRandom() : null;
}
engine.Init(forEncryption, parameters);
@@ -285,24 +285,17 @@ namespace Org.BouncyCastle.Crypto.Encodings
return output;
}
- private byte[] MaskGeneratorFunction(
- byte[] Z,
- int zOff,
- int zLen,
- int length)
+ private byte[] MaskGeneratorFunction(byte[] Z, int zOff, int zLen, int length)
{
- if (mgf1Hash is IXof)
+ if (mgf1Hash is IXof xof)
{
byte[] mask = new byte[length];
- mgf1Hash.BlockUpdate(Z, zOff, zLen);
- ((IXof)mgf1Hash).OutputFinal(mask, 0, mask.Length);
-
+ xof.BlockUpdate(Z, zOff, zLen);
+ xof.OutputFinal(mask, 0, length);
return mask;
}
- else
- {
- return MaskGeneratorFunction1(Z, zOff, zLen, length);
- }
+
+ return MaskGeneratorFunction1(Z, zOff, zLen, length);
}
/**
diff --git a/crypto/src/crypto/encodings/Pkcs1Encoding.cs b/crypto/src/crypto/encodings/Pkcs1Encoding.cs
index 06e59d4f3..299d0ddb0 100644
--- a/crypto/src/crypto/encodings/Pkcs1Encoding.cs
+++ b/crypto/src/crypto/encodings/Pkcs1Encoding.cs
@@ -105,13 +105,13 @@ namespace Org.BouncyCastle.Crypto.Encodings
AsymmetricKeyParameter kParam;
if (parameters is ParametersWithRandom withRandom)
{
- this.random = withRandom.Random;
kParam = (AsymmetricKeyParameter)withRandom.Parameters;
+ this.random = withRandom.Random;
}
else
{
- this.random = CryptoServicesRegistrar.GetSecureRandom();
kParam = (AsymmetricKeyParameter)parameters;
+ this.random = forEncryption && !kParam.IsPrivate ? CryptoServicesRegistrar.GetSecureRandom() : null;
}
engine.Init(forEncryption, parameters);
@@ -119,9 +119,6 @@ namespace Org.BouncyCastle.Crypto.Encodings
this.forPrivateKey = kParam.IsPrivate;
this.forEncryption = forEncryption;
this.blockBuffer = new byte[engine.GetOutputBlockSize()];
-
- if (pLen > 0 && fallback == null && random == null)
- throw new ArgumentException("encoder requires random");
}
public int GetInputBlockSize()
@@ -259,15 +256,10 @@ namespace Org.BouncyCastle.Crypto.Encodings
throw new InvalidCipherTextException("sorry, this method is only for decryption, not for signing");
byte[] block = engine.ProcessBlock(input, inOff, inLen);
- byte[] random;
- if (this.fallback == null)
- {
- random = new byte[this.pLen];
- this.random.NextBytes(random);
- }
- else
+ byte[] fallbackResult = fallback;
+ if (fallbackResult == null)
{
- random = fallback;
+ fallbackResult = SecureRandom.GetNextBytes(SecureRandom.ArbitraryRandom, pLen);
}
byte[] data = (useStrictLength & (block.Length != engine.GetOutputBlockSize())) ? blockBuffer : block;
@@ -284,7 +276,7 @@ namespace Org.BouncyCastle.Crypto.Encodings
byte[] result = new byte[this.pLen];
for (int i = 0; i < this.pLen; i++)
{
- result[i] = (byte)((data[i + (data.Length - pLen)] & (~correct)) | (random[i] & correct));
+ result[i] = (byte)((data[i + (data.Length - pLen)] & (~correct)) | (fallbackResult[i] & correct));
}
Arrays.Fill(data, 0);
diff --git a/crypto/src/crypto/engines/AesEngine.cs b/crypto/src/crypto/engines/AesEngine.cs
index 914550d6d..3977cb893 100644
--- a/crypto/src/crypto/engines/AesEngine.cs
+++ b/crypto/src/crypto/engines/AesEngine.cs
@@ -1,5 +1,4 @@
using System;
-using System.Diagnostics;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Utilities;
@@ -37,7 +36,7 @@ namespace Org.BouncyCastle.Crypto.Engines
// The S box
private static readonly byte[] S =
{
- 99, 124, 119, 123, 242, 107, 111, 197,
+ 99, 124, 119, 123, 242, 107, 111, 197,
48, 1, 103, 43, 254, 215, 171, 118,
202, 130, 201, 125, 250, 89, 71, 240,
173, 212, 162, 175, 156, 164, 114, 192,
diff --git a/crypto/src/crypto/engines/AsconEngine.cs b/crypto/src/crypto/engines/AsconEngine.cs
new file mode 100644
index 000000000..281c4b0df
--- /dev/null
+++ b/crypto/src/crypto/engines/AsconEngine.cs
@@ -0,0 +1,693 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * ASCON AEAD v1.2, https://ascon.iaik.tugraz.at/
+ * https://csrc.nist.gov/CSRC/media/Projects/lightweight-cryptography/documents/finalist-round/updated-spec-doc/ascon-spec-final.pdf
+ * <p>
+ * ASCON AEAD v1.2 with reference to C Reference Impl from: https://github.com/ascon/ascon-c
+ * </p>
+ */
+ public class AsconEngine
+ : IAeadBlockCipher
+ {
+ public enum AsconParameters
+ {
+ ascon80pq,
+ ascon128a,
+ ascon128
+ }
+
+ private readonly AsconParameters asconParameters;
+ private readonly MemoryStream aadData = new MemoryStream();
+ private readonly MemoryStream message = new MemoryStream();
+ private bool encrypted;
+ private bool initialised;
+ private bool forEncryption;
+ private bool aadFinished;
+ private readonly int CRYPTO_KEYBYTES;
+ private readonly int CRYPTO_ABYTES;
+ private readonly int ASCON_AEAD_RATE;
+ private readonly int nr;
+ private byte[] mac;
+ private ulong K0;
+ private ulong K1;
+ private ulong K2;
+ private ulong N0;
+ private ulong N1;
+ private readonly ulong ASCON_IV;
+ private ulong x0;
+ private ulong x1;
+ private ulong x2;
+ private ulong x3;
+ private ulong x4;
+ private String algorithmName;
+
+ public IBlockCipher UnderlyingCipher => throw new NotImplementedException();
+
+ public string AlgorithmName => algorithmName;
+
+ public AsconEngine(AsconParameters asconParameters)
+ {
+ this.asconParameters = asconParameters;
+ switch (asconParameters)
+ {
+ case AsconParameters.ascon80pq:
+ CRYPTO_KEYBYTES = 20;
+ CRYPTO_ABYTES = 16;
+ ASCON_AEAD_RATE = 8;
+ ASCON_IV = 0xa0400c0600000000UL;
+ algorithmName = "Ascon-80pq AEAD";
+ break;
+ case AsconParameters.ascon128a:
+ CRYPTO_KEYBYTES = 16;
+ CRYPTO_ABYTES = 16;
+ ASCON_AEAD_RATE = 16;
+ ASCON_IV = 0x80800c0800000000UL;
+ algorithmName = "Ascon-128a AEAD";
+ break;
+ case AsconParameters.ascon128:
+ CRYPTO_KEYBYTES = 16;
+ CRYPTO_ABYTES = 16;
+ ASCON_AEAD_RATE = 8;
+ ASCON_IV = 0x80400c0600000000UL;
+ algorithmName = "Ascon-128 AEAD";
+ break;
+ default:
+ throw new ArgumentException("invalid parameter setting for ASCON AEAD");
+ }
+ nr = (ASCON_AEAD_RATE == 8) ? 6 : 8;
+ initialised = false;
+ }
+
+ private ulong U64BIG(ulong x)
+ {
+ return (((0x00000000000000FFUL & x) << 56) |
+ ((0x000000000000FF00UL & x) << 40) |
+ ((0x0000000000FF0000UL & x) << 24) |
+ ((0x00000000FF000000UL & x) << 8) |
+ ((0x000000FF00000000UL & x) >> 8) |
+ ((0x0000FF0000000000UL & x) >> 24) |
+ ((0x00FF000000000000UL & x) >> 40) |
+ ((0xFF00000000000000UL & x) >> 56));
+ }
+
+ private ulong ROR(ulong x, int n)
+ {
+ return x >> n | x << (64 - n);
+ }
+
+ private ulong KEYROT(ulong lo2hi, ulong hi2lo)
+ {
+ return lo2hi << 32 | hi2lo >> 32;
+ }
+
+ private ulong PAD(int i)
+ {
+ return 0x80UL << (56 - (i << 3));
+ }
+
+ private ulong MASK(int n)
+ {
+ /* undefined for n == 0 */
+ return ~0UL >> (64 - (n << 3));
+ }
+
+ private ulong LOAD(byte[] bytes, int inOff, int n)
+ {
+ ulong x = 0;
+ int len = System.Math.Min(8, bytes.Length - inOff);
+ for (int i = 0; i < len; ++i)
+ {
+ x |= (bytes[i + inOff] & 0xFFUL) << (i << 3);
+ }
+ return U64BIG(x & MASK(n));
+ }
+
+ private void STORE(byte[] bytes, int inOff, ulong w, int n)
+ {
+ ulong x = 0;
+ for (int i = 0; i < n; ++i)
+ {
+ x |= (bytes[i + inOff] & 0xFFUL) << (i << 3);
+ }
+ x &= ~MASK(n);
+ x |= U64BIG(w);
+ for (int i = 0; i < n; ++i)
+ {
+ bytes[i + inOff] = (byte)(x >> (i << 3));
+ }
+ }
+
+ private ulong LOADBYTES(byte[] bytes, int inOff, int n)
+ {
+ ulong x = 0;
+ for (int i = 0; i < n; ++i)
+ {
+ x |= (bytes[i + inOff] & 0xFFUL) << ((7 - i) << 3);
+ }
+ return x;
+ }
+
+ private void STOREBYTES(byte[] bytes, int inOff, ulong w, int n)
+ {
+ for (int i = 0; i < n; ++i)
+ {
+ bytes[i + inOff] = (byte)(w >> ((7 - i) << 3));
+ }
+ }
+
+ private void ROUND(ulong C)
+ {
+ ulong t0 = x0 ^ x1 ^ x2 ^ x3 ^ C ^ (x1 & (x0 ^ x2 ^ x4 ^ C));
+ ulong t1 = x0 ^ x2 ^ x3 ^ x4 ^ C ^ ((x1 ^ x2 ^ C) & (x1 ^ x3));
+ ulong t2 = x1 ^ x2 ^ x4 ^ C ^ (x3 & x4);
+ ulong t3 = x0 ^ x1 ^ x2 ^ C ^ ((~x0) & (x3 ^ x4));
+ ulong t4 = x1 ^ x3 ^ x4 ^ ((x0 ^ x4) & x1);
+ x0 = t0 ^ ROR(t0, 19) ^ ROR(t0, 28);
+ x1 = t1 ^ ROR(t1, 39) ^ ROR(t1, 61);
+ x2 = ~(t2 ^ ROR(t2, 1) ^ ROR(t2, 6));
+ x3 = t3 ^ ROR(t3, 10) ^ ROR(t3, 17);
+ x4 = t4 ^ ROR(t4, 7) ^ ROR(t4, 41);
+ }
+
+ private void P(int nr)
+ {
+ if (nr == 12)
+ {
+ ROUND(0xf0UL);
+ ROUND(0xe1UL);
+ ROUND(0xd2UL);
+ ROUND(0xc3UL);
+ }
+ if (nr >= 8)
+ {
+ ROUND(0xb4UL);
+ ROUND(0xa5UL);
+ }
+ ROUND(0x96UL);
+ ROUND(0x87UL);
+ ROUND(0x78UL);
+ ROUND(0x69UL);
+ ROUND(0x5aUL);
+ ROUND(0x4bUL);
+ }
+
+ private void ascon_aeadinit()
+ {
+ /* initialize */
+ x0 ^= ASCON_IV;
+ if (CRYPTO_KEYBYTES == 20)
+ {
+ x0 ^= K0;
+ }
+ x1 ^= K1;
+ x2 ^= K2;
+ x3 ^= N0;
+ x4 ^= N1;
+ P(12);
+ if (CRYPTO_KEYBYTES == 20)
+ {
+ x2 ^= K0;
+ }
+ x3 ^= K1;
+ x4 ^= K2;
+ }
+
+ private void ascon_adata(byte[] ad, int adOff, int adlen)
+ {
+ if (adlen != 0)
+ {
+ /* full associated data blocks */
+ while (adlen >= ASCON_AEAD_RATE)
+ {
+ x0 ^= LOAD(ad, adOff, 8);
+ if (ASCON_AEAD_RATE == 16)
+ {
+ x1 ^= LOAD(ad, adOff + 8, 8);
+ }
+ P(nr);
+ adOff += ASCON_AEAD_RATE;
+ adlen -= ASCON_AEAD_RATE;
+ }
+ /* readonly associated data block */
+ if (ASCON_AEAD_RATE == 16 && adlen >= 8)
+ {
+ x0 ^= LOAD(ad, adOff, 8);
+ adOff += 8;
+ adlen -= 8;
+ x1 ^= PAD(adlen);
+ if (adlen != 0)
+ {
+ x1 ^= LOAD(ad, adOff, adlen);
+ }
+ }
+ else
+ {
+ x0 ^= PAD(adlen);
+ if (adlen != 0)
+ {
+ x0 ^= LOAD(ad, adOff, adlen);
+ }
+ }
+ P(nr);
+ }
+ /* domain separation */
+ x4 ^= 1UL;
+ }
+
+ private void ascon_encrypt(byte[] c, int cOff, byte[] m, int mOff, int mlen)
+ {
+ /* full plaintext blocks */
+ while (mlen >= ASCON_AEAD_RATE)
+ {
+ x0 ^= LOAD(m, mOff, 8);
+ STORE(c, cOff, x0, 8);
+ if (ASCON_AEAD_RATE == 16)
+ {
+ x1 ^= LOAD(m, mOff + 8, 8);
+ STORE(c, cOff + 8, x1, 8);
+ }
+ P(nr);
+ mOff += ASCON_AEAD_RATE;
+ cOff += ASCON_AEAD_RATE;
+ mlen -= ASCON_AEAD_RATE;
+ }
+ }
+
+ private void ascon_decrypt(byte[] m, int mOff, byte[] c, int cOff, int clen)
+ {
+ /* full ciphertext blocks */
+ while (clen >= ASCON_AEAD_RATE)
+ {
+ ulong cx = LOAD(c, cOff, 8);
+ x0 ^= cx;
+ STORE(m, mOff, x0, 8);
+ x0 = cx;
+ if (ASCON_AEAD_RATE == 16)
+ {
+ cx = LOAD(c, cOff + 8, 8);
+ x1 ^= cx;
+ STORE(m, mOff + 8, x1, 8);
+ x1 = cx;
+ }
+ P(nr);
+ mOff += ASCON_AEAD_RATE;
+ cOff += ASCON_AEAD_RATE;
+ clen -= ASCON_AEAD_RATE;
+ }
+ }
+
+ private ulong CLEAR(ulong w, int n)
+ {
+ /* undefined for n == 0 */
+ ulong mask = 0x00ffffffffffffffUL >> (n * 8 - 8);
+ return w & mask;
+ }
+
+ private void ascon_final(byte[] c, int cOff, byte[] m, int mOff, int mlen)
+ {
+ if (forEncryption)
+ {
+ /* final plaintext block */
+ if (ASCON_AEAD_RATE == 16 && mlen >= 8)
+ {
+ x0 ^= LOAD(m, mOff, 8);
+ STORE(c, cOff, x0, 8);
+ mOff += 8;
+ cOff += 8;
+ mlen -= 8;
+ x1 ^= PAD(mlen);
+ if (mlen != 0)
+ {
+ x1 ^= LOAD(m, mOff, mlen);
+ STORE(c, cOff, x1, mlen);
+ }
+ }
+ else
+ {
+ x0 ^= PAD(mlen);
+ if (mlen != 0)
+ {
+ x0 ^= LOAD(m, mOff, mlen);
+ STORE(c, cOff, x0, mlen);
+ }
+ }
+ }
+ else
+ {
+ /* final ciphertext block */
+ if (ASCON_AEAD_RATE == 16 && mlen >= 8)
+ {
+ ulong cx = LOAD(m, mOff, 8);
+ x0 ^= cx;
+ STORE(c, cOff, x0, 8);
+ x0 = cx;
+ mOff += 8;
+ cOff += 8;
+ mlen -= 8;
+ x1 ^= PAD(mlen);
+ if (mlen != 0)
+ {
+ cx = LOAD(m, mOff, mlen);
+ x1 ^= cx;
+ STORE(c, cOff, x1, mlen);
+ x1 = CLEAR(x1, mlen);
+ x1 ^= cx;
+ }
+ }
+ else
+ {
+ x0 ^= PAD(mlen);
+ if (mlen != 0)
+ {
+ ulong cx = LOAD(m, mOff, mlen);
+ x0 ^= cx;
+ STORE(c, cOff, x0, mlen);
+ x0 = CLEAR(x0, mlen);
+ x0 ^= cx;
+ }
+ }
+ }
+ /* finalize */
+ switch (asconParameters)
+ {
+ case AsconParameters.ascon128:
+ x1 ^= K1;
+ x2 ^= K2;
+ break;
+ case AsconParameters.ascon128a:
+ x2 ^= K1;
+ x3 ^= K2;
+ break;
+ case AsconParameters.ascon80pq:
+ x1 ^= KEYROT(K0, K1);
+ x2 ^= KEYROT(K1, K2);
+ x3 ^= KEYROT(K2, 0UL);
+ break;
+ }
+ P(12);
+ x3 ^= K1;
+ x4 ^= K2;
+ }
+
+ public void Init(bool forEncryption, ICipherParameters param)
+ {
+ this.forEncryption = forEncryption;
+ if (!(param is ParametersWithIV))
+ {
+ throw new ArgumentException(
+ "ASCON init parameters must include an IV");
+ }
+ ParametersWithIV ivParams = (ParametersWithIV)param;
+ byte[] npub = ivParams.GetIV();
+ if (npub == null || npub.Length != CRYPTO_ABYTES)
+ {
+ throw new ArgumentException(asconParameters + " requires exactly " + CRYPTO_ABYTES + " bytes of IV");
+ }
+ if (!(ivParams.Parameters is KeyParameter))
+ {
+ throw new ArgumentException(
+ "ASCON init parameters must include a key");
+ }
+ KeyParameter key = (KeyParameter)ivParams.Parameters;
+ byte[] k = key.GetKey();
+ if (k.Length != CRYPTO_KEYBYTES)
+ {
+ throw new ArgumentException(asconParameters + " key must be " + CRYPTO_KEYBYTES + " bytes long");
+ }
+ N0 = LOAD(npub, 0, 8);
+ N1 = LOAD(npub, 8, 8);
+ if (CRYPTO_KEYBYTES == 16)
+ {
+ K1 = LOAD(k, 0, 8);
+ K2 = LOAD(k, 8, 8);
+ }
+ else if (CRYPTO_KEYBYTES == 20)
+ {
+ K0 = KEYROT(0, LOADBYTES(k, 0, 4));
+ K1 = LOADBYTES(k, 4, 8);
+ K2 = LOADBYTES(k, 12, 8);
+ }
+ initialised = true;
+ /*Mask-Gen*/
+ reset(false);
+ }
+
+ public void ProcessAadByte(byte input)
+ {
+ if (aadFinished)
+ {
+ throw new ArgumentException("AAD cannot be added after reading a full block(" + ASCON_AEAD_RATE +
+ " bytes) of input for " + (forEncryption ? "encryption" : "decryption"));
+ }
+ aadData.Write(new byte[] { input }, 0, 1);
+ }
+
+
+ public void ProcessAadBytes(byte[] input, int inOff, int len)
+ {
+ if (aadFinished)
+ {
+ throw new ArgumentException("AAD cannot be added after reading a full block(" + ASCON_AEAD_RATE +
+ " bytes) of input for " + (forEncryption ? "encryption" : "decryption"));
+ }
+ if ((inOff + len) > input.Length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+ aadData.Write(input, inOff, len);
+ }
+
+
+ public int ProcessByte(byte input, byte[] output, int outOff)
+ {
+ return ProcessBytes(new byte[] { input }, 0, 1, output, outOff);
+ }
+
+
+ public int ProcessBytes(byte[] input, int inOff, int len, byte[] output, int outOff)
+ {
+ if (!initialised)
+ {
+ throw new ArgumentException("Need call init function before encryption/decryption");
+ }
+ if ((inOff + len) > input.Length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+ message.Write(input, inOff, len);
+ int rv = processBytes(output, outOff);
+ encrypted = true;
+ return rv;
+ }
+
+ private void processAAD()
+ {
+ if (!aadFinished)
+ {
+ byte[] ad = aadData.GetBuffer();
+ int adlen = (int)aadData.Length;
+ /* perform ascon computation */
+ ascon_adata(ad, 0, adlen);
+ aadFinished = true;
+ }
+ }
+
+ private int processBytes(byte[] output, int outOff)
+ {
+ int len = 0;
+ if (forEncryption)
+ {
+ if ((int)message.Length >= ASCON_AEAD_RATE)
+ {
+ processAAD();
+ byte[] input = message.GetBuffer();
+ len = ((int)message.Length / ASCON_AEAD_RATE) * ASCON_AEAD_RATE;
+ if (len + outOff > output.Length)
+ {
+ throw new OutputLengthException("output buffer is too short");
+ }
+ ascon_encrypt(output, outOff, input, 0, len);
+ int len_orig = (int)message.Length;
+ message.SetLength(0);
+ message.Write(input, len, len_orig - len);
+ }
+ }
+ else
+ {
+ if ((int)message.Length - CRYPTO_ABYTES >= ASCON_AEAD_RATE)
+ {
+ processAAD();
+ byte[] input = message.GetBuffer();
+ len = (((int)message.Length - CRYPTO_ABYTES) / ASCON_AEAD_RATE) * ASCON_AEAD_RATE;
+ if (len + outOff > output.Length)
+ {
+ throw new OutputLengthException("output buffer is too short");
+ }
+ ascon_decrypt(output, outOff, input, 0, len);
+ int len_orig = (int)message.Length;
+ message.SetLength(0);
+ message.Write(input, len, len_orig - len);
+ }
+ }
+ return len;
+ }
+
+ public int DoFinal(byte[] output, int outOff)
+ {
+ if (!initialised)
+ {
+ throw new ArgumentException("Need call init function before encryption/decryption");
+ }
+ if (!aadFinished)
+ {
+ processAAD();
+ }
+ if (!encrypted)
+ {
+ ProcessBytes(new byte[] { }, 0, 0, new byte[] { }, 0);
+ }
+ byte[] input = message.GetBuffer();
+ int len = (int)message.Length;
+ if ((forEncryption && outOff + len + CRYPTO_ABYTES > output.Length) ||
+ (!forEncryption && outOff + len - CRYPTO_ABYTES > output.Length))
+ {
+ throw new OutputLengthException("output buffer too short");
+ }
+ if (forEncryption)
+ {
+ ascon_final(output, outOff, input, 0, len);
+ /* set tag */
+ mac = new byte[16];
+ STOREBYTES(mac, 0, x3, 8);
+ STOREBYTES(mac, 8, x4, 8);
+ Array.Copy(mac, 0, output, len + outOff, 16);
+ reset(false);
+ return len + CRYPTO_ABYTES;
+ }
+ else
+ {
+ len -= CRYPTO_ABYTES;
+ ascon_final(output, outOff, input, 0, len);
+ x3 ^= LOADBYTES(input, len, 8);
+ x4 ^= LOADBYTES(input, len + 8, 8);
+ ulong result = x3 | x4;
+ result |= result >> 32;
+ result |= result >> 16;
+ result |= result >> 8;
+ reset(true);
+ if ((((((int)(result & 0xffUL) - 1) >> 8) & 1) - 1) != 0)
+ {
+ throw new ArgumentException("Mac does not match");
+ }
+ return len;
+ }
+ }
+
+
+ public byte[] GetMac()
+ {
+ return mac;
+ }
+
+
+ public int GetUpdateOutputSize(int len)
+ {
+ return len;
+ }
+
+ public int GetOutputSize(int len)
+ {
+ return len + CRYPTO_ABYTES;
+ }
+
+ public void Reset()
+ {
+ reset(true);
+ }
+
+ private void reset(bool clearMac)
+ {
+ if (!initialised)
+ {
+ throw new ArgumentException("Need call init function before encryption/decryption");
+ }
+ x0 = x1 = x2 = x3 = x4 = 0;
+ ascon_aeadinit();
+ aadData.SetLength(0);
+ message.SetLength(0);
+ encrypted = false;
+ aadFinished = false;
+ if (clearMac)
+ {
+ mac = null;
+ }
+ }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public void ProcessAadBytes(ReadOnlySpan<byte> input)
+ {
+ if (aadFinished)
+ {
+ throw new ArgumentException("AAD cannot be added after reading a full block(" + ASCON_AEAD_RATE +
+ " bytes) of input for " + (forEncryption ? "encryption" : "decryption"));
+ }
+ aadData.Write(input);
+ }
+
+ public int ProcessByte(byte input, Span<byte> output)
+ {
+ byte[] rv = new byte[1];
+ int len = ProcessBytes(new byte[] { input }, 0, 1, rv, 0);
+ rv.AsSpan(0, len).CopyTo(output);
+ return len;
+ }
+
+ public int ProcessBytes(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ byte[] rv = new byte[input.Length];
+ int len = ProcessBytes(input.ToArray(), 0, rv.Length, rv, 0);
+ rv.AsSpan(0, len).CopyTo(output);
+ return len;
+ }
+
+ public int DoFinal(Span<byte> output)
+ {
+ byte[] rv;
+ if (forEncryption)
+ {
+ rv = new byte[message.Length + 16];
+ }
+ else
+ {
+ rv = new byte[message.Length];
+ }
+ int len = DoFinal(rv, 0);
+ rv.AsSpan(0, len).CopyTo(output);
+ return rv.Length;
+ }
+#endif
+ public int GetBlockSize()
+ {
+ return ASCON_AEAD_RATE;
+ }
+
+ public int GetKeyBytesSize()
+ {
+ return CRYPTO_KEYBYTES;
+ }
+
+ public int GetIVBytesSize()
+ {
+ return CRYPTO_ABYTES;
+ }
+ }
+}
+
+
diff --git a/crypto/src/crypto/engines/DesEdeWrapEngine.cs b/crypto/src/crypto/engines/DesEdeWrapEngine.cs
index 07f751ab9..3115f65dc 100644
--- a/crypto/src/crypto/engines/DesEdeWrapEngine.cs
+++ b/crypto/src/crypto/engines/DesEdeWrapEngine.cs
@@ -52,45 +52,40 @@ namespace Org.BouncyCastle.Crypto.Engines
* @param forWrapping
* @param param
*/
- public virtual void Init(
- bool forWrapping,
- ICipherParameters parameters)
+ public virtual void Init(bool forWrapping, ICipherParameters parameters)
{
this.forWrapping = forWrapping;
this.engine = new CbcBlockCipher(new DesEdeEngine());
- SecureRandom sr;
+ SecureRandom random = null;
if (parameters is ParametersWithRandom pr)
{
parameters = pr.Parameters;
- sr = pr.Random;
- }
- else
- {
- sr = CryptoServicesRegistrar.GetSecureRandom();
+ random = pr.Random;
}
- if (parameters is KeyParameter)
+ if (parameters is KeyParameter keyParameter)
{
- this.param = (KeyParameter) parameters;
+ this.param = keyParameter;
if (this.forWrapping)
{
// Hm, we have no IV but we want to wrap ?!?
// well, then we have to create our own IV.
this.iv = new byte[8];
- sr.NextBytes(iv);
+
+ CryptoServicesRegistrar.GetSecureRandom(random).NextBytes(iv);
this.paramPlusIV = new ParametersWithIV(this.param, this.iv);
}
}
- else if (parameters is ParametersWithIV)
+ else if (parameters is ParametersWithIV withIV)
{
if (!forWrapping)
throw new ArgumentException("You should not supply an IV for unwrapping");
- this.paramPlusIV = (ParametersWithIV) parameters;
- this.iv = this.paramPlusIV.GetIV();
- this.param = (KeyParameter) this.paramPlusIV.Parameters;
+ this.paramPlusIV = withIV;
+ this.iv = withIV.GetIV();
+ this.param = (KeyParameter)withIV.Parameters;
if (this.iv.Length != 8)
throw new ArgumentException("IV is not 8 octets", "parameters");
diff --git a/crypto/src/crypto/engines/ElGamalEngine.cs b/crypto/src/crypto/engines/ElGamalEngine.cs
index ea5e5bc30..8903f495e 100644
--- a/crypto/src/crypto/engines/ElGamalEngine.cs
+++ b/crypto/src/crypto/engines/ElGamalEngine.cs
@@ -3,6 +3,7 @@ using System;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Engines
{
@@ -38,7 +39,7 @@ namespace Org.BouncyCastle.Crypto.Engines
else
{
this.key = (ElGamalKeyParameters)parameters;
- this.random = CryptoServicesRegistrar.GetSecureRandom();
+ this.random = forEncryption ? CryptoServicesRegistrar.GetSecureRandom() : null;
}
this.forEncryption = forEncryption;
@@ -157,14 +158,12 @@ namespace Org.BouncyCastle.Crypto.Engines
output = new byte[this.GetOutputBlockSize()];
- // TODO Add methods to allow writing BigInteger to existing byte array?
- byte[] out1 = gamma.ToByteArrayUnsigned();
- byte[] out2 = phi.ToByteArrayUnsigned();
- out1.CopyTo(output, output.Length / 2 - out1.Length);
- out2.CopyTo(output, output.Length - out2.Length);
- }
+ int mid = output.Length / 2;
+ BigIntegers.AsUnsignedByteArray(gamma, output, 0, mid);
+ BigIntegers.AsUnsignedByteArray(phi, output, mid, output.Length - mid);
+ }
- return output;
+ return output;
}
}
}
diff --git a/crypto/src/crypto/engines/ElephantEngine.cs b/crypto/src/crypto/engines/ElephantEngine.cs
new file mode 100644
index 000000000..d5f05f658
--- /dev/null
+++ b/crypto/src/crypto/engines/ElephantEngine.cs
@@ -0,0 +1,594 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * Elephant AEAD v2, based on the current round 3 submission, https://www.esat.kuleuven.be/cosic/elephant/
+ * Reference C implementation: https://github.com/TimBeyne/Elephant
+ * Specification: https://csrc.nist.gov/CSRC/media/Projects/lightweight-cryptography/documents/finalist-round/updated-spec-doc/elephant-spec-final.pdf
+ */
+ public class ElephantEngine
+ : IAeadBlockCipher
+ {
+ public enum ElephantParameters
+ {
+ elephant160,
+ elephant176,
+ elephant200
+ }
+
+ private bool forEncryption;
+ private readonly string algorithmName;
+ private ElephantParameters parameters;
+ private int BLOCK_SIZE;
+ private int nBits;
+ private int nSBox;
+ private int nRounds;
+ private byte lfsrIV;
+ private byte[] npub;
+ private byte[] expanded_key;
+ private byte[] tag;
+ private byte CRYPTO_KEYBYTES = 16;
+ private byte CRYPTO_NPUBBYTES = 12;
+ private byte CRYPTO_ABYTES;
+ private bool initialised;
+ private MemoryStream aadData = new MemoryStream();
+ private MemoryStream message = new MemoryStream();
+
+ private readonly byte[] sBoxLayer = {
+ (byte)0xee, (byte)0xed, (byte)0xeb, (byte)0xe0, (byte)0xe2, (byte)0xe1, (byte)0xe4, (byte)0xef, (byte)0xe7, (byte)0xea, (byte)0xe8, (byte)0xe5, (byte)0xe9, (byte)0xec, (byte)0xe3, (byte)0xe6,
+ (byte)0xde, (byte)0xdd, (byte)0xdb, (byte)0xd0, (byte)0xd2, (byte)0xd1, (byte)0xd4, (byte)0xdf, (byte)0xd7, (byte)0xda, (byte)0xd8, (byte)0xd5, (byte)0xd9, (byte)0xdc, (byte)0xd3, (byte)0xd6,
+ (byte)0xbe, (byte)0xbd, (byte)0xbb, (byte)0xb0, (byte)0xb2, (byte)0xb1, (byte)0xb4, (byte)0xbf, (byte)0xb7, (byte)0xba, (byte)0xb8, (byte)0xb5, (byte)0xb9, (byte)0xbc, (byte)0xb3, (byte)0xb6,
+ (byte)0x0e, (byte)0x0d, (byte)0x0b, (byte)0x00, (byte)0x02, (byte)0x01, (byte)0x04, (byte)0x0f, (byte)0x07, (byte)0x0a, (byte)0x08, (byte)0x05, (byte)0x09, (byte)0x0c, (byte)0x03, (byte)0x06,
+ (byte)0x2e, (byte)0x2d, (byte)0x2b, (byte)0x20, (byte)0x22, (byte)0x21, (byte)0x24, (byte)0x2f, (byte)0x27, (byte)0x2a, (byte)0x28, (byte)0x25, (byte)0x29, (byte)0x2c, (byte)0x23, (byte)0x26,
+ (byte)0x1e, (byte)0x1d, (byte)0x1b, (byte)0x10, (byte)0x12, (byte)0x11, (byte)0x14, (byte)0x1f, (byte)0x17, (byte)0x1a, (byte)0x18, (byte)0x15, (byte)0x19, (byte)0x1c, (byte)0x13, (byte)0x16,
+ (byte)0x4e, (byte)0x4d, (byte)0x4b, (byte)0x40, (byte)0x42, (byte)0x41, (byte)0x44, (byte)0x4f, (byte)0x47, (byte)0x4a, (byte)0x48, (byte)0x45, (byte)0x49, (byte)0x4c, (byte)0x43, (byte)0x46,
+ (byte)0xfe, (byte)0xfd, (byte)0xfb, (byte)0xf0, (byte)0xf2, (byte)0xf1, (byte)0xf4, (byte)0xff, (byte)0xf7, (byte)0xfa, (byte)0xf8, (byte)0xf5, (byte)0xf9, (byte)0xfc, (byte)0xf3, (byte)0xf6,
+ (byte)0x7e, (byte)0x7d, (byte)0x7b, (byte)0x70, (byte)0x72, (byte)0x71, (byte)0x74, (byte)0x7f, (byte)0x77, (byte)0x7a, (byte)0x78, (byte)0x75, (byte)0x79, (byte)0x7c, (byte)0x73, (byte)0x76,
+ (byte)0xae, (byte)0xad, (byte)0xab, (byte)0xa0, (byte)0xa2, (byte)0xa1, (byte)0xa4, (byte)0xaf, (byte)0xa7, (byte)0xaa, (byte)0xa8, (byte)0xa5, (byte)0xa9, (byte)0xac, (byte)0xa3, (byte)0xa6,
+ (byte)0x8e, (byte)0x8d, (byte)0x8b, (byte)0x80, (byte)0x82, (byte)0x81, (byte)0x84, (byte)0x8f, (byte)0x87, (byte)0x8a, (byte)0x88, (byte)0x85, (byte)0x89, (byte)0x8c, (byte)0x83, (byte)0x86,
+ (byte)0x5e, (byte)0x5d, (byte)0x5b, (byte)0x50, (byte)0x52, (byte)0x51, (byte)0x54, (byte)0x5f, (byte)0x57, (byte)0x5a, (byte)0x58, (byte)0x55, (byte)0x59, (byte)0x5c, (byte)0x53, (byte)0x56,
+ (byte)0x9e, (byte)0x9d, (byte)0x9b, (byte)0x90, (byte)0x92, (byte)0x91, (byte)0x94, (byte)0x9f, (byte)0x97, (byte)0x9a, (byte)0x98, (byte)0x95, (byte)0x99, (byte)0x9c, (byte)0x93, (byte)0x96,
+ (byte)0xce, (byte)0xcd, (byte)0xcb, (byte)0xc0, (byte)0xc2, (byte)0xc1, (byte)0xc4, (byte)0xcf, (byte)0xc7, (byte)0xca, (byte)0xc8, (byte)0xc5, (byte)0xc9, (byte)0xcc, (byte)0xc3, (byte)0xc6,
+ (byte)0x3e, (byte)0x3d, (byte)0x3b, (byte)0x30, (byte)0x32, (byte)0x31, (byte)0x34, (byte)0x3f, (byte)0x37, (byte)0x3a, (byte)0x38, (byte)0x35, (byte)0x39, (byte)0x3c, (byte)0x33, (byte)0x36,
+ (byte)0x6e, (byte)0x6d, (byte)0x6b, (byte)0x60, (byte)0x62, (byte)0x61, (byte)0x64, (byte)0x6f, (byte)0x67, (byte)0x6a, (byte)0x68, (byte)0x65, (byte)0x69, (byte)0x6c, (byte)0x63, (byte)0x66
+ };
+
+ private readonly byte[] KeccakRoundConstants = {
+ (byte)0x01, (byte)0x82, (byte)0x8a, (byte)0x00, (byte)0x8b, (byte)0x01, (byte)0x81, (byte)0x09, (byte)0x8a,
+ (byte)0x88, (byte)0x09, (byte)0x0a, (byte)0x8b, (byte)0x8b, (byte)0x89, (byte)0x03, (byte)0x02, (byte)0x80
+ };
+
+ private readonly int[] KeccakRhoOffsets = { 0, 1, 6, 4, 3, 4, 4, 6, 7, 4, 3, 2, 3, 1, 7, 1, 5, 7, 5, 0, 2, 2, 5, 0, 6 };
+
+ public ElephantEngine(ElephantParameters parameters)
+ {
+ switch (parameters)
+ {
+ case ElephantParameters.elephant160:
+ BLOCK_SIZE = 20;
+ nBits = 160;
+ nSBox = 20;
+ nRounds = 80;
+ lfsrIV = 0x75;
+ CRYPTO_ABYTES = 8;
+ algorithmName = "Elephant 160 AEAD";
+ break;
+ case ElephantParameters.elephant176:
+ BLOCK_SIZE = 22;
+ nBits = 176;
+ nSBox = 22;
+ nRounds = 90;
+ lfsrIV = 0x45;
+ CRYPTO_ABYTES = 8;
+ algorithmName = "Elephant 176 AEAD";
+ break;
+ case ElephantParameters.elephant200:
+ BLOCK_SIZE = 25;
+ nRounds = 18;
+ CRYPTO_ABYTES = 16;
+ algorithmName = "Elephant 200 AEAD";
+ break;
+ default:
+ throw new ArgumentException("Invalid parameter settings for Elephant");
+ }
+ this.parameters = parameters;
+ initialised = false;
+ reset(false);
+ }
+
+ private void permutation(byte[] state)
+ {
+ switch (parameters)
+ {
+ case ElephantParameters.elephant160:
+ case ElephantParameters.elephant176:
+ byte IV = lfsrIV;
+ byte[] tmp = new byte[nSBox];
+ for (int i = 0; i < nRounds; i++)
+ {
+ /* Add counter values */
+ state[0] ^= IV;
+ state[nSBox - 1] ^= (byte)(((IV & 0x01) << 7) | ((IV & 0x02) << 5) | ((IV & 0x04) << 3) | ((IV & 0x08)
+ << 1) | ((IV & 0x10) >> 1) | ((IV & 0x20) >> 3) | ((IV & 0x40) >> 5) | ((IV & 0x80) >> 7));
+ IV = (byte)(((IV << 1) | (((0x40 & IV) >> 6) ^ ((0x20 & IV) >> 5))) & 0x7f);
+ /* sBoxLayer layer */
+ for (int j = 0; j < nSBox; j++)
+ {
+ state[j] = sBoxLayer[(state[j] & 0xFF)];
+ }
+ /* pLayer */
+ int PermutedBitNo;
+ Arrays.Fill(tmp, (byte)0);
+ for (int j = 0; j < nSBox; j++)
+ {
+ for (int k = 0; k < 8; k++)
+ {
+ PermutedBitNo = (j << 3) + k;
+ if (PermutedBitNo != nBits - 1)
+ {
+ PermutedBitNo = ((PermutedBitNo * nBits) >> 2) % (nBits - 1);
+ }
+ tmp[PermutedBitNo >> 3] ^= (byte)((((state[j] & 0xFF) >> k) & 0x1) << (PermutedBitNo & 7));
+ }
+ }
+ Array.Copy(tmp, 0, state, 0, nSBox);
+ }
+ break;
+ case ElephantParameters.elephant200:
+ for (int i = 0; i < nRounds; i++)
+ {
+ KeccakP200Round(state, i);
+ }
+ break;
+ }
+ }
+
+ private byte rotl(byte b)
+ {
+ return (byte)(((b & 0xFF) << 1) | ((b & 0xFF) >> 7));
+ }
+
+ private byte ROL8(byte a, int offset)
+ {
+ return (byte)((offset != 0) ? (((a & 0xFF) << offset) ^ ((a & 0xFF) >> (8 - offset))) : a);
+ }
+
+ private int index(int x, int y)
+ {
+ return x + y * 5;
+ }
+
+ private void KeccakP200Round(byte[] state, int indexRound)
+ {
+ int x, y;
+ byte[] tempA = new byte[25];
+ //theta
+ for (x = 0; x < 5; x++)
+ {
+ for (y = 0; y < 5; y++)
+ {
+ tempA[x] ^= state[index(x, y)];
+ }
+ }
+ for (x = 0; x < 5; x++)
+ {
+ tempA[x + 5] = (byte)(ROL8(tempA[(x + 1) % 5], 1) ^ tempA[(x + 4) % 5]);
+ }
+ for (x = 0; x < 5; x++)
+ {
+ for (y = 0; y < 5; y++)
+ {
+ state[index(x, y)] ^= tempA[x + 5];
+ }
+ }
+ //rho
+ for (x = 0; x < 5; x++)
+ {
+ for (y = 0; y < 5; y++)
+ {
+ tempA[index(x, y)] = ROL8(state[index(x, y)], KeccakRhoOffsets[index(x, y)]);
+ }
+ }
+ //pi
+ for (x = 0; x < 5; x++)
+ {
+ for (y = 0; y < 5; y++)
+ {
+ state[index(y, (2 * x + 3 * y) % 5)] = tempA[index(x, y)];
+ }
+ }
+ //chi
+ for (y = 0; y < 5; y++)
+ {
+ for (x = 0; x < 5; x++)
+ {
+ tempA[x] = (byte)(state[index(x, y)] ^ ((~state[index((x + 1) % 5, y)]) & state[index((x + 2) % 5, y)]));
+ }
+ for (x = 0; x < 5; x++)
+ {
+ state[index(x, y)] = tempA[x];
+ }
+ }
+ //iota
+ state[index(0, 0)] ^= KeccakRoundConstants[indexRound];
+ }
+
+
+ // State should be BLOCK_SIZE bytes long
+ // Note: input may be equal to output
+ private void lfsr_step(byte[] output, byte[] input)
+ {
+ switch (parameters)
+ {
+ case ElephantParameters.elephant160:
+ output[BLOCK_SIZE - 1] = (byte)((((input[0] & 0xFF) << 3) | ((input[0] & 0xFF) >> 5)) ^
+ ((input[3] & 0xFF) << 7) ^ ((input[13] & 0xFF) >> 7));
+ break;
+ case ElephantParameters.elephant176:
+ output[BLOCK_SIZE - 1] = (byte)(rotl(input[0]) ^ ((input[3] & 0xFF) << 7) ^ ((input[19] & 0xFF) >> 7));
+ break;
+ case ElephantParameters.elephant200:
+ output[BLOCK_SIZE - 1] = (byte)(rotl(input[0]) ^ rotl(input[2]) ^ (input[13] << 1));
+ break;
+ }
+ Array.Copy(input, 1, output, 0, BLOCK_SIZE - 1);
+ }
+
+ private void xor_block(byte[] state, byte[] block, int bOff, int size)
+ {
+ for (int i = 0; i < size; ++i)
+ {
+ state[i] ^= block[i + bOff];
+ }
+ }
+
+ // Write the ith assocated data block to "output".
+ // The nonce is prepended and padding is added as required.
+ // adlen is the length of the associated data in bytes
+ private void get_ad_block(byte[] output, byte[] ad, int adlen, byte[] npub, int i)
+ {
+ int len = 0;
+ // First block contains nonce
+ // Remark: nonce may not be longer then BLOCK_SIZE
+ if (i == 0)
+ {
+ Array.Copy(npub, 0, output, 0, CRYPTO_NPUBBYTES);
+ len += CRYPTO_NPUBBYTES;
+ }
+ int block_offset = i * BLOCK_SIZE - ((i != 0) ? 1 : 0) * CRYPTO_NPUBBYTES;
+ // If adlen is divisible by BLOCK_SIZE, add an additional padding block
+ if (i != 0 && block_offset == adlen)
+ {
+ Arrays.Fill(output, 0, BLOCK_SIZE, (byte)0);
+ output[0] = 0x01;
+ return;
+ }
+ int r_outlen = BLOCK_SIZE - len;
+ int r_adlen = adlen - block_offset;
+ // Fill with associated data if available
+ if (r_outlen <= r_adlen)
+ { // enough AD
+ Array.Copy(ad, block_offset, output, len, r_outlen);
+ }
+ else
+ { // not enough AD, need to pad
+ if (r_adlen > 0) // ad might be nullptr
+ {
+ Array.Copy(ad, block_offset, output, len, r_adlen);
+ }
+ Arrays.Fill(output, len + r_adlen, len + r_outlen, (byte)0);
+ output[len + r_adlen] = 0x01;
+ }
+ }
+
+ // Return the ith ciphertext block.
+ // clen is the length of the ciphertext in bytes
+ private void get_c_block(byte[] output, byte[] c, int cOff, int clen, int i)
+ {
+ int block_offset = i * BLOCK_SIZE;
+ // If clen is divisible by BLOCK_SIZE, add an additional padding block
+ if (block_offset == clen)
+ {
+ Arrays.Fill(output, 0, BLOCK_SIZE, (byte)0);
+ output[0] = 0x01;
+ return;
+ }
+ int r_clen = clen - block_offset;
+ // Fill with ciphertext if available
+ if (BLOCK_SIZE <= r_clen)
+ { // enough ciphertext
+ Array.Copy(c, cOff + block_offset, output, 0, BLOCK_SIZE);
+ }
+ else
+ { // not enough ciphertext, need to pad
+ if (r_clen > 0) // c might be nullptr
+ {
+ Array.Copy(c, cOff + block_offset, output, 0, r_clen);
+ }
+ Arrays.Fill(output, r_clen, BLOCK_SIZE, (byte)0);
+ output[r_clen] = 0x01;
+ }
+ }
+
+
+
+ public void Init(bool forEncryption, ICipherParameters param)
+ {
+ this.forEncryption = forEncryption;
+ if (!(param is ParametersWithIV))
+ {
+ throw new ArgumentException(
+ "Elephant init parameters must include an IV");
+ }
+
+ ParametersWithIV ivParams = (ParametersWithIV)param;
+
+ npub = ivParams.GetIV();
+
+ if (npub == null || npub.Length != 12)
+ {
+ throw new ArgumentException(
+ "Elephant requires exactly 12 bytes of IV");
+ }
+
+ if (!(ivParams.Parameters is KeyParameter))
+ {
+ throw new ArgumentException(
+ "Elephant init parameters must include a key");
+ }
+
+ KeyParameter key = (KeyParameter)ivParams.Parameters;
+ byte[] k = key.GetKey();
+ if (k.Length != 16)
+ {
+ throw new ArgumentException(
+ "Elephant key must be 128 bits long");
+ }
+ // Storage for the expanded key L
+ expanded_key = new byte[BLOCK_SIZE];
+ Array.Copy(k, 0, expanded_key, 0, CRYPTO_KEYBYTES);
+ permutation(expanded_key);
+ initialised = true;
+ reset(false);
+ }
+
+
+ public string AlgorithmName => algorithmName;
+
+ public IBlockCipher UnderlyingCipher => throw new NotImplementedException();
+
+ public void ProcessAadByte(byte input)
+ {
+ aadData.Write(new byte[] { input }, 0, 1);
+ }
+
+
+ public void ProcessAadBytes(byte[] input, int inOff, int len)
+ {
+ if (inOff + len > input.Length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+ aadData.Write(input, inOff, len);
+ }
+
+
+ public int ProcessByte(byte input, byte[] output, int outOff)
+ {
+ message.Write(new byte[] { input }, 0, 1);
+ return 0;
+ }
+
+
+ public int ProcessBytes(byte[] input, int inOff, int len, byte[] output, int outOff)
+ {
+ if (inOff + len > input.Length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+ message.Write(input, inOff, len);
+ return 0;
+ }
+
+
+ public int DoFinal(byte[] output, int outOff)
+ {
+ if (!initialised)
+ {
+ throw new ArgumentException("Need call init function before encryption/decryption");
+ }
+ int mlen = (int)message.Length - (forEncryption ? 0 : CRYPTO_ABYTES);
+ if ((forEncryption && mlen + outOff + CRYPTO_ABYTES > output.Length) ||
+ (!forEncryption && mlen + outOff - CRYPTO_ABYTES > output.Length))
+ {
+ throw new OutputLengthException("output buffer is too short");
+ }
+ byte[] tag_buffer = new byte[BLOCK_SIZE];
+ byte[] m = message.GetBuffer();
+ byte[] ad = aadData.GetBuffer();
+ int adlen = (int)aadData.Length;
+ int nblocks_c = 1 + mlen / BLOCK_SIZE;
+ int nblocks_m = (mlen % BLOCK_SIZE) != 0 ? nblocks_c : nblocks_c - 1;
+ int nblocks_ad = 1 + (CRYPTO_NPUBBYTES + adlen) / BLOCK_SIZE;
+ int nb_it = System.Math.Max(nblocks_c + 1, nblocks_ad - 1);
+ // Buffers for storing previous, current and next mask
+ byte[] previous_mask = new byte[BLOCK_SIZE];
+ byte[] current_mask = new byte[BLOCK_SIZE];
+ byte[] next_mask = new byte[BLOCK_SIZE];
+ Array.Copy(expanded_key, 0, current_mask, 0, BLOCK_SIZE);
+ // Buffer to store current ciphertext/AD block
+ byte[] buffer = new byte[BLOCK_SIZE];
+ // Tag buffer and initialization of tag to first AD block
+ get_ad_block(tag_buffer, ad, adlen, npub, 0);
+ int offset = 0;
+ for (int i = 0; i < nb_it; ++i)
+ {
+ // Compute mask for the next message
+ lfsr_step(next_mask, current_mask);
+ if (i < nblocks_m)
+ {
+ // Compute ciphertext block
+ Array.Copy(npub, 0, buffer, 0, CRYPTO_NPUBBYTES);
+ Arrays.Fill(buffer, CRYPTO_NPUBBYTES, BLOCK_SIZE, (byte)0);
+ xor_block(buffer, current_mask, 0, BLOCK_SIZE);
+ xor_block(buffer, next_mask, 0, BLOCK_SIZE);
+ permutation(buffer);
+ xor_block(buffer, current_mask, 0, BLOCK_SIZE);
+ xor_block(buffer, next_mask, 0, BLOCK_SIZE);
+ int r_size = (i == nblocks_m - 1) ? mlen - offset : BLOCK_SIZE;
+ xor_block(buffer, m, offset, r_size);
+ Array.Copy(buffer, 0, output, offset + outOff, r_size);
+ }
+ if (i > 0 && i <= nblocks_c)
+ {
+ // Compute tag for ciphertext block
+ if (forEncryption)
+ {
+ get_c_block(buffer, output, outOff, mlen, i - 1);
+ }
+ else
+ {
+ get_c_block(buffer, m, 0, mlen, i - 1);
+ }
+ xor_block(buffer, previous_mask, 0, BLOCK_SIZE);
+ xor_block(buffer, next_mask, 0, BLOCK_SIZE);
+ permutation(buffer);
+ xor_block(buffer, previous_mask, 0, BLOCK_SIZE);
+ xor_block(buffer, next_mask, 0, BLOCK_SIZE);
+ xor_block(tag_buffer, buffer, 0, BLOCK_SIZE);
+ }
+ // If there is any AD left, compute tag for AD block
+ if (i + 1 < nblocks_ad)
+ {
+ get_ad_block(buffer, ad, adlen, npub, i + 1);
+ xor_block(buffer, next_mask, 0, BLOCK_SIZE);
+ permutation(buffer);
+ xor_block(buffer, next_mask, 0, BLOCK_SIZE);
+ xor_block(tag_buffer, buffer, 0, BLOCK_SIZE);
+ }
+ // Cyclically shift the mask buffers
+ // Value of next_mask will be computed in the next iteration
+ byte[] temp = previous_mask;
+ previous_mask = current_mask;
+ current_mask = next_mask;
+ next_mask = temp;
+ offset += BLOCK_SIZE;
+ }
+ outOff += mlen;
+ tag = new byte[CRYPTO_ABYTES];
+ xor_block(tag_buffer, expanded_key, 0, BLOCK_SIZE);
+ permutation(tag_buffer);
+ xor_block(tag_buffer, expanded_key, 0, BLOCK_SIZE);
+ if (forEncryption)
+ {
+ Array.Copy(tag_buffer, 0, tag, 0, CRYPTO_ABYTES);
+ Array.Copy(tag, 0, output, outOff, tag.Length);
+ mlen += CRYPTO_ABYTES;
+ }
+ else
+ {
+ for (int i = 0; i < CRYPTO_ABYTES; ++i)
+ {
+ if (tag_buffer[i] != m[mlen + i])
+ {
+ throw new ArgumentException("Mac does not match");
+ }
+ }
+ }
+ reset(false);
+ return mlen;
+ }
+
+
+ public byte[] GetMac()
+ {
+ return tag;
+ }
+
+
+ public int GetUpdateOutputSize(int len)
+ {
+ return len;
+ }
+
+
+ public int GetOutputSize(int len)
+ {
+ return len + CRYPTO_ABYTES;
+ }
+
+
+ public void Reset()
+ {
+ reset(true);
+ }
+
+ private void reset(bool clearMac)
+ {
+ if (clearMac)
+ {
+ tag = null;
+ }
+ aadData.SetLength(0);
+ message.SetLength(0);
+ }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public void ProcessAadBytes(ReadOnlySpan<byte> input)
+ {
+ aadData.Write(input);
+ }
+
+ public int ProcessByte(byte input, Span<byte> output)
+ {
+ message.Write(new byte[] { input });
+ return 0;
+ }
+
+ public int ProcessBytes(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ message.Write(input.ToArray());
+ return 0;
+ }
+
+ public int DoFinal(Span<byte> output)
+ {
+ byte[] rv;
+ if (forEncryption)
+ {
+ rv = new byte[message.Length + CRYPTO_ABYTES];
+ }
+ else
+ {
+ rv = new byte[message.Length - CRYPTO_ABYTES];
+ }
+ int len = DoFinal(rv, 0);
+ rv.AsSpan(0, len).CopyTo(output);
+ return rv.Length;
+
+ }
+#endif
+
+ public int GetKeyBytesSize()
+ {
+ return CRYPTO_KEYBYTES;
+ }
+
+ public int GetIVBytesSize()
+ {
+ return CRYPTO_NPUBBYTES;
+ }
+
+ public int GetBlockSize()
+ {
+ return BLOCK_SIZE;
+ }
+ }
+}
+
diff --git a/crypto/src/crypto/engines/ISAPEngine.cs b/crypto/src/crypto/engines/ISAPEngine.cs
new file mode 100644
index 000000000..0280b1ce1
--- /dev/null
+++ b/crypto/src/crypto/engines/ISAPEngine.cs
@@ -0,0 +1,1034 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * ISAP AEAD v2, https://isap.iaik.tugraz.at/
+ * https://csrc.nist.gov/CSRC/media/Projects/lightweight-cryptography/documents/constist-round/updated-spec-doc/isap-spec-const.pdf
+ * <p>
+ * ISAP AEAD v2 with reference to C Reference Impl from: https://github.com/isap-lwc/isap-code-package
+ * </p>
+ */
+ public class ISAPEngine
+ : IAeadBlockCipher
+ {
+ public enum IsapType
+ {
+ ISAP_A_128A,
+ ISAP_K_128A,
+ ISAP_A_128,
+ ISAP_K_128
+ }
+
+ public ISAPEngine(IsapType isapType)
+ {
+ switch (isapType)
+ {
+ case IsapType.ISAP_A_128A:
+ ISAPAEAD = new ISAPAEAD_A_128A();
+ ISAP_rH = 64;
+ algorithmName = "ISAP-A-128A AEAD";
+ break;
+ case IsapType.ISAP_K_128A:
+ ISAPAEAD = new ISAPAEAD_K_128A();
+ ISAP_rH = 144;
+ algorithmName = "ISAP-K-128A AEAD";
+ break;
+ case IsapType.ISAP_A_128:
+ ISAPAEAD = new ISAPAEAD_A_128();
+ ISAP_rH = 64;
+ algorithmName = "ISAP-A-128 AEAD";
+ break;
+ case IsapType.ISAP_K_128:
+ ISAPAEAD = new ISAPAEAD_K_128();
+ ISAP_rH = 144;
+ algorithmName = "ISAP-K-128 AEAD";
+ break;
+ }
+ ISAP_rH_SZ = (ISAP_rH + 7) >> 3;
+ }
+
+ private string algorithmName;
+ private bool forEncryption;
+ private bool initialised;
+ const int CRYPTO_KEYBYTES = 16;
+ const int CRYPTO_NPUBBYTES = 16;
+ const int ISAP_STATE_SZ = 40;
+ private byte[] c;
+ private byte[] ad;
+ private byte[] mac;
+ private MemoryStream aadData = new MemoryStream();
+ private MemoryStream message = new MemoryStream();
+ private MemoryStream outputStream = new MemoryStream();
+ private ISAP_AEAD ISAPAEAD;
+ private int ISAP_rH;
+ private int ISAP_rH_SZ;
+
+ public IBlockCipher UnderlyingCipher => throw new NotImplementedException();
+
+ public string AlgorithmName => algorithmName;
+
+ protected abstract class ISAP_AEAD
+ {
+ protected byte[] k;
+ protected byte[] npub;
+ protected int ISAP_rH;
+ protected int ISAP_rH_SZ;
+
+ public abstract void isap_enc(byte[] m, int mOff, int mlen, byte[] c, int cOff, int clen);
+
+ public abstract void init(byte[] k, byte[] npub, int ISAP_rH, int ISAP_rH_SZ);
+
+ public abstract void isap_mac(byte[] ad, int adlen, byte[] c, int clen, byte[] tag, int tagOff);
+
+ public abstract void reset();
+ }
+
+ protected abstract class ISAPAEAD_A : ISAP_AEAD
+ {
+ protected ulong[] k64;
+ protected ulong[] npub64;
+ protected ulong ISAP_IV1_64;
+ protected ulong ISAP_IV2_64;
+ protected ulong ISAP_IV3_64;
+ protected ulong x0, x1, x2, x3, x4, t0, t1, t2, t3, t4;
+
+ public override void init(byte[] k, byte[] npub, int ISAP_rH, int ISAP_rH_SZ)
+ {
+ this.k = k;
+ this.npub = npub;
+ this.ISAP_rH = ISAP_rH;
+ this.ISAP_rH_SZ = ISAP_rH_SZ;
+ npub64 = new ulong[getulongSize(npub.Length)];
+ Pack.LE_To_UInt64(npub, 0, npub64, 0, npub64.Length);
+ npub64[0] = U64BIG(npub64[0]);
+ npub64[1] = U64BIG(npub64[1]);
+ k64 = new ulong[getulongSize(k.Length)];
+ Pack.LE_To_UInt64(k, 0, k64, 0, k64.Length);
+ k64[0] = U64BIG(k64[0]);
+ k64[1] = U64BIG(k64[1]);
+ reset();
+ }
+
+ protected abstract void PX1();
+
+ protected abstract void PX2();
+
+ protected void ABSORB_MAC(byte[] src, int len)
+ {
+ ulong[] src64 = new ulong[src.Length >> 3];
+ Pack.LE_To_UInt64(src, 0, src64, 0, src64.Length);
+ int idx = 0;
+ while (len >= ISAP_rH_SZ)
+ {
+ x0 ^= U64BIG(src64[idx++]);
+ P12();
+ len -= ISAP_rH_SZ;
+ }
+ /* Absorb const ad block */
+ for (int i = 0; i < len; ++i)
+ {
+ x0 ^= (src[(idx << 3) + i] & 0xFFUL) << ((7 - i) << 3);
+ }
+ x0 ^= 0x80UL << ((7 - len) << 3);
+ P12();
+ }
+
+ public override void isap_mac(byte[] ad, int adlen, byte[] c, int clen, byte[] tag, int tagOff)
+ {
+ // Init State
+ x0 = npub64[0];
+ x1 = npub64[1];
+ x2 = ISAP_IV1_64;
+ x3 = x4 = 0;
+ P12();
+ ABSORB_MAC(ad, adlen);
+ // Domain seperation
+ x4 ^= 1L;
+ ABSORB_MAC(c, clen);
+ // Derive K*
+ Pack.UInt64_To_LE(U64BIG(x0), tag, 0);
+ Pack.UInt64_To_LE(U64BIG(x1), tag, 8);
+ ulong tmp_x2 = x2, tmp_x3 = x3, tmp_x4 = x4;
+ isap_rk(ISAP_IV2_64, tag, CRYPTO_KEYBYTES);
+ x2 = tmp_x2;
+ x3 = tmp_x3;
+ x4 = tmp_x4;
+ // Squeeze tag
+ P12();
+ Pack.UInt64_To_LE(U64BIG(x0), tag, tagOff);
+ Pack.UInt64_To_LE(U64BIG(x1), tag, tagOff + 8);
+ }
+
+ public void isap_rk(ulong iv64, byte[] y, int ylen)
+ {
+ // Init state
+ x0 = k64[0];
+ x1 = k64[1];
+ x2 = iv64;
+ x3 = x4 = 0;
+ P12();
+ // Absorb Y
+ for (int i = 0; i < (ylen << 3) - 1; i++)
+ {
+ x0 ^= (((((ulong)y[i >> 3] >> (7 - (i & 7))) & 0x01UL) << 7) & 0xFFUL) << 56;
+ PX2();
+ }
+ x0 ^= (((y[ylen - 1]) & 0x01UL) << 7) << 56;
+ P12();
+ }
+
+ public override void isap_enc(byte[] m, int mOff, int mlen, byte[] c, int cOff, int clen)
+ {
+ /* Encrypt m */
+ ulong[] m64 = new ulong[mlen >> 3];
+ Pack.LE_To_UInt64(m, mOff, m64, 0, m64.Length);
+ ulong[] c64 = new ulong[m64.Length];
+ int idx = 0;
+ while (mlen >= ISAP_rH_SZ)
+ {
+ c64[idx] = U64BIG(x0) ^ m64[idx];
+ PX1();
+ idx++;
+ mlen -= ISAP_rH_SZ;
+ }
+ Pack.UInt64_To_LE(c64, 0, c64.Length, c, cOff);
+ /* Encrypt const m block */
+ byte[] xo = Pack.UInt64_To_LE(x0);
+ while (mlen > 0)
+ {
+ c[(idx << 3) + cOff + mlen - 1] = (byte)(xo[ISAP_rH_SZ - mlen] ^ m[(idx << 3) + mOff + --mlen]);
+ }
+ }
+
+ public override void reset()
+ {
+ // Init state
+ isap_rk(ISAP_IV3_64, npub, CRYPTO_NPUBBYTES);
+ x3 = npub64[0];
+ x4 = npub64[1];
+ PX1();
+ }
+
+ private int getulongSize(int x)
+ {
+ return (x >> 3) + ((x & 7) != 0 ? 1 : 0);
+ }
+
+ private ulong ROTR(ulong x, int n)
+ {
+ return (x >> n) | (x << (64 - n));
+ }
+
+ protected ulong U64BIG(ulong x)
+ {
+ return ((ROTR(x, 8) & (0xFF000000FF000000UL)) | (ROTR(x, 24) & (0x00FF000000FF0000UL)) |
+ (ROTR(x, 40) & (0x0000FF000000FF00UL)) | (ROTR(x, 56) & (0x000000FF000000FFUL)));
+ }
+
+ protected void ROUND(ulong C)
+ {
+ t0 = x0 ^ x1 ^ x2 ^ x3 ^ C ^ (x1 & (x0 ^ x2 ^ x4 ^ C));
+ t1 = x0 ^ x2 ^ x3 ^ x4 ^ C ^ ((x1 ^ x2 ^ C) & (x1 ^ x3));
+ t2 = x1 ^ x2 ^ x4 ^ C ^ (x3 & x4);
+ t3 = x0 ^ x1 ^ x2 ^ C ^ ((~x0) & (x3 ^ x4));
+ t4 = x1 ^ x3 ^ x4 ^ ((x0 ^ x4) & x1);
+ x0 = t0 ^ ROTR(t0, 19) ^ ROTR(t0, 28);
+ x1 = t1 ^ ROTR(t1, 39) ^ ROTR(t1, 61);
+ x2 = ~(t2 ^ ROTR(t2, 1) ^ ROTR(t2, 6));
+ x3 = t3 ^ ROTR(t3, 10) ^ ROTR(t3, 17);
+ x4 = t4 ^ ROTR(t4, 7) ^ ROTR(t4, 41);
+ }
+
+ public void P12()
+ {
+ ROUND(0xf0);
+ ROUND(0xe1);
+ ROUND(0xd2);
+ ROUND(0xc3);
+ ROUND(0xb4);
+ ROUND(0xa5);
+ P6();
+ }
+
+ protected void P6()
+ {
+ ROUND(0x96);
+ ROUND(0x87);
+ ROUND(0x78);
+ ROUND(0x69);
+ ROUND(0x5a);
+ ROUND(0x4b);
+ }
+ }
+
+ private class ISAPAEAD_A_128A : ISAPAEAD_A
+ {
+ public ISAPAEAD_A_128A()
+ {
+ ISAP_IV1_64 = 108156764297430540UL;
+ ISAP_IV2_64 = 180214358335358476UL;
+ ISAP_IV3_64 = 252271952373286412UL;
+ }
+
+ protected override void PX1()
+ {
+ P6();
+ }
+
+ protected override void PX2()
+ {
+ ROUND(0x4b);
+ }
+ }
+
+ private class ISAPAEAD_A_128 : ISAPAEAD_A
+ {
+ public ISAPAEAD_A_128()
+ {
+ ISAP_IV1_64 = 108156764298152972L;
+ ISAP_IV2_64 = 180214358336080908L;
+ ISAP_IV3_64 = 252271952374008844L;
+ }
+
+ protected override void PX1()
+ {
+ P12();
+ }
+
+ protected override void PX2()
+ {
+ P12();
+ }
+ }
+
+ private abstract class ISAPAEAD_K : ISAP_AEAD
+ {
+ const int ISAP_STATE_SZ_CRYPTO_NPUBBYTES = ISAP_STATE_SZ - CRYPTO_NPUBBYTES;
+ protected ushort[] ISAP_IV1_16;
+ protected ushort[] ISAP_IV2_16;
+ protected ushort[] ISAP_IV3_16;
+ protected ushort[] k16;
+ protected ushort[] iv16;
+ private readonly int[] KeccakF400RoundConstants = {0x0001, 0x8082, 0x808a, 0x8000, 0x808b, 0x0001, 0x8081, 0x8009,
+ 0x008a, 0x0088, 0x8009, 0x000a, 0x808b, 0x008b, 0x8089, 0x8003, 0x8002, 0x0080, 0x800a, 0x000a};
+ protected ushort[] SX = new ushort[25];
+ protected ushort[] E = new ushort[25];
+ protected ushort[] C = new ushort[5];
+
+ public override void init(byte[] k, byte[] npub, int ISAP_rH, int ISAP_rH_SZ)
+ {
+ this.k = k;
+ this.npub = npub;
+ this.ISAP_rH = ISAP_rH;
+ this.ISAP_rH_SZ = ISAP_rH_SZ;
+ k16 = new ushort[k.Length >> 1];
+ byteToushort(k, k16, k16.Length);
+ iv16 = new ushort[npub.Length >> 1];
+ byteToushort(npub, iv16, iv16.Length);
+ reset();
+ }
+
+ public override void reset()
+ {
+ // Init state
+ SX = new ushort[25];
+ E = new ushort[25];
+ C = new ushort[5];
+ isap_rk(ISAP_IV3_16, npub, CRYPTO_NPUBBYTES, SX, ISAP_STATE_SZ_CRYPTO_NPUBBYTES, C);
+ Array.Copy(iv16, 0, SX, 17, 8);
+ PermuteRoundsKX(SX, E, C);
+ }
+
+ protected abstract void PermuteRoundsHX(ushort[] SX, ushort[] E, ushort[] C);
+
+ protected abstract void PermuteRoundsKX(ushort[] SX, ushort[] E, ushort[] C);
+
+ protected abstract void PermuteRoundsBX(ushort[] SX, ushort[] E, ushort[] C);
+
+ protected void ABSORB_MAC(ushort[] SX, byte[] src, int len, ushort[] E, ushort[] C)
+ {
+ int rem_bytes = len;
+ int idx = 0;
+ while (true)
+ {
+ if (rem_bytes > ISAP_rH_SZ)
+ {
+ byteToushortXor(src, SX, ISAP_rH_SZ >> 1);
+ idx += ISAP_rH_SZ;
+ rem_bytes -= ISAP_rH_SZ;
+ PermuteRoundsHX(SX, E, C);
+ }
+ else if (rem_bytes == ISAP_rH_SZ)
+ {
+ byteToushortXor(src, SX, ISAP_rH_SZ >> 1);
+ PermuteRoundsHX(SX, E, C);
+ SX[0] ^= 0x80;
+ PermuteRoundsHX(SX, E, C);
+ break;
+ }
+ else
+ {
+ for (int i = 0; i < rem_bytes; i++)
+ {
+ SX[i >> 1] ^= (ushort)((src[idx++] & 0xFFU) << ((i & 1) << 3));
+ }
+ SX[rem_bytes >> 1] ^= (ushort)(0x80U << ((rem_bytes & 1) << 3));
+ PermuteRoundsHX(SX, E, C);
+ break;
+ }
+ }
+ }
+
+ public void isap_rk(ushort[] iv16, byte[] y, int ylen, ushort[] out16, int outlen, ushort[] C)
+ {
+ // Init state
+ ushort[] SX = new ushort[25];
+ ushort[] E = new ushort[25];
+ Array.Copy(k16, 0, SX, 0, 8);
+ Array.Copy(iv16, 0, SX, 8, 4);
+ PermuteRoundsKX(SX, E, C);
+ // Absorb all bits of Y
+ for (int i = 0; i < (ylen << 3) - 1; i++)
+ {
+ SX[0] ^= (ushort)(((y[i >> 3] >> (7 - (i & 7))) & 0x01) << 7);
+ PermuteRoundsBX(SX, E, C);
+ }
+ SX[0] ^= (ushort)(((y[ylen - 1]) & 0x01) << 7);
+ PermuteRoundsKX(SX, E, C);
+ // Extract K*
+ Array.Copy(SX, 0, out16, 0, outlen == ISAP_STATE_SZ_CRYPTO_NPUBBYTES ? 17 : 8);
+ }
+
+ public override void isap_mac(byte[] ad, int adlen, byte[] c, int clen, byte[] tag, int tagOff)
+ {
+ SX = new ushort[25];
+ // Init state
+ Array.Copy(iv16, 0, SX, 0, 8);
+ Array.Copy(ISAP_IV1_16, 0, SX, 8, 4);
+ PermuteRoundsHX(SX, E, C);
+ // Absorb AD
+ ABSORB_MAC(SX, ad, adlen, E, C);
+ // Domain seperation
+ SX[24] ^= 0x0100;
+ // Absorb C
+ ABSORB_MAC(SX, c, clen, E, C);
+ // Derive K*
+ ushortToByte(SX, tag, tagOff);
+ isap_rk(ISAP_IV2_16, tag, CRYPTO_KEYBYTES, SX, CRYPTO_KEYBYTES, C);
+ // Squeeze tag
+ PermuteRoundsHX(SX, E, C);
+ ushortToByte(SX, tag, tagOff);
+ }
+
+ public override void isap_enc(byte[] m, int mOff, int mlen, byte[] c, int cOff, int clen)
+ {
+ // Squeeze key stream
+ while (true)
+ {
+ if (mlen >= ISAP_rH_SZ)
+ {
+ // Squeeze full lane and continue
+ for (int i = 0; i < ISAP_rH_SZ; ++i)
+ {
+ c[cOff++] = (byte)((SX[i >> 1] >> ((i & 1) << 3)) ^ m[mOff++]);
+ }
+ mlen -= ISAP_rH_SZ;
+ PermuteRoundsKX(SX, E, C);
+ }
+ else
+ {
+ // Squeeze full or partial lane and stop
+ for (int i = 0; i < mlen; ++i)
+ {
+ c[cOff++] = (byte)((SX[i >> 1] >> ((i & 1) << 3)) ^ m[mOff++]);
+ }
+ break;
+ }
+ }
+ }
+
+ private void byteToushortXor(byte[] input, ushort[] output, int outLen)
+ {
+ for (int i = 0; i < outLen; ++i)
+ {
+ output[i] ^= Pack.LE_To_UInt16(input, (i << 1));
+ }
+ }
+
+ private void byteToushort(byte[] input, ushort[] output, int outLen)
+ {
+ for (int i = 0; i < outLen; ++i)
+ {
+ output[i] = Pack.LE_To_UInt16(input, (i << 1));
+ }
+ }
+
+ private void ushortToByte(ushort[] input, byte[] output, int outOff)
+ {
+ for (int i = 0; i < 8; ++i)
+ {
+ shortToLittleEndian(input[i], output, outOff + (i << 1));
+ }
+ }
+
+ protected void rounds12X(ushort[] SX, ushort[] E, ushort[] C)
+ {
+ prepareThetaX(SX, C);
+ rounds_8_18(SX, E, C);
+ }
+
+ protected void rounds_4_18(ushort[] SX, ushort[] E, ushort[] C)
+ {
+ thetaRhoPiChiIotaPrepareTheta(4, SX, E, C);
+ thetaRhoPiChiIotaPrepareTheta(5, E, SX, C);
+ thetaRhoPiChiIotaPrepareTheta(6, SX, E, C);
+ thetaRhoPiChiIotaPrepareTheta(7, E, SX, C);
+ rounds_8_18(SX, E, C);
+ }
+
+ protected void rounds_8_18(ushort[] SX, ushort[] E, ushort[] C)
+ {
+ thetaRhoPiChiIotaPrepareTheta(8, SX, E, C);
+ thetaRhoPiChiIotaPrepareTheta(9, E, SX, C);
+ thetaRhoPiChiIotaPrepareTheta(10, SX, E, C);
+ thetaRhoPiChiIotaPrepareTheta(11, E, SX, C);
+ rounds_12_18(SX, E, C);
+ }
+
+ protected void rounds_12_18(ushort[] SX, ushort[] E, ushort[] C)
+ {
+ thetaRhoPiChiIotaPrepareTheta(12, SX, E, C);
+ thetaRhoPiChiIotaPrepareTheta(13, E, SX, C);
+ thetaRhoPiChiIotaPrepareTheta(14, SX, E, C);
+ thetaRhoPiChiIotaPrepareTheta(15, E, SX, C);
+ thetaRhoPiChiIotaPrepareTheta(16, SX, E, C);
+ thetaRhoPiChiIotaPrepareTheta(17, E, SX, C);
+ thetaRhoPiChiIotaPrepareTheta(18, SX, E, C);
+ thetaRhoPiChiIota(E, SX, C);
+ }
+
+ protected void prepareThetaX(ushort[] SX, ushort[] C)
+ {
+ C[0] = (ushort)(SX[0] ^ SX[5] ^ SX[10] ^ SX[15] ^ SX[20]);
+ C[1] = (ushort)(SX[1] ^ SX[6] ^ SX[11] ^ SX[16] ^ SX[21]);
+ C[2] = (ushort)(SX[2] ^ SX[7] ^ SX[12] ^ SX[17] ^ SX[22]);
+ C[3] = (ushort)(SX[3] ^ SX[8] ^ SX[13] ^ SX[18] ^ SX[23]);
+ C[4] = (ushort)(SX[4] ^ SX[9] ^ SX[14] ^ SX[19] ^ SX[24]);
+ }
+
+ private ushort ROL16(ushort a, int offset)
+ {
+ return (ushort)(((a & 0xFFFF) << offset) ^ ((a & 0xFFFF) >> (16 - offset)));
+ }
+
+ protected void thetaRhoPiChiIotaPrepareTheta(int i, ushort[] A, ushort[] E, ushort[] C)
+ {
+ ushort Da = (ushort)(C[4] ^ ROL16(C[1], 1));
+ ushort De = (ushort)(C[0] ^ ROL16(C[2], 1));
+ ushort Di = (ushort)(C[1] ^ ROL16(C[3], 1));
+ ushort Do = (ushort)(C[2] ^ ROL16(C[4], 1));
+ ushort Du = (ushort)(C[3] ^ ROL16(C[0], 1));
+
+ ushort Ba = A[0] ^= Da;
+ A[6] ^= De;
+ ushort Be = ROL16(A[6], 12);
+ A[12] ^= Di;
+ ushort Bi = ROL16(A[12], 11);
+ A[18] ^= Do;
+ ushort Bo = ROL16(A[18], 5);
+ A[24] ^= Du;
+ ushort Bu = ROL16(A[24], 14);
+ C[0] = E[0] = (ushort)(Ba ^ ((~Be) & Bi) ^ KeccakF400RoundConstants[i]);
+ C[1] = E[1] = (ushort)(Be ^ ((~Bi) & Bo));
+ C[2] = E[2] = (ushort)(Bi ^ ((~Bo) & Bu));
+ C[3] = E[3] = (ushort)(Bo ^ ((~Bu) & Ba));
+ C[4] = E[4] = (ushort)(Bu ^ ((~Ba) & Be));
+
+ A[3] ^= Do;
+ Ba = ROL16(A[3], 12);
+ A[9] ^= Du;
+ Be = ROL16(A[9], 4);
+ A[10] ^= Da;
+ Bi = ROL16(A[10], 3);
+ A[16] ^= De;
+ Bo = ROL16(A[16], 13);
+ A[22] ^= Di;
+ Bu = ROL16(A[22], 13);
+ E[5] = (ushort)(Ba ^ ((~Be) & Bi));
+ C[0] ^= E[5];
+ E[6] = (ushort)(Be ^ ((~Bi) & Bo));
+ C[1] ^= E[6];
+ E[7] = (ushort)(Bi ^ ((~Bo) & Bu));
+ C[2] ^= E[7];
+ E[8] = (ushort)(Bo ^ ((~Bu) & Ba));
+ C[3] ^= E[8];
+ E[9] = (ushort)(Bu ^ ((~Ba) & Be));
+ C[4] ^= E[9];
+
+ A[1] ^= De;
+ Ba = ROL16(A[1], 1);
+ A[7] ^= Di;
+ Be = ROL16(A[7], 6);
+ A[13] ^= Do;
+ Bi = ROL16(A[13], 9);
+ A[19] ^= Du;
+ Bo = ROL16(A[19], 8);
+ A[20] ^= Da;
+ Bu = ROL16(A[20], 2);
+ E[10] = (ushort)(Ba ^ ((~Be) & Bi));
+ C[0] ^= E[10];
+ E[11] = (ushort)(Be ^ ((~Bi) & Bo));
+ C[1] ^= E[11];
+ E[12] = (ushort)(Bi ^ ((~Bo) & Bu));
+ C[2] ^= E[12];
+ E[13] = (ushort)(Bo ^ ((~Bu) & Ba));
+ C[3] ^= E[13];
+ E[14] = (ushort)(Bu ^ ((~Ba) & Be));
+ C[4] ^= E[14];
+
+ A[4] ^= Du;
+ Ba = ROL16(A[4], 11);
+ A[5] ^= Da;
+ Be = ROL16(A[5], 4);
+ A[11] ^= De;
+ Bi = ROL16(A[11], 10);
+ A[17] ^= Di;
+ Bo = ROL16(A[17], 15);
+ A[23] ^= Do;
+ Bu = ROL16(A[23], 8);
+ E[15] = (ushort)(Ba ^ ((~Be) & Bi));
+ C[0] ^= E[15];
+ E[16] = (ushort)(Be ^ ((~Bi) & Bo));
+ C[1] ^= E[16];
+ E[17] = (ushort)(Bi ^ ((~Bo) & Bu));
+ C[2] ^= E[17];
+ E[18] = (ushort)(Bo ^ ((~Bu) & Ba));
+ C[3] ^= E[18];
+ E[19] = (ushort)(Bu ^ ((~Ba) & Be));
+ C[4] ^= E[19];
+
+ A[2] ^= Di;
+ Ba = ROL16(A[2], 14);
+ A[8] ^= Do;
+ Be = ROL16(A[8], 7);
+ A[14] ^= Du;
+ Bi = ROL16(A[14], 7);
+ A[15] ^= Da;
+ Bo = ROL16(A[15], 9);
+ A[21] ^= De;
+ Bu = ROL16(A[21], 2);
+ E[20] = (ushort)(Ba ^ ((~Be) & Bi));
+ C[0] ^= E[20];
+ E[21] = (ushort)(Be ^ ((~Bi) & Bo));
+ C[1] ^= E[21];
+ E[22] = (ushort)(Bi ^ ((~Bo) & Bu));
+ C[2] ^= E[22];
+ E[23] = (ushort)(Bo ^ ((~Bu) & Ba));
+ C[3] ^= E[23];
+ E[24] = (ushort)(Bu ^ ((~Ba) & Be));
+ C[4] ^= E[24];
+ }
+
+ protected void thetaRhoPiChiIota(ushort[] A, ushort[] E, ushort[] C)
+ {
+ ushort Da = (ushort)(C[4] ^ ROL16(C[1], 1));
+ ushort De = (ushort)(C[0] ^ ROL16(C[2], 1));
+ ushort Di = (ushort)(C[1] ^ ROL16(C[3], 1));
+ ushort Do = (ushort)(C[2] ^ ROL16(C[4], 1));
+ ushort Du = (ushort)(C[3] ^ ROL16(C[0], 1));
+
+ ushort Ba = A[0] ^= Da;
+ A[6] ^= De;
+ ushort Be = ROL16(A[6], 12);
+ A[12] ^= Di;
+ ushort Bi = ROL16(A[12], 11);
+ A[18] ^= Do;
+ ushort Bo = ROL16(A[18], 5);
+ A[24] ^= Du;
+ ushort Bu = ROL16(A[24], 14);
+ E[0] = (ushort)(Ba ^ ((~Be) & Bi) ^ KeccakF400RoundConstants[19]);
+ E[1] = (ushort)(Be ^ ((~Bi) & Bo));
+ E[2] = (ushort)(Bi ^ ((~Bo) & Bu));
+ E[3] = (ushort)(Bo ^ ((~Bu) & Ba));
+ E[4] = (ushort)(Bu ^ ((~Ba) & Be));
+
+ A[3] ^= Do;
+ Ba = ROL16(A[3], 12);
+ A[9] ^= Du;
+ Be = ROL16(A[9], 4);
+ A[10] ^= Da;
+ Bi = ROL16(A[10], 3);
+ A[16] ^= De;
+ Bo = ROL16(A[16], 13);
+ A[22] ^= Di;
+ Bu = ROL16(A[22], 13);
+ E[5] = (ushort)(Ba ^ ((~Be) & Bi));
+ E[6] = (ushort)(Be ^ ((~Bi) & Bo));
+ E[7] = (ushort)(Bi ^ ((~Bo) & Bu));
+ E[8] = (ushort)(Bo ^ ((~Bu) & Ba));
+ E[9] = (ushort)(Bu ^ ((~Ba) & Be));
+
+ A[1] ^= De;
+ Ba = ROL16(A[1], 1);
+ A[7] ^= Di;
+ Be = ROL16(A[7], 6);
+ A[13] ^= Do;
+ Bi = ROL16(A[13], 9);
+ A[19] ^= Du;
+ Bo = ROL16(A[19], 8);
+ A[20] ^= Da;
+ Bu = ROL16(A[20], 2);
+ E[10] = (ushort)(Ba ^ ((~Be) & Bi));
+ E[11] = (ushort)(Be ^ ((~Bi) & Bo));
+ E[12] = (ushort)(Bi ^ ((~Bo) & Bu));
+ E[13] = (ushort)(Bo ^ ((~Bu) & Ba));
+ E[14] = (ushort)(Bu ^ ((~Ba) & Be));
+
+ A[4] ^= Du;
+ Ba = ROL16(A[4], 11);
+ A[5] ^= Da;
+ Be = ROL16(A[5], 4);
+ A[11] ^= De;
+ Bi = ROL16(A[11], 10);
+ A[17] ^= Di;
+ Bo = ROL16(A[17], 15);
+ A[23] ^= Do;
+ Bu = ROL16(A[23], 8);
+ E[15] = (ushort)(Ba ^ ((~Be) & Bi));
+ E[16] = (ushort)(Be ^ ((~Bi) & Bo));
+ E[17] = (ushort)(Bi ^ ((~Bo) & Bu));
+ E[18] = (ushort)(Bo ^ ((~Bu) & Ba));
+ E[19] = (ushort)(Bu ^ ((~Ba) & Be));
+
+ A[2] ^= Di;
+ Ba = ROL16(A[2], 14);
+ A[8] ^= Do;
+ Be = ROL16(A[8], 7);
+ A[14] ^= Du;
+ Bi = ROL16(A[14], 7);
+ A[15] ^= Da;
+ Bo = ROL16(A[15], 9);
+ A[21] ^= De;
+ Bu = ROL16(A[21], 2);
+ E[20] = (ushort)(Ba ^ ((~Be) & Bi));
+ E[21] = (ushort)(Be ^ ((~Bi) & Bo));
+ E[22] = (ushort)(Bi ^ ((~Bo) & Bu));
+ E[23] = (ushort)(Bo ^ ((~Bu) & Ba));
+ E[24] = (ushort)(Bu ^ ((~Ba) & Be));
+ }
+ }
+
+ private class ISAPAEAD_K_128A : ISAPAEAD_K
+ {
+ public ISAPAEAD_K_128A()
+ {
+ ISAP_IV1_16 = new ushort[] { 32769, 400, 272, 2056 };
+ ISAP_IV2_16 = new ushort[] { 32770, 400, 272, 2056 };
+ ISAP_IV3_16 = new ushort[] { 32771, 400, 272, 2056 };
+ }
+
+ protected override void PermuteRoundsHX(ushort[] SX, ushort[] E, ushort[] C)
+ {
+ prepareThetaX(SX, C);
+ rounds_4_18(SX, E, C);
+ }
+
+ protected override void PermuteRoundsKX(ushort[] SX, ushort[] E, ushort[] C)
+ {
+ prepareThetaX(SX, C);
+ rounds_12_18(SX, E, C);
+ }
+
+ protected override void PermuteRoundsBX(ushort[] SX, ushort[] E, ushort[] C)
+ {
+ prepareThetaX(SX, C);
+ thetaRhoPiChiIotaPrepareTheta(19, SX, E, C);
+ Array.Copy(E, 0, SX, 0, E.Length);
+ }
+ }
+
+ private class ISAPAEAD_K_128
+ : ISAPAEAD_K
+ {
+ public ISAPAEAD_K_128()
+ {
+ ISAP_IV1_16 = new ushort[] { 32769, 400, 3092, 3084 };
+ ISAP_IV2_16 = new ushort[] { 32770, 400, 3092, 3084 };
+ ISAP_IV3_16 = new ushort[] { 32771, 400, 3092, 3084 };
+ }
+
+ protected override void PermuteRoundsHX(ushort[] SX, ushort[] E, ushort[] C)
+ {
+ prepareThetaX(SX, C);
+ thetaRhoPiChiIotaPrepareTheta(0, SX, E, C);
+ thetaRhoPiChiIotaPrepareTheta(1, E, SX, C);
+ thetaRhoPiChiIotaPrepareTheta(2, SX, E, C);
+ thetaRhoPiChiIotaPrepareTheta(3, E, SX, C);
+ rounds_4_18(SX, E, C);
+ }
+
+ protected override void PermuteRoundsKX(ushort[] SX, ushort[] E, ushort[] C)
+ {
+ rounds12X(SX, E, C);
+ }
+
+ protected override void PermuteRoundsBX(ushort[] SX, ushort[] E, ushort[] C)
+ {
+ rounds12X(SX, E, C);
+ }
+ }
+
+
+
+ public void Init(bool forEncryption, ICipherParameters param)
+ {
+ this.forEncryption = forEncryption;
+ if (!(param is ParametersWithIV))
+ {
+ throw new ArgumentException(
+ "ISAP AEAD init parameters must include an IV");
+ }
+
+ ParametersWithIV ivParams = (ParametersWithIV)param;
+
+ byte[] iv = ivParams.GetIV();
+
+ if (iv == null || iv.Length != 16)
+ {
+ throw new ArgumentException(
+ "ISAP AEAD requires exactly 12 bytes of IV");
+ }
+
+ if (!(ivParams.Parameters is KeyParameter))
+ {
+ throw new ArgumentException(
+ "ISAP AEAD init parameters must include a key");
+ }
+
+ KeyParameter key = (KeyParameter)ivParams.Parameters;
+ byte[] keyBytes = key.GetKey();
+ if (keyBytes.Length != 16)
+ {
+ throw new ArgumentException(
+ "ISAP AEAD key must be 128 bits ulong");
+ }
+
+ /*
+ * Initialize variables.
+ */
+ byte[] npub = new byte[iv.Length];
+ byte[] k = new byte[keyBytes.Length];
+ Array.Copy(iv, 0, npub, 0, iv.Length);
+ Array.Copy(keyBytes, 0, k, 0, keyBytes.Length);
+ initialised = true;
+ ISAPAEAD.init(k, npub, ISAP_rH, ISAP_rH_SZ);
+ Reset();
+ }
+
+ public void ProcessAadByte(byte input)
+ {
+ aadData.Write(new byte[] { input }, 0, 1);
+ }
+
+
+ public void ProcessAadBytes(byte[] input, int inOff, int len)
+ {
+ if ((inOff + len) > input.Length)
+ {
+ throw new DataLengthException("input buffer too short" + (forEncryption ? "encryption" : "decryption"));
+ }
+ aadData.Write(input, inOff, len);
+ }
+
+
+ public int ProcessByte(byte input, byte[] output, int outOff)
+ {
+
+ return ProcessBytes(new byte[] { input }, 0, 1, output, outOff);
+ }
+
+
+ public int ProcessBytes(byte[] input, int inOff, int len, byte[] output, int outOff)
+ {
+ if (!initialised)
+ {
+ throw new ArgumentException("Need call init function before encryption/decryption");
+ }
+ if ((inOff + len) > input.Length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+ message.Write(input, inOff, len);
+ if (forEncryption)
+ {
+ if (message.Length >= ISAP_rH_SZ)
+ {
+ len = (int)message.Length / ISAP_rH_SZ * ISAP_rH_SZ;
+ if (outOff + len > output.Length)
+ {
+ throw new OutputLengthException("output buffer is too short");
+ }
+ byte[] enc_input = message.GetBuffer();
+ ISAPAEAD.isap_enc(enc_input, 0, len, output, outOff, output.Length);
+ outputStream.Write(output, outOff, len);
+ int enc_input_len = (int)message.Length;
+ message.SetLength(0);
+ message.Write(enc_input, len, enc_input_len - len);
+ return len;
+ }
+ }
+ return 0;
+ }
+
+
+ public int DoFinal(byte[] output, int outOff)
+ {
+ if (!initialised)
+ {
+ throw new ArgumentException("Need call init function before encryption/decryption");
+ }
+ int len;
+ if (forEncryption)
+ {
+ byte[] enc_input = message.GetBuffer();
+ len = (int)message.Length;
+ if (outOff + len + 16 > output.Length)
+ {
+ throw new OutputLengthException("output buffer is too short");
+ }
+ ISAPAEAD.isap_enc(enc_input, 0, len, output, outOff, output.Length);
+ outputStream.Write(output, outOff, len);
+ outOff += len;
+ ad = aadData.GetBuffer();
+ c = outputStream.GetBuffer();
+ mac = new byte[16];
+ ISAPAEAD.isap_mac(ad, (int)aadData.Length, c, (int)outputStream.Length, mac, 0);
+ Array.Copy(mac, 0, output, outOff, 16);
+ len += 16;
+ }
+ else
+ {
+ ad = aadData.GetBuffer();
+ int adlen = (int)aadData.Length;
+ c = message.GetBuffer();
+ int clen = (int)message.Length;
+ mac = new byte[16];
+ len = clen - mac.Length;
+ if (len + outOff > output.Length)
+ {
+ throw new OutputLengthException("output buffer is too short");
+ }
+ ISAPAEAD.isap_mac(ad, adlen, c, len, mac, 0);
+ ISAPAEAD.reset();
+ for (int i = 0; i < 16; ++i)
+ {
+ if (mac[i] != c[len + i])
+ {
+ throw new ArgumentException("Mac does not match");
+ }
+ }
+ ISAPAEAD.isap_enc(c, 0, len, output, outOff, output.Length);
+ }
+ return len;
+ }
+
+
+ public byte[] GetMac()
+ {
+ return mac;
+ }
+
+
+ public int GetUpdateOutputSize(int len)
+ {
+ return len;
+ }
+
+
+ public int GetOutputSize(int len)
+ {
+ return len + 16;
+ }
+
+
+ public void Reset()
+ {
+ if (!initialised)
+ {
+ throw new ArgumentException("Need call init function before encryption/decryption");
+ }
+ aadData.SetLength(0);
+ ISAPAEAD.reset();
+ message.SetLength(0);
+ outputStream.SetLength(0);
+ }
+
+ private static void shortToLittleEndian(ushort n, byte[] bs, int off)
+ {
+ bs[off] = (byte)(n);
+ bs[++off] = (byte)(n >> 8);
+ }
+
+ public int GetBlockSize()
+ {
+ return ISAP_rH_SZ;
+ }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public void ProcessAadBytes(ReadOnlySpan<byte> input)
+ {
+ aadData.Write(input);
+ }
+
+ public int ProcessByte(byte input, Span<byte> output)
+ {
+ byte[] rv = new byte[1];
+ int len = ProcessBytes(new byte[] { input }, 0, 1, rv, 0);
+ rv.AsSpan(0, len).CopyTo(output);
+ return len;
+ }
+
+ public int ProcessBytes(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ byte[] rv = new byte[input.Length];
+ int len = ProcessBytes(input.ToArray(), 0, rv.Length, rv, 0);
+ rv.AsSpan(0, len).CopyTo(output);
+ return len;
+ }
+
+ public int DoFinal(Span<byte> output)
+ {
+ byte[] rv;
+ if (forEncryption)
+ {
+ rv = new byte[message.Length + 16];
+ }
+ else
+ {
+ rv = new byte[message.Length];
+ }
+ int len = DoFinal(rv, 0);
+ rv.AsSpan(0, len).CopyTo(output);
+ return rv.Length;
+ }
+#endif
+
+ public int GetKeyBytesSize()
+ {
+ return CRYPTO_KEYBYTES;
+ }
+
+ public int GetIVBytesSize()
+ {
+ return CRYPTO_NPUBBYTES;
+ }
+ }
+}
+
+
diff --git a/crypto/src/crypto/engines/NaccacheSternEngine.cs b/crypto/src/crypto/engines/NaccacheSternEngine.cs
index 39fb7c9ec..16f62a4e5 100644
--- a/crypto/src/crypto/engines/NaccacheSternEngine.cs
+++ b/crypto/src/crypto/engines/NaccacheSternEngine.cs
@@ -31,15 +31,13 @@ namespace Org.BouncyCastle.Crypto.Engines
* @see org.bouncycastle.crypto.AsymmetricBlockCipher#init(bool,
* org.bouncycastle.crypto.CipherParameters)
*/
- public virtual void Init(
- bool forEncryption,
- ICipherParameters parameters)
+ public virtual void Init(bool forEncryption, ICipherParameters parameters)
{
this.forEncryption = forEncryption;
- if (parameters is ParametersWithRandom)
+ if (parameters is ParametersWithRandom withRandom)
{
- parameters = ((ParametersWithRandom) parameters).Parameters;
+ parameters = withRandom.Parameters;
}
key = (NaccacheSternKeyParameters)parameters;
diff --git a/crypto/src/crypto/engines/PhotonBeetleEngine.cs b/crypto/src/crypto/engines/PhotonBeetleEngine.cs
new file mode 100644
index 000000000..0d5728a76
--- /dev/null
+++ b/crypto/src/crypto/engines/PhotonBeetleEngine.cs
@@ -0,0 +1,461 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * Photon-Beetle, https://www.isical.ac.in/~lightweight/beetle/
+ * https://csrc.nist.gov/CSRC/media/Projects/lightweight-cryptography/documents/readonlyist-round/updated-spec-doc/photon-beetle-spec-readonly.pdf
+ * <p>
+ * Photon-Beetle with reference to C Reference Impl from: https://github.com/PHOTON-Beetle/Software
+ * </p>
+ */
+ public class PhotonBeetleEngine
+ : IAeadBlockCipher
+ {
+ public enum PhotonBeetleParameters
+ {
+ pb32,
+ pb128
+ }
+
+ private bool input_empty;
+ private bool forEncryption;
+ private bool initialised;
+ private byte[] K;
+ private byte[] N;
+ private byte[] state;
+ private byte[][] state_2d;
+ private byte[] A;
+ private byte[] T;
+ private MemoryStream aadData = new MemoryStream();
+ private MemoryStream message = new MemoryStream();
+ private readonly int CRYPTO_KEYBYTES = 16;
+ private readonly int CRYPTO_NPUBBYTES = 16;
+ private readonly int RATE_INBYTES;
+ private readonly int RATE_INBYTES_HALF;
+ private int STATE_INBYTES;
+ private int TAG_INBYTES = 16;
+ private int LAST_THREE_BITS_OFFSET;
+ private int ROUND = 12;
+ private int D = 8;
+ private int Dq = 3;
+ private int Dr = 7;
+ private int DSquare = 64;
+ private int S = 4;
+ private int S_1 = 3;
+ private byte[][] RC = {
+ new byte[]{1, 3, 7, 14, 13, 11, 6, 12, 9, 2, 5, 10},
+ new byte[]{0, 2, 6, 15, 12, 10, 7, 13, 8, 3, 4, 11},
+ new byte[]{2, 0, 4, 13, 14, 8, 5, 15, 10, 1, 6, 9},
+ new byte[]{6, 4, 0, 9, 10, 12, 1, 11, 14, 5, 2, 13},
+ new byte[]{14, 12, 8, 1, 2, 4, 9, 3, 6, 13, 10, 5},
+ new byte[]{15, 13, 9, 0, 3, 5, 8, 2, 7, 12, 11, 4},
+ new byte[]{13, 15, 11, 2, 1, 7, 10, 0, 5, 14, 9, 6},
+ new byte[]{9, 11, 15, 6, 5, 3, 14, 4, 1, 10, 13, 2}
+ };
+ private byte[][] MixColMatrix = {
+ new byte[]{2, 4, 2, 11, 2, 8, 5, 6},
+ new byte[]{12, 9, 8, 13, 7, 7, 5, 2},
+ new byte[]{4, 4, 13, 13, 9, 4, 13, 9},
+ new byte[]{1, 6, 5, 1, 12, 13, 15, 14},
+ new byte[]{15, 12, 9, 13, 14, 5, 14, 13},
+ new byte[]{9, 14, 5, 15, 4, 12, 9, 6},
+ new byte[]{12, 2, 2, 10, 3, 1, 1, 14},
+ new byte[]{15, 1, 13, 10, 5, 10, 2, 3}
+ };
+
+ private byte[] sbox = { 12, 5, 6, 11, 9, 0, 10, 13, 3, 14, 15, 8, 4, 7, 1, 2 };
+ public PhotonBeetleEngine(PhotonBeetleParameters pbp)
+ {
+ int CAPACITY_INBITS = 0, RATE_INBITS = 0;
+ switch (pbp)
+ {
+ case PhotonBeetleParameters.pb32:
+ RATE_INBITS = 32;
+ CAPACITY_INBITS = 224;
+ break;
+ case PhotonBeetleParameters.pb128:
+ RATE_INBITS = 128;
+ CAPACITY_INBITS = 128;
+ break;
+ }
+ RATE_INBYTES = (RATE_INBITS + 7) >> 3;
+ RATE_INBYTES_HALF = RATE_INBYTES >> 1;
+ int STATE_INBITS = RATE_INBITS + CAPACITY_INBITS;
+ STATE_INBYTES = (STATE_INBITS + 7) >> 3;
+ LAST_THREE_BITS_OFFSET = (STATE_INBITS - ((STATE_INBYTES - 1) << 3) - 3);
+ initialised = false;
+ }
+
+ public string AlgorithmName => "Photon-Beetle AEAD";
+
+ public IBlockCipher UnderlyingCipher => throw new NotImplementedException();
+
+ public byte[] GetMac()
+ {
+ return T;
+ }
+
+ public int GetOutputSize(int len)
+ {
+ return len + TAG_INBYTES;
+ }
+
+ public int GetUpdateOutputSize(int len)
+ {
+ return len;
+ }
+
+ public void Init(bool forEncryption, ICipherParameters parameters)
+ {
+ this.forEncryption = forEncryption;
+ if (!(parameters is ParametersWithIV param))
+ {
+ throw new ArgumentException("Photon-Beetle AEAD init parameters must include an IV");
+ }
+ ParametersWithIV ivParams = param;
+ N = ivParams.GetIV();
+ if (N == null || N.Length != CRYPTO_NPUBBYTES)
+ {
+ throw new ArgumentException("Photon-Beetle AEAD requires exactly 16 bytes of IV");
+ }
+ if (!(ivParams.Parameters is KeyParameter))
+ {
+ throw new ArgumentException("Photon-Beetle AEAD init parameters must include a key");
+ }
+ KeyParameter key = (KeyParameter)ivParams.Parameters;
+ K = key.GetKey();
+ if (K.Length != CRYPTO_KEYBYTES)
+ {
+ throw new ArgumentException("Photon-Beetle AEAD key must be 128 bits long");
+ }
+
+ state = new byte[STATE_INBYTES];
+ state_2d = new byte[D][];
+ for (int i = 0; i < D; ++i)
+ {
+ state_2d[i] = new byte[D];
+ }
+ T = new byte[TAG_INBYTES];
+ initialised = true;
+ reset(false);
+ }
+
+ public void ProcessAadByte(byte input)
+ {
+ aadData.Write(new byte[] { input }, 0, 1);
+ }
+
+ public void ProcessAadBytes(byte[] input, int inOff, int len)
+ {
+ if (inOff + len > input.Length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+ aadData.Write(input, inOff, len);
+ }
+
+ public int ProcessByte(byte input, byte[] output, int outOff)
+ {
+ message.Write(new byte[] { input }, 0, 1);
+ return 0;
+ }
+
+ public int ProcessBytes(byte[] input, int inOff, int len, byte[] output, int outOff)
+ {
+ if (inOff + len > input.Length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+ message.Write(input, inOff, len);
+ return 0;
+ }
+
+ public void Reset()
+ {
+ if (!initialised)
+ {
+ throw new ArgumentException("Need call init function before encryption/decryption");
+ }
+ reset(true);
+ }
+
+ private void reset(bool clearMac)
+ {
+ if (clearMac)
+ {
+ T = null;
+ }
+ input_empty = true;
+ aadData.SetLength(0);
+ message.SetLength(0);
+ Array.Copy(K, 0, state, 0, K.Length);
+ Array.Copy(N, 0, state, K.Length, N.Length);
+ }
+
+ void PHOTON_Permutation()
+ {
+ int i, j, k, l;
+ for (i = 0; i < DSquare; i++)
+ {
+ state_2d[i >> Dq][i & Dr] = (byte)(((state[i >> 1] & 0xFF) >> (4 * (i & 1))) & 0xf);
+ }
+ for (int round = 0; round < ROUND; round++)
+ {
+ //AddKey
+ for (i = 0; i < D; i++)
+ {
+ state_2d[i][0] ^= RC[i][round];
+ }
+ //SubCell
+ for (i = 0; i < D; i++)
+ {
+ for (j = 0; j < D; j++)
+ {
+ state_2d[i][j] = sbox[state_2d[i][j]];
+ }
+ }
+ //ShiftRow
+ for (i = 1; i < D; i++)
+ {
+ Array.Copy(state_2d[i], 0, state, 0, D);
+ Array.Copy(state, i, state_2d[i], 0, D - i);
+ Array.Copy(state, 0, state_2d[i], D - i, i);
+ }
+ //MixColumn
+ for (j = 0; j < D; j++)
+ {
+ for (i = 0; i < D; i++)
+ {
+ byte sum = 0;
+ for (k = 0; k < D; k++)
+ {
+ int x = MixColMatrix[i][k], ret = 0, b = state_2d[k][j];
+ for (l = 0; l < S; l++)
+ {
+ if (((b >> l) & 1) != 0)
+ {
+ ret ^= x;
+ }
+ if (((x >> S_1) & 1) != 0)
+ {
+ x <<= 1;
+ x ^= 0x3;
+ }
+ else
+ {
+ x <<= 1;
+ }
+ }
+ sum ^= (byte)(ret & 15);
+ }
+ state[i] = sum;
+ }
+ for (i = 0; i < D; i++)
+ {
+ state_2d[i][j] = state[i];
+ }
+ }
+ }
+ for (i = 0; i < DSquare; i += 2)
+ {
+ state[i >> 1] = (byte)(((state_2d[i >> Dq][i & Dr] & 0xf)) | ((state_2d[i >> Dq][(i + 1) & Dr] & 0xf) << 4));
+ }
+ }
+
+ private byte select(bool condition1, bool condition2, byte option3, byte option4)
+ {
+ if (condition1 && condition2)
+ {
+ return 1;
+ }
+ if (condition1)
+ {
+ return 2;
+ }
+ if (condition2)
+ {
+ return option3;
+ }
+ return option4;
+ }
+
+ void rhoohr(byte[] ciphertext, int offset, byte[] plaintext, int inOff, int DBlen_inbytes)
+ {
+ byte[] OuterState_part1_ROTR1 = state_2d[0];
+ int i, loop_end = System.Math.Min(DBlen_inbytes, RATE_INBYTES_HALF);
+ for (i = 0; i < RATE_INBYTES_HALF - 1; i++)
+ {
+ OuterState_part1_ROTR1[i] = (byte)(((state[i] & 0xFF) >> 1) | ((state[(i + 1)] & 1) << 7));
+ }
+ OuterState_part1_ROTR1[RATE_INBYTES_HALF - 1] = (byte)(((state[i] & 0xFF) >> 1) | ((state[0] & 1) << 7));
+ i = 0;
+ while (i < loop_end)
+ {
+ ciphertext[i + offset] = (byte)(state[i + RATE_INBYTES_HALF] ^ plaintext[i++ + inOff]);
+ }
+ while (i < DBlen_inbytes)
+ {
+ ciphertext[i + offset] = (byte)(OuterState_part1_ROTR1[i - RATE_INBYTES_HALF] ^ plaintext[i++ + inOff]);
+ }
+ if (forEncryption)
+ {
+ XOR(plaintext, inOff, DBlen_inbytes);
+ }
+ else
+ {
+ XOR(ciphertext, inOff, DBlen_inbytes);
+ }
+ }
+
+ void XOR(byte[] in_right, int rOff, int iolen_inbytes)
+ {
+ for (int i = 0; i < iolen_inbytes; i++)
+ {
+ state[i] ^= in_right[rOff++];
+ }
+ }
+
+ public int DoFinal(byte[] output, int outOff)
+ {
+ if (!initialised)
+ {
+ throw new ArgumentException("Need call init function before encryption/decryption");
+ }
+ int len = (int)message.Length - (forEncryption ? 0 : TAG_INBYTES);
+ if ((forEncryption && len + TAG_INBYTES + outOff > output.Length) ||
+ (!forEncryption && len + outOff > output.Length))
+ {
+ throw new OutputLengthException("output buffer too short");
+ }
+ byte[] input = message.GetBuffer();
+ int inOff = 0;
+ A = aadData.GetBuffer();
+ int adlen = (int)aadData.Length, i;
+ if (adlen != 0 || len != 0)
+ {
+ input_empty = false;
+ }
+ byte c0 = select((len != 0), ((adlen % RATE_INBYTES) == 0), (byte)3, (byte)4);
+ byte c1 = select((adlen != 0), ((len % RATE_INBYTES) == 0), (byte)5, (byte)6);
+ int Dlen_inblocks, LastDBlocklen;
+ if (adlen != 0)
+ {
+ Dlen_inblocks = (adlen + RATE_INBYTES - 1) / RATE_INBYTES;
+ for (i = 0; i < Dlen_inblocks - 1; i++)
+ {
+ PHOTON_Permutation();
+ XOR(A, i * RATE_INBYTES, RATE_INBYTES);
+ }
+ PHOTON_Permutation();
+ LastDBlocklen = adlen - i * RATE_INBYTES;
+ XOR(A, i * RATE_INBYTES, LastDBlocklen);
+ if (LastDBlocklen < RATE_INBYTES)
+ {
+ state[LastDBlocklen] ^= 0x01; // ozs
+ }
+ state[STATE_INBYTES - 1] ^= (byte)(c0 << LAST_THREE_BITS_OFFSET);
+ }
+ if (len != 0)
+ {
+ Dlen_inblocks = (len + RATE_INBYTES - 1) / RATE_INBYTES;
+ for (i = 0; i < Dlen_inblocks - 1; i++)
+ {
+ PHOTON_Permutation();
+ rhoohr(output, outOff + i * RATE_INBYTES, input, inOff + i * RATE_INBYTES, RATE_INBYTES);
+ }
+ PHOTON_Permutation();
+ LastDBlocklen = len - i * RATE_INBYTES;
+ rhoohr(output, outOff + i * RATE_INBYTES, input, inOff + i * RATE_INBYTES, LastDBlocklen);
+ if (LastDBlocklen < RATE_INBYTES)
+ {
+ state[LastDBlocklen] ^= 0x01; // ozs
+ }
+ state[STATE_INBYTES - 1] ^= (byte)(c1 << LAST_THREE_BITS_OFFSET);
+ }
+ outOff += len;
+ if (input_empty)
+ {
+ state[STATE_INBYTES - 1] ^= (byte)(1 << LAST_THREE_BITS_OFFSET);
+ }
+ PHOTON_Permutation();
+ T = new byte[TAG_INBYTES];
+ Array.Copy(state, 0, T, 0, TAG_INBYTES);
+ if (forEncryption)
+ {
+ Array.Copy(T, 0, output, outOff, TAG_INBYTES);
+ len += TAG_INBYTES;
+ }
+ else
+ {
+ for (i = 0; i < TAG_INBYTES; ++i)
+ {
+ if (T[i] != input[len + i])
+ {
+ throw new ArgumentException("Mac does not match");
+ }
+ }
+ }
+ reset(false);
+ return len;
+ }
+
+ public int GetBlockSize()
+ {
+ return RATE_INBYTES;
+ }
+
+ public int GetKeyBytesSize()
+ {
+ return CRYPTO_KEYBYTES;
+ }
+
+ public int GetIVBytesSize()
+ {
+ return CRYPTO_NPUBBYTES;
+ }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public void ProcessAadBytes(ReadOnlySpan<byte> input)
+ {
+ aadData.Write(input);
+ }
+
+ public int ProcessByte(byte input, Span<byte> output)
+ {
+ byte[] rv = new byte[1];
+ int len = ProcessBytes(new byte[] { input }, 0, 1, rv, 0);
+ rv.AsSpan(0, len).CopyTo(output);
+ return len;
+ }
+
+ public int ProcessBytes(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ byte[] rv = new byte[input.Length];
+ int len = ProcessBytes(input.ToArray(), 0, rv.Length, rv, 0);
+ rv.AsSpan(0, len).CopyTo(output);
+ return len;
+ }
+
+ public int DoFinal(Span<byte> output)
+ {
+ byte[] rv;
+ if (forEncryption)
+ {
+ rv = new byte[message.Length + 16];
+ }
+ else
+ {
+ rv = new byte[message.Length - 16];
+ }
+ int len = DoFinal(rv, 0);
+ rv.AsSpan(0, len).CopyTo(output);
+ return rv.Length;
+ }
+#endif
+ }
+}
diff --git a/crypto/src/crypto/engines/RC2WrapEngine.cs b/crypto/src/crypto/engines/RC2WrapEngine.cs
index bc50f0db4..0dd20c176 100644
--- a/crypto/src/crypto/engines/RC2WrapEngine.cs
+++ b/crypto/src/crypto/engines/RC2WrapEngine.cs
@@ -56,14 +56,14 @@ namespace Org.BouncyCastle.Crypto.Engines
this.forWrapping = forWrapping;
this.engine = new CbcBlockCipher(new RC2Engine());
- if (parameters is ParametersWithRandom pWithR)
+ if (parameters is ParametersWithRandom withRandom)
{
- sr = pWithR.Random;
- parameters = pWithR.Parameters;
+ sr = withRandom.Random;
+ parameters = withRandom.Parameters;
}
else
{
- sr = CryptoServicesRegistrar.GetSecureRandom();
+ sr = forWrapping ? CryptoServicesRegistrar.GetSecureRandom() : null;
}
if (parameters is ParametersWithIV)
@@ -111,96 +111,66 @@ namespace Org.BouncyCastle.Crypto.Engines
* @param inLen
* @return
*/
- public virtual byte[] Wrap(
- byte[] input,
- int inOff,
- int length)
+ public virtual byte[] Wrap(byte[] input, int inOff, int length)
{
if (!forWrapping)
- {
throw new InvalidOperationException("Not initialized for wrapping");
- }
- int len = length + 1;
- if ((len % 8) != 0)
- {
- len += 8 - (len % 8);
- }
+ int len = (length + 8) & ~7;
+ int ivLen = iv.Length;
- byte [] keyToBeWrapped = new byte[len];
+ // Let TEMP = IV || WKCKS.
+ byte[] TEMP = Arrays.CopyOf(iv, ivLen + len + 8);
+ TEMP[ivLen] = (byte)length;
+ Array.Copy(input, inOff, TEMP, ivLen + 1, length);
- keyToBeWrapped[0] = (byte)length;
- Array.Copy(input, inOff, keyToBeWrapped, 1, length);
-
- byte[] pad = new byte[keyToBeWrapped.Length - length - 1];
-
- if (pad.Length > 0)
+ int padLen = len - length - 1;
+ if (padLen > 0)
{
- sr.NextBytes(pad);
- Array.Copy(pad, 0, keyToBeWrapped, length + 1, pad.Length);
- }
+ sr.NextBytes(TEMP, ivLen + len - padLen, padLen);
+ }
- // Compute the CMS Key Checksum, (section 5.6.1), call this CKS.
- byte[] CKS = CalculateCmsKeyChecksum(keyToBeWrapped);
+ // Compute the CMS Key Checksum, (section 5.6.1), call this CKS.
+ CalculateCmsKeyChecksum(TEMP, ivLen, len, TEMP, ivLen + len);
- // Let WKCKS = WK || CKS where || is concatenation.
- byte[] WKCKS = new byte[keyToBeWrapped.Length + CKS.Length];
-
- Array.Copy(keyToBeWrapped, 0, WKCKS, 0, keyToBeWrapped.Length);
- Array.Copy(CKS, 0, WKCKS, keyToBeWrapped.Length, CKS.Length);
-
- // Encrypt WKCKS in CBC mode using KEK as the key and IV as the
- // initialization vector. Call the results TEMP1.
- byte [] TEMP1 = new byte[WKCKS.Length];
-
- Array.Copy(WKCKS, 0, TEMP1, 0, WKCKS.Length);
-
- int noOfBlocks = WKCKS.Length / engine.GetBlockSize();
- int extraBytes = WKCKS.Length % engine.GetBlockSize();
-
- if (extraBytes != 0)
- {
- throw new InvalidOperationException("Not multiple of block length");
- }
+ int blockSize = engine.GetBlockSize();
- engine.Init(true, paramPlusIV);
+ // Encrypt WKCKS in CBC mode using KEK as the key and IV as the initialization vector.
+ {
+ engine.Init(true, paramPlusIV);
- for (int i = 0; i < noOfBlocks; i++)
- {
- int currentBytePos = i * engine.GetBlockSize();
+ int pos = ivLen;
+ while (pos < TEMP.Length)
+ {
+ engine.ProcessBlock(TEMP, pos, TEMP, pos);
+ pos += blockSize;
+ }
- engine.ProcessBlock(TEMP1, currentBytePos, TEMP1, currentBytePos);
+ if (pos != TEMP.Length)
+ throw new InvalidOperationException("Not multiple of block length");
}
- // Left TEMP2 = IV || TEMP1.
- byte[] TEMP2 = new byte[this.iv.Length + TEMP1.Length];
-
- Array.Copy(this.iv, 0, TEMP2, 0, this.iv.Length);
- Array.Copy(TEMP1, 0, TEMP2, this.iv.Length, TEMP1.Length);
-
- // Reverse the order of the octets in TEMP2 and call the result TEMP3.
- byte[] TEMP3 = new byte[TEMP2.Length];
-
- for (int i = 0; i < TEMP2.Length; i++)
- {
- TEMP3[i] = TEMP2[TEMP2.Length - (i + 1)];
- }
+ // Reverse the order of the octets in TEMP.
+ Array.Reverse(TEMP);
- // Encrypt TEMP3 in CBC mode using the KEK and an initialization vector
+ // Encrypt TEMP in CBC mode using the KEK and an initialization vector
// of 0x 4a dd a2 2c 79 e8 21 05. The resulting cipher text is the desired
// result. It is 40 octets long if a 168 bit key is being wrapped.
- ParametersWithIV param2 = new ParametersWithIV(this.parameters, IV2);
-
- this.engine.Init(true, param2);
-
- for (int i = 0; i < noOfBlocks + 1; i++)
{
- int currentBytePos = i * engine.GetBlockSize();
+ engine.Init(true, new ParametersWithIV(this.parameters, IV2));
- engine.ProcessBlock(TEMP3, currentBytePos, TEMP3, currentBytePos);
- }
+ int pos = 0;
+ while (pos < TEMP.Length)
+ {
+ engine.ProcessBlock(TEMP, pos, TEMP, pos);
+ pos += blockSize;
+ }
- return TEMP3;
+ if (pos != TEMP.Length)
+ throw new InvalidOperationException("Not multiple of block length");
+ }
+
+ return TEMP;
}
/**
@@ -212,28 +182,16 @@ namespace Org.BouncyCastle.Crypto.Engines
* @return
* @throws InvalidCipherTextException
*/
- public virtual byte[] Unwrap(
- byte[] input,
- int inOff,
- int length)
+ public virtual byte[] Unwrap(byte[] input, int inOff, int length)
{
if (forWrapping)
- {
throw new InvalidOperationException("Not set for unwrapping");
- }
-
if (input == null)
- {
throw new InvalidCipherTextException("Null pointer as ciphertext");
- }
-
if (length % engine.GetBlockSize() != 0)
- {
- throw new InvalidCipherTextException("Ciphertext not multiple of "
- + engine.GetBlockSize());
- }
+ throw new InvalidCipherTextException("Ciphertext not multiple of " + engine.GetBlockSize());
- /*
+ /*
// Check if the length of the cipher text is reasonable given the key
// type. It must be 40 bytes for a 168 bit key and either 32, 40, or
// 48 bytes for a 128, 192, or 256 bit key. If the length is not supported
@@ -249,82 +207,64 @@ namespace Org.BouncyCastle.Crypto.Engines
}
*/
- // Decrypt the cipher text with TRIPLedeS in CBC mode using the KEK
- // and an initialization vector (IV) of 0x4adda22c79e82105. Call the output TEMP3.
- ParametersWithIV param2 = new ParametersWithIV(this.parameters, IV2);
-
- this.engine.Init(false, param2);
+ int blockSize = engine.GetBlockSize();
- byte [] TEMP3 = new byte[length];
+ byte[] TEMP = new byte[length];
- Array.Copy(input, inOff, TEMP3, 0, length);
+ // Decrypt the cipher text with TRIPLedeS in CBC mode using the KEK
+ // and an initialization vector (IV) of 0x4adda22c79e82105. Call the output TEMP.
+ {
+ engine.Init(false, new ParametersWithIV(this.parameters, IV2));
- for (int i = 0; i < (TEMP3.Length / engine.GetBlockSize()); i++)
- {
- int currentBytePos = i * engine.GetBlockSize();
-
- engine.ProcessBlock(TEMP3, currentBytePos, TEMP3, currentBytePos);
- }
-
- // Reverse the order of the octets in TEMP3 and call the result TEMP2.
- byte[] TEMP2 = new byte[TEMP3.Length];
-
- for (int i = 0; i < TEMP3.Length; i++)
- {
- TEMP2[i] = TEMP3[TEMP3.Length - (i + 1)];
- }
-
- // Decompose TEMP2 into IV, the first 8 octets, and TEMP1, the remaining octets.
- this.iv = new byte[8];
-
- byte[] TEMP1 = new byte[TEMP2.Length - 8];
-
- Array.Copy(TEMP2, 0, this.iv, 0, 8);
- Array.Copy(TEMP2, 8, TEMP1, 0, TEMP2.Length - 8);
+ int pos = 0;
+ while (pos < TEMP.Length)
+ {
+ engine.ProcessBlock(input, inOff + pos, TEMP, pos);
+ pos += blockSize;
+ }
- // Decrypt TEMP1 using TRIPLedeS in CBC mode using the KEK and the IV
- // found in the previous step. Call the result WKCKS.
- this.paramPlusIV = new ParametersWithIV(this.parameters, this.iv);
+ if (pos != TEMP.Length)
+ throw new InvalidOperationException("Not multiple of block length");
+ }
- this.engine.Init(false, this.paramPlusIV);
+ // Reverse the order of the octets in TEMP.
+ Array.Reverse(TEMP);
- byte[] LCEKPADICV = new byte[TEMP1.Length];
+ // Decompose TEMP into IV, the first 8 octets, and LCEKPADICV, the remaining octets.
+ this.iv = Arrays.CopyOf(TEMP, 8);
- Array.Copy(TEMP1, 0, LCEKPADICV, 0, TEMP1.Length);
+ // Decrypt LCEKPADICV using TRIPLedeS in CBC mode using the KEK and the IV
+ // found in the previous step. Call the result WKCKS.
+ this.paramPlusIV = new ParametersWithIV(this.parameters, this.iv);
- for (int i = 0; i < (LCEKPADICV.Length / engine.GetBlockSize()); i++)
{
- int currentBytePos = i * engine.GetBlockSize();
+ this.engine.Init(false, this.paramPlusIV);
- engine.ProcessBlock(LCEKPADICV, currentBytePos, LCEKPADICV, currentBytePos);
- }
+ int pos = 8;
+ while (pos < TEMP.Length)
+ {
+ engine.ProcessBlock(TEMP, pos, TEMP, pos);
+ pos += blockSize;
+ }
- // Decompose LCEKPADICV. CKS is the last 8 octets and WK, the wrapped key, are
- // those octets before the CKS.
- byte[] result = new byte[LCEKPADICV.Length - 8];
- byte[] CKStoBeVerified = new byte[8];
+ if (pos != TEMP.Length)
+ throw new InvalidOperationException("Not multiple of block length");
+ }
- Array.Copy(LCEKPADICV, 0, result, 0, LCEKPADICV.Length - 8);
- Array.Copy(LCEKPADICV, LCEKPADICV.Length - 8, CKStoBeVerified, 0, 8);
+ // Decompose LCEKPADICV. CKS is the last 8 octets and WK, the wrapped key, are
+ // those octets before the CKS.
- // Calculate a CMS Key Checksum, (section 5.6.1), over the WK and compare
- // with the CKS extracted in the above step. If they are not equal, return error.
- if (!CheckCmsKeyChecksum(result, CKStoBeVerified))
- {
- throw new InvalidCipherTextException(
- "Checksum inside ciphertext is corrupted");
- }
+ // Calculate a CMS Key Checksum, (section 5.6.1), over the WK and compare
+ // with the CKS extracted in the above step. If they are not equal, return error.
+ if (!CheckCmsKeyChecksum(TEMP, 8, TEMP.Length - 16, TEMP, TEMP.Length - 8))
+ throw new InvalidCipherTextException("Checksum inside ciphertext is corrupted");
- if ((result.Length - ((result[0] & 0xff) + 1)) > 7)
- {
- throw new InvalidCipherTextException(
- "too many pad bytes (" + (result.Length - ((result[0] & 0xff) + 1)) + ")");
- }
+ int padLen = TEMP.Length - 16 - TEMP[8] - 1;
+ if ((padLen & 7) != padLen)
+ throw new InvalidCipherTextException("Invalid padding length (" + padLen + ")");
// CEK is the wrapped key, now extracted for use in data decryption.
- byte[] CEK = new byte[result[0]];
- Array.Copy(result, 1, CEK, 0, CEK.Length);
- return CEK;
+ return Arrays.CopyOfRange(TEMP, 9, 9 + TEMP[8]);
}
/**
@@ -340,15 +280,12 @@ namespace Org.BouncyCastle.Crypto.Engines
* @throws Exception
* @see http://www.w3.org/TR/xmlenc-core/#sec-CMSKeyChecksum
*/
- private byte[] CalculateCmsKeyChecksum(
- byte[] key)
+ private void CalculateCmsKeyChecksum(byte[] key, int keyOff, int keyLen, byte[] cks, int cksOff)
{
- sha1.BlockUpdate(key, 0, key.Length);
+ sha1.BlockUpdate(key, keyOff, keyLen);
sha1.DoFinal(digest, 0);
- byte[] result = new byte[8];
- Array.Copy(digest, 0, result, 0, 8);
- return result;
+ Array.Copy(digest, 0, cks, cksOff, 8);
}
/**
@@ -357,11 +294,12 @@ namespace Org.BouncyCastle.Crypto.Engines
* @return
* @see http://www.w3.org/TR/xmlenc-core/#sec-CMSKeyChecksum
*/
- private bool CheckCmsKeyChecksum(
- byte[] key,
- byte[] checksum)
+ private bool CheckCmsKeyChecksum(byte[] key, int keyOff, int keyLen, byte[] cks, int cksOff)
{
- return Arrays.FixedTimeEquals(CalculateCmsKeyChecksum(key), checksum);
+ sha1.BlockUpdate(key, keyOff, keyLen);
+ sha1.DoFinal(digest, 0);
+
+ return Arrays.FixedTimeEquals(8, digest, 0, cks, cksOff);
}
}
}
diff --git a/crypto/src/crypto/engines/RC4Engine.cs b/crypto/src/crypto/engines/RC4Engine.cs
index 5ee07c766..fe9594e10 100644
--- a/crypto/src/crypto/engines/RC4Engine.cs
+++ b/crypto/src/crypto/engines/RC4Engine.cs
@@ -68,12 +68,7 @@ namespace Org.BouncyCastle.Crypto.Engines
return (byte)(input ^ engineState[(engineState[x] + engineState[y]) & 0xff]);
}
- public virtual void ProcessBytes(
- byte[] input,
- int inOff,
- int length,
- byte[] output,
- int outOff)
+ public virtual void ProcessBytes(byte[] input, int inOff, int length, byte[] output, int outOff)
{
Check.DataLength(input, inOff, length, "input buffer too short");
Check.OutputLength(output, outOff, length, "output buffer too short");
diff --git a/crypto/src/crypto/engines/RFC3211WrapEngine.cs b/crypto/src/crypto/engines/RFC3211WrapEngine.cs
index 42027cf25..86bd08f8f 100644
--- a/crypto/src/crypto/engines/RFC3211WrapEngine.cs
+++ b/crypto/src/crypto/engines/RFC3211WrapEngine.cs
@@ -30,17 +30,13 @@ namespace Org.BouncyCastle.Crypto.Engines
if (param is ParametersWithRandom withRandom)
{
- this.rand = withRandom.Random;
this.param = withRandom.Parameters as ParametersWithIV;
- }
- else
+ this.rand = withRandom.Random;
+ }
+ else
{
- if (forWrapping)
- {
- rand = CryptoServicesRegistrar.GetSecureRandom();
- }
-
this.param = param as ParametersWithIV;
+ this.rand = forWrapping ? CryptoServicesRegistrar.GetSecureRandom() : null;
}
if (null == this.param)
diff --git a/crypto/src/crypto/engines/RFC3394WrapEngine.cs b/crypto/src/crypto/engines/RFC3394WrapEngine.cs
index 9744130d2..e1368f25b 100644
--- a/crypto/src/crypto/engines/RFC3394WrapEngine.cs
+++ b/crypto/src/crypto/engines/RFC3394WrapEngine.cs
@@ -34,31 +34,28 @@ namespace Org.BouncyCastle.Crypto.Engines
this.wrapCipherMode = !useReverseDirection;
}
- public virtual void Init(
- bool forWrapping,
- ICipherParameters parameters)
+ public virtual void Init(bool forWrapping, ICipherParameters parameters)
{
this.forWrapping = forWrapping;
- if (parameters is ParametersWithRandom)
+ if (parameters is ParametersWithRandom withRandom)
{
- parameters = ((ParametersWithRandom) parameters).Parameters;
+ parameters = withRandom.Parameters;
}
- if (parameters is KeyParameter)
+ if (parameters is KeyParameter keyParameter)
{
- this.param = (KeyParameter) parameters;
+ this.param = keyParameter;
}
- else if (parameters is ParametersWithIV)
+ else if (parameters is ParametersWithIV withIV)
{
- ParametersWithIV pIV = (ParametersWithIV) parameters;
- byte[] iv = pIV.GetIV();
+ byte[] iv = withIV.GetIV();
if (iv.Length != 8)
throw new ArgumentException("IV length not equal to 8", "parameters");
this.iv = iv;
- this.param = (KeyParameter) pIV.Parameters;
+ this.param = (KeyParameter)withIV.Parameters;
}
else
{
diff --git a/crypto/src/crypto/engines/RSABlindingEngine.cs b/crypto/src/crypto/engines/RSABlindingEngine.cs
index 11bb8d9d9..13b364582 100644
--- a/crypto/src/crypto/engines/RSABlindingEngine.cs
+++ b/crypto/src/crypto/engines/RSABlindingEngine.cs
@@ -49,10 +49,8 @@ namespace Org.BouncyCastle.Crypto.Engines
{
RsaBlindingParameters p;
- if (param is ParametersWithRandom)
+ if (param is ParametersWithRandom rParam)
{
- ParametersWithRandom rParam = (ParametersWithRandom)param;
-
p = (RsaBlindingParameters)rParam.Parameters;
}
else
diff --git a/crypto/src/crypto/engines/RSACoreEngine.cs b/crypto/src/crypto/engines/RSACoreEngine.cs
index bd3d62f7c..ffa448b3d 100644
--- a/crypto/src/crypto/engines/RSACoreEngine.cs
+++ b/crypto/src/crypto/engines/RSACoreEngine.cs
@@ -33,15 +33,15 @@ namespace Org.BouncyCastle.Crypto.Engines
bool forEncryption,
ICipherParameters parameters)
{
- if (parameters is ParametersWithRandom)
+ if (parameters is ParametersWithRandom withRandom)
{
- parameters = ((ParametersWithRandom) parameters).Parameters;
+ parameters = withRandom.Parameters;
}
- if (!(parameters is RsaKeyParameters))
+ if (!(parameters is RsaKeyParameters rsaKeyParameters))
throw new InvalidKeyException("Not an RSA key");
- this.key = (RsaKeyParameters) parameters;
+ this.key = rsaKeyParameters;
this.forEncryption = forEncryption;
this.bitSize = key.Modulus.BitLength;
}
@@ -118,39 +118,30 @@ namespace Org.BouncyCastle.Crypto.Engines
{
CheckInitialised();
- if (key is RsaPrivateCrtKeyParameters)
+ if (key is RsaPrivateCrtKeyParameters crt)
{
//
// we have the extra factors, use the Chinese Remainder Theorem - the author
// wishes to express his thanks to Dirk Bonekaemper at rtsffm.com for
// advice regarding the expression of this.
//
- RsaPrivateCrtKeyParameters crtKey = (RsaPrivateCrtKeyParameters)key;
-
- BigInteger p = crtKey.P;
- BigInteger q = crtKey.Q;
- BigInteger dP = crtKey.DP;
- BigInteger dQ = crtKey.DQ;
- BigInteger qInv = crtKey.QInv;
-
- BigInteger mP, mQ, h, m;
+ BigInteger p = crt.P;
+ BigInteger q = crt.Q;
+ BigInteger dP = crt.DP;
+ BigInteger dQ = crt.DQ;
+ BigInteger qInv = crt.QInv;
// mP = ((input Mod p) ^ dP)) Mod p
- mP = (input.Remainder(p)).ModPow(dP, p);
+ BigInteger mP = (input.Remainder(p)).ModPow(dP, p);
- // mQ = ((input Mod q) ^ dQ)) Mod q
- mQ = (input.Remainder(q)).ModPow(dQ, q);
+ // mQ = ((input Mod q) ^ dQ)) Mod q
+ BigInteger mQ = (input.Remainder(q)).ModPow(dQ, q);
// h = qInv * (mP - mQ) Mod p
- h = mP.Subtract(mQ);
- h = h.Multiply(qInv);
- h = h.Mod(p); // Mod (in Java) returns the positive residual
-
- // m = h * q + mQ
- m = h.Multiply(q);
- m = m.Add(mQ);
+ BigInteger h = mP.Subtract(mQ).Multiply(qInv).Mod(p);
- return m;
+ // m = h * q + mQ
+ return h.Multiply(q).Add(mQ);
}
return input.ModPow(key.Exponent, key.Modulus);
diff --git a/crypto/src/crypto/engines/SM2Engine.cs b/crypto/src/crypto/engines/SM2Engine.cs
index e0734d424..96bad4eb2 100644
--- a/crypto/src/crypto/engines/SM2Engine.cs
+++ b/crypto/src/crypto/engines/SM2Engine.cs
@@ -55,23 +55,27 @@ namespace Org.BouncyCastle.Crypto.Engines
{
this.mForEncryption = forEncryption;
- if (forEncryption)
+ SecureRandom random = null;
+ if (param is ParametersWithRandom withRandom)
{
- ParametersWithRandom rParam = (ParametersWithRandom)param;
+ param = withRandom.Parameters;
+ random = withRandom.Random;
+ }
+
+ mECKey = (ECKeyParameters)param;
+ mECParams = mECKey.Parameters;
- mECKey = (ECKeyParameters)rParam.Parameters;
- mECParams = mECKey.Parameters;
+ if (forEncryption)
+ {
+ mRandom = CryptoServicesRegistrar.GetSecureRandom(random);
ECPoint s = ((ECPublicKeyParameters)mECKey).Q.Multiply(mECParams.H);
if (s.IsInfinity)
throw new ArgumentException("invalid key: [h]Q at infinity");
-
- mRandom = rParam.Random;
}
else
{
- mECKey = (ECKeyParameters)param;
- mECParams = mECKey.Parameters;
+ mRandom = null;
}
mCurveLength = (mECParams.Curve.FieldSize + 7) / 8;
diff --git a/crypto/src/crypto/engines/Salsa20Engine.cs b/crypto/src/crypto/engines/Salsa20Engine.cs
index 7c2c1e1f9..2e8f8e50a 100644
--- a/crypto/src/crypto/engines/Salsa20Engine.cs
+++ b/crypto/src/crypto/engines/Salsa20Engine.cs
@@ -27,7 +27,7 @@ namespace Org.BouncyCastle.Crypto.Engines
private readonly static uint[] TAU_SIGMA = Pack.LE_To_UInt32(Strings.ToAsciiByteArray("expand 16-byte k" + "expand 32-byte k"), 0, 8);
- internal void PackTauOrSigma(int keyLength, uint[] state, int stateOffset)
+ internal static void PackTauOrSigma(int keyLength, uint[] state, int stateOffset)
{
int tsOff = (keyLength - 16) / 4;
state[stateOffset] = TAU_SIGMA[tsOff];
diff --git a/crypto/src/crypto/engines/XoodyakEngine.cs b/crypto/src/crypto/engines/XoodyakEngine.cs
new file mode 100644
index 000000000..caf49e53c
--- /dev/null
+++ b/crypto/src/crypto/engines/XoodyakEngine.cs
@@ -0,0 +1,452 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * Xoodyak v1, https://csrc.nist.gov/CSRC/media/Projects/lightweight-cryptography/documents/finalist-round/updated-spec-doc/xoodyak-spec-final.pdf
+ * <p>
+ * Xoodyak with reference to C Reference Impl from: https://github.com/XKCP/XKCP
+ * </p>
+*/
+ public sealed class XoodyakEngine
+ : IAeadBlockCipher
+ {
+ private bool forEncryption;
+ private byte[] state;
+ private int phase;
+ private MODE mode;
+ private int Rabsorb;
+ private const int f_bPrime = 48;
+ private const int Rkout = 24;
+ private byte[] K;
+ private byte[] iv;
+ private const int PhaseDown = 1;
+ private const int PhaseUp = 2;
+ private const int NLANES = 12;
+ private const int NROWS = 3;
+ private const int NCOLUMS = 4;
+ private const int MAXROUNDS = 12;
+ private const int TAGLEN = 16;
+ const int Rkin = 44;
+ private byte[] tag;
+ private readonly uint[] RC = {0x00000058, 0x00000038, 0x000003C0, 0x000000D0, 0x00000120, 0x00000014, 0x00000060,
+ 0x0000002C, 0x00000380, 0x000000F0, 0x000001A0, 0x00000012};
+ private bool aadFinished;
+ private bool encrypted;
+ private bool initialised = false;
+ public string AlgorithmName => "Xoodak AEAD";
+
+ public IBlockCipher UnderlyingCipher => throw new NotImplementedException();
+
+ private MemoryStream aadData = new MemoryStream();
+ private MemoryStream message = new MemoryStream();
+
+ enum MODE
+ {
+ ModeHash,
+ ModeKeyed
+ }
+
+ public void Init(bool forEncryption, ICipherParameters param)
+ {
+ this.forEncryption = forEncryption;
+ if (!(param is ParametersWithIV))
+ {
+ throw new ArgumentException("Xoodyak init parameters must include an IV");
+ }
+ ParametersWithIV ivParams = (ParametersWithIV)param;
+ iv = ivParams.GetIV();
+ if (iv == null || iv.Length != 16)
+ {
+ throw new ArgumentException("Xoodyak requires exactly 16 bytes of IV");
+ }
+ if (!(ivParams.Parameters is KeyParameter))
+ {
+ throw new ArgumentException("Xoodyak init parameters must include a key");
+ }
+ KeyParameter key = (KeyParameter)ivParams.Parameters;
+ K = key.GetKey();
+ if (K.Length != 16)
+ {
+ throw new ArgumentException("Xoodyak key must be 128 bits long");
+ }
+ state = new byte[48];
+ tag = new byte[TAGLEN];
+ initialised = true;
+ reset(false);
+ }
+
+ public void ProcessAadByte(byte input)
+ {
+ if (aadFinished)
+ {
+ throw new ArgumentException("AAD cannot be added after reading a full block(" + GetBlockSize() +
+ " bytes) of input for " + (forEncryption ? "encryption" : "decryption"));
+ }
+ aadData.Write(new byte[] { input }, 0, 1);
+ }
+
+
+ public void ProcessAadBytes(byte[] input, int inOff, int len)
+ {
+ if (aadFinished)
+ {
+ throw new ArgumentException("AAD cannot be added after reading a full block(" + GetBlockSize() +
+ " bytes) of input for " + (forEncryption ? "encryption" : "decryption"));
+ }
+ if ((inOff + len) > input.Length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+ aadData.Write(input, inOff, len);
+ }
+
+
+ public int ProcessByte(byte input, byte[] output, int outOff)
+ {
+ return ProcessBytes(new byte[] { input }, 0, 1, output, outOff);
+ }
+
+ private void processAAD()
+ {
+ if (!aadFinished)
+ {
+ byte[] ad = aadData.GetBuffer();
+ AbsorbAny(ad, 0, (int)aadData.Length, Rabsorb, 0x03);
+ aadFinished = true;
+ }
+ }
+
+ public int ProcessBytes(byte[] input, int inOff, int len, byte[] output, int outOff)
+ {
+ if (!initialised)
+ {
+ throw new ArgumentException("Need call init function before encryption/decryption");
+ }
+ if (mode != MODE.ModeKeyed)
+ {
+ throw new ArgumentException("Xoodyak has not been initialised");
+ }
+ if (inOff + len > input.Length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+ message.Write(input, inOff, len);
+ int blockLen = (int)message.Length - (forEncryption ? 0 : TAGLEN);
+ if (blockLen >= GetBlockSize())
+ {
+ byte[] blocks = message.GetBuffer();
+ len = blockLen / GetBlockSize() * GetBlockSize();
+ if (len + outOff > output.Length)
+ {
+ throw new OutputLengthException("output buffer is too short");
+ }
+ processAAD();
+ encrypt(blocks, 0, len, output, outOff);
+ int messageLen = (int)message.Length;
+ message.SetLength(0);
+ message.Write(blocks, len, messageLen - len);
+ return len;
+ }
+ return 0;
+ }
+
+ private int encrypt(byte[] input, int inOff, int len, byte[] output, int outOff)
+ {
+ int IOLen = len;
+ int splitLen;
+ byte[] P = new byte[Rkout];
+ uint Cu = encrypted ? 0u : 0x80u;
+ while (IOLen != 0 || !encrypted)
+ {
+ splitLen = System.Math.Min(IOLen, Rkout); /* use Rkout instead of Rsqueeze, this function is only called in keyed mode */
+ if (forEncryption)
+ {
+ Array.Copy(input, inOff, P, 0, splitLen);
+ }
+ Up(null, 0, Cu); /* Up without extract */
+ /* Extract from Up and Add */
+ for (int i = 0; i < splitLen; i++)
+ {
+ output[outOff + i] = (byte)(input[inOff++] ^ state[i]);
+ }
+ if (forEncryption)
+ {
+ Down(P, 0, splitLen, 0x00);
+ }
+ else
+ {
+ Down(output, outOff, splitLen, 0x00);
+ }
+ Cu = 0x00;
+ outOff += splitLen;
+ IOLen -= splitLen;
+ encrypted = true;
+ }
+ return len;
+ }
+
+
+ public int DoFinal(byte[] output, int outOff)
+ {
+ if (!initialised)
+ {
+ throw new ArgumentException("Need call init function before encryption/decryption");
+ }
+
+ byte[] blocks = message.GetBuffer();
+ int len = (int)message.Length;
+ if ((forEncryption && len + TAGLEN + outOff > output.Length) ||
+ (!forEncryption && len - TAGLEN + outOff > output.Length))
+ {
+ throw new OutputLengthException("output buffer too short");
+ }
+ processAAD();
+ int rv = 0;
+ if (forEncryption)
+ {
+ encrypt(blocks, 0, len, output, outOff);
+ outOff += len;
+ tag = new byte[TAGLEN];
+ Up(tag, TAGLEN, 0x40);
+ Array.Copy(tag, 0, output, outOff, TAGLEN);
+ rv = len + TAGLEN;
+ }
+ else
+ {
+ int inOff = len - TAGLEN;
+ rv = inOff;
+ encrypt(blocks, 0, inOff, output, outOff);
+ tag = new byte[TAGLEN];
+ Up(tag, TAGLEN, 0x40);
+ for (int i = 0; i < TAGLEN; ++i)
+ {
+ if (tag[i] != blocks[inOff++])
+ {
+ throw new ArgumentException("Mac does not match");
+ }
+ }
+ }
+ reset(false);
+ return rv;
+ }
+
+
+ public byte[] GetMac()
+ {
+ return tag;
+ }
+
+
+ public int GetUpdateOutputSize(int len)
+ {
+ return len;
+ }
+
+
+ public int GetOutputSize(int len)
+ {
+ return len + TAGLEN;
+ }
+
+
+ public void Reset()
+ {
+ if (!initialised)
+ {
+ throw new ArgumentException("Need call init function before encryption/decryption");
+ }
+ reset(true);
+ }
+
+ private void reset(bool clearMac)
+ {
+ if (clearMac)
+ {
+ tag = null;
+ }
+ Arrays.Fill(state, (byte)0);
+ aadFinished = false;
+ encrypted = false;
+ phase = PhaseUp;
+ message.SetLength(0);
+ aadData.SetLength(0);
+ //Absorb key
+ int KLen = K.Length;
+ int IDLen = iv.Length;
+ byte[] KID = new byte[Rkin];
+ mode = MODE.ModeKeyed;
+ Rabsorb = Rkin;
+ Array.Copy(K, 0, KID, 0, KLen);
+ Array.Copy(iv, 0, KID, KLen, IDLen);
+ KID[KLen + IDLen] = (byte)IDLen;
+ AbsorbAny(KID, 0, KLen + IDLen + 1, Rabsorb, 0x02);
+ }
+
+ private void AbsorbAny(byte[] X, int Xoff, int XLen, int r, uint Cd)
+ {
+ int splitLen;
+ do
+ {
+ if (phase != PhaseUp)
+ {
+ Up(null, 0, 0);
+ }
+ splitLen = System.Math.Min(XLen, r);
+ Down(X, Xoff, splitLen, Cd);
+ Cd = 0;
+ Xoff += splitLen;
+ XLen -= splitLen;
+ }
+ while (XLen != 0);
+ }
+
+ private void Up(byte[] Yi, int YiLen, uint Cu)
+ {
+ if (mode != MODE.ModeHash)
+ {
+ state[f_bPrime - 1] ^= (byte)Cu;
+ }
+ uint[] a = new uint[NLANES];
+ Pack.LE_To_UInt32(state, 0, a, 0, a.Length);
+ uint x, y;
+ uint[] b = new uint[NLANES];
+ uint[] p = new uint[NCOLUMS];
+ uint[] e = new uint[NCOLUMS];
+ for (int i = 0; i < MAXROUNDS; ++i)
+ {
+ /* Theta: Column Parity Mixer */
+ for (x = 0; x < NCOLUMS; ++x)
+ {
+ p[x] = a[index(x, 0)] ^ a[index(x, 1)] ^ a[index(x, 2)];
+ }
+ for (x = 0; x < NCOLUMS; ++x)
+ {
+ y = p[(x + 3) & 3];
+ e[x] = ROTL32(y, 5) ^ ROTL32(y, 14);
+ }
+ for (x = 0; x < NCOLUMS; ++x)
+ {
+ for (y = 0; y < NROWS; ++y)
+ {
+ a[index(x, y)] ^= e[x];
+ }
+ }
+ /* Rho-west: plane shift */
+ for (x = 0; x < NCOLUMS; ++x)
+ {
+ b[index(x, 0)] = a[index(x, 0)];
+ b[index(x, 1)] = a[index(x + 3, 1)];
+ b[index(x, 2)] = ROTL32(a[index(x, 2)], 11);
+ }
+ /* Iota: round ant */
+ b[0] ^= RC[i];
+ /* Chi: non linear layer */
+ for (x = 0; x < NCOLUMS; ++x)
+ {
+ for (y = 0; y < NROWS; ++y)
+ {
+ a[index(x, y)] = b[index(x, y)] ^ (~b[index(x, y + 1)] & b[index(x, y + 2)]);
+ }
+ }
+ /* Rho-east: plane shift */
+ for (x = 0; x < NCOLUMS; ++x)
+ {
+ b[index(x, 0)] = a[index(x, 0)];
+ b[index(x, 1)] = ROTL32(a[index(x, 1)], 1);
+ b[index(x, 2)] = ROTL32(a[index(x + 2, 2)], 8);
+ }
+ Array.Copy(b, 0, a, 0, NLANES);
+ }
+ Pack.UInt32_To_LE(a, 0, a.Length, state, 0);
+ phase = PhaseUp;
+ if (Yi != null)
+ {
+ Array.Copy(state, 0, Yi, 0, YiLen);
+ }
+ }
+
+ void Down(byte[] Xi, int XiOff, int XiLen, uint Cd)
+ {
+ for (int i = 0; i < XiLen; i++)
+ {
+ state[i] ^= Xi[XiOff++];
+ }
+ state[XiLen] ^= 0x01;
+ state[f_bPrime - 1] ^= (byte)((mode == MODE.ModeHash) ? (Cd & 0x01) : Cd);
+ phase = PhaseDown;
+ }
+
+ private uint index(uint x, uint y)
+ {
+ return (((y % NROWS) * NCOLUMS) + ((x) % NCOLUMS));
+ }
+
+ private uint ROTL32(uint a, int offset)
+ {
+ return (a << (offset & 31)) ^ (a >> ((32 - (offset)) & 31));
+ }
+
+ public int GetBlockSize()
+ {
+ return Rkout;
+ }
+
+ public int GetKeyBytesSize()
+ {
+ return 16;
+ }
+
+ public int GetIVBytesSize()
+ {
+ return 16;
+ }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public void ProcessAadBytes(ReadOnlySpan<byte> input)
+ {
+ aadData.Write(input);
+ }
+
+ public int ProcessByte(byte input, Span<byte> output)
+ {
+ byte[] rv = new byte[1];
+ int len = ProcessBytes(new byte[] { input }, 0, 1, rv, 0);
+ rv.AsSpan(0, len).CopyTo(output);
+ return len;
+ }
+
+ public int ProcessBytes(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ byte[] rv = new byte[input.Length];
+ int len = ProcessBytes(input.ToArray(), 0, rv.Length, rv, 0);
+ rv.AsSpan(0, len).CopyTo(output);
+ return len;
+ }
+
+ public int DoFinal(Span<byte> output)
+ {
+ byte[] rv;
+ if (forEncryption)
+ {
+ rv = new byte[message.Length + 16];
+ }
+ else
+ {
+ rv = new byte[message.Length - 16];
+ }
+ int len = DoFinal(rv, 0);
+ rv.AsSpan(0, len).CopyTo(output);
+ return rv.Length;
+ }
+
+#endif
+
+ }
+}
\ No newline at end of file
diff --git a/crypto/src/crypto/fpe/SP80038G.cs b/crypto/src/crypto/fpe/SP80038G.cs
index 65dad0797..c57a34762 100644
--- a/crypto/src/crypto/fpe/SP80038G.cs
+++ b/crypto/src/crypto/fpe/SP80038G.cs
@@ -303,7 +303,8 @@ namespace Org.BouncyCastle.Crypto.Fpe
return tweak64;
}
- private static BigInteger CalculateY_FF1(IBlockCipher cipher, BigInteger bigRadix, byte[] T, int b, int d, int round, byte[] P, ushort[] AB)
+ private static BigInteger CalculateY_FF1(IBlockCipher cipher, BigInteger bigRadix, byte[] T, int b, int d,
+ int round, byte[] P, ushort[] AB)
{
int t = T.Length;
@@ -579,7 +580,7 @@ namespace Org.BouncyCastle.Crypto.Fpe
for (int i = 0; i < m; ++i)
{
- Xor(x, i * BLOCK_SIZE, y, 0, BLOCK_SIZE);
+ Bytes.XorTo(BLOCK_SIZE, x, i * BLOCK_SIZE, y, 0);
c.ProcessBlock(y, 0, y, 0);
}
@@ -601,14 +602,6 @@ namespace Org.BouncyCastle.Crypto.Fpe
throw new ArgumentException();
}
- private static void Xor(byte[] x, int xOff, byte[] y, int yOff, int len)
- {
- for (int i = 0; i < len; ++i)
- {
- y[yOff + i] ^= x[xOff + i];
- }
- }
-
private static byte[] ToByte(ushort[] buf)
{
byte[] s = new byte[buf.Length];
diff --git a/crypto/src/crypto/generators/ECKeyPairGenerator.cs b/crypto/src/crypto/generators/ECKeyPairGenerator.cs
index 6aba6921e..9ef5cdefd 100644
--- a/crypto/src/crypto/generators/ECKeyPairGenerator.cs
+++ b/crypto/src/crypto/generators/ECKeyPairGenerator.cs
@@ -50,26 +50,26 @@ namespace Org.BouncyCastle.Crypto.Generators
DerObjectIdentifier oid;
switch (parameters.Strength)
{
- case 192:
- oid = X9ObjectIdentifiers.Prime192v1;
- break;
- case 224:
- oid = SecObjectIdentifiers.SecP224r1;
- break;
- case 239:
- oid = X9ObjectIdentifiers.Prime239v1;
- break;
- case 256:
- oid = X9ObjectIdentifiers.Prime256v1;
- break;
- case 384:
- oid = SecObjectIdentifiers.SecP384r1;
- break;
- case 521:
- oid = SecObjectIdentifiers.SecP521r1;
- break;
- default:
- throw new InvalidParameterException("unknown key size.");
+ case 192:
+ oid = X9ObjectIdentifiers.Prime192v1;
+ break;
+ case 224:
+ oid = SecObjectIdentifiers.SecP224r1;
+ break;
+ case 239:
+ oid = X9ObjectIdentifiers.Prime239v1;
+ break;
+ case 256:
+ oid = X9ObjectIdentifiers.Prime256v1;
+ break;
+ case 384:
+ oid = SecObjectIdentifiers.SecP384r1;
+ break;
+ case 521:
+ oid = SecObjectIdentifiers.SecP521r1;
+ break;
+ default:
+ throw new InvalidParameterException("unknown key size.");
}
X9ECParameters ecps = FindECCurveByOid(oid);
@@ -131,42 +131,22 @@ namespace Org.BouncyCastle.Crypto.Generators
internal static X9ECParameters FindECCurveByName(string name)
{
- X9ECParameters ecP = CustomNamedCurves.GetByName(name);
- if (ecP == null)
- {
- ecP = ECNamedCurveTable.GetByName(name);
- }
- return ecP;
+ return CustomNamedCurves.GetByName(name) ?? ECNamedCurveTable.GetByName(name);
}
internal static X9ECParametersHolder FindECCurveByNameLazy(string name)
{
- X9ECParametersHolder holder = CustomNamedCurves.GetByNameLazy(name);
- if (holder == null)
- {
- holder = ECNamedCurveTable.GetByNameLazy(name);
- }
- return holder;
+ return CustomNamedCurves.GetByNameLazy(name) ?? ECNamedCurveTable.GetByNameLazy(name);
}
internal static X9ECParameters FindECCurveByOid(DerObjectIdentifier oid)
{
- X9ECParameters ecP = CustomNamedCurves.GetByOid(oid);
- if (ecP == null)
- {
- ecP = ECNamedCurveTable.GetByOid(oid);
- }
- return ecP;
+ return CustomNamedCurves.GetByOid(oid) ?? ECNamedCurveTable.GetByOid(oid);
}
internal static X9ECParametersHolder FindECCurveByOidLazy(DerObjectIdentifier oid)
{
- X9ECParametersHolder holder = CustomNamedCurves.GetByOidLazy(oid);
- if (holder == null)
- {
- holder = ECNamedCurveTable.GetByOidLazy(oid);
- }
- return holder;
+ return CustomNamedCurves.GetByOidLazy(oid) ?? ECNamedCurveTable.GetByOidLazy(oid);
}
internal static ECPublicKeyParameters GetCorrespondingPublicKey(
diff --git a/crypto/src/crypto/generators/HkdfBytesGenerator.cs b/crypto/src/crypto/generators/HkdfBytesGenerator.cs
index 43cd66525..c8bf333c2 100644
--- a/crypto/src/crypto/generators/HkdfBytesGenerator.cs
+++ b/crypto/src/crypto/generators/HkdfBytesGenerator.cs
@@ -2,7 +2,6 @@
using Org.BouncyCastle.Crypto.Macs;
using Org.BouncyCastle.Crypto.Parameters;
-using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Generators
{
diff --git a/crypto/src/crypto/generators/KDFCounterBytesGenerator.cs b/crypto/src/crypto/generators/KDFCounterBytesGenerator.cs
index 7fa50e2fa..7c08034c5 100644
--- a/crypto/src/crypto/generators/KDFCounterBytesGenerator.cs
+++ b/crypto/src/crypto/generators/KDFCounterBytesGenerator.cs
@@ -57,10 +57,7 @@ namespace Org.BouncyCastle.Crypto.Generators
public IMac Mac => prf;
- public IDigest Digest
- {
- get { return (prf as HMac)?.GetUnderlyingDigest(); }
- }
+ public IDigest Digest => (prf as HMac)?.GetUnderlyingDigest();
public int GenerateBytes(byte[] output, int outOff, int length)
{
diff --git a/crypto/src/crypto/generators/KDFDoublePipelineIterationBytesGenerator.cs b/crypto/src/crypto/generators/KDFDoublePipelineIterationBytesGenerator.cs
index 01feda6f4..cffd99132 100644
--- a/crypto/src/crypto/generators/KDFDoublePipelineIterationBytesGenerator.cs
+++ b/crypto/src/crypto/generators/KDFDoublePipelineIterationBytesGenerator.cs
@@ -9,6 +9,9 @@ namespace Org.BouncyCastle.Crypto.Generators
public sealed class KdfDoublePipelineIterationBytesGenerator
: IMacDerivationFunction
{
+ // please refer to the standard for the meaning of the variable names
+ // all field lengths are in bytes, not in bits as specified by the standard
+
// fields set by the constructor
private readonly IMac prf;
private readonly int h;
@@ -68,6 +71,78 @@ namespace Org.BouncyCastle.Crypto.Generators
generatedBytes = 0;
}
+ public IMac Mac => prf;
+
+ public IDigest Digest
+ {
+ get { return (prf as HMac)?.GetUnderlyingDigest(); }
+ }
+
+ public int GenerateBytes(byte[] output, int outOff, int length)
+ {
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ return GenerateBytes(output.AsSpan(outOff, length));
+#else
+ if (generatedBytes >= maxSizeExcl - length)
+ throw new DataLengthException("Current KDFCTR may only be used for " + maxSizeExcl + " bytes");
+
+ int toGenerate = length;
+ int posInK = generatedBytes % h;
+ if (posInK != 0)
+ {
+ // copy what is left in the currentT (1..hash
+ int toCopy = System.Math.Min(h - posInK, toGenerate);
+ Array.Copy(k, posInK, output, outOff, toCopy);
+ generatedBytes += toCopy;
+ toGenerate -= toCopy;
+ outOff += toCopy;
+ }
+
+ while (toGenerate > 0)
+ {
+ GenerateNext();
+ int toCopy = System.Math.Min(h, toGenerate);
+ Array.Copy(k, 0, output, outOff, toCopy);
+ generatedBytes += toCopy;
+ toGenerate -= toCopy;
+ outOff += toCopy;
+ }
+
+ return length;
+#endif
+ }
+
+ #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public int GenerateBytes(Span<byte> output)
+ {
+ int length = output.Length;
+ if (generatedBytes >= maxSizeExcl - length)
+ throw new DataLengthException("Current KDFCTR may only be used for " + maxSizeExcl + " bytes");
+
+ int posInK = generatedBytes % h;
+ if (posInK != 0)
+ {
+ // copy what is left in the currentT (1..hash
+ GenerateNext();
+ int toCopy = System.Math.Min(h - posInK, output.Length);
+ k.AsSpan(posInK, toCopy).CopyTo(output);
+ generatedBytes += toCopy;
+ output = output[toCopy..];
+ }
+
+ while (!output.IsEmpty)
+ {
+ GenerateNext();
+ int toCopy = System.Math.Min(h, output.Length);
+ k.AsSpan(0, toCopy).CopyTo(output);
+ generatedBytes += toCopy;
+ output = output[toCopy..];
+ }
+
+ return length;
+ }
+ #endif
+
private void GenerateNext()
{
if (generatedBytes == 0)
@@ -117,77 +192,5 @@ namespace Org.BouncyCastle.Crypto.Generators
prf.BlockUpdate(fixedInputData, 0, fixedInputData.Length);
prf.DoFinal(k, 0);
}
-
- public IDigest Digest
- {
- get { return (prf as HMac)?.GetUnderlyingDigest(); }
- }
-
- public int GenerateBytes(byte[] output, int outOff, int length)
- {
-#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
- return GenerateBytes(output.AsSpan(outOff, length));
-#else
- if (generatedBytes >= maxSizeExcl - length)
- throw new DataLengthException("Current KDFCTR may only be used for " + maxSizeExcl + " bytes");
-
- int toGenerate = length;
- int posInK = generatedBytes % h;
- if (posInK != 0)
- {
- // copy what is left in the currentT (1..hash
- int toCopy = System.Math.Min(h - posInK, toGenerate);
- Array.Copy(k, posInK, output, outOff, toCopy);
- generatedBytes += toCopy;
- toGenerate -= toCopy;
- outOff += toCopy;
- }
-
- while (toGenerate > 0)
- {
- GenerateNext();
- int toCopy = System.Math.Min(h, toGenerate);
- Array.Copy(k, 0, output, outOff, toCopy);
- generatedBytes += toCopy;
- toGenerate -= toCopy;
- outOff += toCopy;
- }
-
- return length;
-#endif
- }
-
-#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
- public int GenerateBytes(Span<byte> output)
- {
- int length = output.Length;
- if (generatedBytes >= maxSizeExcl - length)
- throw new DataLengthException("Current KDFCTR may only be used for " + maxSizeExcl + " bytes");
-
- int posInK = generatedBytes % h;
- if (posInK != 0)
- {
- // copy what is left in the currentT (1..hash
- GenerateNext();
- int toCopy = System.Math.Min(h - posInK, output.Length);
- k.AsSpan(posInK, toCopy).CopyTo(output);
- generatedBytes += toCopy;
- output = output[toCopy..];
- }
-
- while (!output.IsEmpty)
- {
- GenerateNext();
- int toCopy = System.Math.Min(h, output.Length);
- k.AsSpan(0, toCopy).CopyTo(output);
- generatedBytes += toCopy;
- output = output[toCopy..];
- }
-
- return length;
- }
-#endif
-
- public IMac Mac => prf;
}
}
diff --git a/crypto/src/crypto/generators/KDFFeedbackBytesGenerator.cs b/crypto/src/crypto/generators/KDFFeedbackBytesGenerator.cs
index 58a035ef6..c07e1de42 100644
--- a/crypto/src/crypto/generators/KDFFeedbackBytesGenerator.cs
+++ b/crypto/src/crypto/generators/KDFFeedbackBytesGenerator.cs
@@ -71,6 +71,8 @@ namespace Org.BouncyCastle.Crypto.Generators
generatedBytes = 0;
}
+ public IMac Mac => prf;
+
public IDigest Digest
{
get { return (prf as HMac)?.GetUnderlyingDigest(); }
@@ -183,7 +185,5 @@ namespace Org.BouncyCastle.Crypto.Generators
prf.BlockUpdate(fixedInputData, 0, fixedInputData.Length);
prf.DoFinal(k, 0);
}
-
- public IMac Mac => prf;
}
}
diff --git a/crypto/src/crypto/io/CipherStream.cs b/crypto/src/crypto/io/CipherStream.cs
index 1d9a768a1..bcfbb2afb 100644
--- a/crypto/src/crypto/io/CipherStream.cs
+++ b/crypto/src/crypto/io/CipherStream.cs
@@ -45,7 +45,7 @@ namespace Org.BouncyCastle.Crypto.IO
get { return m_stream.CanRead; }
}
- public sealed override bool CanSeek
+ public override bool CanSeek
{
get { return false; }
}
@@ -74,12 +74,12 @@ namespace Org.BouncyCastle.Crypto.IO
m_stream.Flush();
}
- public sealed override long Length
+ public override long Length
{
get { throw new NotSupportedException(); }
}
- public sealed override long Position
+ public override long Position
{
get { throw new NotSupportedException(); }
set { throw new NotSupportedException(); }
@@ -153,12 +153,12 @@ namespace Org.BouncyCastle.Crypto.IO
return m_readBuf[m_readBufPos++];
}
- public sealed override long Seek(long offset, SeekOrigin origin)
+ public override long Seek(long offset, SeekOrigin origin)
{
throw new NotSupportedException();
}
- public sealed override void SetLength(long length)
+ public override void SetLength(long length)
{
throw new NotSupportedException();
}
diff --git a/crypto/src/crypto/io/DigestStream.cs b/crypto/src/crypto/io/DigestStream.cs
index 5d4d8bcb8..e57a2f851 100644
--- a/crypto/src/crypto/io/DigestStream.cs
+++ b/crypto/src/crypto/io/DigestStream.cs
@@ -1,8 +1,6 @@
using System;
using System.IO;
-using Org.BouncyCastle.Utilities;
-
namespace Org.BouncyCastle.Crypto.IO
{
public sealed class DigestStream
@@ -28,7 +26,7 @@ namespace Org.BouncyCastle.Crypto.IO
get { return m_stream.CanRead; }
}
- public sealed override bool CanSeek
+ public override bool CanSeek
{
get { return false; }
}
@@ -57,12 +55,12 @@ namespace Org.BouncyCastle.Crypto.IO
m_stream.Flush();
}
- public sealed override long Length
+ public override long Length
{
get { throw new NotSupportedException(); }
}
- public sealed override long Position
+ public override long Position
{
get { throw new NotSupportedException(); }
set { throw new NotSupportedException(); }
@@ -106,12 +104,12 @@ namespace Org.BouncyCastle.Crypto.IO
return b;
}
- public sealed override long Seek(long offset, SeekOrigin origin)
+ public override long Seek(long offset, SeekOrigin origin)
{
throw new NotSupportedException();
}
- public sealed override void SetLength(long length)
+ public override void SetLength(long length)
{
throw new NotSupportedException();
}
diff --git a/crypto/src/crypto/io/MacStream.cs b/crypto/src/crypto/io/MacStream.cs
index b47025d5b..bf144bf82 100644
--- a/crypto/src/crypto/io/MacStream.cs
+++ b/crypto/src/crypto/io/MacStream.cs
@@ -1,8 +1,6 @@
using System;
using System.IO;
-using Org.BouncyCastle.Utilities;
-
namespace Org.BouncyCastle.Crypto.IO
{
public sealed class MacStream
@@ -28,7 +26,7 @@ namespace Org.BouncyCastle.Crypto.IO
get { return m_stream.CanRead; }
}
- public sealed override bool CanSeek
+ public override bool CanSeek
{
get { return false; }
}
@@ -57,12 +55,12 @@ namespace Org.BouncyCastle.Crypto.IO
m_stream.Flush();
}
- public sealed override long Length
+ public override long Length
{
get { throw new NotSupportedException(); }
}
- public sealed override long Position
+ public override long Position
{
get { throw new NotSupportedException(); }
set { throw new NotSupportedException(); }
@@ -106,12 +104,12 @@ namespace Org.BouncyCastle.Crypto.IO
return b;
}
- public sealed override long Seek(long offset, SeekOrigin origin)
+ public override long Seek(long offset, SeekOrigin origin)
{
throw new NotSupportedException();
}
- public sealed override void SetLength(long length)
+ public override void SetLength(long length)
{
throw new NotSupportedException();
}
diff --git a/crypto/src/crypto/io/SignerStream.cs b/crypto/src/crypto/io/SignerStream.cs
index ee7be1cd7..e527e5450 100644
--- a/crypto/src/crypto/io/SignerStream.cs
+++ b/crypto/src/crypto/io/SignerStream.cs
@@ -1,49 +1,47 @@
using System;
using System.IO;
-using Org.BouncyCastle.Utilities;
-
namespace Org.BouncyCastle.Crypto.IO
{
public sealed class SignerStream
: Stream
{
- private readonly Stream stream;
- private readonly ISigner inSigner;
- private readonly ISigner outSigner;
+ private readonly Stream m_stream;
+ private readonly ISigner m_readSigner;
+ private readonly ISigner m_writeSigner;
public SignerStream(Stream stream, ISigner readSigner, ISigner writeSigner)
{
- this.stream = stream;
- this.inSigner = readSigner;
- this.outSigner = writeSigner;
+ m_stream = stream;
+ m_readSigner = readSigner;
+ m_writeSigner = writeSigner;
}
- public ISigner ReadSigner => inSigner;
+ public ISigner ReadSigner => m_readSigner;
- public ISigner WriteSigner => outSigner;
+ public ISigner WriteSigner => m_writeSigner;
public override bool CanRead
{
- get { return stream.CanRead; }
+ get { return m_stream.CanRead; }
}
- public sealed override bool CanSeek
+ public override bool CanSeek
{
get { return false; }
}
public override bool CanWrite
{
- get { return stream.CanWrite; }
+ get { return m_stream.CanWrite; }
}
#if NETCOREAPP2_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER
public override void CopyTo(Stream destination, int bufferSize)
{
- if (inSigner == null)
+ if (m_readSigner == null)
{
- stream.CopyTo(destination, bufferSize);
+ m_stream.CopyTo(destination, bufferSize);
}
else
{
@@ -54,15 +52,15 @@ namespace Org.BouncyCastle.Crypto.IO
public override void Flush()
{
- stream.Flush();
+ m_stream.Flush();
}
- public sealed override long Length
+ public override long Length
{
get { throw new NotSupportedException(); }
}
- public sealed override long Position
+ public override long Position
{
get { throw new NotSupportedException(); }
set { throw new NotSupportedException(); }
@@ -70,11 +68,11 @@ namespace Org.BouncyCastle.Crypto.IO
public override int Read(byte[] buffer, int offset, int count)
{
- int n = stream.Read(buffer, offset, count);
+ int n = m_stream.Read(buffer, offset, count);
- if (inSigner != null && n > 0)
+ if (m_readSigner != null && n > 0)
{
- inSigner.BlockUpdate(buffer, offset, n);
+ m_readSigner.BlockUpdate(buffer, offset, n);
}
return n;
@@ -83,11 +81,11 @@ namespace Org.BouncyCastle.Crypto.IO
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
public override int Read(Span<byte> buffer)
{
- int n = stream.Read(buffer);
+ int n = m_stream.Read(buffer);
- if (inSigner != null && n > 0)
+ if (m_readSigner != null && n > 0)
{
- inSigner.BlockUpdate(buffer[..n]);
+ m_readSigner.BlockUpdate(buffer[..n]);
}
return n;
@@ -96,55 +94,55 @@ namespace Org.BouncyCastle.Crypto.IO
public override int ReadByte()
{
- int b = stream.ReadByte();
+ int b = m_stream.ReadByte();
- if (inSigner != null && b >= 0)
+ if (m_readSigner != null && b >= 0)
{
- inSigner.Update((byte)b);
+ m_readSigner.Update((byte)b);
}
return b;
}
- public sealed override long Seek(long offset, SeekOrigin origin)
+ public override long Seek(long offset, SeekOrigin origin)
{
throw new NotSupportedException();
}
- public sealed override void SetLength(long length)
+ public override void SetLength(long length)
{
throw new NotSupportedException();
}
public override void Write(byte[] buffer, int offset, int count)
{
- stream.Write(buffer, offset, count);
+ m_stream.Write(buffer, offset, count);
- if (outSigner != null && count > 0)
+ if (m_writeSigner != null && count > 0)
{
- outSigner.BlockUpdate(buffer, offset, count);
+ m_writeSigner.BlockUpdate(buffer, offset, count);
}
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
public override void Write(ReadOnlySpan<byte> buffer)
{
- stream.Write(buffer);
+ m_stream.Write(buffer);
- if (outSigner != null && !buffer.IsEmpty)
+ if (m_writeSigner != null && !buffer.IsEmpty)
{
- outSigner.BlockUpdate(buffer);
+ m_writeSigner.BlockUpdate(buffer);
}
}
#endif
public override void WriteByte(byte value)
{
- stream.WriteByte(value);
+ m_stream.WriteByte(value);
- if (outSigner != null)
+ if (m_writeSigner != null)
{
- outSigner.Update(value);
+ m_writeSigner.Update(value);
}
}
@@ -152,7 +150,7 @@ namespace Org.BouncyCastle.Crypto.IO
{
if (disposing)
{
- stream.Dispose();
+ m_stream.Dispose();
}
base.Dispose(disposing);
}
diff --git a/crypto/src/crypto/macs/Poly1305.cs b/crypto/src/crypto/macs/Poly1305.cs
index d02216309..adf4975ba 100644
--- a/crypto/src/crypto/macs/Poly1305.cs
+++ b/crypto/src/crypto/macs/Poly1305.cs
@@ -4,6 +4,7 @@ using System.Diagnostics;
using System.Runtime.CompilerServices;
#endif
+using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Utilities;
@@ -22,7 +23,7 @@ namespace Org.BouncyCastle.Crypto.Macs
/// href="https://github.com/floodyberry/poly1305-donna">poly1305-donna-unrolled</a> C implementation
/// by Andrew M (@floodyberry).
/// </remarks>
- /// <seealso cref="Org.BouncyCastle.Crypto.Generators.Poly1305KeyGenerator"/>
+ /// <seealso cref="Poly1305KeyGenerator"/>
public class Poly1305
: IMac
{
diff --git a/crypto/src/crypto/modes/CcmBlockCipher.cs b/crypto/src/crypto/modes/CcmBlockCipher.cs
index e002c1f71..c2d3e7e76 100644
--- a/crypto/src/crypto/modes/CcmBlockCipher.cs
+++ b/crypto/src/crypto/modes/CcmBlockCipher.cs
@@ -275,7 +275,7 @@ namespace Org.BouncyCastle.Crypto.Modes
iv[0] = (byte)((q - 1) & 0x7);
nonce.CopyTo(iv, 1);
- IBlockCipher ctrCipher = new SicBlockCipher(cipher);
+ var ctrCipher = new SicBlockCipher(cipher);
ctrCipher.Init(forEncryption, new ParametersWithIV(keyParam, iv));
int outputLen;
@@ -375,7 +375,7 @@ namespace Org.BouncyCastle.Crypto.Modes
iv[0] = (byte)((q - 1) & 0x7);
nonce.CopyTo(iv, 1);
- IBlockCipher ctrCipher = new SicBlockCipher(cipher);
+ var ctrCipher = new SicBlockCipher(cipher);
ctrCipher.Init(forEncryption, new ParametersWithIV(keyParam, iv));
int outputLen;
@@ -452,8 +452,7 @@ namespace Org.BouncyCastle.Crypto.Modes
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
return CalculateMac(data.AsSpan(dataOff, dataLen), macBlock);
#else
- IMac cMac = new CbcBlockCipherMac(cipher, macSize * 8);
-
+ var cMac = new CbcBlockCipherMac(cipher, macSize * 8);
cMac.Init(keyParam);
//
@@ -544,8 +543,7 @@ namespace Org.BouncyCastle.Crypto.Modes
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
private int CalculateMac(ReadOnlySpan<byte> data, Span<byte> macBlock)
{
- IMac cMac = new CbcBlockCipherMac(cipher, macSize * 8);
-
+ var cMac = new CbcBlockCipherMac(cipher, macSize * 8);
cMac.Init(keyParam);
//
diff --git a/crypto/src/crypto/modes/CfbBlockCipher.cs b/crypto/src/crypto/modes/CfbBlockCipher.cs
index 7bce9843f..cdb17dd3c 100644
--- a/crypto/src/crypto/modes/CfbBlockCipher.cs
+++ b/crypto/src/crypto/modes/CfbBlockCipher.cs
@@ -61,9 +61,8 @@ namespace Org.BouncyCastle.Crypto.Modes
ICipherParameters parameters)
{
this.encrypting = forEncryption;
- if (parameters is ParametersWithIV)
+ if (parameters is ParametersWithIV ivParam)
{
- ParametersWithIV ivParam = (ParametersWithIV) parameters;
byte[] iv = ivParam.GetIV();
int diff = IV.Length - iv.Length;
Array.Copy(iv, 0, IV, diff, iv.Length);
diff --git a/crypto/src/crypto/modes/EAXBlockCipher.cs b/crypto/src/crypto/modes/EAXBlockCipher.cs
index 770c432e2..3b95cd7f2 100644
--- a/crypto/src/crypto/modes/EAXBlockCipher.cs
+++ b/crypto/src/crypto/modes/EAXBlockCipher.cs
@@ -115,9 +115,7 @@ namespace Org.BouncyCastle.Crypto.Modes
private void InitCipher()
{
if (cipherInitialized)
- {
return;
- }
cipherInitialized = true;
@@ -173,9 +171,8 @@ namespace Org.BouncyCastle.Crypto.Modes
public virtual void ProcessAadByte(byte input)
{
if (cipherInitialized)
- {
throw new InvalidOperationException("AAD data cannot be added after encryption/decryption processing has begun.");
- }
+
mac.Update(input);
}
@@ -219,11 +216,11 @@ namespace Org.BouncyCastle.Crypto.Modes
public virtual int ProcessBytes(byte[] inBytes, int inOff, int len, byte[] outBytes, int outOff)
{
- InitCipher();
-
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
return ProcessBytes(inBytes.AsSpan(inOff, len), Spans.FromNullable(outBytes, outOff));
#else
+ InitCipher();
+
int resultLen = 0;
for (int i = 0; i != len; i++)
@@ -233,7 +230,7 @@ namespace Org.BouncyCastle.Crypto.Modes
return resultLen;
#endif
- }
+ }
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
public virtual int ProcessBytes(ReadOnlySpan<byte> input, Span<byte> output)
@@ -379,8 +376,7 @@ namespace Org.BouncyCastle.Crypto.Modes
return mac;
}
- public virtual int GetUpdateOutputSize(
- int len)
+ public virtual int GetUpdateOutputSize(int len)
{
int totalData = len + bufOff;
if (!forEncryption)
@@ -394,8 +390,7 @@ namespace Org.BouncyCastle.Crypto.Modes
return totalData - totalData % blockSize;
}
- public virtual int GetOutputSize(
- int len)
+ public virtual int GetOutputSize(int len)
{
int totalData = len + bufOff;
@@ -489,14 +484,7 @@ namespace Org.BouncyCastle.Crypto.Modes
private bool VerifyMac(byte[] mac, int off)
{
- int nonEqual = 0;
-
- for (int i = 0; i < macSize; i++)
- {
- nonEqual |= (macBlock[i] ^ mac[off + i]);
- }
-
- return nonEqual == 0;
+ return Arrays.FixedTimeEquals(macSize, mac, off, macBlock, 0);
}
}
}
diff --git a/crypto/src/crypto/modes/EcbBlockCipher.cs b/crypto/src/crypto/modes/EcbBlockCipher.cs
index 96f9811dd..b41452622 100644
--- a/crypto/src/crypto/modes/EcbBlockCipher.cs
+++ b/crypto/src/crypto/modes/EcbBlockCipher.cs
@@ -17,10 +17,7 @@ namespace Org.BouncyCastle.Crypto.Modes
public EcbBlockCipher(IBlockCipher cipher)
{
- if (cipher == null)
- throw new ArgumentNullException(nameof(cipher));
-
- m_cipher = cipher;
+ m_cipher = cipher ?? throw new ArgumentNullException(nameof(cipher));
}
public bool IsPartialBlockOkay => false;
diff --git a/crypto/src/crypto/modes/GCMBlockCipher.cs b/crypto/src/crypto/modes/GCMBlockCipher.cs
index f75235cf2..aed9ef311 100644
--- a/crypto/src/crypto/modes/GCMBlockCipher.cs
+++ b/crypto/src/crypto/modes/GCMBlockCipher.cs
@@ -108,30 +108,24 @@ namespace Org.BouncyCastle.Crypto.Modes
KeyParameter keyParam;
byte[] newNonce;
- if (parameters is AeadParameters)
+ if (parameters is AeadParameters aeadParameters)
{
- AeadParameters param = (AeadParameters)parameters;
+ newNonce = aeadParameters.GetNonce();
+ initialAssociatedText = aeadParameters.GetAssociatedText();
- newNonce = param.GetNonce();
- initialAssociatedText = param.GetAssociatedText();
-
- int macSizeBits = param.MacSize;
+ int macSizeBits = aeadParameters.MacSize;
if (macSizeBits < 32 || macSizeBits > 128 || macSizeBits % 8 != 0)
- {
throw new ArgumentException("Invalid value for MAC size: " + macSizeBits);
- }
macSize = macSizeBits / 8;
- keyParam = param.Key;
+ keyParam = aeadParameters.Key;
}
- else if (parameters is ParametersWithIV)
+ else if (parameters is ParametersWithIV withIV)
{
- ParametersWithIV param = (ParametersWithIV)parameters;
-
- newNonce = param.GetIV();
+ newNonce = withIV.GetIV();
initialAssociatedText = null;
macSize = 16;
- keyParam = (KeyParameter)param.Parameters;
+ keyParam = (KeyParameter)withIV.Parameters;
}
else
{
@@ -142,22 +136,17 @@ namespace Org.BouncyCastle.Crypto.Modes
this.bufBlock = new byte[bufLength];
if (newNonce == null || newNonce.Length < 1)
- {
throw new ArgumentException("IV must be at least 1 byte");
- }
if (forEncryption)
{
if (nonce != null && Arrays.AreEqual(nonce, newNonce))
{
if (keyParam == null)
- {
throw new ArgumentException("cannot reuse nonce for GCM encryption");
- }
+
if (lastKey != null && Arrays.AreEqual(lastKey, keyParam.GetKey()))
- {
throw new ArgumentException("cannot reuse nonce for GCM encryption");
- }
}
}
@@ -223,9 +212,7 @@ namespace Org.BouncyCastle.Crypto.Modes
public byte[] GetMac()
{
- return macBlock == null
- ? new byte[macSize]
- : Arrays.Clone(macBlock);
+ return macBlock == null ? new byte[macSize] : (byte[])macBlock.Clone();
}
public int GetOutputSize(int len)
@@ -233,9 +220,7 @@ namespace Org.BouncyCastle.Crypto.Modes
int totalData = len + bufOff;
if (forEncryption)
- {
return totalData + macSize;
- }
return totalData < macSize ? 0 : totalData - macSize;
}
@@ -246,9 +231,8 @@ namespace Org.BouncyCastle.Crypto.Modes
if (!forEncryption)
{
if (totalData < macSize)
- {
return 0;
- }
+
totalData -= macSize;
}
return totalData - totalData % BlockSize;
@@ -1490,9 +1474,8 @@ namespace Org.BouncyCastle.Crypto.Modes
if (!initialised)
{
if (forEncryption)
- {
throw new InvalidOperationException("GCM cipher cannot be reused for encryption");
- }
+
throw new InvalidOperationException("GCM cipher needs to be initialised");
}
}
diff --git a/crypto/src/crypto/modes/OpenPgpCfbBlockCipher.cs b/crypto/src/crypto/modes/OpenPgpCfbBlockCipher.cs
index 4e6e0ffaa..dff5af1c6 100644
--- a/crypto/src/crypto/modes/OpenPgpCfbBlockCipher.cs
+++ b/crypto/src/crypto/modes/OpenPgpCfbBlockCipher.cs
@@ -161,7 +161,6 @@ namespace Org.BouncyCastle.Crypto.Modes
return (byte)(FRE[blockOff] ^ data);
}
-
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
private int EncryptBlock(ReadOnlySpan<byte> input, Span<byte> output)
{
diff --git a/crypto/src/crypto/modes/SicBlockCipher.cs b/crypto/src/crypto/modes/SicBlockCipher.cs
index fee8bb028..ee204c18c 100644
--- a/crypto/src/crypto/modes/SicBlockCipher.cs
+++ b/crypto/src/crypto/modes/SicBlockCipher.cs
@@ -1,7 +1,6 @@
using System;
using Org.BouncyCastle.Crypto.Parameters;
-using Org.BouncyCastle.Math;
using Org.BouncyCastle.Utilities;
@@ -45,8 +44,7 @@ namespace Org.BouncyCastle.Crypto.Modes
bool forEncryption, //ignored by this CTR mode
ICipherParameters parameters)
{
- ParametersWithIV ivParam = parameters as ParametersWithIV;
- if (ivParam == null)
+ if (!(parameters is ParametersWithIV ivParam))
throw new ArgumentException("CTR/SIC mode requires ParametersWithIV", "parameters");
this.IV = Arrays.Clone(ivParam.GetIV());
@@ -58,13 +56,13 @@ namespace Org.BouncyCastle.Crypto.Modes
if (blockSize - IV.Length > maxCounterSize)
throw new ArgumentException("CTR/SIC mode requires IV of at least: " + (blockSize - maxCounterSize) + " bytes.");
+ Reset();
+
// if null it's an IV changed only.
if (ivParam.Parameters != null)
{
cipher.Init(true, ivParam.Parameters);
}
-
- Reset();
}
public virtual string AlgorithmName
diff --git a/crypto/src/crypto/modes/gcm/GcmUtilities.cs b/crypto/src/crypto/modes/gcm/GcmUtilities.cs
index 97b34fb61..a239e9ec0 100644
--- a/crypto/src/crypto/modes/gcm/GcmUtilities.cs
+++ b/crypto/src/crypto/modes/gcm/GcmUtilities.cs
@@ -14,7 +14,7 @@ using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Modes.Gcm
{
- internal abstract class GcmUtilities
+ internal static class GcmUtilities
{
internal struct FieldElement
{
@@ -177,13 +177,13 @@ namespace Org.BouncyCastle.Crypto.Modes.Gcm
ulong z1 = Interleave.Expand64To128Rev(x.n0, out ulong z0);
ulong z3 = Interleave.Expand64To128Rev(x.n1, out ulong z2);
- Debug.Assert(z3 << 63 == 0);
+ Debug.Assert(z3 << 63 == 0UL);
z1 ^= z3 ^ (z3 >> 1) ^ (z3 >> 2) ^ (z3 >> 7);
// z2 ^= (z3 << 63) ^ (z3 << 62) ^ (z3 << 57);
z2 ^= (z3 << 62) ^ (z3 << 57);
- Debug.Assert(z2 << 63 == 0);
+ Debug.Assert(z2 << 63 == 0UL);
z0 ^= z2 ^ (z2 >> 1) ^ (z2 >> 2) ^ (z2 >> 7);
// z1 ^= (z2 << 63) ^ (z2 << 62) ^ (z2 << 57);
diff --git a/crypto/src/crypto/operators/Asn1Signature.cs b/crypto/src/crypto/operators/Asn1Signature.cs
index ea8d28771..acbeb12e8 100644
--- a/crypto/src/crypto/operators/Asn1Signature.cs
+++ b/crypto/src/crypto/operators/Asn1Signature.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.EdEC;
using Org.BouncyCastle.Asn1.Nist;
using Org.BouncyCastle.Asn1.Oiw;
using Org.BouncyCastle.Asn1.Pkcs;
@@ -97,6 +98,9 @@ namespace Org.BouncyCastle.Crypto.Operators
m_algorithms.Add("GOST3411-2012-256WITHECGOST3410-2012-256", RosstandartObjectIdentifiers.id_tc26_signwithdigest_gost_3410_12_256);
m_algorithms.Add("GOST3411-2012-512WITHECGOST3410", RosstandartObjectIdentifiers.id_tc26_signwithdigest_gost_3410_12_512);
m_algorithms.Add("GOST3411-2012-512WITHECGOST3410-2012-512", RosstandartObjectIdentifiers.id_tc26_signwithdigest_gost_3410_12_512);
+ m_algorithms.Add("Ed25519", EdECObjectIdentifiers.id_Ed25519);
+ m_algorithms.Add("Ed448", EdECObjectIdentifiers.id_Ed448);
+ // TODO Ed25519ctx, Ed25519ph, Ed448ph
//
// According to RFC 3279, the ASN.1 encoding SHALL (id-dsa-with-sha1) or MUST (ecdsa-with-SHA*) omit the parameters field.
diff --git a/crypto/src/crypto/paddings/ISO10126d2Padding.cs b/crypto/src/crypto/paddings/ISO10126d2Padding.cs
index 21e007f1b..168b7ecc9 100644
--- a/crypto/src/crypto/paddings/ISO10126d2Padding.cs
+++ b/crypto/src/crypto/paddings/ISO10126d2Padding.cs
@@ -4,42 +4,25 @@ using Org.BouncyCastle.Security;
namespace Org.BouncyCastle.Crypto.Paddings
{
-
- /**
- * A padder that adds ISO10126-2 padding to a block.
- */
- public class ISO10126d2Padding: IBlockCipherPadding
+ /// <summary>A padder that adds ISO10126-2 padding to a block.</summary>
+ public class ISO10126d2Padding
+ : IBlockCipherPadding
{
- private SecureRandom random;
+ private SecureRandom m_random = null;
- /**
- * Initialise the padder.
- *
- * @param random a SecureRandom if available.
- */
- public void Init(
- SecureRandom random)
- //throws ArgumentException
+ public void Init(SecureRandom random)
{
- this.random = CryptoServicesRegistrar.GetSecureRandom(random);
+ m_random = CryptoServicesRegistrar.GetSecureRandom(random);
}
- /**
- * Return the name of the algorithm the cipher implements.
- *
- * @return the name of the algorithm the cipher implements.
- */
- public string PaddingName
- {
- get { return "ISO10126-2"; }
- }
+ public string PaddingName => "ISO10126-2";
public int AddPadding(byte[] input, int inOff)
{
int count = input.Length - inOff;
if (count > 1)
{
- random.NextBytes(input, inOff, count - 1);
+ m_random.NextBytes(input, inOff, count - 1);
}
input[input.Length - 1] = (byte)count;
@@ -52,7 +35,7 @@ namespace Org.BouncyCastle.Crypto.Paddings
int count = block.Length - position;
if (count > 1)
{
- random.NextBytes(block[position..(block.Length - 1)]);
+ m_random.NextBytes(block[position..(block.Length - 1)]);
}
block[block.Length - 1] = (byte)count;
@@ -62,7 +45,7 @@ namespace Org.BouncyCastle.Crypto.Paddings
public int PadCount(byte[] input)
{
- int count = input[input.Length -1];
+ int count = input[input.Length - 1];
int position = input.Length - count;
int failed = (position | (count - 1)) >> 31;
diff --git a/crypto/src/crypto/paddings/ISO7816d4Padding.cs b/crypto/src/crypto/paddings/ISO7816d4Padding.cs
index 7b1834626..987b69439 100644
--- a/crypto/src/crypto/paddings/ISO7816d4Padding.cs
+++ b/crypto/src/crypto/paddings/ISO7816d4Padding.cs
@@ -1,37 +1,22 @@
using System;
-using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Security;
namespace Org.BouncyCastle.Crypto.Paddings
{
- /**
- * A padder that adds the padding according to the scheme referenced in
- * ISO 7814-4 - scheme 2 from ISO 9797-1. The first byte is 0x80, rest is 0x00
- */
+ /// <summary>
+ /// A padder that adds the padding according to the scheme referenced in ISO 7814-4 - scheme 2 from ISO 9797-1.
+ /// The first byte is 0x80, rest is 0x00
+ /// </summary>
public class ISO7816d4Padding
: IBlockCipherPadding
{
- /**
- * Initialise the padder.
- *
- * @param random - a SecureRandom if available.
- */
- public void Init(
- SecureRandom random)
+ public void Init(SecureRandom random)
{
// nothing to do.
}
- /**
- * Return the name of the algorithm the padder implements.
- *
- * @return the name of the algorithm the padder implements.
- */
- public string PaddingName
- {
- get { return "ISO7816-4"; }
- }
+ public string PaddingName => "ISO7816-4";
public int AddPadding(byte[] input, int inOff)
{
diff --git a/crypto/src/crypto/paddings/Pkcs7Padding.cs b/crypto/src/crypto/paddings/Pkcs7Padding.cs
index 46d97c9eb..61355af34 100644
--- a/crypto/src/crypto/paddings/Pkcs7Padding.cs
+++ b/crypto/src/crypto/paddings/Pkcs7Padding.cs
@@ -1,36 +1,19 @@
using System;
-using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Security;
namespace Org.BouncyCastle.Crypto.Paddings
{
- /**
- * A padder that adds Pkcs7/Pkcs5 padding to a block.
- */
+ /// <summary>A padder that adds PKCS7/PKCS5 padding to a block.</summary>
public class Pkcs7Padding
: IBlockCipherPadding
{
- /**
- * Initialise the padder.
- *
- * @param random - a SecureRandom if available.
- */
- public void Init(
- SecureRandom random)
+ public void Init(SecureRandom random)
{
// nothing to do.
}
- /**
- * Return the name of the algorithm the cipher implements.
- *
- * @return the name of the algorithm the cipher implements.
- */
- public string PaddingName
- {
- get { return "PKCS7"; }
- }
+ public string PaddingName => "PKCS7";
public int AddPadding(byte[] input, int inOff)
{
diff --git a/crypto/src/crypto/paddings/TbcPadding.cs b/crypto/src/crypto/paddings/TbcPadding.cs
index b54c5f4d0..aeefa59a8 100644
--- a/crypto/src/crypto/paddings/TbcPadding.cs
+++ b/crypto/src/crypto/paddings/TbcPadding.cs
@@ -4,38 +4,18 @@ using Org.BouncyCastle.Security;
namespace Org.BouncyCastle.Crypto.Paddings
{
-
- /// <summary> A padder that adds Trailing-Bit-Compliment padding to a block.
- /// <p>
- /// This padding pads the block out compliment of the last bit
- /// of the plain text.
- /// </p>
- /// </summary>
+ /// <summary> A padder that adds Trailing-Bit-Compliment padding to a block.</summary>
+ /// <remarks>This padding pads the block out compliment of the last bit of the plain text.</remarks>
public class TbcPadding
: IBlockCipherPadding
{
- /// <summary> Return the name of the algorithm the cipher implements.</summary>
- /// <returns> the name of the algorithm the cipher implements.
- /// </returns>
- public string PaddingName
- {
- get { return "TBC"; }
- }
-
- /// <summary> Initialise the padder.</summary>
- /// <param name="random">- a SecureRandom if available.
- /// </param>
public virtual void Init(SecureRandom random)
{
// nothing to do.
}
- /// <summary> add the pad bytes to the passed in block, returning the number of bytes added.</summary>
- /// <remarks>
- /// This assumes that the last block of plain text is always passed to it inside <paramref name="input"/>.
- /// i.e. if <paramref name="inOff"/> is zero, indicating the padding will fill the entire block,the value of
- /// <paramref name="input"/> should be the same as the last block of plain text.
- /// </remarks>
+ public string PaddingName => "TBC";
+
public virtual int AddPadding(byte[] input, int inOff)
{
int count = input.Length - inOff;
@@ -51,12 +31,6 @@ namespace Org.BouncyCastle.Crypto.Paddings
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
- /// <summary> add the pad bytes to the passed in block, returning the number of bytes added.</summary>
- /// <remarks>
- /// This assumes that the last block of plain text is always passed to it inside <paramref name="block"/>.
- /// i.e. if <paramref name="position"/> is zero, indicating the padding will fill the entire block,the value of
- /// <paramref name="block"/> should be the same as the last block of plain text.
- /// </remarks>
public virtual int AddPadding(Span<byte> block, int position)
{
byte lastByte = position > 0 ? block[position - 1] : block[block.Length - 1];
diff --git a/crypto/src/crypto/paddings/X923Padding.cs b/crypto/src/crypto/paddings/X923Padding.cs
index 12338aa04..24cc54255 100644
--- a/crypto/src/crypto/paddings/X923Padding.cs
+++ b/crypto/src/crypto/paddings/X923Padding.cs
@@ -5,48 +5,35 @@ using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Paddings
{
- /**
- * A padder that adds X9.23 padding to a block - if a SecureRandom is
- * passed in random padding is assumed, otherwise padding with zeros is used.
- */
+ /// <summary>
+ /// A padder that adds X9.23 padding to a block - if a SecureRandom is passed in random padding is assumed,
+ /// otherwise padding with zeros is used.
+ /// </summary>
public class X923Padding
: IBlockCipherPadding
{
- private SecureRandom random;
+ private SecureRandom m_random = null;
- /**
- * Initialise the padder.
- *
- * @param random a SecureRandom if one is available.
- */
- public void Init(
- SecureRandom random)
+ public void Init(SecureRandom random)
{
- this.random = random;
+ // NOTE: If random is null, zero padding is used
+ m_random = random;
}
- /**
- * Return the name of the algorithm the cipher implements.
- *
- * @return the name of the algorithm the cipher implements.
- */
- public string PaddingName
- {
- get { return "X9.23"; }
- }
+ public string PaddingName => "X9.23";
public int AddPadding(byte[] input, int inOff)
{
int count = input.Length - inOff;
if (count > 1)
{
- if (random == null)
+ if (m_random == null)
{
Arrays.Fill(input, inOff, input.Length - 1, 0x00);
}
else
{
- random.NextBytes(input, inOff, count - 1);
+ m_random.NextBytes(input, inOff, count - 1);
}
}
input[input.Length - 1] = (byte)count;
@@ -60,13 +47,13 @@ namespace Org.BouncyCastle.Crypto.Paddings
if (count > 1)
{
var body = block[position..(block.Length - 1)];
- if (random == null)
+ if (m_random == null)
{
body.Fill(0x00);
}
else
{
- random.NextBytes(body);
+ m_random.NextBytes(body);
}
}
block[block.Length - 1] = (byte)count;
diff --git a/crypto/src/crypto/paddings/ZeroBytePadding.cs b/crypto/src/crypto/paddings/ZeroBytePadding.cs
index 910fe7154..09b1a73ae 100644
--- a/crypto/src/crypto/paddings/ZeroBytePadding.cs
+++ b/crypto/src/crypto/paddings/ZeroBytePadding.cs
@@ -4,25 +4,12 @@ using Org.BouncyCastle.Security;
namespace Org.BouncyCastle.Crypto.Paddings
{
-
- /// <summary> A padder that adds Null byte padding to a block.</summary>
- public class ZeroBytePadding : IBlockCipherPadding
+ /// <summary> A padder that adds zero byte padding to a block.</summary>
+ public class ZeroBytePadding
+ : IBlockCipherPadding
{
- /// <summary> Return the name of the algorithm the cipher implements.
- ///
- /// </summary>
- /// <returns> the name of the algorithm the cipher implements.
- /// </returns>
- public string PaddingName
- {
- get { return "ZeroBytePadding"; }
- }
+ public string PaddingName => "ZeroBytePadding";
- /// <summary> Initialise the padder.
- ///
- /// </summary>
- /// <param name="random">- a SecureRandom if available.
- /// </param>
public void Init(SecureRandom random)
{
// nothing to do.
diff --git a/crypto/src/crypto/parameters/DHKeyParameters.cs b/crypto/src/crypto/parameters/DHKeyParameters.cs
index 1a5c1386f..8aabddd8b 100644
--- a/crypto/src/crypto/parameters/DHKeyParameters.cs
+++ b/crypto/src/crypto/parameters/DHKeyParameters.cs
@@ -57,7 +57,7 @@ namespace Org.BouncyCastle.Crypto.Parameters
protected bool Equals(
DHKeyParameters other)
{
- return Platform.Equals(parameters, other.parameters)
+ return Objects.Equals(parameters, other.parameters)
&& base.Equals(other);
}
diff --git a/crypto/src/crypto/parameters/DHParameters.cs b/crypto/src/crypto/parameters/DHParameters.cs
index bdea12432..a71678a88 100644
--- a/crypto/src/crypto/parameters/DHParameters.cs
+++ b/crypto/src/crypto/parameters/DHParameters.cs
@@ -167,7 +167,7 @@ namespace Org.BouncyCastle.Crypto.Parameters
{
return p.Equals(other.p)
&& g.Equals(other.g)
- && Platform.Equals(q, other.q);
+ && Objects.Equals(q, other.q);
}
public override int GetHashCode()
diff --git a/crypto/src/crypto/parameters/DHPublicKeyParameters.cs b/crypto/src/crypto/parameters/DHPublicKeyParameters.cs
index a72f247a5..be4a93eb6 100644
--- a/crypto/src/crypto/parameters/DHPublicKeyParameters.cs
+++ b/crypto/src/crypto/parameters/DHPublicKeyParameters.cs
@@ -13,13 +13,13 @@ namespace Org.BouncyCastle.Crypto.Parameters
private static BigInteger Validate(BigInteger y, DHParameters dhParams)
{
if (y == null)
- throw new ArgumentNullException("y");
+ throw new ArgumentNullException(nameof(y));
BigInteger p = dhParams.P;
// TLS check
if (y.CompareTo(BigInteger.Two) < 0 || y.CompareTo(p.Subtract(BigInteger.Two)) > 0)
- throw new ArgumentException("invalid DH public key", "y");
+ throw new ArgumentException("invalid DH public key", nameof(y));
BigInteger q = dhParams.Q;
@@ -41,56 +41,44 @@ namespace Org.BouncyCastle.Crypto.Parameters
return y;
}
- throw new ArgumentException("value does not appear to be in correct group", "y");
+ throw new ArgumentException("value does not appear to be in correct group", nameof(y));
}
- private readonly BigInteger y;
+ private readonly BigInteger m_y;
- public DHPublicKeyParameters(
- BigInteger y,
- DHParameters parameters)
+ public DHPublicKeyParameters(BigInteger y, DHParameters parameters)
: base(false, parameters)
{
- this.y = Validate(y, parameters);
+ m_y = Validate(y, parameters);
}
- public DHPublicKeyParameters(
- BigInteger y,
- DHParameters parameters,
- DerObjectIdentifier algorithmOid)
+ public DHPublicKeyParameters(BigInteger y, DHParameters parameters, DerObjectIdentifier algorithmOid)
: base(false, parameters, algorithmOid)
{
- this.y = Validate(y, parameters);
+ m_y = Validate(y, parameters);
}
- public virtual BigInteger Y
- {
- get { return y; }
- }
+ public virtual BigInteger Y => m_y;
- public override bool Equals(
- object obj)
+ public override bool Equals(object obj)
{
if (obj == this)
return true;
- DHPublicKeyParameters other = obj as DHPublicKeyParameters;
-
- if (other == null)
+ if (!(obj is DHPublicKeyParameters other))
return false;
return Equals(other);
}
- protected bool Equals(
- DHPublicKeyParameters other)
+ protected bool Equals(DHPublicKeyParameters other)
{
- return y.Equals(other.y) && base.Equals(other);
+ return m_y.Equals(other.m_y) && base.Equals(other);
}
public override int GetHashCode()
{
- return y.GetHashCode() ^ base.GetHashCode();
+ return m_y.GetHashCode() ^ base.GetHashCode();
}
private static int Legendre(BigInteger a, BigInteger b)
diff --git a/crypto/src/crypto/parameters/DsaKeyParameters.cs b/crypto/src/crypto/parameters/DsaKeyParameters.cs
index 5fe6d7ab4..4097144a5 100644
--- a/crypto/src/crypto/parameters/DsaKeyParameters.cs
+++ b/crypto/src/crypto/parameters/DsaKeyParameters.cs
@@ -40,7 +40,7 @@ namespace Org.BouncyCastle.Crypto.Parameters
protected bool Equals(
DsaKeyParameters other)
{
- return Platform.Equals(parameters, other.parameters)
+ return Objects.Equals(parameters, other.parameters)
&& base.Equals(other);
}
diff --git a/crypto/src/crypto/parameters/ElGamalKeyParameters.cs b/crypto/src/crypto/parameters/ElGamalKeyParameters.cs
index 8b6e27957..146049aca 100644
--- a/crypto/src/crypto/parameters/ElGamalKeyParameters.cs
+++ b/crypto/src/crypto/parameters/ElGamalKeyParameters.cs
@@ -40,7 +40,7 @@ namespace Org.BouncyCastle.Crypto.Parameters
protected bool Equals(
ElGamalKeyParameters other)
{
- return Platform.Equals(parameters, other.parameters)
+ return Objects.Equals(parameters, other.parameters)
&& base.Equals(other);
}
diff --git a/crypto/src/crypto/parameters/KDFDoublePipelineIterationParameters.cs b/crypto/src/crypto/parameters/KDFDoublePipelineIterationParameters.cs
index 9e2a68b71..c63926fe3 100644
--- a/crypto/src/crypto/parameters/KDFDoublePipelineIterationParameters.cs
+++ b/crypto/src/crypto/parameters/KDFDoublePipelineIterationParameters.cs
@@ -4,7 +4,8 @@ using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Parameters
{
- public class KdfDoublePipelineIterationParameters : IDerivationParameters
+ public class KdfDoublePipelineIterationParameters
+ : IDerivationParameters
{
// could be any valid value, using 32, don't know why
private static readonly int UNUSED_R = 32;
@@ -17,9 +18,7 @@ namespace Org.BouncyCastle.Crypto.Parameters
private KdfDoublePipelineIterationParameters(byte[] ki, byte[] fixedInputData, int r, bool useCounter)
{
if (ki == null)
- {
- throw new ArgumentException("A KDF requires Ki (a seed) as input");
- }
+ throw new ArgumentNullException("A KDF requires Ki (a seed) as input", nameof(ki));
this.ki = Arrays.Clone(ki);
@@ -33,9 +32,7 @@ namespace Org.BouncyCastle.Crypto.Parameters
}
if (r != 8 && r != 16 && r != 24 && r != 32)
- {
throw new ArgumentException("Length of counter should be 8, 16, 24 or 32");
- }
this.r = r;
@@ -59,15 +56,9 @@ namespace Org.BouncyCastle.Crypto.Parameters
get { return Arrays.Clone(ki); }
}
- public bool UseCounter
- {
- get { return useCounter; }
- }
+ public bool UseCounter => useCounter;
- public int R
- {
- get { return r; }
- }
+ public int R => r;
public byte[] FixedInputData
{
diff --git a/crypto/src/crypto/parameters/KdfParameters.cs b/crypto/src/crypto/parameters/KdfParameters.cs
index 78cf81855..3e2ddc541 100644
--- a/crypto/src/crypto/parameters/KdfParameters.cs
+++ b/crypto/src/crypto/parameters/KdfParameters.cs
@@ -1,6 +1,3 @@
-using System;
-using Org.BouncyCastle.Crypto;
-
namespace Org.BouncyCastle.Crypto.Parameters
{
/**
diff --git a/crypto/src/crypto/parameters/KeyParameter.cs b/crypto/src/crypto/parameters/KeyParameter.cs
index bc6c28368..8d35a19f1 100644
--- a/crypto/src/crypto/parameters/KeyParameter.cs
+++ b/crypto/src/crypto/parameters/KeyParameter.cs
@@ -1,7 +1,5 @@
using System;
-using Org.BouncyCastle.Crypto;
-
namespace Org.BouncyCastle.Crypto.Parameters
{
public class KeyParameter
diff --git a/crypto/src/crypto/parameters/ParametersWithID.cs b/crypto/src/crypto/parameters/ParametersWithID.cs
index 2bc4ac86c..2e88026e1 100644
--- a/crypto/src/crypto/parameters/ParametersWithID.cs
+++ b/crypto/src/crypto/parameters/ParametersWithID.cs
@@ -1,7 +1,5 @@
using System;
-using Org.BouncyCastle.Utilities;
-
namespace Org.BouncyCastle.Crypto.Parameters
{
public class ParametersWithID
@@ -13,17 +11,29 @@ namespace Org.BouncyCastle.Crypto.Parameters
public ParametersWithID(ICipherParameters parameters, byte[] id)
: this(parameters, id, 0, id.Length)
{
+ // NOTE: 'parameters' may be null to imply key re-use
+ if (id == null)
+ throw new ArgumentNullException(nameof(id));
+
+ m_parameters = parameters;
+ m_id = (byte[])id.Clone();
}
public ParametersWithID(ICipherParameters parameters, byte[] id, int idOff, int idLen)
{
+ // NOTE: 'parameters' may be null to imply key re-use
+ if (id == null)
+ throw new ArgumentNullException(nameof(id));
+
m_parameters = parameters;
- m_id = Arrays.CopyOfRange(id, idOff, idOff + idLen);
+ m_id = new byte[idLen];
+ Array.Copy(id, idOff, m_id, 0, idLen);
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
public ParametersWithID(ICipherParameters parameters, ReadOnlySpan<byte> id)
{
+ // NOTE: 'parameters' may be null to imply key re-use
m_parameters = parameters;
m_id = id.ToArray();
}
@@ -31,7 +41,7 @@ namespace Org.BouncyCastle.Crypto.Parameters
public byte[] GetID()
{
- return m_id;
+ return (byte[])m_id.Clone();
}
public ICipherParameters Parameters => m_parameters;
diff --git a/crypto/src/crypto/parameters/ParametersWithIV.cs b/crypto/src/crypto/parameters/ParametersWithIV.cs
index ac55afc8d..ea1773d54 100644
--- a/crypto/src/crypto/parameters/ParametersWithIV.cs
+++ b/crypto/src/crypto/parameters/ParametersWithIV.cs
@@ -1,29 +1,44 @@
using System;
-using Org.BouncyCastle.Utilities;
-
namespace Org.BouncyCastle.Crypto.Parameters
{
public class ParametersWithIV
: ICipherParameters
{
+ internal static ICipherParameters ApplyOptionalIV(ICipherParameters parameters, byte[] iv)
+ {
+ return iv == null ? parameters : new ParametersWithIV(parameters, iv);
+ }
+
private readonly ICipherParameters m_parameters;
private readonly byte[] m_iv;
public ParametersWithIV(ICipherParameters parameters, byte[] iv)
: this(parameters, iv, 0, iv.Length)
{
+ // NOTE: 'parameters' may be null to imply key re-use
+ if (iv == null)
+ throw new ArgumentNullException(nameof(iv));
+
+ m_parameters = parameters;
+ m_iv = (byte[])iv.Clone();
}
public ParametersWithIV(ICipherParameters parameters, byte[] iv, int ivOff, int ivLen)
{
+ // NOTE: 'parameters' may be null to imply key re-use
+ if (iv == null)
+ throw new ArgumentNullException(nameof(iv));
+
m_parameters = parameters;
- m_iv = Arrays.CopyOfRange(iv, ivOff, ivOff + ivLen);
+ m_iv = new byte[ivLen];
+ Array.Copy(iv, ivOff, m_iv, 0, ivLen);
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
public ParametersWithIV(ICipherParameters parameters, ReadOnlySpan<byte> iv)
{
+ // NOTE: 'parameters' may be null to imply key re-use
m_parameters = parameters;
m_iv = iv.ToArray();
}
diff --git a/crypto/src/crypto/parameters/ParametersWithSBox.cs b/crypto/src/crypto/parameters/ParametersWithSBox.cs
index 6473796e3..f64ac5d08 100644
--- a/crypto/src/crypto/parameters/ParametersWithSBox.cs
+++ b/crypto/src/crypto/parameters/ParametersWithSBox.cs
@@ -1,24 +1,19 @@
-using System;
-
-using Org.BouncyCastle.Crypto;
-
namespace Org.BouncyCastle.Crypto.Parameters
{
- public class ParametersWithSBox : ICipherParameters
+ public class ParametersWithSBox
+ : ICipherParameters
{
- private ICipherParameters parameters;
- private byte[] sBox;
+ private readonly ICipherParameters m_parameters;
+ private readonly byte[] m_sBox;
- public ParametersWithSBox(
- ICipherParameters parameters,
- byte[] sBox)
+ public ParametersWithSBox(ICipherParameters parameters, byte[] sBox)
{
- this.parameters = parameters;
- this.sBox = sBox;
+ this.m_parameters = parameters;
+ this.m_sBox = sBox;
}
- public byte[] GetSBox() { return sBox; }
+ public byte[] GetSBox() => m_sBox;
- public ICipherParameters Parameters { get { return parameters; } }
+ public ICipherParameters Parameters => m_parameters;
}
}
diff --git a/crypto/src/crypto/parameters/ParametersWithSalt.cs b/crypto/src/crypto/parameters/ParametersWithSalt.cs
index 277cd213c..a78acf18a 100644
--- a/crypto/src/crypto/parameters/ParametersWithSalt.cs
+++ b/crypto/src/crypto/parameters/ParametersWithSalt.cs
@@ -1,8 +1,5 @@
using System;
-using Org.BouncyCastle.Crypto;
-using Org.BouncyCastle.Utilities;
-
namespace Org.BouncyCastle.Crypto.Parameters
{
@@ -14,19 +11,30 @@ namespace Org.BouncyCastle.Crypto.Parameters
private readonly byte[] m_salt;
public ParametersWithSalt(ICipherParameters parameters, byte[] salt)
- : this(parameters, salt, 0, salt.Length)
{
+ // NOTE: 'parameters' may be null to imply key re-use
+ if (salt == null)
+ throw new ArgumentNullException(nameof(salt));
+
+ m_parameters = parameters;
+ m_salt = (byte[])salt.Clone();
}
public ParametersWithSalt(ICipherParameters parameters, byte[] salt, int saltOff, int saltLen)
{
+ // NOTE: 'parameters' may be null to imply key re-use
+ if (salt == null)
+ throw new ArgumentNullException(nameof(salt));
+
m_parameters = parameters;
- m_salt = Arrays.CopyOfRange(salt, saltOff, saltOff + saltLen);
+ m_salt = new byte[saltLen];
+ Array.Copy(salt, saltOff, m_salt, 0, saltLen);
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
public ParametersWithSalt(ICipherParameters parameters, ReadOnlySpan<byte> salt)
{
+ // NOTE: 'parameters' may be null to imply key re-use
m_parameters = parameters;
m_salt = salt.ToArray();
}
@@ -34,7 +42,7 @@ namespace Org.BouncyCastle.Crypto.Parameters
public byte[] GetSalt()
{
- return m_salt;
+ return (byte[])m_salt.Clone();
}
public ICipherParameters Parameters => m_parameters;
diff --git a/crypto/src/crypto/prng/BasicEntropySourceProvider.cs b/crypto/src/crypto/prng/BasicEntropySourceProvider.cs
index 5de1e4e5e..7a3e2b2b4 100644
--- a/crypto/src/crypto/prng/BasicEntropySourceProvider.cs
+++ b/crypto/src/crypto/prng/BasicEntropySourceProvider.cs
@@ -71,7 +71,7 @@ namespace Org.BouncyCastle.Crypto.Prng
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
int IEntropySource.GetEntropy(Span<byte> output)
{
- int length = (mEntropySize + 7) / 8;
+ int length = System.Math.Min(output.Length, (mEntropySize + 7) / 8);
mSecureRandom.NextBytes(output[..length]);
return length;
}
diff --git a/crypto/src/crypto/prng/CryptoApiEntropySourceProvider.cs b/crypto/src/crypto/prng/CryptoApiEntropySourceProvider.cs
index 9a2f6de2c..d20b5b22b 100644
--- a/crypto/src/crypto/prng/CryptoApiEntropySourceProvider.cs
+++ b/crypto/src/crypto/prng/CryptoApiEntropySourceProvider.cs
@@ -59,7 +59,7 @@ namespace Org.BouncyCastle.Crypto.Prng
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
int IEntropySource.GetEntropy(Span<byte> output)
{
- int length = (mEntropySize + 7) / 8;
+ int length = System.Math.Min(output.Length, (mEntropySize + 7) / 8);
mRng.GetBytes(output[..length]);
return length;
}
diff --git a/crypto/src/crypto/prng/CryptoApiRandomGenerator.cs b/crypto/src/crypto/prng/CryptoApiRandomGenerator.cs
index dcd3baa1c..bafb4fd5e 100644
--- a/crypto/src/crypto/prng/CryptoApiRandomGenerator.cs
+++ b/crypto/src/crypto/prng/CryptoApiRandomGenerator.cs
@@ -52,8 +52,8 @@ namespace Org.BouncyCastle.Crypto.Prng
m_randomNumberGenerator.GetBytes(bytes, start, len);
#else
if (start < 0)
- throw new ArgumentException("Start offset cannot be negative", "start");
- if (bytes.Length < (start + len))
+ throw new ArgumentException("Start offset cannot be negative", nameof(start));
+ if (start > bytes.Length - len)
throw new ArgumentException("Byte array too small for requested offset and length");
if (bytes.Length == len && start == 0)
@@ -62,9 +62,9 @@ namespace Org.BouncyCastle.Crypto.Prng
}
else
{
- byte[] tmpBuf = new byte[len];
- NextBytes(tmpBuf);
- Array.Copy(tmpBuf, 0, bytes, start, len);
+ byte[] tmp = new byte[len];
+ NextBytes(tmp);
+ tmp.CopyTo(bytes, start);
}
#endif
}
diff --git a/crypto/src/crypto/prng/EntropyUtilities.cs b/crypto/src/crypto/prng/EntropyUtilities.cs
index 58c8703f4..156b46622 100644
--- a/crypto/src/crypto/prng/EntropyUtilities.cs
+++ b/crypto/src/crypto/prng/EntropyUtilities.cs
@@ -16,6 +16,10 @@ namespace Org.BouncyCastle.Crypto.Prng
public static byte[] GenerateSeed(IEntropySource entropySource, int numBytes)
{
byte[] bytes = new byte[numBytes];
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ GenerateSeed(entropySource, bytes);
+#else
int count = 0;
while (count < numBytes)
{
@@ -24,7 +28,20 @@ namespace Org.BouncyCastle.Crypto.Prng
Array.Copy(entropy, 0, bytes, count, toCopy);
count += toCopy;
}
+#endif
+
return bytes;
}
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public static void GenerateSeed(IEntropySource entropySource, Span<byte> seed)
+ {
+ while (!seed.IsEmpty)
+ {
+ int len = entropySource.GetEntropy(seed);
+ seed = seed[len..];
+ }
+ }
+#endif
}
}
diff --git a/crypto/src/crypto/prng/SP800SecureRandom.cs b/crypto/src/crypto/prng/SP800SecureRandom.cs
index a18576d03..4fbbc927f 100644
--- a/crypto/src/crypto/prng/SP800SecureRandom.cs
+++ b/crypto/src/crypto/prng/SP800SecureRandom.cs
@@ -113,6 +113,13 @@ namespace Org.BouncyCastle.Crypto.Prng
return EntropyUtilities.GenerateSeed(mEntropySource, numBytes);
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public override void GenerateSeed(Span<byte> seed)
+ {
+ EntropyUtilities.GenerateSeed(mEntropySource, seed);
+ }
+#endif
+
/// <summary>Force a reseed of the DRBG.</summary>
/// <param name="additionalInput">optional additional input</param>
public virtual void Reseed(byte[] additionalInput)
diff --git a/crypto/src/crypto/prng/X931SecureRandom.cs b/crypto/src/crypto/prng/X931SecureRandom.cs
index d40134851..6c0114cb2 100644
--- a/crypto/src/crypto/prng/X931SecureRandom.cs
+++ b/crypto/src/crypto/prng/X931SecureRandom.cs
@@ -96,5 +96,12 @@ namespace Org.BouncyCastle.Crypto.Prng
{
return EntropyUtilities.GenerateSeed(mDrbg.EntropySource, numBytes);
}
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public override void GenerateSeed(Span<byte> seed)
+ {
+ EntropyUtilities.GenerateSeed(mDrbg.EntropySource, seed);
+ }
+#endif
}
}
diff --git a/crypto/src/crypto/prng/drbg/CtrSP800Drbg.cs b/crypto/src/crypto/prng/drbg/CtrSP800Drbg.cs
index cf566ff9c..fd7b107e0 100644
--- a/crypto/src/crypto/prng/drbg/CtrSP800Drbg.cs
+++ b/crypto/src/crypto/prng/drbg/CtrSP800Drbg.cs
@@ -60,10 +60,10 @@ namespace Org.BouncyCastle.Crypto.Prng.Drbg
mSeedLength = keySizeInBits + engine.GetBlockSize() * 8;
mIsTdea = IsTdea(engine);
- CTR_DRBG_Instantiate_algorithm(nonce, personalizationString);
+ CTR_DRBG_Instantiate_algorithm(personalizationString, nonce);
}
- private void CTR_DRBG_Instantiate_algorithm(byte[] nonce, byte[] personalisationString)
+ private void CTR_DRBG_Instantiate_algorithm(byte[] personalisationString, byte[] nonce)
{
byte[] entropy = GetEntropy(); // Get_entropy_input
byte[] seedMaterial = Arrays.ConcatenateAll(entropy, nonce, personalisationString);
diff --git a/crypto/src/crypto/signers/DsaDigestSigner.cs b/crypto/src/crypto/signers/DsaDigestSigner.cs
index f546785bd..608e55304 100644
--- a/crypto/src/crypto/signers/DsaDigestSigner.cs
+++ b/crypto/src/crypto/signers/DsaDigestSigner.cs
@@ -78,7 +78,7 @@ namespace Org.BouncyCastle.Crypto.Signers
public virtual byte[] GenerateSignature()
{
if (!forSigning)
- throw new InvalidOperationException("DSADigestSigner not initialised for signature generation.");
+ throw new InvalidOperationException("DsaDigestSigner not initialized for signature generation.");
byte[] hash = new byte[digest.GetDigestSize()];
digest.DoFinal(hash, 0);
@@ -98,7 +98,7 @@ namespace Org.BouncyCastle.Crypto.Signers
public virtual bool VerifySignature(byte[] signature)
{
if (forSigning)
- throw new InvalidOperationException("DSADigestSigner not initialised for verification");
+ throw new InvalidOperationException("DsaDigestSigner not initialized for verification");
byte[] hash = new byte[digest.GetDigestSize()];
digest.DoFinal(hash, 0);
diff --git a/crypto/src/crypto/signers/DsaSigner.cs b/crypto/src/crypto/signers/DsaSigner.cs
index 318eeeb48..a45c05c33 100644
--- a/crypto/src/crypto/signers/DsaSigner.cs
+++ b/crypto/src/crypto/signers/DsaSigner.cs
@@ -48,25 +48,23 @@ namespace Org.BouncyCastle.Crypto.Signers
if (forSigning)
{
- if (parameters is ParametersWithRandom)
+ if (parameters is ParametersWithRandom rParam)
{
- ParametersWithRandom rParam = (ParametersWithRandom)parameters;
-
providedRandom = rParam.Random;
parameters = rParam.Parameters;
}
- if (!(parameters is DsaPrivateKeyParameters))
+ if (!(parameters is DsaPrivateKeyParameters dsaPrivateKeyParameters))
throw new InvalidKeyException("DSA private key required for signing");
- this.key = (DsaPrivateKeyParameters)parameters;
+ this.key = dsaPrivateKeyParameters;
}
else
{
- if (!(parameters is DsaPublicKeyParameters))
+ if (!(parameters is DsaPublicKeyParameters dsaPublicKeyParameters))
throw new InvalidKeyException("DSA public key required for verification");
- this.key = (DsaPublicKeyParameters)parameters;
+ this.key = dsaPublicKeyParameters;
}
this.random = InitSecureRandom(forSigning && !kCalculator.IsDeterministic, providedRandom);
diff --git a/crypto/src/crypto/signers/ECDsaSigner.cs b/crypto/src/crypto/signers/ECDsaSigner.cs
index d78e92516..32225ec82 100644
--- a/crypto/src/crypto/signers/ECDsaSigner.cs
+++ b/crypto/src/crypto/signers/ECDsaSigner.cs
@@ -51,25 +51,23 @@ namespace Org.BouncyCastle.Crypto.Signers
if (forSigning)
{
- if (parameters is ParametersWithRandom)
+ if (parameters is ParametersWithRandom rParam)
{
- ParametersWithRandom rParam = (ParametersWithRandom)parameters;
-
providedRandom = rParam.Random;
parameters = rParam.Parameters;
}
- if (!(parameters is ECPrivateKeyParameters))
+ if (!(parameters is ECPrivateKeyParameters ecPrivateKeyParameters))
throw new InvalidKeyException("EC private key required for signing");
- this.key = (ECPrivateKeyParameters)parameters;
+ this.key = ecPrivateKeyParameters;
}
else
{
- if (!(parameters is ECPublicKeyParameters))
+ if (!(parameters is ECPublicKeyParameters ecPublicKeyParameters))
throw new InvalidKeyException("EC public key required for verification");
- this.key = (ECPublicKeyParameters)parameters;
+ this.key = ecPublicKeyParameters;
}
this.random = InitSecureRandom(forSigning && !kCalculator.IsDeterministic, providedRandom);
diff --git a/crypto/src/crypto/signers/Ed25519phSigner.cs b/crypto/src/crypto/signers/Ed25519phSigner.cs
index d4ff2aae9..60bf3376c 100644
--- a/crypto/src/crypto/signers/Ed25519phSigner.cs
+++ b/crypto/src/crypto/signers/Ed25519phSigner.cs
@@ -1,9 +1,7 @@
using System;
-using System.IO;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math.EC.Rfc8032;
-using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Signers
{
@@ -74,7 +72,7 @@ namespace Org.BouncyCastle.Crypto.Signers
byte[] msg = new byte[Ed25519.PrehashSize];
if (Ed25519.PrehashSize != prehash.DoFinal(msg, 0))
- throw new InvalidOperationException("Prehash digest failed");
+ throw new InvalidOperationException("Prehash calculation failed");
byte[] signature = new byte[Ed25519PrivateKeyParameters.SignatureSize];
privateKey.Sign(Ed25519.Algorithm.Ed25519ph, context, msg, 0, Ed25519.PrehashSize, signature, 0);
@@ -93,7 +91,7 @@ namespace Org.BouncyCastle.Crypto.Signers
byte[] msg = new byte[Ed25519.PrehashSize];
if (Ed25519.PrehashSize != prehash.DoFinal(msg, 0))
- throw new InvalidOperationException("Prehash digest failed");
+ throw new InvalidOperationException("Prehash calculation failed");
return publicKey.Verify(Ed25519.Algorithm.Ed25519ph, context, msg, 0, Ed25519.PrehashSize, signature, 0);
}
diff --git a/crypto/src/crypto/signers/Ed448Signer.cs b/crypto/src/crypto/signers/Ed448Signer.cs
index 79c0fefce..5bacb0a46 100644
--- a/crypto/src/crypto/signers/Ed448Signer.cs
+++ b/crypto/src/crypto/signers/Ed448Signer.cs
@@ -3,7 +3,6 @@ using System.IO;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math.EC.Rfc8032;
-using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Signers
{
diff --git a/crypto/src/crypto/signers/Ed448phSigner.cs b/crypto/src/crypto/signers/Ed448phSigner.cs
index 75f841923..02d65b6fb 100644
--- a/crypto/src/crypto/signers/Ed448phSigner.cs
+++ b/crypto/src/crypto/signers/Ed448phSigner.cs
@@ -1,9 +1,7 @@
using System;
-using System.IO;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math.EC.Rfc8032;
-using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Signers
{
@@ -74,7 +72,7 @@ namespace Org.BouncyCastle.Crypto.Signers
byte[] msg = new byte[Ed448.PrehashSize];
if (Ed448.PrehashSize != prehash.OutputFinal(msg, 0, Ed448.PrehashSize))
- throw new InvalidOperationException("Prehash digest failed");
+ throw new InvalidOperationException("Prehash calculation failed");
byte[] signature = new byte[Ed448PrivateKeyParameters.SignatureSize];
privateKey.Sign(Ed448.Algorithm.Ed448ph, context, msg, 0, Ed448.PrehashSize, signature, 0);
@@ -93,7 +91,7 @@ namespace Org.BouncyCastle.Crypto.Signers
byte[] msg = new byte[Ed448.PrehashSize];
if (Ed448.PrehashSize != prehash.OutputFinal(msg, 0, Ed448.PrehashSize))
- throw new InvalidOperationException("Prehash digest failed");
+ throw new InvalidOperationException("Prehash calculation failed");
return publicKey.Verify(Ed448.Algorithm.Ed448ph, context, msg, 0, Ed448.PrehashSize, signature, 0);
}
diff --git a/crypto/src/crypto/signers/GOST3410DigestSigner.cs b/crypto/src/crypto/signers/GOST3410DigestSigner.cs
index 63e65986b..dcbf67723 100644
--- a/crypto/src/crypto/signers/GOST3410DigestSigner.cs
+++ b/crypto/src/crypto/signers/GOST3410DigestSigner.cs
@@ -35,9 +35,9 @@ namespace Org.BouncyCastle.Crypto.Signers
this.forSigning = forSigning;
AsymmetricKeyParameter k;
- if (parameters is ParametersWithRandom)
+ if (parameters is ParametersWithRandom withRandom)
{
- k = (AsymmetricKeyParameter)((ParametersWithRandom)parameters).Parameters;
+ k = (AsymmetricKeyParameter)withRandom.Parameters;
}
else
{
@@ -45,15 +45,10 @@ namespace Org.BouncyCastle.Crypto.Signers
}
if (forSigning && !k.IsPrivate)
- {
throw new InvalidKeyException("Signing Requires Private Key.");
- }
if (!forSigning && k.IsPrivate)
- {
throw new InvalidKeyException("Verification Requires Public Key.");
- }
-
Reset();
diff --git a/crypto/src/crypto/signers/GenericSigner.cs b/crypto/src/crypto/signers/GenericSigner.cs
index 36a9cc9a5..5de4c162f 100644
--- a/crypto/src/crypto/signers/GenericSigner.cs
+++ b/crypto/src/crypto/signers/GenericSigner.cs
@@ -39,9 +39,9 @@ namespace Org.BouncyCastle.Crypto.Signers
this.forSigning = forSigning;
AsymmetricKeyParameter k;
- if (parameters is ParametersWithRandom)
+ if (parameters is ParametersWithRandom withRandom)
{
- k = (AsymmetricKeyParameter)((ParametersWithRandom)parameters).Parameters;
+ k = (AsymmetricKeyParameter)withRandom.Parameters;
}
else
{
diff --git a/crypto/src/crypto/signers/Iso9796d2PssSigner.cs b/crypto/src/crypto/signers/Iso9796d2PssSigner.cs
index ce7130538..8657f6eaf 100644
--- a/crypto/src/crypto/signers/Iso9796d2PssSigner.cs
+++ b/crypto/src/crypto/signers/Iso9796d2PssSigner.cs
@@ -115,11 +115,7 @@ namespace Org.BouncyCastle.Crypto.Signers
if (parameters is ParametersWithRandom withRandom)
{
kParam = (RsaKeyParameters)withRandom.Parameters;
-
- if (forSigning)
- {
- random = withRandom.Random;
- }
+ random = forSigning ? withRandom.Random : null;
}
else if (parameters is ParametersWithSalt withSalt)
{
@@ -135,11 +131,7 @@ namespace Org.BouncyCastle.Crypto.Signers
else
{
kParam = (RsaKeyParameters)parameters;
-
- if (forSigning)
- {
- random = CryptoServicesRegistrar.GetSecureRandom();
- }
+ random = forSigning ? CryptoServicesRegistrar.GetSecureRandom() : null;
}
cipher.Init(forSigning, kParam);
diff --git a/crypto/src/crypto/signers/IsoTrailers.cs b/crypto/src/crypto/signers/IsoTrailers.cs
index 61006b848..83b9c192d 100644
--- a/crypto/src/crypto/signers/IsoTrailers.cs
+++ b/crypto/src/crypto/signers/IsoTrailers.cs
@@ -42,7 +42,10 @@ namespace Org.BouncyCastle.Crypto.Signers
public static int GetTrailer(IDigest digest)
{
- return TrailerMap[digest.AlgorithmName];
+ if (TrailerMap.TryGetValue(digest.AlgorithmName, out var trailer))
+ return trailer;
+
+ throw new InvalidOperationException("No trailer for digest");
}
public static bool NoTrailerAvailable(IDigest digest)
diff --git a/crypto/src/crypto/signers/PssSigner.cs b/crypto/src/crypto/signers/PssSigner.cs
index 69f9e96e4..2e4c37772 100644
--- a/crypto/src/crypto/signers/PssSigner.cs
+++ b/crypto/src/crypto/signers/PssSigner.cs
@@ -158,21 +158,18 @@ namespace Org.BouncyCastle.Crypto.Signers
{
parameters = withRandom.Parameters;
random = withRandom.Random;
- }
- else
+ cipher.Init(forSigning, withRandom);
+ }
+ else
{
- if (forSigning)
- {
- random = CryptoServicesRegistrar.GetSecureRandom();
- }
- }
-
- cipher.Init(forSigning, parameters);
+ random = forSigning ? CryptoServicesRegistrar.GetSecureRandom() : null;
+ cipher.Init(forSigning, parameters);
+ }
- RsaKeyParameters kParam;
- if (parameters is RsaBlindingParameters)
+ RsaKeyParameters kParam;
+ if (parameters is RsaBlindingParameters blinding)
{
- kParam = ((RsaBlindingParameters)parameters).PublicKey;
+ kParam = blinding.PublicKey;
}
else
{
@@ -188,8 +185,7 @@ namespace Org.BouncyCastle.Crypto.Signers
}
/// <summary> clear possible sensitive data</summary>
- private void ClearBlock(
- byte[] block)
+ private void ClearBlock(byte[] block)
{
Array.Clear(block, 0, block.Length);
}
@@ -346,24 +342,17 @@ namespace Org.BouncyCastle.Crypto.Signers
sp[3] = (byte)((uint) i >> 0);
}
- private byte[] MaskGeneratorFunction(
- byte[] Z,
- int zOff,
- int zLen,
- int length)
- {
- if (mgfDigest is IXof)
+ private byte[] MaskGeneratorFunction(byte[] Z, int zOff, int zLen, int length)
+ {
+ if (mgfDigest is IXof xof)
{
byte[] mask = new byte[length];
- mgfDigest.BlockUpdate(Z, zOff, zLen);
- ((IXof)mgfDigest).OutputFinal(mask, 0, mask.Length);
-
+ xof.BlockUpdate(Z, zOff, zLen);
+ xof.OutputFinal(mask, 0, mask.Length);
return mask;
}
- else
- {
- return MaskGeneratorFunction1(Z, zOff, zLen, length);
- }
+
+ return MaskGeneratorFunction1(Z, zOff, zLen, length);
}
/// <summary> mask generator function, as described in Pkcs1v2.</summary>
diff --git a/crypto/src/crypto/signers/RsaDigestSigner.cs b/crypto/src/crypto/signers/RsaDigestSigner.cs
index 77d9b9ac3..80b1a4356 100644
--- a/crypto/src/crypto/signers/RsaDigestSigner.cs
+++ b/crypto/src/crypto/signers/RsaDigestSigner.cs
@@ -100,11 +100,11 @@ namespace Org.BouncyCastle.Crypto.Signers
ICipherParameters parameters)
{
this.forSigning = forSigning;
- AsymmetricKeyParameter k;
- if (parameters is ParametersWithRandom)
+ AsymmetricKeyParameter k;
+ if (parameters is ParametersWithRandom withRandom)
{
- k = (AsymmetricKeyParameter)((ParametersWithRandom)parameters).Parameters;
+ k = (AsymmetricKeyParameter)withRandom.Parameters;
}
else
{
diff --git a/crypto/src/crypto/signers/SM2Signer.cs b/crypto/src/crypto/signers/SM2Signer.cs
index 60fae3264..cd4b2d554 100644
--- a/crypto/src/crypto/signers/SM2Signer.cs
+++ b/crypto/src/crypto/signers/SM2Signer.cs
@@ -55,10 +55,10 @@ namespace Org.BouncyCastle.Crypto.Signers
ICipherParameters baseParam;
byte[] userID;
- if (parameters is ParametersWithID)
+ if (parameters is ParametersWithID withID)
{
- baseParam = ((ParametersWithID)parameters).Parameters;
- userID = ((ParametersWithID)parameters).GetID();
+ baseParam = withID.Parameters;
+ userID = withID.GetID();
if (userID.Length >= 8192)
throw new ArgumentException("SM2 user ID must be less than 2^16 bits long");
@@ -72,18 +72,23 @@ namespace Org.BouncyCastle.Crypto.Signers
if (forSigning)
{
+ SecureRandom random = null;
if (baseParam is ParametersWithRandom rParam)
{
ecKey = (ECKeyParameters)rParam.Parameters;
ecParams = ecKey.Parameters;
- kCalculator.Init(ecParams.N, rParam.Random);
+ random = rParam.Random;
}
else
{
ecKey = (ECKeyParameters)baseParam;
ecParams = ecKey.Parameters;
- kCalculator.Init(ecParams.N, CryptoServicesRegistrar.GetSecureRandom());
}
+ if (!kCalculator.IsDeterministic)
+ {
+ random = CryptoServicesRegistrar.GetSecureRandom(random);
+ }
+ kCalculator.Init(ecParams.N, random);
pubPoint = CreateBasePointMultiplier().Multiply(ecParams.G, ((ECPrivateKeyParameters)ecKey).D).Normalize();
}
else
diff --git a/crypto/src/crypto/signers/StandardDsaEncoding.cs b/crypto/src/crypto/signers/StandardDsaEncoding.cs
index 77cd6124d..8fa195982 100644
--- a/crypto/src/crypto/signers/StandardDsaEncoding.cs
+++ b/crypto/src/crypto/signers/StandardDsaEncoding.cs
@@ -24,7 +24,7 @@ namespace Org.BouncyCastle.Crypto.Signers
return new BigInteger[]{ r, s };
}
- throw new ArgumentException("Malformed signature", "encoding");
+ throw new ArgumentException("Malformed signature", nameof(encoding));
}
public virtual byte[] Encode(BigInteger n, BigInteger r, BigInteger s)
@@ -55,7 +55,7 @@ namespace Org.BouncyCastle.Crypto.Signers
protected virtual BigInteger CheckValue(BigInteger n, BigInteger x)
{
if (x.SignValue < 0 || (null != n && x.CompareTo(n) >= 0))
- throw new ArgumentException("Value out of range", "x");
+ throw new ArgumentException("Value out of range", nameof(x));
return x;
}
diff --git a/crypto/src/crypto/signers/X931Signer.cs b/crypto/src/crypto/signers/X931Signer.cs
index 9db4e1642..2b0854925 100644
--- a/crypto/src/crypto/signers/X931Signer.cs
+++ b/crypto/src/crypto/signers/X931Signer.cs
@@ -28,6 +28,17 @@ namespace Org.BouncyCastle.Crypto.Signers
private byte[] block;
/**
+ * Constructor for a signer with an explicit digest trailer.
+ *
+ * @param cipher cipher to use.
+ * @param digest digest to sign with.
+ */
+ public X931Signer(IAsymmetricBlockCipher cipher, IDigest digest)
+ : this(cipher, digest, false)
+ {
+ }
+
+ /**
* Generate a signer with either implicit or explicit trailers for X9.31.
*
* @param cipher base cipher to use for signature creation/verification
@@ -53,17 +64,6 @@ namespace Org.BouncyCastle.Crypto.Signers
}
}
- /**
- * Constructor for a signer with an explicit digest trailer.
- *
- * @param cipher cipher to use.
- * @param digest digest to sign with.
- */
- public X931Signer(IAsymmetricBlockCipher cipher, IDigest digest)
- : this(cipher, digest, false)
- {
- }
-
public virtual string AlgorithmName
{
get { return digest.AlgorithmName + "with" + cipher.AlgorithmName + "/X9.31"; }
@@ -71,9 +71,16 @@ namespace Org.BouncyCastle.Crypto.Signers
public virtual void Init(bool forSigning, ICipherParameters parameters)
{
- kParam = (RsaKeyParameters)parameters;
+ if (parameters is ParametersWithRandom withRandom)
+ {
+ kParam = (RsaKeyParameters)withRandom.Parameters;
+ }
+ else
+ {
+ kParam = (RsaKeyParameters)parameters;
+ }
- cipher.Init(forSigning, kParam);
+ cipher.Init(forSigning, parameters);
keyBits = kParam.Modulus.BitLength;
@@ -114,33 +121,6 @@ namespace Org.BouncyCastle.Crypto.Signers
return BigIntegers.AsUnsignedByteArray(size, t);
}
- private void CreateSignatureBlock()
- {
- int digSize = digest.GetDigestSize();
-
- int delta;
- if (trailer == IsoTrailers.TRAILER_IMPLICIT)
- {
- delta = block.Length - digSize - 1;
- digest.DoFinal(block, delta);
- block[block.Length - 1] = (byte)IsoTrailers.TRAILER_IMPLICIT;
- }
- else
- {
- delta = block.Length - digSize - 2;
- digest.DoFinal(block, delta);
- block[block.Length - 2] = (byte)(trailer >> 8);
- block[block.Length - 1] = (byte)trailer;
- }
-
- block[0] = 0x6b;
- for (int i = delta - 2; i != 0; i--)
- {
- block[i] = (byte)0xbb;
- }
- block[delta - 1] = (byte)0xba;
- }
-
public virtual bool VerifySignature(byte[] signature)
{
try
@@ -196,5 +176,32 @@ namespace Org.BouncyCastle.Crypto.Signers
{
digest.Reset();
}
+
+ private void CreateSignatureBlock()
+ {
+ int digSize = digest.GetDigestSize();
+
+ int delta;
+ if (trailer == IsoTrailers.TRAILER_IMPLICIT)
+ {
+ delta = block.Length - digSize - 1;
+ digest.DoFinal(block, delta);
+ block[block.Length - 1] = (byte)IsoTrailers.TRAILER_IMPLICIT;
+ }
+ else
+ {
+ delta = block.Length - digSize - 2;
+ digest.DoFinal(block, delta);
+ block[block.Length - 2] = (byte)(trailer >> 8);
+ block[block.Length - 1] = (byte)trailer;
+ }
+
+ block[0] = 0x6b;
+ for (int i = delta - 2; i != 0; i--)
+ {
+ block[i] = (byte)0xbb;
+ }
+ block[delta - 1] = (byte)0xba;
+ }
}
}
|