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;
}
- /// <summary>
- /// Modifies an existing 32 byte key value to comply with the requirements of the Poly1305 key by
- /// clearing required bits in the <code>r</code> (second 16 bytes) portion of the key.<br/>
- /// Specifically:
- /// <ul>
- /// <li>r[3], r[7], r[11], r[15] have top four bits clear (i.e., are {0, 1, . . . , 15})</li>
- /// <li>r[4], r[8], r[12] have bottom two bits clear (i.e., are in {0, 4, 8, . . . , 252})</li>
- /// </ul>
- /// </summary>
- /// <param name="key">a 32 byte key value <code>k[0] ... k[15], r[0] ... r[15]</code></param>
- 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
+
+ /// <summary>
+ /// Modifies an existing 32 byte key value to comply with the requirements of the Poly1305 key by
+ /// clearing required bits in the <code>r</code> (second 16 bytes) portion of the key.<br/>
+ /// Specifically:
+ /// <ul>
+ /// <li>r[3], r[7], r[11], r[15] have top four bits clear (i.e., are {0, 1, . . . , 15})</li>
+ /// <li>r[4], r[8], r[12] have bottom two bits clear (i.e., are in {0, 4, 8, . . . , 252})</li>
+ /// </ul>
+ /// </summary>
+ /// <param name="key">a 32 byte key value <code>k[0] ... k[15], r[0] ... r[15]</code></param>
+ 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
}
- /// <summary>
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public static void Clamp(Span<byte> 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
+
+ /// <summary>
/// Checks a 32 byte key for compliance with the Poly1305 key requirements, e.g.
/// <code>k[0] ... k[15], r[0] ... r[15]</code> with the required bits in <code>r</code> cleared
/// as per <see cref="Clamp(byte[])"/>.
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<byte> 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<byte> 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<byte> key)
+ {
+ return key.Length == 16 ? IsReal2Key(key) : IsReal3Key(key);
+ }
+
+ public static bool IsReal2Key(ReadOnlySpan<byte> key)
+ {
+ bool isValid = false;
+ for (int i = 0; i != 8; i++)
+ {
+ isValid |= (key[i] != key[i + 8]);
+ }
+ return isValid;
+ }
+
+ public static bool IsReal3Key(ReadOnlySpan<byte> 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<byte> 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<TState>(int length, TState state, SpanAction<byte, TState> 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<byte> 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
@@ -798,6 +798,12 @@ namespace Org.BouncyCastle.Crypto.Utilities
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static uint LE_To_UInt32(ReadOnlySpan<byte> bs, int off)
+ {
+ return BinaryPrimitives.ReadUInt32LittleEndian(bs[off..]);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void LE_To_UInt32(ReadOnlySpan<byte> bs, Span<uint> ns)
{
for (int i = 0; i < ns.Length; ++i)
|