summary refs log tree commit diff
path: root/crypto/src/crypto
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/src/crypto')
-rw-r--r--crypto/src/crypto/BufferedAeadBlockCipher.cs18
-rw-r--r--crypto/src/crypto/BufferedAeadCipher.cs13
-rw-r--r--crypto/src/crypto/BufferedStreamCipher.cs5
-rw-r--r--crypto/src/crypto/CryptoServicesRegistrar.cs2
-rw-r--r--crypto/src/crypto/IBlockResult.cs1
-rw-r--r--crypto/src/crypto/IDerivationFunction.cs8
-rw-r--r--crypto/src/crypto/agreement/DHBasicAgreement.cs15
-rw-r--r--crypto/src/crypto/agreement/ECDHBasicAgreement.cs12
-rw-r--r--crypto/src/crypto/agreement/ECDHCBasicAgreement.cs12
-rw-r--r--crypto/src/crypto/agreement/ECMqvBasicAgreement.cs7
-rw-r--r--crypto/src/crypto/agreement/kdf/ConcatenationKdfGenerator.cs7
-rw-r--r--crypto/src/crypto/digests/ISAPDigest.cs149
-rw-r--r--crypto/src/crypto/digests/LongDigest.cs2
-rw-r--r--crypto/src/crypto/digests/MD5Digest.cs141
-rw-r--r--crypto/src/crypto/digests/PhotonBeetleDigest.cs247
-rw-r--r--crypto/src/crypto/digests/XoodyakDigest.cs207
-rw-r--r--crypto/src/crypto/encodings/OaepEncoding.cs21
-rw-r--r--crypto/src/crypto/encodings/Pkcs1Encoding.cs20
-rw-r--r--crypto/src/crypto/engines/AesEngine.cs3
-rw-r--r--crypto/src/crypto/engines/AsconEngine.cs693
-rw-r--r--crypto/src/crypto/engines/DesEdeWrapEngine.cs27
-rw-r--r--crypto/src/crypto/engines/ElGamalEngine.cs15
-rw-r--r--crypto/src/crypto/engines/ElephantEngine.cs594
-rw-r--r--crypto/src/crypto/engines/ISAPEngine.cs1034
-rw-r--r--crypto/src/crypto/engines/NaccacheSternEngine.cs8
-rw-r--r--crypto/src/crypto/engines/PhotonBeetleEngine.cs461
-rw-r--r--crypto/src/crypto/engines/RC2WrapEngine.cs256
-rw-r--r--crypto/src/crypto/engines/RC4Engine.cs7
-rw-r--r--crypto/src/crypto/engines/RFC3211WrapEngine.cs12
-rw-r--r--crypto/src/crypto/engines/RFC3394WrapEngine.cs19
-rw-r--r--crypto/src/crypto/engines/RSABlindingEngine.cs4
-rw-r--r--crypto/src/crypto/engines/RSACoreEngine.cs41
-rw-r--r--crypto/src/crypto/engines/SM2Engine.cs20
-rw-r--r--crypto/src/crypto/engines/Salsa20Engine.cs2
-rw-r--r--crypto/src/crypto/engines/XoodyakEngine.cs452
-rw-r--r--crypto/src/crypto/fpe/SP80038G.cs13
-rw-r--r--crypto/src/crypto/generators/ECKeyPairGenerator.cs68
-rw-r--r--crypto/src/crypto/generators/HkdfBytesGenerator.cs1
-rw-r--r--crypto/src/crypto/generators/KDFCounterBytesGenerator.cs5
-rw-r--r--crypto/src/crypto/generators/KDFDoublePipelineIterationBytesGenerator.cs147
-rw-r--r--crypto/src/crypto/generators/KDFFeedbackBytesGenerator.cs4
-rw-r--r--crypto/src/crypto/io/CipherStream.cs10
-rw-r--r--crypto/src/crypto/io/DigestStream.cs12
-rw-r--r--crypto/src/crypto/io/MacStream.cs12
-rw-r--r--crypto/src/crypto/io/SignerStream.cs76
-rw-r--r--crypto/src/crypto/macs/Poly1305.cs3
-rw-r--r--crypto/src/crypto/modes/CcmBlockCipher.cs10
-rw-r--r--crypto/src/crypto/modes/CfbBlockCipher.cs3
-rw-r--r--crypto/src/crypto/modes/EAXBlockCipher.cs26
-rw-r--r--crypto/src/crypto/modes/EcbBlockCipher.cs5
-rw-r--r--crypto/src/crypto/modes/GCMBlockCipher.cs41
-rw-r--r--crypto/src/crypto/modes/OpenPgpCfbBlockCipher.cs1
-rw-r--r--crypto/src/crypto/modes/SicBlockCipher.cs8
-rw-r--r--crypto/src/crypto/modes/gcm/GcmUtilities.cs6
-rw-r--r--crypto/src/crypto/operators/Asn1Signature.cs4
-rw-r--r--crypto/src/crypto/paddings/ISO10126d2Padding.cs37
-rw-r--r--crypto/src/crypto/paddings/ISO7816d4Padding.cs27
-rw-r--r--crypto/src/crypto/paddings/Pkcs7Padding.cs23
-rw-r--r--crypto/src/crypto/paddings/TbcPadding.cs34
-rw-r--r--crypto/src/crypto/paddings/X923Padding.cs39
-rw-r--r--crypto/src/crypto/paddings/ZeroBytePadding.cs21
-rw-r--r--crypto/src/crypto/parameters/DHKeyParameters.cs2
-rw-r--r--crypto/src/crypto/parameters/DHParameters.cs2
-rw-r--r--crypto/src/crypto/parameters/DHPublicKeyParameters.cs40
-rw-r--r--crypto/src/crypto/parameters/DsaKeyParameters.cs2
-rw-r--r--crypto/src/crypto/parameters/ElGamalKeyParameters.cs2
-rw-r--r--crypto/src/crypto/parameters/KDFDoublePipelineIterationParameters.cs19
-rw-r--r--crypto/src/crypto/parameters/KdfParameters.cs3
-rw-r--r--crypto/src/crypto/parameters/KeyParameter.cs2
-rw-r--r--crypto/src/crypto/parameters/ParametersWithID.cs18
-rw-r--r--crypto/src/crypto/parameters/ParametersWithIV.cs21
-rw-r--r--crypto/src/crypto/parameters/ParametersWithSBox.cs23
-rw-r--r--crypto/src/crypto/parameters/ParametersWithSalt.cs20
-rw-r--r--crypto/src/crypto/prng/BasicEntropySourceProvider.cs2
-rw-r--r--crypto/src/crypto/prng/CryptoApiEntropySourceProvider.cs2
-rw-r--r--crypto/src/crypto/prng/CryptoApiRandomGenerator.cs10
-rw-r--r--crypto/src/crypto/prng/EntropyUtilities.cs17
-rw-r--r--crypto/src/crypto/prng/SP800SecureRandom.cs7
-rw-r--r--crypto/src/crypto/prng/X931SecureRandom.cs7
-rw-r--r--crypto/src/crypto/prng/drbg/CtrSP800Drbg.cs4
-rw-r--r--crypto/src/crypto/signers/DsaDigestSigner.cs4
-rw-r--r--crypto/src/crypto/signers/DsaSigner.cs12
-rw-r--r--crypto/src/crypto/signers/ECDsaSigner.cs12
-rw-r--r--crypto/src/crypto/signers/Ed25519phSigner.cs6
-rw-r--r--crypto/src/crypto/signers/Ed448Signer.cs1
-rw-r--r--crypto/src/crypto/signers/Ed448phSigner.cs6
-rw-r--r--crypto/src/crypto/signers/GOST3410DigestSigner.cs9
-rw-r--r--crypto/src/crypto/signers/GenericSigner.cs4
-rw-r--r--crypto/src/crypto/signers/Iso9796d2PssSigner.cs12
-rw-r--r--crypto/src/crypto/signers/IsoTrailers.cs5
-rw-r--r--crypto/src/crypto/signers/PssSigner.cs45
-rw-r--r--crypto/src/crypto/signers/RsaDigestSigner.cs6
-rw-r--r--crypto/src/crypto/signers/SM2Signer.cs15
-rw-r--r--crypto/src/crypto/signers/StandardDsaEncoding.cs4
-rw-r--r--crypto/src/crypto/signers/X931Signer.cs87
95 files changed, 4577 insertions, 1025 deletions
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; + } } }