diff options
Diffstat (limited to 'crypto/src/crypto/prng/drbg/CtrSP800Drbg.cs')
-rw-r--r-- | crypto/src/crypto/prng/drbg/CtrSP800Drbg.cs | 579 |
1 files changed, 409 insertions, 170 deletions
diff --git a/crypto/src/crypto/prng/drbg/CtrSP800Drbg.cs b/crypto/src/crypto/prng/drbg/CtrSP800Drbg.cs index ddb503aa0..cf566ff9c 100644 --- a/crypto/src/crypto/prng/drbg/CtrSP800Drbg.cs +++ b/crypto/src/crypto/prng/drbg/CtrSP800Drbg.cs @@ -1,6 +1,7 @@ using System; using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Crypto.Utilities; using Org.BouncyCastle.Utilities; using Org.BouncyCastle.Utilities.Encoders; @@ -9,7 +10,7 @@ namespace Org.BouncyCastle.Crypto.Prng.Drbg /** * A SP800-90A CTR DRBG. */ - public class CtrSP800Drbg + public sealed class CtrSP800Drbg : ISP80090Drbg { private static readonly long TDEA_RESEED_MAX = 1L << (32 - 1); @@ -59,20 +60,19 @@ namespace Org.BouncyCastle.Crypto.Prng.Drbg mSeedLength = keySizeInBits + engine.GetBlockSize() * 8; mIsTdea = IsTdea(engine); - byte[] entropy = GetEntropy(); // Get_entropy_input - - CTR_DRBG_Instantiate_algorithm(entropy, nonce, personalizationString); + CTR_DRBG_Instantiate_algorithm(nonce, personalizationString); } - private void CTR_DRBG_Instantiate_algorithm(byte[] entropy, byte[] nonce, byte[] personalisationString) + private void CTR_DRBG_Instantiate_algorithm(byte[] nonce, byte[] personalisationString) { - byte[] seedMaterial = Arrays.ConcatenateAll(entropy, nonce, personalisationString); - byte[] seed = Block_Cipher_df(seedMaterial, mSeedLength); + byte[] entropy = GetEntropy(); // Get_entropy_input + byte[] seedMaterial = Arrays.ConcatenateAll(entropy, nonce, personalisationString); + byte[] seed = BlockCipherDF(seedMaterial, mSeedLength / 8); - int outlen = mEngine.GetBlockSize(); + int blockSize = mEngine.GetBlockSize(); mKey = new byte[(mKeySizeInBits + 7) / 8]; - mV = new byte[outlen]; + mV = new byte[blockSize]; // mKey & mV are modified by this call CTR_DRBG_Update(seed, mKey, mV); @@ -80,55 +80,130 @@ namespace Org.BouncyCastle.Crypto.Prng.Drbg mReseedCounter = 1; } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + private void CTR_DRBG_Update(ReadOnlySpan<byte> seed, Span<byte> key, Span<byte> v) + { + int seedLength = seed.Length; + Span<byte> temp = seedLength <= 256 + ? stackalloc byte[seedLength] + : new byte[seedLength]; + + int blockSize = mEngine.GetBlockSize(); + Span<byte> block = blockSize <= 64 + ? stackalloc byte[blockSize] + : new byte[blockSize]; + + mEngine.Init(true, ExpandToKeyParameter(key)); + for (int i = 0; i * blockSize < seed.Length; ++i) + { + AddOneTo(v); + mEngine.ProcessBlock(v, block); + + int bytesToCopy = System.Math.Min(blockSize, temp.Length - i * blockSize); + block[..bytesToCopy].CopyTo(temp[(i * blockSize)..]); + } + + XorWith(seed, temp); + + key.CopyFrom(temp); + v.CopyFrom(temp[key.Length..]); + } +#else private void CTR_DRBG_Update(byte[] seed, byte[] key, byte[] v) { - byte[] temp = new byte[seed.Length]; + byte[] temp = new byte[seed.Length]; byte[] outputBlock = new byte[mEngine.GetBlockSize()]; int i = 0; int outLen = mEngine.GetBlockSize(); - mEngine.Init(true, new KeyParameter(ExpandKey(key))); - while (i*outLen < seed.Length) + mEngine.Init(true, ExpandToKeyParameter(key)); + while (i * outLen < seed.Length) { AddOneTo(v); mEngine.ProcessBlock(v, 0, outputBlock, 0); - int bytesToCopy = ((temp.Length - i * outLen) > outLen) - ? outLen : (temp.Length - i * outLen); - + int bytesToCopy = System.Math.Min(outLen, temp.Length - i * outLen); Array.Copy(outputBlock, 0, temp, i * outLen, bytesToCopy); ++i; } - XOR(temp, seed, temp, 0); + Xor(temp, seed, temp, 0); Array.Copy(temp, 0, key, 0, key.Length); Array.Copy(temp, key.Length, v, 0, v.Length); - } - - private void CTR_DRBG_Reseed_algorithm(byte[] additionalInput) - { - byte[] seedMaterial = Arrays.Concatenate(GetEntropy(), additionalInput); + } +#endif - seedMaterial = Block_Cipher_df(seedMaterial, mSeedLength); + private void CTR_DRBG_Reseed_algorithm(byte[] additionalInput) + { +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + CTR_DRBG_Reseed_algorithm(Spans.FromNullableReadOnly(additionalInput)); +#else + byte[] seedMaterial = Arrays.Concatenate(GetEntropy(), additionalInput); + + seedMaterial = BlockCipherDF(seedMaterial, mSeedLength / 8); CTR_DRBG_Update(seedMaterial, mKey, mV); mReseedCounter = 1; - } +#endif + } - private void XOR(byte[] output, byte[] a, byte[] b, int bOff) +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + private void CTR_DRBG_Reseed_algorithm(ReadOnlySpan<byte> additionalInput) + { + int entropyLength = GetEntropyLength(); + int seedLength = entropyLength + additionalInput.Length; + + Span<byte> seedMaterial = seedLength <= 256 + ? stackalloc byte[seedLength] + : new byte[seedLength]; + + GetEntropy(seedMaterial[..entropyLength]); + additionalInput.CopyTo(seedMaterial[entropyLength..]); + + seedMaterial = BlockCipherDF(seedMaterial, mSeedLength / 8); + + CTR_DRBG_Update(seedMaterial, mKey, mV); + + mReseedCounter = 1; + } +#endif + +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + private void Xor(ReadOnlySpan<byte> x, ReadOnlySpan<byte> y, Span<byte> z) + { + for (int i = 0; i < z.Length; ++i) + { + z[i] = (byte)(x[i] ^ y[i]); + } + } + + private void XorWith(ReadOnlySpan<byte> x, Span<byte> z) + { + for (int i = 0; i < z.Length; ++i) + { + z[i] ^= x[i]; + } + } +#else + private void Xor(byte[] output, byte[] a, byte[] b, int bOff) { for (int i = 0; i < output.Length; i++) { output[i] = (byte)(a[i] ^ b[bOff + i]); } } +#endif - private void AddOneTo(byte[] longer) - { - uint carry = 1; +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + private void AddOneTo(Span<byte> longer) +#else + private void AddOneTo(byte[] longer) +#endif + { + uint carry = 1; int i = longer.Length; while (--i >= 0) { @@ -146,83 +221,101 @@ namespace Org.BouncyCastle.Crypto.Prng.Drbg return entropy; } - // -- Internal state migration --- +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + private int GetEntropy(Span<byte> output) + { + int length = mEntropySource.GetEntropy(output); + if (length < (mSecurityStrength + 7) / 8) + throw new InvalidOperationException("Insufficient entropy provided by entropy source"); + return length; + } - private static readonly byte[] K_BITS = Hex.DecodeStrict("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F"); + private int GetEntropyLength() + { + return (mEntropySource.EntropySize + 7) / 8; + } +#endif + + // -- Internal state migration --- + + private static readonly byte[] K_BITS = Hex.DecodeStrict( + "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F"); // 1. If (number_of_bits_to_return > max_number_of_bits), then return an - // ERROR_FLAG. - // 2. L = len (input_string)/8. - // 3. N = number_of_bits_to_return/8. - // Comment: L is the bitstring represention of - // the integer resulting from len (input_string)/8. - // L shall be represented as a 32-bit integer. - // - // Comment : N is the bitstring represention of - // the integer resulting from - // number_of_bits_to_return/8. N shall be - // represented as a 32-bit integer. - // - // 4. S = L || N || input_string || 0x80. - // 5. While (len (S) mod outlen) - // Comment : Pad S with zeros, if necessary. - // 0, S = S || 0x00. - // - // Comment : Compute the starting value. - // 6. temp = the Null string. - // 7. i = 0. - // 8. K = Leftmost keylen bits of 0x00010203...1D1E1F. - // 9. While len (temp) < keylen + outlen, do - // - // IV = i || 0outlen - len (i). - // - // 9.1 - // - // temp = temp || BCC (K, (IV || S)). - // - // 9.2 - // - // i = i + 1. - // - // 9.3 - // - // Comment : i shall be represented as a 32-bit - // integer, i.e., len (i) = 32. - // - // Comment: The 32-bit integer represenation of - // i is padded with zeros to outlen bits. - // - // Comment: Compute the requested number of - // bits. - // - // 10. K = Leftmost keylen bits of temp. - // - // 11. X = Next outlen bits of temp. - // - // 12. temp = the Null string. - // - // 13. While len (temp) < number_of_bits_to_return, do - // - // 13.1 X = Block_Encrypt (K, X). - // - // 13.2 temp = temp || X. - // - // 14. requested_bits = Leftmost number_of_bits_to_return of temp. - // - // 15. Return SUCCESS and requested_bits. - private byte[] Block_Cipher_df(byte[] inputString, int bitLength) - { - int outLen = mEngine.GetBlockSize(); - int L = inputString.Length; // already in bytes - int N = bitLength / 8; - // 4 S = L || N || inputstring || 0x80 + // ERROR_FLAG. + // 2. L = len (input_string)/8. + // 3. N = number_of_bits_to_return/8. + // Comment: L is the bitstring represention of + // the integer resulting from len (input_string)/8. + // L shall be represented as a 32-bit integer. + // + // Comment : N is the bitstring represention of + // the integer resulting from + // number_of_bits_to_return/8. N shall be + // represented as a 32-bit integer. + // + // 4. S = L || N || input_string || 0x80. + // 5. While (len (S) mod outlen) + // Comment : Pad S with zeros, if necessary. + // 0, S = S || 0x00. + // + // Comment : Compute the starting value. + // 6. temp = the Null string. + // 7. i = 0. + // 8. K = Leftmost keylen bits of 0x00010203...1D1E1F. + // 9. While len (temp) < keylen + outlen, do + // + // IV = i || 0outlen - len (i). + // + // 9.1 + // + // temp = temp || BCC (K, (IV || S)). + // + // 9.2 + // + // i = i + 1. + // + // 9.3 + // + // Comment : i shall be represented as a 32-bit + // integer, i.e., len (i) = 32. + // + // Comment: The 32-bit integer represenation of + // i is padded with zeros to outlen bits. + // + // Comment: Compute the requested number of + // bits. + // + // 10. K = Leftmost keylen bits of temp. + // + // 11. X = Next outlen bits of temp. + // + // 12. temp = the Null string. + // + // 13. While len (temp) < number_of_bits_to_return, do + // + // 13.1 X = Block_Encrypt (K, X). + // + // 13.2 temp = temp || X. + // + // 14. requested_bits = Leftmost number_of_bits_to_return of temp. + // + // 15. Return SUCCESS and requested_bits. + private byte[] BlockCipherDF(byte[] input, int N) + { +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + return BlockCipherDF(input.AsSpan(), N); +#else + int outLen = mEngine.GetBlockSize(); + int L = input.Length; // already in bytes + // 4 S = L || N || input || 0x80 int sLen = 4 + 4 + L + 1; int blockLen = ((sLen + outLen - 1) / outLen) * outLen; byte[] S = new byte[blockLen]; - copyIntToByteArray(S, L, 0); - copyIntToByteArray(S, N, 4); - Array.Copy(inputString, 0, S, 8, L); - S[8 + L] = (byte)0x80; + Pack.UInt32_To_BE((uint)L, S, 0); + Pack.UInt32_To_BE((uint)N, S, 4); + Array.Copy(input, 0, S, 8, L); + S[8 + L] = 0x80; // S already padded with zeros byte[] temp = new byte[mKeySizeInBits / 8 + outLen]; @@ -233,16 +326,15 @@ namespace Org.BouncyCastle.Crypto.Prng.Drbg int i = 0; byte[] K = new byte[mKeySizeInBits / 8]; Array.Copy(K_BITS, 0, K, 0, K.Length); + var K1 = ExpandToKeyParameter(K); + mEngine.Init(true, K1); while (i*outLen*8 < mKeySizeInBits + outLen *8) { - copyIntToByteArray(IV, i, 0); - BCC(bccOut, K, IV, S); + Pack.UInt32_To_BE((uint)i, IV, 0); + BCC(bccOut, IV, S); - int bytesToCopy = ((temp.Length - i * outLen) > outLen) - ? outLen - : (temp.Length - i * outLen); - + int bytesToCopy = System.Math.Min(outLen, temp.Length - i * outLen); Array.Copy(bccOut, 0, temp, i * outLen, bytesToCopy); ++i; } @@ -251,39 +343,120 @@ namespace Org.BouncyCastle.Crypto.Prng.Drbg Array.Copy(temp, 0, K, 0, K.Length); Array.Copy(temp, K.Length, X, 0, X.Length); - temp = new byte[bitLength / 2]; + temp = new byte[N]; i = 0; - mEngine.Init(true, new KeyParameter(ExpandKey(K))); + mEngine.Init(true, ExpandToKeyParameter(K)); while (i * outLen < temp.Length) { mEngine.ProcessBlock(X, 0, X, 0); - int bytesToCopy = ((temp.Length - i * outLen) > outLen) - ? outLen - : (temp.Length - i * outLen); - + int bytesToCopy = System.Math.Min(outLen, temp.Length - i * outLen); Array.Copy(X, 0, temp, i * outLen, bytesToCopy); i++; } return temp; - } +#endif + } - /* - * 1. chaining_value = 0^outlen - * . Comment: Set the first chaining value to outlen zeros. - * 2. n = len (data)/outlen. - * 3. Starting with the leftmost bits of data, split the data into n blocks of outlen bits - * each, forming block(1) to block(n). - * 4. For i = 1 to n do - * 4.1 input_block = chaining_value ^ block(i) . - * 4.2 chaining_value = Block_Encrypt (Key, input_block). - * 5. output_block = chaining_value. - * 6. Return output_block. - */ - private void BCC(byte[] bccOut, byte[] k, byte[] iV, byte[] data) +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + private byte[] BlockCipherDF(ReadOnlySpan<byte> input, int N) + { + int blockSize = mEngine.GetBlockSize(); + int L = input.Length; // already in bytes + // 4 S = L || N || input || 0x80 + int sLen = 4 + 4 + L + 1; + int blockLen = ((sLen + blockSize - 1) / blockSize) * blockSize; + Span<byte> S = blockLen <= 256 + ? stackalloc byte[blockLen] + : new byte[blockLen]; + Pack.UInt32_To_BE((uint)L, S); + Pack.UInt32_To_BE((uint)N, S[4..]); + input.CopyTo(S[8..]); + S[8 + L] = 0x80; + // S already padded with zeros + + int keySize = mKeySizeInBits / 8; + int tempSize = keySize + blockSize; + Span<byte> temp = tempSize <= 128 + ? stackalloc byte[tempSize] + : new byte[tempSize]; + + Span<byte> bccOut = blockSize <= 64 + ? stackalloc byte[blockSize] + : new byte[blockSize]; + + Span<byte> IV = blockSize <= 64 + ? stackalloc byte[blockSize] + : new byte[blockSize]; + + var K1 = ExpandToKeyParameter(K_BITS.AsSpan(0, keySize)); + mEngine.Init(true, K1); + + for (int i = 0; i * blockSize < tempSize; ++i) + { + Pack.UInt32_To_BE((uint)i, IV); + BCC(bccOut, IV, S); + + int bytesToCopy = System.Math.Min(blockSize, tempSize - i * blockSize); + bccOut[..bytesToCopy].CopyTo(temp[(i * blockSize)..]); + } + + var K2 = ExpandToKeyParameter(temp[..keySize]); + mEngine.Init(true, K2); + var X = temp[keySize..]; + + byte[] result = new byte[N]; + for (int i = 0; i * blockSize < result.Length; ++i) + { + mEngine.ProcessBlock(X, X); + + int bytesToCopy = System.Math.Min(blockSize, result.Length - i * blockSize); + X[..bytesToCopy].CopyTo(result.AsSpan(i * blockSize)); + } + return result; + } +#endif + + /* + * 1. chaining_value = 0^outlen + * . Comment: Set the first chaining value to outlen zeros. + * 2. n = len (data)/outlen. + * 3. Starting with the leftmost bits of data, split the data into n blocks of outlen bits + * each, forming block(1) to block(n). + * 4. For i = 1 to n do + * 4.1 input_block = chaining_value ^ block(i) . + * 4.2 chaining_value = Block_Encrypt (Key, input_block). + * 5. output_block = chaining_value. + * 6. Return output_block. + */ +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + private void BCC(Span<byte> bccOut, ReadOnlySpan<byte> iV, ReadOnlySpan<byte> data) + { + int blockSize = mEngine.GetBlockSize(); + + Span<byte> chainingValue = blockSize <= 64 + ? stackalloc byte[blockSize] + : new byte[blockSize]; + Span<byte> inputBlock = blockSize <= 64 + ? stackalloc byte[blockSize] + : new byte[blockSize]; + + mEngine.ProcessBlock(iV, chainingValue); + + int n = data.Length / blockSize; + for (int i = 0; i < n; i++) + { + Xor(chainingValue, data[(i * blockSize)..], inputBlock); + mEngine.ProcessBlock(inputBlock, chainingValue); + } + + bccOut.CopyFrom(chainingValue); + } +#else + private void BCC(byte[] bccOut, byte[] iV, byte[] data) { int outlen = mEngine.GetBlockSize(); byte[] chainingValue = new byte[outlen]; // initial values = 0 @@ -291,33 +464,24 @@ namespace Org.BouncyCastle.Crypto.Prng.Drbg byte[] inputBlock = new byte[outlen]; - mEngine.Init(true, new KeyParameter(ExpandKey(k))); - mEngine.ProcessBlock(iV, 0, chainingValue, 0); for (int i = 0; i < n; i++) { - XOR(inputBlock, chainingValue, data, i*outlen); + Xor(inputBlock, chainingValue, data, i*outlen); mEngine.ProcessBlock(inputBlock, 0, chainingValue, 0); } Array.Copy(chainingValue, 0, bccOut, 0, bccOut.Length); } +#endif - private void copyIntToByteArray(byte[] buf, int value, int offSet) - { - buf[offSet + 0] = ((byte)(value >> 24)); - buf[offSet + 1] = ((byte)(value >> 16)); - buf[offSet + 2] = ((byte)(value >> 8)); - buf[offSet + 3] = ((byte)(value)); - } - - /** + /** * Return the block size (in bits) of the DRBG. * * @return the number of bits produced on each internal round of the DRBG. */ - public int BlockSize + public int BlockSize { get { return mV.Length * 8; } } @@ -335,7 +499,9 @@ namespace Org.BouncyCastle.Crypto.Prng.Drbg bool predictionResistant) { #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER - return Generate(output.AsSpan(outputOff, outputLen), additionalInput, predictionResistant); + return additionalInput == null + ? Generate(output.AsSpan(outputOff, outputLen), predictionResistant) + : GenerateWithInput(output.AsSpan(outputOff, outputLen), additionalInput.AsSpan(), predictionResistant); #else if (mIsTdea) { @@ -362,7 +528,7 @@ namespace Org.BouncyCastle.Crypto.Prng.Drbg if (additionalInput != null) { - additionalInput = Block_Cipher_df(additionalInput, mSeedLength); + additionalInput = BlockCipherDF(additionalInput, mSeedLength / 8); CTR_DRBG_Update(additionalInput, mKey, mV); } else @@ -372,7 +538,7 @@ namespace Org.BouncyCastle.Crypto.Prng.Drbg byte[] tmp = new byte[mV.Length]; - mEngine.Init(true, new KeyParameter(ExpandKey(mKey))); + mEngine.Init(true, ExpandToKeyParameter(mKey)); for (int i = 0, limit = outputLen / tmp.Length; i <= limit; i++) { @@ -397,9 +563,9 @@ namespace Org.BouncyCastle.Crypto.Prng.Drbg } #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER - public int Generate(Span<byte> output, byte[] additionalInput, bool predictionResistant) - { - int outputLen = output.Length; + public int Generate(Span<byte> output, bool predictionResistant) + { + int outputLen = output.Length; if (mIsTdea) { if (mReseedCounter > TDEA_RESEED_MAX) @@ -419,24 +585,57 @@ namespace Org.BouncyCastle.Crypto.Prng.Drbg if (predictionResistant) { - CTR_DRBG_Reseed_algorithm(additionalInput); - additionalInput = null; + CTR_DRBG_Reseed_algorithm(ReadOnlySpan<byte>.Empty); } - if (additionalInput != null) + byte[] seed = new byte[mSeedLength / 8]; + + return ImplGenerate(seed, output); + } + + public int GenerateWithInput(Span<byte> output, ReadOnlySpan<byte> additionalInput, bool predictionResistant) + { + int outputLen = output.Length; + if (mIsTdea) { - additionalInput = Block_Cipher_df(additionalInput, mSeedLength); - CTR_DRBG_Update(additionalInput, mKey, mV); + if (mReseedCounter > TDEA_RESEED_MAX) + return -1; + + if (outputLen > TDEA_MAX_BITS_REQUEST / 8) + throw new ArgumentException("Number of bits per request limited to " + TDEA_MAX_BITS_REQUEST, "output"); } else { - additionalInput = new byte[mSeedLength]; + if (mReseedCounter > AES_RESEED_MAX) + return -1; + + if (outputLen > AES_MAX_BITS_REQUEST / 8) + throw new ArgumentException("Number of bits per request limited to " + AES_MAX_BITS_REQUEST, "output"); } + int seedLength = mSeedLength / 8; + byte[] seed; + if (predictionResistant) + { + CTR_DRBG_Reseed_algorithm(additionalInput); + seed = new byte[seedLength]; + } + else + { + seed = BlockCipherDF(additionalInput, seedLength); + CTR_DRBG_Update(seed, mKey, mV); + } + + return ImplGenerate(seed, output); + } + + private int ImplGenerate(ReadOnlySpan<byte> seed, Span<byte> output) + { byte[] tmp = new byte[mV.Length]; - mEngine.Init(true, new KeyParameter(ExpandKey(mKey))); + mEngine.Init(true, ExpandToKeyParameter(mKey)); + int outputLen = output.Length; for (int i = 0, limit = outputLen / tmp.Length; i <= limit; i++) { int bytesToCopy = System.Math.Min(tmp.Length, outputLen - i * tmp.Length); @@ -447,11 +646,11 @@ namespace Org.BouncyCastle.Crypto.Prng.Drbg mEngine.ProcessBlock(mV, 0, tmp, 0); - tmp[..bytesToCopy].CopyTo(output[(i * tmp.Length)..]); + tmp[..bytesToCopy].CopyTo(output[(i * tmp.Length)..]); } } - CTR_DRBG_Update(additionalInput, mKey, mV); + CTR_DRBG_Update(seed, mKey, mV); mReseedCounter++; @@ -466,9 +665,20 @@ namespace Org.BouncyCastle.Crypto.Prng.Drbg */ public void Reseed(byte[] additionalInput) { - CTR_DRBG_Reseed_algorithm(additionalInput); +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + Reseed(Spans.FromNullableReadOnly(additionalInput)); +#else + CTR_DRBG_Reseed_algorithm(additionalInput); +#endif } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public void Reseed(ReadOnlySpan<byte> additionalInput) + { + CTR_DRBG_Reseed_algorithm(additionalInput); + } +#endif + private bool IsTdea(IBlockCipher cipher) { return cipher.AlgorithmName.Equals("DESede") || cipher.AlgorithmName.Equals("TDEA"); @@ -488,26 +698,39 @@ namespace Org.BouncyCastle.Crypto.Prng.Drbg return -1; } - private byte[] ExpandKey(byte[] key) + private KeyParameter ExpandToKeyParameter(byte[] key) { - if (mIsTdea) - { - // expand key to 192 bits. - byte[] tmp = new byte[24]; + if (!mIsTdea) + return new KeyParameter(key); - PadKey(key, 0, tmp, 0); - PadKey(key, 7, tmp, 8); - PadKey(key, 14, tmp, 16); + // expand key to 192 bits. + byte[] tmp = new byte[24]; - return tmp; - } - else - { - return key; - } - } + PadKey(key, 0, tmp, 0); + PadKey(key, 7, tmp, 8); + PadKey(key, 14, tmp, 16); - /** + return new KeyParameter(tmp); + } + +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + private KeyParameter ExpandToKeyParameter(ReadOnlySpan<byte> key) + { + if (!mIsTdea) + return new KeyParameter(key); + + // expand key to 192 bits. + Span<byte> tmp = stackalloc byte[24]; + + PadKey(key, tmp); + PadKey(key[7..], tmp[8..]); + PadKey(key[14..], tmp[16..]); + + return new KeyParameter(tmp); + } +#endif + + /** * Pad out a key for TDEA, setting odd parity for each byte. * * @param keyMaster @@ -528,5 +751,21 @@ namespace Org.BouncyCastle.Crypto.Prng.Drbg DesParameters.SetOddParity(tmp, tmpOff, 8); } - } + +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + private void PadKey(ReadOnlySpan<byte> keyMaster, Span<byte> tmp) + { + tmp[0] = (byte)(keyMaster[0] & 0xFE); + tmp[1] = (byte)((keyMaster[0] << 7) | ((keyMaster[1] & 0xfc) >> 1)); + tmp[2] = (byte)((keyMaster[1] << 6) | ((keyMaster[2] & 0xf8) >> 2)); + tmp[3] = (byte)((keyMaster[2] << 5) | ((keyMaster[3] & 0xf0) >> 3)); + tmp[4] = (byte)((keyMaster[3] << 4) | ((keyMaster[4] & 0xe0) >> 4)); + tmp[5] = (byte)((keyMaster[4] << 3) | ((keyMaster[5] & 0xc0) >> 5)); + tmp[6] = (byte)((keyMaster[5] << 2) | ((keyMaster[6] & 0x80) >> 6)); + tmp[7] = (byte)(keyMaster[6] << 1); + + DesParameters.SetOddParity(tmp[..8]); + } +#endif + } } |