From 8df051272b46c358f8edb4cea86b2298ee696deb Mon Sep 17 00:00:00 2001 From: Peter Dettman Date: Wed, 12 Apr 2023 20:07:41 +0700 Subject: Refactoring around KeyParameter --- crypto/src/crypto/CipherKeyGenerator.cs | 54 ++++++++++++++---- crypto/src/crypto/engines/AesEngine.cs | 10 +++- crypto/src/crypto/engines/AesLightEngine.cs | 10 +++- crypto/src/crypto/engines/RijndaelEngine.cs | 27 ++++----- crypto/src/crypto/fpe/FpeFf3_1Engine.cs | 15 ++++- crypto/src/crypto/generators/DesEdeKeyGenerator.cs | 15 +++++ crypto/src/crypto/generators/DesKeyGenerator.cs | 15 +++++ .../src/crypto/generators/Poly1305KeyGenerator.cs | 65 ++++++++++++++++++---- crypto/src/crypto/macs/Poly1305.cs | 47 +++++++++------- crypto/src/crypto/modes/ChaCha20Poly1305.cs | 12 ++-- crypto/src/crypto/modes/GCMBlockCipher.cs | 2 +- crypto/src/crypto/operators/Asn1CipherBuilder.cs | 2 +- crypto/src/crypto/parameters/DesEdeParameters.cs | 53 +++++++++++++++--- crypto/src/crypto/parameters/DesParameters.cs | 41 +++++++++++--- crypto/src/crypto/parameters/KeyParameter.cs | 40 +++++++++++++ crypto/src/crypto/util/Pack.cs | 6 ++ 16 files changed, 326 insertions(+), 88 deletions(-) (limited to 'crypto/src') diff --git a/crypto/src/crypto/CipherKeyGenerator.cs b/crypto/src/crypto/CipherKeyGenerator.cs index 2d5d8c2e0..fcf8c324a 100644 --- a/crypto/src/crypto/CipherKeyGenerator.cs +++ b/crypto/src/crypto/CipherKeyGenerator.cs @@ -1,13 +1,14 @@ using System; +using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Security; namespace Org.BouncyCastle.Crypto { - /** + /** * The base class for symmetric, or secret, cipher key generators. */ - public class CipherKeyGenerator + public class CipherKeyGenerator { protected internal SecureRandom random; protected internal int strength; @@ -60,22 +61,51 @@ namespace Org.BouncyCastle.Crypto */ public byte[] GenerateKey() { - if (uninitialised) - { - if (defaultStrength < 1) - throw new InvalidOperationException("Generator has not been initialised"); - - uninitialised = false; - - EngineInit(new KeyGenerationParameters(CryptoServicesRegistrar.GetSecureRandom(), defaultStrength)); - } + EnsureInitialized(); return EngineGenerateKey(); } + public KeyParameter GenerateKeyParameter() + { + EnsureInitialized(); + + return EngineGenerateKeyParameter(); + } + protected virtual byte[] EngineGenerateKey() { return SecureRandom.GetNextBytes(random, strength); } - } + + protected virtual KeyParameter EngineGenerateKeyParameter() + { +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + // TODO[api] Redesign to avoid this exceptional case + // Avoid problems if EngineGenerateKey() was overridden before this method even existed. + if (GetType() == typeof(CipherKeyGenerator)) + { + return KeyParameter.Create(strength, random, (bytes, random) => + { + random.NextBytes(bytes); + }); + } +#endif + + return new KeyParameter(EngineGenerateKey()); + } + + protected virtual void EnsureInitialized() + { + if (uninitialised) + { + if (defaultStrength < 1) + throw new InvalidOperationException("Generator has not been initialised"); + + uninitialised = false; + + EngineInit(new KeyGenerationParameters(CryptoServicesRegistrar.GetSecureRandom(), defaultStrength)); + } + } + } } diff --git a/crypto/src/crypto/engines/AesEngine.cs b/crypto/src/crypto/engines/AesEngine.cs index 3977cb893..0c69969f6 100644 --- a/crypto/src/crypto/engines/AesEngine.cs +++ b/crypto/src/crypto/engines/AesEngine.cs @@ -288,8 +288,14 @@ namespace Org.BouncyCastle.Crypto.Engines * AES specified a fixed block size of 128 bits and key sizes 128/192/256 bits * This code is written assuming those are the only possible values */ - private uint[][] GenerateWorkingKey(byte[] key, bool forEncryption) + private uint[][] GenerateWorkingKey(KeyParameter keyParameter, bool forEncryption) { +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + var key = keyParameter.Key; +#else + byte[] key = keyParameter.GetKey(); +#endif + int keyLen = key.Length; if (keyLen < 16 || keyLen > 32 || (keyLen & 7) != 0) throw new ArgumentException("Key length not 128/192/256 bits."); @@ -452,7 +458,7 @@ namespace Org.BouncyCastle.Crypto.Engines throw new ArgumentException("invalid parameter passed to AES init - " + Platform.GetTypeName(parameters)); - WorkingKey = GenerateWorkingKey(keyParameter.GetKey(), forEncryption); + WorkingKey = GenerateWorkingKey(keyParameter, forEncryption); this.forEncryption = forEncryption; this.s = Arrays.Clone(forEncryption ? S : Si); diff --git a/crypto/src/crypto/engines/AesLightEngine.cs b/crypto/src/crypto/engines/AesLightEngine.cs index 8d76f4388..42aa74420 100644 --- a/crypto/src/crypto/engines/AesLightEngine.cs +++ b/crypto/src/crypto/engines/AesLightEngine.cs @@ -186,8 +186,14 @@ namespace Org.BouncyCastle.Crypto.Engines * AES specified a fixed block size of 128 bits and key sizes 128/192/256 bits * This code is written assuming those are the only possible values */ - private uint[][] GenerateWorkingKey(byte[] key, bool forEncryption) + private uint[][] GenerateWorkingKey(KeyParameter keyParameter, bool forEncryption) { +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + var key = keyParameter.Key; +#else + byte[] key = keyParameter.GetKey(); +#endif + int keyLen = key.Length; if (keyLen < 16 || keyLen > 32 || (keyLen & 7) != 0) throw new ArgumentException("Key length not 128/192/256 bits."); @@ -348,7 +354,7 @@ namespace Org.BouncyCastle.Crypto.Engines throw new ArgumentException("invalid parameter passed to AES init - " + Platform.GetTypeName(parameters)); - WorkingKey = GenerateWorkingKey(keyParameter.GetKey(), forEncryption); + WorkingKey = GenerateWorkingKey(keyParameter, forEncryption); this.forEncryption = forEncryption; } diff --git a/crypto/src/crypto/engines/RijndaelEngine.cs b/crypto/src/crypto/engines/RijndaelEngine.cs index 422664ce0..81aa012e5 100644 --- a/crypto/src/crypto/engines/RijndaelEngine.cs +++ b/crypto/src/crypto/engines/RijndaelEngine.cs @@ -379,10 +379,15 @@ namespace Org.BouncyCastle.Crypto.Engines * Calculate the necessary round keys * The number of calculations depends on keyBits and blockBits */ - private long[][] GenerateWorkingKey( - byte[] key) + private long[][] GenerateWorkingKey(KeyParameter keyParameter) { - int KC; +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + var key = keyParameter.Key; +#else + byte[] key = keyParameter.GetKey(); +#endif + + int KC; int t, rconpointer = 0; int keyBits = key.Length * 8; byte[,] tk = new byte[4,MAXKC]; @@ -572,18 +577,14 @@ namespace Org.BouncyCastle.Crypto.Engines * @exception ArgumentException if the parameters argument is * inappropriate. */ - public virtual void Init( - bool forEncryption, - ICipherParameters parameters) + public virtual void Init(bool forEncryption, ICipherParameters parameters) { - if (typeof(KeyParameter).IsInstanceOfType(parameters)) - { - workingKey = GenerateWorkingKey(((KeyParameter)parameters).GetKey()); - this.forEncryption = forEncryption; - return; - } + if (!(parameters is KeyParameter keyParameter)) + throw new ArgumentException("invalid parameter passed to Rijndael init - " + + Platform.GetTypeName(parameters)); - throw new ArgumentException("invalid parameter passed to Rijndael init - " + Platform.GetTypeName(parameters)); + this.workingKey = GenerateWorkingKey(keyParameter); + this.forEncryption = forEncryption; } public virtual string AlgorithmName diff --git a/crypto/src/crypto/fpe/FpeFf3_1Engine.cs b/crypto/src/crypto/fpe/FpeFf3_1Engine.cs index 71203aecf..bc8d22fae 100644 --- a/crypto/src/crypto/fpe/FpeFf3_1Engine.cs +++ b/crypto/src/crypto/fpe/FpeFf3_1Engine.cs @@ -29,7 +29,7 @@ namespace Org.BouncyCastle.Crypto.Fpe this.forEncryption = forEncryption; this.fpeParameters = (FpeParameters)parameters; - baseCipher.Init(!fpeParameters.UseInverseFunction, new KeyParameter(Arrays.Reverse(fpeParameters.Key.GetKey()))); + baseCipher.Init(!fpeParameters.UseInverseFunction, ReverseKey(fpeParameters.Key)); if (fpeParameters.GetTweak().Length != 7) throw new ArgumentException("tweak should be 56 bits"); @@ -82,5 +82,18 @@ namespace Org.BouncyCastle.Crypto.Fpe return length; } + + private static KeyParameter ReverseKey(KeyParameter key) + { +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + return KeyParameter.Create(key.KeyLength, key, (bytes, key) => + { + key.Key.CopyTo(bytes); + bytes.Reverse(); + }); +#else + return new KeyParameter(Arrays.Reverse(key.GetKey())); +#endif + } } } diff --git a/crypto/src/crypto/generators/DesEdeKeyGenerator.cs b/crypto/src/crypto/generators/DesEdeKeyGenerator.cs index 24197e9da..9e14702d1 100644 --- a/crypto/src/crypto/generators/DesEdeKeyGenerator.cs +++ b/crypto/src/crypto/generators/DesEdeKeyGenerator.cs @@ -62,5 +62,20 @@ namespace Org.BouncyCastle.Crypto.Generators return newKey; } + +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + protected override KeyParameter EngineGenerateKeyParameter() + { + return KeyParameter.Create(strength, random, (bytes, random) => + { + do + { + random.NextBytes(bytes); + DesEdeParameters.SetOddParity(bytes); + } + while (DesEdeParameters.IsWeakKey(bytes) || !DesEdeParameters.IsRealEdeKey(bytes)); + }); + } +#endif } } diff --git a/crypto/src/crypto/generators/DesKeyGenerator.cs b/crypto/src/crypto/generators/DesKeyGenerator.cs index 5a1befd71..7a5a40c5c 100644 --- a/crypto/src/crypto/generators/DesKeyGenerator.cs +++ b/crypto/src/crypto/generators/DesKeyGenerator.cs @@ -52,5 +52,20 @@ namespace Org.BouncyCastle.Crypto.Generators return newKey; } + +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + protected override KeyParameter EngineGenerateKeyParameter() + { + return KeyParameter.Create(strength, random, (bytes, random) => + { + do + { + random.NextBytes(bytes); + DesParameters.SetOddParity(bytes); + } + while (DesParameters.IsWeakKey(bytes)); + }); + } +#endif } } diff --git a/crypto/src/crypto/generators/Poly1305KeyGenerator.cs b/crypto/src/crypto/generators/Poly1305KeyGenerator.cs index d7827fea9..a84807a76 100644 --- a/crypto/src/crypto/generators/Poly1305KeyGenerator.cs +++ b/crypto/src/crypto/generators/Poly1305KeyGenerator.cs @@ -50,18 +50,32 @@ namespace Org.BouncyCastle.Crypto.Generators return key; } - /// - /// Modifies an existing 32 byte key value to comply with the requirements of the Poly1305 key by - /// clearing required bits in the r (second 16 bytes) portion of the key.
- /// Specifically: - /// - ///
- /// a 32 byte key value k[0] ... k[15], r[0] ... r[15] - public static void Clamp(byte[] key) +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + protected override KeyParameter EngineGenerateKeyParameter() + { + return KeyParameter.Create(strength, random, (bytes, random) => + { + random.NextBytes(bytes); + Clamp(bytes); + }); + } +#endif + + /// + /// Modifies an existing 32 byte key value to comply with the requirements of the Poly1305 key by + /// clearing required bits in the r (second 16 bytes) portion of the key.
+ /// Specifically: + /// + ///
+ /// a 32 byte key value k[0] ... k[15], r[0] ... r[15] + public static void Clamp(byte[] key) { +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + Clamp(key.AsSpan()); +#else /* * Key is k[0] ... k[15], r[0] ... r[15] as per poly1305_aes_clamp in ref impl. */ @@ -82,9 +96,36 @@ namespace Org.BouncyCastle.Crypto.Generators key[4] &= R_MASK_LOW_2; key[8] &= R_MASK_LOW_2; key[12] &= R_MASK_LOW_2; +#endif } - /// +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public static void Clamp(Span key) + { + /* + * Key is k[0] ... k[15], r[0] ... r[15] as per poly1305_aes_clamp in ref impl. + */ + if (key.Length != 32) + throw new ArgumentException("Poly1305 key must be 256 bits."); + + /* + * r[3], r[7], r[11], r[15] have top four bits clear (i.e., are {0, 1, . . . , 15}) + */ + key[3] &= R_MASK_HIGH_4; + key[7] &= R_MASK_HIGH_4; + key[11] &= R_MASK_HIGH_4; + key[15] &= R_MASK_HIGH_4; + + /* + * r[4], r[8], r[12] have bottom two bits clear (i.e., are in {0, 4, 8, . . . , 252}). + */ + key[4] &= R_MASK_LOW_2; + key[8] &= R_MASK_LOW_2; + key[12] &= R_MASK_LOW_2; + } +#endif + + /// /// Checks a 32 byte key for compliance with the Poly1305 key requirements, e.g. /// k[0] ... k[15], r[0] ... r[15] with the required bits in r cleared /// as per . diff --git a/crypto/src/crypto/macs/Poly1305.cs b/crypto/src/crypto/macs/Poly1305.cs index adf4975ba..61f13a972 100644 --- a/crypto/src/crypto/macs/Poly1305.cs +++ b/crypto/src/crypto/macs/Poly1305.cs @@ -84,26 +84,29 @@ namespace Org.BouncyCastle.Crypto.Macs if (cipher != null) { - if (!(parameters is ParametersWithIV)) - throw new ArgumentException("Poly1305 requires an IV when used with a block cipher.", "parameters"); + if (!(parameters is ParametersWithIV ivParams)) + throw new ArgumentException("Poly1305 requires an IV when used with a block cipher.", nameof(parameters)); - ParametersWithIV ivParams = (ParametersWithIV)parameters; nonce = ivParams.GetIV(); parameters = ivParams.Parameters; } - if (!(parameters is KeyParameter)) + if (!(parameters is KeyParameter keyParameter)) throw new ArgumentException("Poly1305 requires a key."); - KeyParameter keyParams = (KeyParameter)parameters; - - SetKey(keyParams.GetKey(), nonce); + SetKey(keyParameter, nonce); Reset(); } - private void SetKey(byte[] key, byte[] nonce) + private void SetKey(KeyParameter keyParameter, byte[] nonce) { +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + var key = keyParameter.Key; +#else + byte[] key = keyParameter.GetKey(); +#endif + if (key.Length != 32) throw new ArgumentException("Poly1305 key must be 256 bits."); @@ -129,28 +132,32 @@ namespace Org.BouncyCastle.Crypto.Macs s3 = r3 * 5; s4 = r4 * 5; - byte[] kBytes; - int kOff; - if (cipher == null) { - kBytes = key; - kOff = BlockSize; + k0 = Pack.LE_To_UInt32(key, BlockSize + 0); + k1 = Pack.LE_To_UInt32(key, BlockSize + 4); + k2 = Pack.LE_To_UInt32(key, BlockSize + 8); + k3 = Pack.LE_To_UInt32(key, BlockSize + 12); } else { // Compute encrypted nonce - kBytes = new byte[BlockSize]; - kOff = 0; +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + Span kBytes = stackalloc byte[BlockSize]; + cipher.Init(true, new KeyParameter(key.Slice(BlockSize, BlockSize))); + cipher.ProcessBlock(nonce, kBytes); +#else + byte[] kBytes = new byte[BlockSize]; cipher.Init(true, new KeyParameter(key, BlockSize, BlockSize)); cipher.ProcessBlock(nonce, 0, kBytes, 0); - } +#endif - k0 = Pack.LE_To_UInt32(kBytes, kOff + 0); - k1 = Pack.LE_To_UInt32(kBytes, kOff + 4); - k2 = Pack.LE_To_UInt32(kBytes, kOff + 8); - k3 = Pack.LE_To_UInt32(kBytes, kOff + 12); + k0 = Pack.LE_To_UInt32(kBytes, 0); + k1 = Pack.LE_To_UInt32(kBytes, 4); + k2 = Pack.LE_To_UInt32(kBytes, 8); + k3 = Pack.LE_To_UInt32(kBytes, 12); + } } public string AlgorithmName diff --git a/crypto/src/crypto/modes/ChaCha20Poly1305.cs b/crypto/src/crypto/modes/ChaCha20Poly1305.cs index 7e2348932..01bf6ccb8 100644 --- a/crypto/src/crypto/modes/ChaCha20Poly1305.cs +++ b/crypto/src/crypto/modes/ChaCha20Poly1305.cs @@ -75,10 +75,8 @@ namespace Org.BouncyCastle.Crypto.Modes byte[] initNonce; ICipherParameters chacha20Params; - if (parameters is AeadParameters) + if (parameters is AeadParameters aeadParams) { - AeadParameters aeadParams = (AeadParameters)parameters; - int macSizeBits = aeadParams.MacSize; if ((MacSize * 8) != macSizeBits) throw new ArgumentException("Invalid value for MAC size: " + macSizeBits); @@ -89,10 +87,8 @@ namespace Org.BouncyCastle.Crypto.Modes this.mInitialAad = aeadParams.GetAssociatedText(); } - else if (parameters is ParametersWithIV) + else if (parameters is ParametersWithIV ivParams) { - ParametersWithIV ivParams = (ParametersWithIV)parameters; - initKeyParam = (KeyParameter)ivParams.Parameters; initNonce = ivParams.GetIV(); chacha20Params = ivParams; @@ -123,13 +119,13 @@ namespace Org.BouncyCastle.Crypto.Modes // Check for encryption with reused nonce if (State.Uninitialized != mState && forEncryption && Arrays.AreEqual(mNonce, initNonce)) { - if (null == initKeyParam || Arrays.AreEqual(mKey, initKeyParam.GetKey())) + if (null == initKeyParam || initKeyParam.FixedTimeEquals(mKey)) throw new ArgumentException("cannot reuse nonce for ChaCha20Poly1305 encryption"); } if (null != initKeyParam) { - Array.Copy(initKeyParam.GetKey(), 0, mKey, 0, KeySize); + initKeyParam.CopyTo(mKey, 0, KeySize); } Array.Copy(initNonce, 0, mNonce, 0, NonceSize); diff --git a/crypto/src/crypto/modes/GCMBlockCipher.cs b/crypto/src/crypto/modes/GCMBlockCipher.cs index f41214c5d..fef980091 100644 --- a/crypto/src/crypto/modes/GCMBlockCipher.cs +++ b/crypto/src/crypto/modes/GCMBlockCipher.cs @@ -156,7 +156,7 @@ namespace Org.BouncyCastle.Crypto.Modes if (keyParam == null) throw new ArgumentException("cannot reuse nonce for GCM encryption"); - if (lastKey != null && Arrays.AreEqual(lastKey, keyParam.GetKey())) + if (lastKey != null && keyParam.FixedTimeEquals(lastKey)) throw new ArgumentException("cannot reuse nonce for GCM encryption"); } } diff --git a/crypto/src/crypto/operators/Asn1CipherBuilder.cs b/crypto/src/crypto/operators/Asn1CipherBuilder.cs index 4f58ef58a..9baca94c2 100644 --- a/crypto/src/crypto/operators/Asn1CipherBuilder.cs +++ b/crypto/src/crypto/operators/Asn1CipherBuilder.cs @@ -22,7 +22,7 @@ namespace Org.BouncyCastle.Crypto.Operators CipherKeyGenerator keyGen = CipherKeyGeneratorFactory.CreateKeyGenerator(encryptionOID, random); - encKey = new KeyParameter(keyGen.GenerateKey()); + encKey = keyGen.GenerateKeyParameter(); algorithmIdentifier = AlgorithmIdentifierFactory.GenerateEncryptionAlgID(encryptionOID, encKey.KeyLength * 8, random); } diff --git a/crypto/src/crypto/parameters/DesEdeParameters.cs b/crypto/src/crypto/parameters/DesEdeParameters.cs index 6be56fb2c..19150c6bb 100644 --- a/crypto/src/crypto/parameters/DesEdeParameters.cs +++ b/crypto/src/crypto/parameters/DesEdeParameters.cs @@ -57,17 +57,12 @@ namespace Org.BouncyCastle.Crypto.Parameters * @param offset offset into the byte array the key starts at * @param length number of bytes making up the key */ - public static bool IsWeakKey( - byte[] key, - int offset, - int length) + public static bool IsWeakKey(byte[] key, int offset, int length) { for (int i = offset; i < length; i += DesKeyLength) { if (DesParameters.IsWeakKey(key, i)) - { return true; - } } return false; @@ -79,9 +74,7 @@ namespace Org.BouncyCastle.Crypto.Parameters * @param key bytes making up the key * @param offset offset into the byte array the key starts at */ - public static new bool IsWeakKey( - byte[] key, - int offset) + public static new bool IsWeakKey(byte[] key, int offset) { return IsWeakKey(key, offset, key.Length - offset); } @@ -92,6 +85,19 @@ namespace Org.BouncyCastle.Crypto.Parameters return IsWeakKey(key, 0, key.Length); } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public static new bool IsWeakKey(ReadOnlySpan key) + { + for (int i = 0; i < key.Length; i += DesKeyLength) + { + if (DesParameters.IsWeakKey(key[i..])) + return true; + } + + return false; + } +#endif + /** * return true if the passed in key is a real 2/3 part DES-EDE key. * @@ -136,5 +142,34 @@ namespace Org.BouncyCastle.Crypto.Parameters } return diff12 && diff13 && diff23; } + +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public static bool IsRealEdeKey(ReadOnlySpan key) + { + return key.Length == 16 ? IsReal2Key(key) : IsReal3Key(key); + } + + public static bool IsReal2Key(ReadOnlySpan key) + { + bool isValid = false; + for (int i = 0; i != 8; i++) + { + isValid |= (key[i] != key[i + 8]); + } + return isValid; + } + + public static bool IsReal3Key(ReadOnlySpan key) + { + bool diff12 = false, diff13 = false, diff23 = false; + for (int i = 0; i != 8; i++) + { + diff12 |= (key[i] != key[i + 8]); + diff13 |= (key[i] != key[i + 16]); + diff23 |= (key[i + 8] != key[i + 16]); + } + return diff12 && diff13 && diff23; + } +#endif } } diff --git a/crypto/src/crypto/parameters/DesParameters.cs b/crypto/src/crypto/parameters/DesParameters.cs index 28881f21c..dd575604c 100644 --- a/crypto/src/crypto/parameters/DesParameters.cs +++ b/crypto/src/crypto/parameters/DesParameters.cs @@ -67,10 +67,11 @@ namespace Org.BouncyCastle.Crypto.Parameters * @return true if the given DES key material is weak or semi-weak, * false otherwise. */ - public static bool IsWeakKey( - byte[] key, - int offset) + public static bool IsWeakKey(byte[] key, int offset) { +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + return IsWeakKey(key.AsSpan(offset)); +#else if (key.Length - offset < DesKeyLength) throw new ArgumentException("key material too short."); @@ -89,20 +90,46 @@ namespace Org.BouncyCastle.Crypto.Parameters } if (!unmatch) - { return true; - } } return false; +#endif } - public static bool IsWeakKey( - byte[] key) + public static bool IsWeakKey(byte[] key) { return IsWeakKey(key, 0); } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public static bool IsWeakKey(ReadOnlySpan key) + { + if (key.Length < DesKeyLength) + throw new ArgumentException("key material too short."); + + //nextkey: + for (int i = 0; i < N_DES_WEAK_KEYS; i++) + { + bool unmatch = false; + for (int j = 0; j < DesKeyLength; j++) + { + if (key[j] != DES_weak_keys[i * DesKeyLength + j]) + { + //continue nextkey; + unmatch = true; + break; + } + } + + if (!unmatch) + return true; + } + + return false; + } +#endif + public static byte SetOddParity(byte b) { uint parity = b ^ 1U; diff --git a/crypto/src/crypto/parameters/KeyParameter.cs b/crypto/src/crypto/parameters/KeyParameter.cs index 7ee47de9a..bd2482f22 100644 --- a/crypto/src/crypto/parameters/KeyParameter.cs +++ b/crypto/src/crypto/parameters/KeyParameter.cs @@ -1,10 +1,29 @@ using System; +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER +using System.Buffers; +#endif + +using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Crypto.Parameters { public class KeyParameter : ICipherParameters { +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public static KeyParameter Create(int length, TState state, SpanAction action) + { + if (action == null) + throw new ArgumentNullException(nameof(action)); + if (length < 1) + throw new ArgumentOutOfRangeException(nameof(length)); + + KeyParameter result = new KeyParameter(length); + action(result.m_key, state); + return result; + } +#endif + private readonly byte[] m_key; public KeyParameter(byte[] key) @@ -35,6 +54,22 @@ namespace Org.BouncyCastle.Crypto.Parameters } #endif + private KeyParameter(int length) + { + if (length < 1) + throw new ArgumentOutOfRangeException(nameof(length)); + + m_key = new byte[length]; + } + + internal void CopyTo(byte[] buf, int off, int len) + { + if (m_key.Length != len) + throw new ArgumentOutOfRangeException(nameof(len)); + + Array.Copy(m_key, 0, buf, off, len); + } + public byte[] GetKey() { return (byte[])m_key.Clone(); @@ -42,6 +77,11 @@ namespace Org.BouncyCastle.Crypto.Parameters public int KeyLength => m_key.Length; + internal bool FixedTimeEquals(byte[] data) + { + return Arrays.FixedTimeEquals(m_key, data); + } + #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER internal ReadOnlySpan Key => m_key; #endif diff --git a/crypto/src/crypto/util/Pack.cs b/crypto/src/crypto/util/Pack.cs index cd8010f5a..dc87cf7d8 100644 --- a/crypto/src/crypto/util/Pack.cs +++ b/crypto/src/crypto/util/Pack.cs @@ -797,6 +797,12 @@ namespace Org.BouncyCastle.Crypto.Utilities return BinaryPrimitives.ReadUInt32LittleEndian(bs); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static uint LE_To_UInt32(ReadOnlySpan bs, int off) + { + return BinaryPrimitives.ReadUInt32LittleEndian(bs[off..]); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static void LE_To_UInt32(ReadOnlySpan bs, Span ns) { -- cgit 1.4.1