diff --git a/crypto/crypto.csproj b/crypto/crypto.csproj
index 28d0b19b3..0c6dba76c 100644
--- a/crypto/crypto.csproj
+++ b/crypto/crypto.csproj
@@ -4314,6 +4314,11 @@
BuildAction = "Compile"
/>
<File
+ RelPath = "src\crypto\prng\BasicEntropySourceProvider.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
RelPath = "src\crypto\prng\CryptoApiRandomGenerator.cs"
SubType = "Code"
BuildAction = "Compile"
@@ -4324,6 +4329,21 @@
BuildAction = "Compile"
/>
<File
+ RelPath = "src\crypto\prng\IDrbgProvider.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "src\crypto\prng\IEntropySource.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "src\crypto\prng\IEntropySourceProvider.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
RelPath = "src\crypto\prng\IRandomGenerator.cs"
SubType = "Code"
BuildAction = "Compile"
@@ -4334,6 +4354,16 @@
BuildAction = "Compile"
/>
<File
+ RelPath = "src\crypto\prng\SP800SecureRandom.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "src\crypto\prng\SP800SecureRandomBuilder.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
RelPath = "src\crypto\prng\ThreadedSeedGenerator.cs"
SubType = "Code"
BuildAction = "Compile"
@@ -4344,6 +4374,46 @@
BuildAction = "Compile"
/>
<File
+ RelPath = "src\crypto\prng\X931Rng.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "src\crypto\prng\X931SecureRandom.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "src\crypto\prng\X931SecureRandomBuilder.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "src\crypto\prng\drbg\CtrSP800Drbg.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "src\crypto\prng\drbg\DrbgUtilities.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "src\crypto\prng\drbg\HashSP800Drbg.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "src\crypto\prng\drbg\HMacSP800Drbg.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "src\crypto\prng\drbg\ISP80090Drbg.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
RelPath = "src\crypto\signers\DSADigestSigner.cs"
SubType = "Code"
BuildAction = "Compile"
@@ -11070,6 +11140,41 @@
BuildAction = "Compile"
/>
<File
+ RelPath = "test\src\crypto\prng\test\CtrDrbgTest.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "test\src\crypto\prng\test\DrbgTestVector.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "test\src\crypto\prng\test\HashDrbgTest.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "test\src\crypto\prng\test\HMacDrbgTest.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "test\src\crypto\prng\test\TestEntropySourcProvider.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "test\src\crypto\prng\test\X931Test.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "test\src\crypto\prng\test\X931TestVector.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
RelPath = "test\src\crypto\test\AeadTestUtilities.cs"
SubType = "Code"
BuildAction = "Compile"
diff --git a/crypto/src/asn1/DerApplicationSpecific.cs b/crypto/src/asn1/DerApplicationSpecific.cs
index 394c7431e..9149930e0 100644
--- a/crypto/src/asn1/DerApplicationSpecific.cs
+++ b/crypto/src/asn1/DerApplicationSpecific.cs
@@ -160,7 +160,7 @@ namespace Org.BouncyCastle.Asn1
tmp[0] |= Asn1Tags.Constructed;
}
- return FromByteArray(tmp);;
+ return FromByteArray(tmp);
}
internal override void Encode(
diff --git a/crypto/src/crypto/engines/RSACoreEngine.cs b/crypto/src/crypto/engines/RSACoreEngine.cs
index 38326371f..fd44e3cc1 100644
--- a/crypto/src/crypto/engines/RSACoreEngine.cs
+++ b/crypto/src/crypto/engines/RSACoreEngine.cs
@@ -124,7 +124,7 @@ namespace Org.BouncyCastle.Crypto.Engines
//
RsaPrivateCrtKeyParameters crtKey = (RsaPrivateCrtKeyParameters)key;
- BigInteger p = crtKey.P;;
+ BigInteger p = crtKey.P;
BigInteger q = crtKey.Q;
BigInteger dP = crtKey.DP;
BigInteger dQ = crtKey.DQ;
diff --git a/crypto/src/crypto/prng/BasicEntropySourceProvider.cs b/crypto/src/crypto/prng/BasicEntropySourceProvider.cs
new file mode 100644
index 000000000..0e929e0fd
--- /dev/null
+++ b/crypto/src/crypto/prng/BasicEntropySourceProvider.cs
@@ -0,0 +1,70 @@
+using System;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Prng
+{
+ /**
+ * An EntropySourceProvider where entropy generation is based on a SecureRandom output using SecureRandom.generateSeed().
+ */
+ public class BasicEntropySourceProvider
+ : IEntropySourceProvider
+ {
+ private readonly SecureRandom mSecureRandom;
+ private readonly bool mPredictionResistant;
+
+ /**
+ * Create a entropy source provider based on the passed in SecureRandom.
+ *
+ * @param secureRandom the SecureRandom to base EntropySource construction on.
+ * @param isPredictionResistant boolean indicating if the SecureRandom is based on prediction resistant entropy or not (true if it is).
+ */
+ public BasicEntropySourceProvider(SecureRandom secureRandom, bool isPredictionResistant)
+ {
+ mSecureRandom = secureRandom;
+ mPredictionResistant = isPredictionResistant;
+ }
+
+ /**
+ * Return an entropy source that will create bitsRequired bits of entropy on
+ * each invocation of getEntropy().
+ *
+ * @param bitsRequired size (in bits) of entropy to be created by the provided source.
+ * @return an EntropySource that generates bitsRequired bits of entropy on each call to its getEntropy() method.
+ */
+ public IEntropySource Get(int bitsRequired)
+ {
+ return new BasicEntropySource(mSecureRandom, mPredictionResistant, bitsRequired);
+ }
+
+ private class BasicEntropySource
+ : IEntropySource
+ {
+ private readonly SecureRandom mSecureRandom;
+ private readonly bool mPredictionResistant;
+ private readonly int mEntropySize;
+
+ internal BasicEntropySource(SecureRandom secureRandom, bool predictionResistant, int entropySize)
+ {
+ this.mSecureRandom = secureRandom;
+ this.mPredictionResistant = predictionResistant;
+ this.mEntropySize = entropySize;
+ }
+
+ bool IEntropySource.IsPredictionResistant
+ {
+ get { return mPredictionResistant; }
+ }
+
+ byte[] IEntropySource.GetEntropy()
+ {
+ return mSecureRandom.GenerateSeed((mEntropySize + 7) / 8);
+ }
+
+ int IEntropySource.EntropySize
+ {
+ get { return mEntropySize; }
+ }
+ }
+ }
+}
diff --git a/crypto/src/crypto/prng/IDrbgProvider.cs b/crypto/src/crypto/prng/IDrbgProvider.cs
new file mode 100644
index 000000000..5ebf5fd8d
--- /dev/null
+++ b/crypto/src/crypto/prng/IDrbgProvider.cs
@@ -0,0 +1,11 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Prng.Drbg;
+
+namespace Org.BouncyCastle.Crypto.Prng
+{
+ internal interface IDrbgProvider
+ {
+ ISP80090Drbg Get(IEntropySource entropySource);
+ }
+}
diff --git a/crypto/src/crypto/prng/IEntropySource.cs b/crypto/src/crypto/prng/IEntropySource.cs
new file mode 100644
index 000000000..90b9e61af
--- /dev/null
+++ b/crypto/src/crypto/prng/IEntropySource.cs
@@ -0,0 +1,29 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Prng
+{
+ /// <summary>
+ /// Base interface describing an entropy source for a DRBG.
+ /// </summary>
+ public interface IEntropySource
+ {
+ /// <summary>
+ /// Return whether or not this entropy source is regarded as prediction resistant.
+ /// </summary>
+ /// <value><c>true</c> if this instance is prediction resistant; otherwise, <c>false</c>.</value>
+ bool IsPredictionResistant { get; }
+
+ /// <summary>
+ /// Return a byte array of entropy.
+ /// </summary>
+ /// <returns>The entropy bytes.</returns>
+ byte[] GetEntropy();
+
+ /// <summary>
+ /// Return the number of bits of entropy this source can produce.
+ /// </summary>
+ /// <value>The size, in bits, of the return value of getEntropy.</value>
+ int EntropySize { get; }
+ }
+}
+
diff --git a/crypto/src/crypto/prng/IEntropySourceProvider.cs b/crypto/src/crypto/prng/IEntropySourceProvider.cs
new file mode 100644
index 000000000..643f92ef8
--- /dev/null
+++ b/crypto/src/crypto/prng/IEntropySourceProvider.cs
@@ -0,0 +1,17 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Prng
+{
+ /// <summary>
+ /// Base interface describing a provider of entropy sources.
+ /// </summary>
+ public interface IEntropySourceProvider
+ {
+ /// <summary>
+ /// Return an entropy source providing a block of entropy.
+ /// </summary>
+ /// <param name="bitsRequired">The size of the block of entropy required.</param>
+ /// <returns>An entropy source providing bitsRequired blocks of entropy.</returns>
+ IEntropySource Get(int bitsRequired);
+ }
+}
diff --git a/crypto/src/crypto/prng/SP800SecureRandom.cs b/crypto/src/crypto/prng/SP800SecureRandom.cs
new file mode 100644
index 000000000..996ba0846
--- /dev/null
+++ b/crypto/src/crypto/prng/SP800SecureRandom.cs
@@ -0,0 +1,82 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Prng.Drbg;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Prng
+{
+ public class SP800SecureRandom
+ : SecureRandom
+ {
+ private readonly IDrbgProvider mDrbgProvider;
+ private readonly bool mPredictionResistant;
+ private readonly SecureRandom mRandomSource;
+ private readonly IEntropySource mEntropySource;
+
+ private ISP80090Drbg mDrbg;
+
+ internal SP800SecureRandom(SecureRandom randomSource, IEntropySource entropySource, IDrbgProvider drbgProvider, bool predictionResistant)
+ : base((IRandomGenerator)null)
+ {
+ this.mRandomSource = randomSource;
+ this.mEntropySource = entropySource;
+ this.mDrbgProvider = drbgProvider;
+ this.mPredictionResistant = predictionResistant;
+ }
+
+ public override void SetSeed(byte[] seed)
+ {
+ lock (this)
+ {
+ if (mRandomSource != null)
+ {
+ this.mRandomSource.SetSeed(seed);
+ }
+ }
+ }
+
+ public override void SetSeed(long seed)
+ {
+ lock (this)
+ {
+ // this will happen when SecureRandom() is created
+ if (mRandomSource != null)
+ {
+ this.mRandomSource.SetSeed(seed);
+ }
+ }
+ }
+
+ public override void NextBytes(byte[] bytes)
+ {
+ lock (this)
+ {
+ if (mDrbg == null)
+ {
+ mDrbg = mDrbgProvider.Get(mEntropySource);
+ }
+
+ // check if a reseed is required...
+ if (mDrbg.Generate(bytes, null, mPredictionResistant) < 0)
+ {
+ mDrbg.Reseed(null);
+ mDrbg.Generate(bytes, null, mPredictionResistant);
+ }
+ }
+ }
+
+ public override void NextBytes(byte[] buf, int off, int len)
+ {
+ byte[] bytes = new byte[len];
+ NextBytes(bytes);
+ Array.Copy(bytes, 0, buf, off, len);
+ }
+
+ public override byte[] GenerateSeed(int numBytes)
+ {
+ byte[] bytes = new byte[numBytes];
+ NextBytes(bytes);
+ return bytes;
+ }
+ }
+}
diff --git a/crypto/src/crypto/prng/SP800SecureRandomBuilder.cs b/crypto/src/crypto/prng/SP800SecureRandomBuilder.cs
new file mode 100644
index 000000000..7199f1ae7
--- /dev/null
+++ b/crypto/src/crypto/prng/SP800SecureRandomBuilder.cs
@@ -0,0 +1,208 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Prng.Drbg;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Prng
+{
+ /**
+ * Builder class for making SecureRandom objects based on SP 800-90A Deterministic Random Bit Generators (DRBG).
+ */
+ public class SP800SecureRandomBuilder
+ {
+ private readonly SecureRandom mRandom;
+ private readonly IEntropySourceProvider mEntropySourceProvider;
+
+ private byte[] mPersonalizationString = null;
+ private int mSecurityStrength = 256;
+ private int mEntropyBitsRequired = 256;
+
+ /**
+ * Basic constructor, creates a builder using an EntropySourceProvider based on the default SecureRandom with
+ * predictionResistant set to false.
+ * <p>
+ * Any SecureRandom created from a builder constructed like this will make use of input passed to SecureRandom.setSeed() if
+ * the default SecureRandom does for its generateSeed() call.
+ * </p>
+ */
+ public SP800SecureRandomBuilder()
+ : this(new SecureRandom(), false)
+ {
+ }
+
+ /**
+ * Construct a builder with an EntropySourceProvider based on the passed in SecureRandom and the passed in value
+ * for prediction resistance.
+ * <p>
+ * Any SecureRandom created from a builder constructed like this will make use of input passed to SecureRandom.setSeed() if
+ * the passed in SecureRandom does for its generateSeed() call.
+ * </p>
+ * @param entropySource
+ * @param predictionResistant
+ */
+ public SP800SecureRandomBuilder(SecureRandom entropySource, bool predictionResistant)
+ {
+ this.mRandom = entropySource;
+ this.mEntropySourceProvider = new BasicEntropySourceProvider(entropySource, predictionResistant);
+ }
+
+ /**
+ * Create a builder which makes creates the SecureRandom objects from a specified entropy source provider.
+ * <p>
+ * <b>Note:</b> If this constructor is used any calls to setSeed() in the resulting SecureRandom will be ignored.
+ * </p>
+ * @param entropySourceProvider a provider of EntropySource objects.
+ */
+ public SP800SecureRandomBuilder(IEntropySourceProvider entropySourceProvider)
+ {
+ this.mRandom = null;
+ this.mEntropySourceProvider = entropySourceProvider;
+ }
+
+ /**
+ * Set the personalization string for DRBG SecureRandoms created by this builder
+ * @param personalizationString the personalisation string for the underlying DRBG.
+ * @return the current builder.
+ */
+ public SP800SecureRandomBuilder SetPersonalizationString(byte[] personalizationString)
+ {
+ this.mPersonalizationString = personalizationString;
+ return this;
+ }
+
+ /**
+ * Set the security strength required for DRBGs used in building SecureRandom objects.
+ *
+ * @param securityStrength the security strength (in bits)
+ * @return the current builder.
+ */
+ public SP800SecureRandomBuilder SetSecurityStrength(int securityStrength)
+ {
+ this.mSecurityStrength = securityStrength;
+ return this;
+ }
+
+ /**
+ * Set the amount of entropy bits required for seeding and reseeding DRBGs used in building SecureRandom objects.
+ *
+ * @param entropyBitsRequired the number of bits of entropy to be requested from the entropy source on each seed/reseed.
+ * @return the current builder.
+ */
+ public SP800SecureRandomBuilder SetEntropyBitsRequired(int entropyBitsRequired)
+ {
+ this.mEntropyBitsRequired = entropyBitsRequired;
+ return this;
+ }
+
+ /**
+ * Build a SecureRandom based on a SP 800-90A Hash DRBG.
+ *
+ * @param digest digest algorithm to use in the DRBG underneath the SecureRandom.
+ * @param nonce nonce value to use in DRBG construction.
+ * @param predictionResistant specify whether the underlying DRBG in the resulting SecureRandom should reseed on each request for bytes.
+ * @return a SecureRandom supported by a Hash DRBG.
+ */
+ public SP800SecureRandom BuildHash(IDigest digest, byte[] nonce, bool predictionResistant)
+ {
+ return new SP800SecureRandom(mRandom, mEntropySourceProvider.Get(mEntropyBitsRequired),
+ new HashDrbgProvider(digest, nonce, mPersonalizationString, mSecurityStrength), predictionResistant);
+ }
+
+ /**
+ * Build a SecureRandom based on a SP 800-90A CTR DRBG.
+ *
+ * @param cipher the block cipher to base the DRBG on.
+ * @param keySizeInBits key size in bits to be used with the block cipher.
+ * @param nonce nonce value to use in DRBG construction.
+ * @param predictionResistant specify whether the underlying DRBG in the resulting SecureRandom should reseed on each request for bytes.
+ * @return a SecureRandom supported by a CTR DRBG.
+ */
+ public SP800SecureRandom BuildCtr(IBlockCipher cipher, int keySizeInBits, byte[] nonce, bool predictionResistant)
+ {
+ return new SP800SecureRandom(mRandom, mEntropySourceProvider.Get(mEntropyBitsRequired),
+ new CtrDrbgProvider(cipher, keySizeInBits, nonce, mPersonalizationString, mSecurityStrength), predictionResistant);
+ }
+
+ /**
+ * Build a SecureRandom based on a SP 800-90A HMAC DRBG.
+ *
+ * @param hMac HMAC algorithm to use in the DRBG underneath the SecureRandom.
+ * @param nonce nonce value to use in DRBG construction.
+ * @param predictionResistant specify whether the underlying DRBG in the resulting SecureRandom should reseed on each request for bytes.
+ * @return a SecureRandom supported by a HMAC DRBG.
+ */
+ public SP800SecureRandom BuildHMac(IMac hMac, byte[] nonce, bool predictionResistant)
+ {
+ return new SP800SecureRandom(mRandom, mEntropySourceProvider.Get(mEntropyBitsRequired),
+ new HMacDrbgProvider(hMac, nonce, mPersonalizationString, mSecurityStrength), predictionResistant);
+ }
+
+ private class HashDrbgProvider
+ : IDrbgProvider
+ {
+ private readonly IDigest mDigest;
+ private readonly byte[] mNonce;
+ private readonly byte[] mPersonalizationString;
+ private readonly int mSecurityStrength;
+
+ public HashDrbgProvider(IDigest digest, byte[] nonce, byte[] personalizationString, int securityStrength)
+ {
+ this.mDigest = digest;
+ this.mNonce = nonce;
+ this.mPersonalizationString = personalizationString;
+ this.mSecurityStrength = securityStrength;
+ }
+
+ public ISP80090Drbg Get(IEntropySource entropySource)
+ {
+ return new HashSP800Drbg(mDigest, mSecurityStrength, entropySource, mPersonalizationString, mNonce);
+ }
+ }
+
+ private class HMacDrbgProvider
+ : IDrbgProvider
+ {
+ private readonly IMac mHMac;
+ private readonly byte[] mNonce;
+ private readonly byte[] mPersonalizationString;
+ private readonly int mSecurityStrength;
+
+ public HMacDrbgProvider(IMac hMac, byte[] nonce, byte[] personalizationString, int securityStrength)
+ {
+ this.mHMac = hMac;
+ this.mNonce = nonce;
+ this.mPersonalizationString = personalizationString;
+ this.mSecurityStrength = securityStrength;
+ }
+
+ public ISP80090Drbg Get(IEntropySource entropySource)
+ {
+ return new HMacSP800Drbg(mHMac, mSecurityStrength, entropySource, mPersonalizationString, mNonce);
+ }
+ }
+
+ private class CtrDrbgProvider
+ : IDrbgProvider
+ {
+ private readonly IBlockCipher mBlockCipher;
+ private readonly int mKeySizeInBits;
+ private readonly byte[] mNonce;
+ private readonly byte[] mPersonalizationString;
+ private readonly int mSecurityStrength;
+
+ public CtrDrbgProvider(IBlockCipher blockCipher, int keySizeInBits, byte[] nonce, byte[] personalizationString, int securityStrength)
+ {
+ this.mBlockCipher = blockCipher;
+ this.mKeySizeInBits = keySizeInBits;
+ this.mNonce = nonce;
+ this.mPersonalizationString = personalizationString;
+ this.mSecurityStrength = securityStrength;
+ }
+
+ public ISP80090Drbg Get(IEntropySource entropySource)
+ {
+ return new CtrSP800Drbg(mBlockCipher, mKeySizeInBits, mSecurityStrength, entropySource, mPersonalizationString, mNonce);
+ }
+ }
+ }
+}
diff --git a/crypto/src/crypto/prng/X931Rng.cs b/crypto/src/crypto/prng/X931Rng.cs
new file mode 100644
index 000000000..d09cc6618
--- /dev/null
+++ b/crypto/src/crypto/prng/X931Rng.cs
@@ -0,0 +1,141 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Prng
+{
+ internal class X931Rng
+ {
+ private const long BLOCK64_RESEED_MAX = 1L << (16 - 1);
+ private const long BLOCK128_RESEED_MAX = 1L << (24 - 1);
+ private const int BLOCK64_MAX_BITS_REQUEST = 1 << (13 - 1);
+ private const int BLOCK128_MAX_BITS_REQUEST = 1 << (19 - 1);
+
+ private readonly IBlockCipher mEngine;
+ private readonly IEntropySource mEntropySource;
+
+ private readonly byte[] mDT;
+ private readonly byte[] mI;
+ private readonly byte[] mR;
+
+ private byte[] mV;
+
+ private long mReseedCounter = 1;
+
+ /**
+ *
+ * @param engine
+ * @param entropySource
+ */
+ internal X931Rng(IBlockCipher engine, byte[] dateTimeVector, IEntropySource entropySource)
+ {
+ this.mEngine = engine;
+ this.mEntropySource = entropySource;
+
+ this.mDT = new byte[engine.GetBlockSize()];
+
+ Array.Copy(dateTimeVector, 0, mDT, 0, mDT.Length);
+
+ this.mI = new byte[engine.GetBlockSize()];
+ this.mR = new byte[engine.GetBlockSize()];
+ }
+
+ /**
+ * Populate a passed in array with random data.
+ *
+ * @param output output array for generated bits.
+ * @param predictionResistant true if a reseed should be forced, false otherwise.
+ *
+ * @return number of bits generated, -1 if a reseed required.
+ */
+ internal int Generate(byte[] output, bool predictionResistant)
+ {
+ if (mR.Length == 8) // 64 bit block size
+ {
+ if (mReseedCounter > BLOCK64_RESEED_MAX)
+ return -1;
+
+ if (IsTooLarge(output, BLOCK64_MAX_BITS_REQUEST / 8))
+ throw new ArgumentException("Number of bits per request limited to " + BLOCK64_MAX_BITS_REQUEST, "output");
+ }
+ else
+ {
+ if (mReseedCounter > BLOCK128_RESEED_MAX)
+ return -1;
+
+ if (IsTooLarge(output, BLOCK128_MAX_BITS_REQUEST / 8))
+ throw new ArgumentException("Number of bits per request limited to " + BLOCK128_MAX_BITS_REQUEST, "output");
+ }
+
+ if (predictionResistant || mV == null)
+ {
+ mV = mEntropySource.GetEntropy();
+ if (mV.Length != mEngine.GetBlockSize())
+ throw new InvalidOperationException("Insufficient entropy returned");
+ }
+
+ int m = output.Length / mR.Length;
+
+ for (int i = 0; i < m; i++)
+ {
+ mEngine.ProcessBlock(mDT, 0, mI, 0);
+ Process(mR, mI, mV);
+ Process(mV, mR, mI);
+
+ Array.Copy(mR, 0, output, i * mR.Length, mR.Length);
+
+ Increment(mDT);
+ }
+
+ int bytesToCopy = (output.Length - m * mR.Length);
+
+ if (bytesToCopy > 0)
+ {
+ mEngine.ProcessBlock(mDT, 0, mI, 0);
+ Process(mR, mI, mV);
+ Process(mV, mR, mI);
+
+ Array.Copy(mR, 0, output, m * mR.Length, bytesToCopy);
+
+ Increment(mDT);
+ }
+
+ mReseedCounter++;
+
+ return output.Length;
+ }
+
+ /**
+ * Reseed the RNG.
+ */
+ internal void Reseed()
+ {
+ mV = mEntropySource.GetEntropy();
+ if (mV.Length != mEngine.GetBlockSize())
+ throw new InvalidOperationException("Insufficient entropy returned");
+ mReseedCounter = 1;
+ }
+
+ private void Process(byte[] res, byte[] a, byte[] b)
+ {
+ for (int i = 0; i != res.Length; i++)
+ {
+ res[i] = (byte)(a[i] ^ b[i]);
+ }
+
+ mEngine.ProcessBlock(res, 0, res, 0);
+ }
+
+ private void Increment(byte[] val)
+ {
+ for (int i = val.Length - 1; i >= 0; i--)
+ {
+ if (++val[i] != 0)
+ break;
+ }
+ }
+
+ private static bool IsTooLarge(byte[] bytes, int maxBytes)
+ {
+ return bytes != null && bytes.Length > maxBytes;
+ }
+ }
+}
diff --git a/crypto/src/crypto/prng/X931SecureRandom.cs b/crypto/src/crypto/prng/X931SecureRandom.cs
new file mode 100644
index 000000000..a87bf1567
--- /dev/null
+++ b/crypto/src/crypto/prng/X931SecureRandom.cs
@@ -0,0 +1,72 @@
+using System;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Prng
+{
+ public class X931SecureRandom
+ : SecureRandom
+ {
+ private readonly bool mPredictionResistant;
+ private readonly SecureRandom mRandomSource;
+ private readonly X931Rng mDrbg;
+
+ internal X931SecureRandom(SecureRandom randomSource, X931Rng drbg, bool predictionResistant)
+ : base((IRandomGenerator)null)
+ {
+ this.mRandomSource = randomSource;
+ this.mDrbg = drbg;
+ this.mPredictionResistant = predictionResistant;
+ }
+
+ public override void SetSeed(byte[] seed)
+ {
+ lock (this)
+ {
+ if (mRandomSource != null)
+ {
+ this.mRandomSource.SetSeed(seed);
+ }
+ }
+ }
+
+ public override void SetSeed(long seed)
+ {
+ lock (this)
+ {
+ // this will happen when SecureRandom() is created
+ if (mRandomSource != null)
+ {
+ this.mRandomSource.SetSeed(seed);
+ }
+ }
+ }
+
+ public override void NextBytes(byte[] bytes)
+ {
+ lock (this)
+ {
+ // check if a reseed is required...
+ if (mDrbg.Generate(bytes, mPredictionResistant) < 0)
+ {
+ mDrbg.Reseed();
+ mDrbg.Generate(bytes, mPredictionResistant);
+ }
+ }
+ }
+
+ public override void NextBytes(byte[] buf, int off, int len)
+ {
+ byte[] bytes = new byte[len];
+ NextBytes(bytes);
+ Array.Copy(bytes, 0, buf, off, len);
+ }
+
+ public override byte[] GenerateSeed(int numBytes)
+ {
+ byte[] bytes = new byte[numBytes];
+ NextBytes(bytes);
+ return bytes;
+ }
+ }
+}
diff --git a/crypto/src/crypto/prng/X931SecureRandomBuilder.cs b/crypto/src/crypto/prng/X931SecureRandomBuilder.cs
new file mode 100644
index 000000000..31e94312e
--- /dev/null
+++ b/crypto/src/crypto/prng/X931SecureRandomBuilder.cs
@@ -0,0 +1,87 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Date;
+
+namespace Org.BouncyCastle.Crypto.Prng
+{
+ public class X931SecureRandomBuilder
+ {
+ private readonly SecureRandom mRandom; // JDK 1.1 complains on final.
+
+ private IEntropySourceProvider mEntropySourceProvider;
+ private byte[] mDateTimeVector;
+
+ /**
+ * Basic constructor, creates a builder using an EntropySourceProvider based on the default SecureRandom with
+ * predictionResistant set to false.
+ * <p>
+ * Any SecureRandom created from a builder constructed like this will make use of input passed to SecureRandom.setSeed() if
+ * the default SecureRandom does for its generateSeed() call.
+ * </p>
+ */
+ public X931SecureRandomBuilder()
+ : this(new SecureRandom(), false)
+ {
+ }
+
+ /**
+ * Construct a builder with an EntropySourceProvider based on the passed in SecureRandom and the passed in value
+ * for prediction resistance.
+ * <p>
+ * Any SecureRandom created from a builder constructed like this will make use of input passed to SecureRandom.setSeed() if
+ * the passed in SecureRandom does for its generateSeed() call.
+ * </p>
+ * @param entropySource
+ * @param predictionResistant
+ */
+ public X931SecureRandomBuilder(SecureRandom entropySource, bool predictionResistant)
+ {
+ this.mRandom = entropySource;
+ this.mEntropySourceProvider = new BasicEntropySourceProvider(mRandom, predictionResistant);
+ }
+
+ /**
+ * Create a builder which makes creates the SecureRandom objects from a specified entropy source provider.
+ * <p>
+ * <b>Note:</b> If this constructor is used any calls to setSeed() in the resulting SecureRandom will be ignored.
+ * </p>
+ * @param entropySourceProvider a provider of EntropySource objects.
+ */
+ public X931SecureRandomBuilder(IEntropySourceProvider entropySourceProvider)
+ {
+ this.mRandom = null;
+ this.mEntropySourceProvider = entropySourceProvider;
+ }
+
+ public X931SecureRandomBuilder SetDateTimeVector(byte[] dateTimeVector)
+ {
+ this.mDateTimeVector = dateTimeVector;
+ return this;
+ }
+
+ /**
+ * Construct a X9.31 secure random generator using the passed in engine and key. If predictionResistant is true the
+ * generator will be reseeded on each request.
+ *
+ * @param engine a block cipher to use as the operator.
+ * @param key the block cipher key to initialise engine with.
+ * @param predictionResistant true if engine to be reseeded on each use, false otherwise.
+ * @return a SecureRandom.
+ */
+ public X931SecureRandom Build(IBlockCipher engine, KeyParameter key, bool predictionResistant)
+ {
+ if (mDateTimeVector == null)
+ {
+ mDateTimeVector = new byte[engine.GetBlockSize()];
+ Pack.UInt64_To_BE((ulong)DateTimeUtilities.CurrentUnixMs(), mDateTimeVector, 0);
+ }
+
+ engine.Init(true, key);
+
+ return new X931SecureRandom(mRandom, new X931Rng(engine, mDateTimeVector, mEntropySourceProvider.Get(engine.GetBlockSize() * 8)), predictionResistant);
+ }
+ }
+}
diff --git a/crypto/src/crypto/prng/drbg/CtrSP800Drbg.cs b/crypto/src/crypto/prng/drbg/CtrSP800Drbg.cs
new file mode 100644
index 000000000..2e4fbe4ed
--- /dev/null
+++ b/crypto/src/crypto/prng/drbg/CtrSP800Drbg.cs
@@ -0,0 +1,477 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Crypto.Prng.Drbg
+{
+ /**
+ * A SP800-90A CTR DRBG.
+ */
+ public class CtrSP800Drbg
+ : ISP80090Drbg
+ {
+ private static readonly long TDEA_RESEED_MAX = 1L << (32 - 1);
+ private static readonly long AES_RESEED_MAX = 1L << (48 - 1);
+ private static readonly int TDEA_MAX_BITS_REQUEST = 1 << (13 - 1);
+ private static readonly int AES_MAX_BITS_REQUEST = 1 << (19 - 1);
+
+ private readonly IEntropySource mEntropySource;
+ private readonly IBlockCipher mEngine;
+ private readonly int mKeySizeInBits;
+ private readonly int mSeedLength;
+ private readonly int mSecurityStrength;
+
+ // internal state
+ private byte[] mKey;
+ private byte[] mV;
+ private long mReseedCounter = 0;
+ private bool mIsTdea = false;
+
+ /**
+ * Construct a SP800-90A CTR DRBG.
+ * <p>
+ * Minimum entropy requirement is the security strength requested.
+ * </p>
+ * @param engine underlying block cipher to use to support DRBG
+ * @param keySizeInBits size of the key to use with the block cipher.
+ * @param securityStrength security strength required (in bits)
+ * @param entropySource source of entropy to use for seeding/reseeding.
+ * @param personalizationString personalization string to distinguish this DRBG (may be null).
+ * @param nonce nonce to further distinguish this DRBG (may be null).
+ */
+ public CtrSP800Drbg(IBlockCipher engine, int keySizeInBits, int securityStrength, IEntropySource entropySource,
+ byte[] personalizationString, byte[] nonce)
+ {
+ if (securityStrength > 256)
+ throw new ArgumentException("Requested security strength is not supported by the derivation function");
+ if (GetMaxSecurityStrength(engine, keySizeInBits) < securityStrength)
+ throw new ArgumentException("Requested security strength is not supported by block cipher and key size");
+ if (entropySource.EntropySize < securityStrength)
+ throw new ArgumentException("Not enough entropy for security strength required");
+
+ mEntropySource = entropySource;
+ mEngine = engine;
+
+ mKeySizeInBits = keySizeInBits;
+ mSecurityStrength = securityStrength;
+ mSeedLength = keySizeInBits + engine.GetBlockSize() * 8;
+ mIsTdea = IsTdea(engine);
+
+ byte[] entropy = GetEntropy(); // Get_entropy_input
+
+ CTR_DRBG_Instantiate_algorithm(entropy, nonce, personalizationString);
+ }
+
+ private void CTR_DRBG_Instantiate_algorithm(byte[] entropy, byte[] nonce, byte[] personalisationString)
+ {
+ byte[] seedMaterial = Arrays.ConcatenateAll(entropy, nonce, personalisationString);
+ byte[] seed = Block_Cipher_df(seedMaterial, mSeedLength);
+
+ int outlen = mEngine.GetBlockSize();
+
+ mKey = new byte[(mKeySizeInBits + 7) / 8];
+ mV = new byte[outlen];
+
+ // mKey & mV are modified by this call
+ CTR_DRBG_Update(seed, mKey, mV);
+
+ mReseedCounter = 1;
+ }
+
+ private void CTR_DRBG_Update(byte[] seed, byte[] key, byte[] v)
+ {
+ 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)
+ {
+ AddOneTo(v);
+ mEngine.ProcessBlock(v, 0, outputBlock, 0);
+
+ int bytesToCopy = ((temp.Length - i * outLen) > outLen)
+ ? outLen : (temp.Length - i * outLen);
+
+ Array.Copy(outputBlock, 0, temp, i * outLen, bytesToCopy);
+ ++i;
+ }
+
+ 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);
+
+ seedMaterial = Block_Cipher_df(seedMaterial, mSeedLength);
+
+ CTR_DRBG_Update(seedMaterial, mKey, mV);
+
+ mReseedCounter = 1;
+ }
+
+ 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]);
+ }
+ }
+
+ private void AddOneTo(byte[] longer)
+ {
+ uint carry = 1;
+ int i = longer.Length;
+ while (--i >= 0)
+ {
+ carry += longer[i];
+ longer[i] = (byte)carry;
+ carry >>= 8;
+ }
+ }
+
+ private byte[] GetEntropy()
+ {
+ byte[] entropy = mEntropySource.GetEntropy();
+ if (entropy.Length < (mSecurityStrength + 7) / 8)
+ throw new InvalidOperationException("Insufficient entropy provided by entropy source");
+ return entropy;
+ }
+
+ // -- Internal state migration ---
+
+ private static readonly byte[] K_BITS = Hex.Decode("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
+ 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;
+ // S already padded with zeros
+
+ byte[] temp = new byte[mKeySizeInBits / 8 + outLen];
+ byte[] bccOut = new byte[outLen];
+
+ byte[] IV = new byte[outLen];
+
+ int i = 0;
+ byte[] K = new byte[mKeySizeInBits / 8];
+ Array.Copy(K_BITS, 0, K, 0, K.Length);
+
+ while (i*outLen*8 < mKeySizeInBits + outLen *8)
+ {
+ copyIntToByteArray(IV, i, 0);
+ BCC(bccOut, K, IV, S);
+
+ int bytesToCopy = ((temp.Length - i * outLen) > outLen)
+ ? outLen
+ : (temp.Length - i * outLen);
+
+ Array.Copy(bccOut, 0, temp, i * outLen, bytesToCopy);
+ ++i;
+ }
+
+ byte[] X = new byte[outLen];
+ Array.Copy(temp, 0, K, 0, K.Length);
+ Array.Copy(temp, K.Length, X, 0, X.Length);
+
+ temp = new byte[bitLength / 2];
+
+ i = 0;
+ mEngine.Init(true, new KeyParameter(ExpandKey(K)));
+
+ while (i * outLen < temp.Length)
+ {
+ mEngine.ProcessBlock(X, 0, X, 0);
+
+ int bytesToCopy = ((temp.Length - i * outLen) > outLen)
+ ? outLen
+ : (temp.Length - i * outLen);
+
+ Array.Copy(X, 0, temp, i * outLen, bytesToCopy);
+ i++;
+ }
+
+ return temp;
+ }
+
+ /*
+ * 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)
+ {
+ int outlen = mEngine.GetBlockSize();
+ byte[] chainingValue = new byte[outlen]; // initial values = 0
+ int n = data.Length / outlen;
+
+ 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);
+ mEngine.ProcessBlock(inputBlock, 0, chainingValue, 0);
+ }
+
+ Array.Copy(chainingValue, 0, bccOut, 0, bccOut.Length);
+ }
+
+ 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
+ {
+ get { return mV.Length * 8; }
+ }
+
+ /**
+ * Populate a passed in array with random data.
+ *
+ * @param output output array for generated bits.
+ * @param additionalInput additional input to be added to the DRBG in this step.
+ * @param predictionResistant true if a reseed should be forced, false otherwise.
+ *
+ * @return number of bits generated, -1 if a reseed required.
+ */
+ public int Generate(byte[] output, byte[] additionalInput, bool predictionResistant)
+ {
+ if (mIsTdea)
+ {
+ if (mReseedCounter > TDEA_RESEED_MAX)
+ return -1;
+
+ if (DrbgUtilities.IsTooLarge(output, TDEA_MAX_BITS_REQUEST / 8))
+ throw new ArgumentException("Number of bits per request limited to " + TDEA_MAX_BITS_REQUEST, "output");
+ }
+ else
+ {
+ if (mReseedCounter > AES_RESEED_MAX)
+ return -1;
+
+ if (DrbgUtilities.IsTooLarge(output, AES_MAX_BITS_REQUEST / 8))
+ throw new ArgumentException("Number of bits per request limited to " + AES_MAX_BITS_REQUEST, "output");
+ }
+
+ if (predictionResistant)
+ {
+ CTR_DRBG_Reseed_algorithm(additionalInput);
+ additionalInput = null;
+ }
+
+ if (additionalInput != null)
+ {
+ additionalInput = Block_Cipher_df(additionalInput, mSeedLength);
+ CTR_DRBG_Update(additionalInput, mKey, mV);
+ }
+ else
+ {
+ additionalInput = new byte[mSeedLength];
+ }
+
+ byte[] tmp = new byte[mV.Length];
+
+ mEngine.Init(true, new KeyParameter(ExpandKey(mKey)));
+
+ for (int i = 0; i <= output.Length / tmp.Length; i++)
+ {
+ int bytesToCopy = ((output.Length - i * tmp.Length) > tmp.Length)
+ ? tmp.Length
+ : (output.Length - i * mV.Length);
+
+ if (bytesToCopy != 0)
+ {
+ AddOneTo(mV);
+
+ mEngine.ProcessBlock(mV, 0, tmp, 0);
+
+ Array.Copy(tmp, 0, output, i * tmp.Length, bytesToCopy);
+ }
+ }
+
+ CTR_DRBG_Update(additionalInput, mKey, mV);
+
+ mReseedCounter++;
+
+ return output.Length * 8;
+ }
+
+ /**
+ * Reseed the DRBG.
+ *
+ * @param additionalInput additional input to be added to the DRBG in this step.
+ */
+ public void Reseed(byte[] additionalInput)
+ {
+ CTR_DRBG_Reseed_algorithm(additionalInput);
+ }
+
+ private bool IsTdea(IBlockCipher cipher)
+ {
+ return cipher.AlgorithmName.Equals("DESede") || cipher.AlgorithmName.Equals("TDEA");
+ }
+
+ private int GetMaxSecurityStrength(IBlockCipher cipher, int keySizeInBits)
+ {
+ if (IsTdea(cipher) && keySizeInBits == 168)
+ {
+ return 112;
+ }
+ if (cipher.AlgorithmName.Equals("AES"))
+ {
+ return keySizeInBits;
+ }
+
+ return -1;
+ }
+
+ private byte[] ExpandKey(byte[] key)
+ {
+ if (mIsTdea)
+ {
+ // expand key to 192 bits.
+ byte[] tmp = new byte[24];
+
+ PadKey(key, 0, tmp, 0);
+ PadKey(key, 7, tmp, 8);
+ PadKey(key, 14, tmp, 16);
+
+ return tmp;
+ }
+ else
+ {
+ return key;
+ }
+ }
+
+ /**
+ * Pad out a key for TDEA, setting odd parity for each byte.
+ *
+ * @param keyMaster
+ * @param keyOff
+ * @param tmp
+ * @param tmpOff
+ */
+ private void PadKey(byte[] keyMaster, int keyOff, byte[] tmp, int tmpOff)
+ {
+ tmp[tmpOff + 0] = (byte)(keyMaster[keyOff + 0] & 0xfe);
+ tmp[tmpOff + 1] = (byte)((keyMaster[keyOff + 0] << 7) | ((keyMaster[keyOff + 1] & 0xfc) >> 1));
+ tmp[tmpOff + 2] = (byte)((keyMaster[keyOff + 1] << 6) | ((keyMaster[keyOff + 2] & 0xf8) >> 2));
+ tmp[tmpOff + 3] = (byte)((keyMaster[keyOff + 2] << 5) | ((keyMaster[keyOff + 3] & 0xf0) >> 3));
+ tmp[tmpOff + 4] = (byte)((keyMaster[keyOff + 3] << 4) | ((keyMaster[keyOff + 4] & 0xe0) >> 4));
+ tmp[tmpOff + 5] = (byte)((keyMaster[keyOff + 4] << 3) | ((keyMaster[keyOff + 5] & 0xc0) >> 5));
+ tmp[tmpOff + 6] = (byte)((keyMaster[keyOff + 5] << 2) | ((keyMaster[keyOff + 6] & 0x80) >> 6));
+ tmp[tmpOff + 7] = (byte)(keyMaster[keyOff + 6] << 1);
+
+ for (int i = tmpOff; i <= tmpOff + 7; i++)
+ {
+ uint b = tmp[i];
+
+ uint parity = b ^ 1U;
+ parity ^= (parity >> 4);
+ parity ^= (parity >> 2);
+ parity ^= (parity >> 1);
+ parity &= 1U;
+
+ tmp[i] = (byte)(b ^ parity);
+ }
+ }
+ }
+}
diff --git a/crypto/src/crypto/prng/drbg/DrbgUtilities.cs b/crypto/src/crypto/prng/drbg/DrbgUtilities.cs
new file mode 100644
index 000000000..d9a1c439c
--- /dev/null
+++ b/crypto/src/crypto/prng/drbg/DrbgUtilities.cs
@@ -0,0 +1,103 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Prng.Drbg
+{
+ internal class DrbgUtilities
+ {
+ private static readonly IDictionary maxSecurityStrengths = Platform.CreateHashtable();
+
+ static DrbgUtilities()
+ {
+ maxSecurityStrengths.Add("SHA-1", 128);
+
+ maxSecurityStrengths.Add("SHA-224", 192);
+ maxSecurityStrengths.Add("SHA-256", 256);
+ maxSecurityStrengths.Add("SHA-384", 256);
+ maxSecurityStrengths.Add("SHA-512", 256);
+
+ maxSecurityStrengths.Add("SHA-512/224", 192);
+ maxSecurityStrengths.Add("SHA-512/256", 256);
+ }
+
+ internal static int GetMaxSecurityStrength(IDigest d)
+ {
+ return (int)maxSecurityStrengths[d.AlgorithmName];
+ }
+
+ internal static int GetMaxSecurityStrength(IMac m)
+ {
+ string name = m.AlgorithmName;
+
+ return (int)maxSecurityStrengths[name.Substring(0, name.IndexOf("/"))];
+ }
+
+ /**
+ * Used by both Dual EC and Hash.
+ */
+ internal static byte[] HashDF(IDigest digest, byte[] seedMaterial, int seedLength)
+ {
+ // 1. temp = the Null string.
+ // 2. .
+ // 3. counter = an 8-bit binary value representing the integer "1".
+ // 4. For i = 1 to len do
+ // Comment : In step 4.1, no_of_bits_to_return
+ // is used as a 32-bit string.
+ // 4.1 temp = temp || Hash (counter || no_of_bits_to_return ||
+ // input_string).
+ // 4.2 counter = counter + 1.
+ // 5. requested_bits = Leftmost (no_of_bits_to_return) of temp.
+ // 6. Return SUCCESS and requested_bits.
+ byte[] temp = new byte[(seedLength + 7) / 8];
+
+ int len = temp.Length / digest.GetDigestSize();
+ int counter = 1;
+
+ byte[] dig = new byte[digest.GetDigestSize()];
+
+ for (int i = 0; i <= len; i++)
+ {
+ digest.Update((byte)counter);
+
+ digest.Update((byte)(seedLength >> 24));
+ digest.Update((byte)(seedLength >> 16));
+ digest.Update((byte)(seedLength >> 8));
+ digest.Update((byte)seedLength);
+
+ digest.BlockUpdate(seedMaterial, 0, seedMaterial.Length);
+
+ digest.DoFinal(dig, 0);
+
+ int bytesToCopy = ((temp.Length - i * dig.Length) > dig.Length)
+ ? dig.Length
+ : (temp.Length - i * dig.Length);
+ Array.Copy(dig, 0, temp, i * dig.Length, bytesToCopy);
+
+ counter++;
+ }
+
+ // do a left shift to get rid of excess bits.
+ if (seedLength % 8 != 0)
+ {
+ int shift = 8 - (seedLength % 8);
+ uint carry = 0;
+
+ for (int i = 0; i != temp.Length; i++)
+ {
+ uint b = temp[i];
+ temp[i] = (byte)((b >> shift) | (carry << (8 - shift)));
+ carry = b;
+ }
+ }
+
+ return temp;
+ }
+
+ internal static bool IsTooLarge(byte[] bytes, int maxBytes)
+ {
+ return bytes != null && bytes.Length > maxBytes;
+ }
+ }
+}
diff --git a/crypto/src/crypto/prng/drbg/HMacSP800Drbg.cs b/crypto/src/crypto/prng/drbg/HMacSP800Drbg.cs
new file mode 100644
index 000000000..78331705e
--- /dev/null
+++ b/crypto/src/crypto/prng/drbg/HMacSP800Drbg.cs
@@ -0,0 +1,186 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Prng.Drbg
+{
+ /**
+ * A SP800-90A HMAC DRBG.
+ */
+ public class HMacSP800Drbg
+ : ISP80090Drbg
+ {
+ private readonly static long RESEED_MAX = 1L << (48 - 1);
+ private readonly static int MAX_BITS_REQUEST = 1 << (19 - 1);
+
+ private readonly byte[] mK;
+ private readonly byte[] mV;
+ private readonly IEntropySource mEntropySource;
+ private readonly IMac mHMac;
+ private readonly int mSecurityStrength;
+
+ private long mReseedCounter;
+
+ /**
+ * Construct a SP800-90A Hash DRBG.
+ * <p>
+ * Minimum entropy requirement is the security strength requested.
+ * </p>
+ * @param hMac Hash MAC to base the DRBG on.
+ * @param securityStrength security strength required (in bits)
+ * @param entropySource source of entropy to use for seeding/reseeding.
+ * @param personalizationString personalization string to distinguish this DRBG (may be null).
+ * @param nonce nonce to further distinguish this DRBG (may be null).
+ */
+ public HMacSP800Drbg(IMac hMac, int securityStrength, IEntropySource entropySource, byte[] personalizationString, byte[] nonce)
+ {
+ if (securityStrength > DrbgUtilities.GetMaxSecurityStrength(hMac))
+ throw new ArgumentException("Requested security strength is not supported by the derivation function");
+ if (entropySource.EntropySize < securityStrength)
+ throw new ArgumentException("Not enough entropy for security strength required");
+
+ mHMac = hMac;
+ mSecurityStrength = securityStrength;
+ mEntropySource = entropySource;
+
+ byte[] entropy = GetEntropy();
+ byte[] seedMaterial = Arrays.ConcatenateAll(entropy, nonce, personalizationString);
+
+ mK = new byte[hMac.GetMacSize()];
+ mV = new byte[mK.Length];
+ Arrays.Fill(mV, (byte)1);
+
+ hmac_DRBG_Update(seedMaterial);
+
+ mReseedCounter = 1;
+ }
+
+ private void hmac_DRBG_Update(byte[] seedMaterial)
+ {
+ hmac_DRBG_Update_Func(seedMaterial, (byte)0x00);
+ if (seedMaterial != null)
+ {
+ hmac_DRBG_Update_Func(seedMaterial, (byte)0x01);
+ }
+ }
+
+ private void hmac_DRBG_Update_Func(byte[] seedMaterial, byte vValue)
+ {
+ mHMac.Init(new KeyParameter(mK));
+
+ mHMac.BlockUpdate(mV, 0, mV.Length);
+ mHMac.Update(vValue);
+
+ if (seedMaterial != null)
+ {
+ mHMac.BlockUpdate(seedMaterial, 0, seedMaterial.Length);
+ }
+
+ mHMac.DoFinal(mK, 0);
+
+ mHMac.Init(new KeyParameter(mK));
+ mHMac.BlockUpdate(mV, 0, mV.Length);
+
+ mHMac.DoFinal(mV, 0);
+ }
+
+ /**
+ * Return the block size (in bits) of the DRBG.
+ *
+ * @return the number of bits produced on each round of the DRBG.
+ */
+ public int BlockSize
+ {
+ get { return mV.Length * 8; }
+ }
+
+ /**
+ * Populate a passed in array with random data.
+ *
+ * @param output output array for generated bits.
+ * @param additionalInput additional input to be added to the DRBG in this step.
+ * @param predictionResistant true if a reseed should be forced, false otherwise.
+ *
+ * @return number of bits generated, -1 if a reseed required.
+ */
+ public int Generate(byte[] output, byte[] additionalInput, bool predictionResistant)
+ {
+ int numberOfBits = output.Length * 8;
+
+ if (numberOfBits > MAX_BITS_REQUEST)
+ throw new ArgumentException("Number of bits per request limited to " + MAX_BITS_REQUEST, "output");
+
+ if (mReseedCounter > RESEED_MAX)
+ {
+ return -1;
+ }
+
+ if (predictionResistant)
+ {
+ Reseed(additionalInput);
+ additionalInput = null;
+ }
+
+ // 2.
+ if (additionalInput != null)
+ {
+ hmac_DRBG_Update(additionalInput);
+ }
+
+ // 3.
+ byte[] rv = new byte[output.Length];
+
+ int m = output.Length / mV.Length;
+
+ mHMac.Init(new KeyParameter(mK));
+
+ for (int i = 0; i < m; i++)
+ {
+ mHMac.BlockUpdate(mV, 0, mV.Length);
+ mHMac.DoFinal(mV, 0);
+
+ Array.Copy(mV, 0, rv, i * mV.Length, mV.Length);
+ }
+
+ if (m * mV.Length < rv.Length)
+ {
+ mHMac.BlockUpdate(mV, 0, mV.Length);
+ mHMac.DoFinal(mV, 0);
+
+ Array.Copy(mV, 0, rv, m * mV.Length, rv.Length - (m * mV.Length));
+ }
+
+ hmac_DRBG_Update(additionalInput);
+
+ mReseedCounter++;
+
+ Array.Copy(rv, 0, output, 0, output.Length);
+
+ return numberOfBits;
+ }
+
+ /**
+ * Reseed the DRBG.
+ *
+ * @param additionalInput additional input to be added to the DRBG in this step.
+ */
+ public void Reseed(byte[] additionalInput)
+ {
+ byte[] entropy = GetEntropy();
+ byte[] seedMaterial = Arrays.Concatenate(entropy, additionalInput);
+
+ hmac_DRBG_Update(seedMaterial);
+
+ mReseedCounter = 1;
+ }
+
+ private byte[] GetEntropy()
+ {
+ byte[] entropy = mEntropySource.GetEntropy();
+ if (entropy.Length < (mSecurityStrength + 7) / 8)
+ throw new InvalidOperationException("Insufficient entropy provided by entropy source");
+ return entropy;
+ }
+ }
+}
diff --git a/crypto/src/crypto/prng/drbg/HashSP800Drbg.cs b/crypto/src/crypto/prng/drbg/HashSP800Drbg.cs
new file mode 100644
index 000000000..493da5a75
--- /dev/null
+++ b/crypto/src/crypto/prng/drbg/HashSP800Drbg.cs
@@ -0,0 +1,287 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Prng.Drbg
+{
+ /**
+ * A SP800-90A Hash DRBG.
+ */
+ public class HashSP800Drbg
+ : ISP80090Drbg
+ {
+ private readonly static byte[] ONE = { 0x01 };
+
+ private readonly static long RESEED_MAX = 1L << (48 - 1);
+ private readonly static int MAX_BITS_REQUEST = 1 << (19 - 1);
+
+ private static readonly IDictionary seedlens = Platform.CreateHashtable();
+
+ static HashSP800Drbg()
+ {
+ seedlens.Add("SHA-1", 440);
+ seedlens.Add("SHA-224", 440);
+ seedlens.Add("SHA-256", 440);
+ seedlens.Add("SHA-512/256", 440);
+ seedlens.Add("SHA-512/224", 440);
+ seedlens.Add("SHA-384", 888);
+ seedlens.Add("SHA-512", 888);
+ }
+
+ private readonly IDigest mDigest;
+ private readonly IEntropySource mEntropySource;
+ private readonly int mSecurityStrength;
+ private readonly int mSeedLength;
+
+ private byte[] mV;
+ private byte[] mC;
+ private long mReseedCounter;
+
+ /**
+ * Construct a SP800-90A Hash DRBG.
+ * <p>
+ * Minimum entropy requirement is the security strength requested.
+ * </p>
+ * @param digest source digest to use for DRB stream.
+ * @param securityStrength security strength required (in bits)
+ * @param entropySource source of entropy to use for seeding/reseeding.
+ * @param personalizationString personalization string to distinguish this DRBG (may be null).
+ * @param nonce nonce to further distinguish this DRBG (may be null).
+ */
+ public HashSP800Drbg(IDigest digest, int securityStrength, IEntropySource entropySource, byte[] personalizationString, byte[] nonce)
+ {
+ if (securityStrength > DrbgUtilities.GetMaxSecurityStrength(digest))
+ throw new ArgumentException("Requested security strength is not supported by the derivation function");
+ if (entropySource.EntropySize < securityStrength)
+ throw new ArgumentException("Not enough entropy for security strength required");
+
+ mDigest = digest;
+ mEntropySource = entropySource;
+ mSecurityStrength = securityStrength;
+ mSeedLength = (int)seedlens[digest.AlgorithmName];
+
+ // 1. seed_material = entropy_input || nonce || personalization_string.
+ // 2. seed = Hash_df (seed_material, seedlen).
+ // 3. V = seed.
+ // 4. C = Hash_df ((0x00 || V), seedlen). Comment: Preceed V with a byte
+ // of zeros.
+ // 5. reseed_counter = 1.
+ // 6. Return V, C, and reseed_counter as the initial_working_state
+
+ byte[] entropy = GetEntropy();
+ byte[] seedMaterial = Arrays.ConcatenateAll(entropy, nonce, personalizationString);
+ byte[] seed = DrbgUtilities.HashDF(mDigest, seedMaterial, mSeedLength);
+
+ mV = seed;
+ byte[] subV = new byte[mV.Length + 1];
+ Array.Copy(mV, 0, subV, 1, mV.Length);
+ mC = DrbgUtilities.HashDF(mDigest, subV, mSeedLength);
+
+ mReseedCounter = 1;
+ }
+
+ /**
+ * 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
+ {
+ get { return mDigest.GetDigestSize () * 8; }
+ }
+
+ /**
+ * Populate a passed in array with random data.
+ *
+ * @param output output array for generated bits.
+ * @param additionalInput additional input to be added to the DRBG in this step.
+ * @param predictionResistant true if a reseed should be forced, false otherwise.
+ *
+ * @return number of bits generated, -1 if a reseed required.
+ */
+ public int Generate(byte[] output, byte[] additionalInput, bool predictionResistant)
+ {
+ // 1. If reseed_counter > reseed_interval, then return an indication that a
+ // reseed is required.
+ // 2. If (additional_input != Null), then do
+ // 2.1 w = Hash (0x02 || V || additional_input).
+ // 2.2 V = (V + w) mod 2^seedlen
+ // .
+ // 3. (returned_bits) = Hashgen (requested_number_of_bits, V).
+ // 4. H = Hash (0x03 || V).
+ // 5. V = (V + H + C + reseed_counter) mod 2^seedlen
+ // .
+ // 6. reseed_counter = reseed_counter + 1.
+ // 7. Return SUCCESS, returned_bits, and the new values of V, C, and
+ // reseed_counter for the new_working_state.
+ int numberOfBits = output.Length * 8;
+
+ if (numberOfBits > MAX_BITS_REQUEST)
+ throw new ArgumentException("Number of bits per request limited to " + MAX_BITS_REQUEST, "output");
+
+ if (mReseedCounter > RESEED_MAX)
+ return -1;
+
+ if (predictionResistant)
+ {
+ Reseed(additionalInput);
+ additionalInput = null;
+ }
+
+ // 2.
+ if (additionalInput != null)
+ {
+ byte[] newInput = new byte[1 + mV.Length + additionalInput.Length];
+ newInput[0] = 0x02;
+ Array.Copy(mV, 0, newInput, 1, mV.Length);
+ // TODO: inOff / inLength
+ Array.Copy(additionalInput, 0, newInput, 1 + mV.Length, additionalInput.Length);
+ byte[] w = Hash(newInput);
+
+ AddTo(mV, w);
+ }
+
+ // 3.
+ byte[] rv = hashgen(mV, numberOfBits);
+
+ // 4.
+ byte[] subH = new byte[mV.Length + 1];
+ Array.Copy(mV, 0, subH, 1, mV.Length);
+ subH[0] = 0x03;
+
+ byte[] H = Hash(subH);
+
+ // 5.
+ AddTo(mV, H);
+ AddTo(mV, mC);
+ byte[] c = new byte[4];
+ c[0] = (byte)(mReseedCounter >> 24);
+ c[1] = (byte)(mReseedCounter >> 16);
+ c[2] = (byte)(mReseedCounter >> 8);
+ c[3] = (byte)mReseedCounter;
+
+ AddTo(mV, c);
+
+ mReseedCounter++;
+
+ Array.Copy(rv, 0, output, 0, output.Length);
+
+ return numberOfBits;
+ }
+
+ private byte[] GetEntropy()
+ {
+ byte[] entropy = mEntropySource.GetEntropy();
+ if (entropy.Length < (mSecurityStrength + 7) / 8)
+ throw new InvalidOperationException("Insufficient entropy provided by entropy source");
+ return entropy;
+ }
+
+ // this will always add the shorter length byte array mathematically to the
+ // longer length byte array.
+ // be careful....
+ private void AddTo(byte[] longer, byte[] shorter)
+ {
+ int off = longer.Length - shorter.Length;
+
+ uint carry = 0;
+ int i = shorter.Length;
+ while (--i >= 0)
+ {
+ carry += (uint)longer[off + i] + (uint)shorter[i];
+ longer[off + i] = (byte)carry;
+ carry >>= 8;
+ }
+
+ i = off;
+ while (--i >= 0)
+ {
+ carry += longer[i];
+ longer[i] = (byte)carry;
+ carry >>= 8;
+ }
+ }
+
+ /**
+ * Reseed the DRBG.
+ *
+ * @param additionalInput additional input to be added to the DRBG in this step.
+ */
+ public void Reseed(byte[] additionalInput)
+ {
+ // 1. seed_material = 0x01 || V || entropy_input || additional_input.
+ //
+ // 2. seed = Hash_df (seed_material, seedlen).
+ //
+ // 3. V = seed.
+ //
+ // 4. C = Hash_df ((0x00 || V), seedlen).
+ //
+ // 5. reseed_counter = 1.
+ //
+ // 6. Return V, C, and reseed_counter for the new_working_state.
+ //
+ // Comment: Precede with a byte of all zeros.
+ byte[] entropy = GetEntropy();
+ byte[] seedMaterial = Arrays.ConcatenateAll(ONE, mV, entropy, additionalInput);
+ byte[] seed = DrbgUtilities.HashDF(mDigest, seedMaterial, mSeedLength);
+
+ mV = seed;
+ byte[] subV = new byte[mV.Length + 1];
+ subV[0] = 0x00;
+ Array.Copy(mV, 0, subV, 1, mV.Length);
+ mC = DrbgUtilities.HashDF(mDigest, subV, mSeedLength);
+
+ mReseedCounter = 1;
+ }
+
+ private byte[] Hash(byte[] input)
+ {
+ byte[] hash = new byte[mDigest.GetDigestSize()];
+ DoHash(input, hash);
+ return hash;
+ }
+
+ private void DoHash(byte[] input, byte[] output)
+ {
+ mDigest.BlockUpdate(input, 0, input.Length);
+ mDigest.DoFinal(output, 0);
+ }
+
+ // 1. m = [requested_number_of_bits / outlen]
+ // 2. data = V.
+ // 3. W = the Null string.
+ // 4. For i = 1 to m
+ // 4.1 wi = Hash (data).
+ // 4.2 W = W || wi.
+ // 4.3 data = (data + 1) mod 2^seedlen
+ // .
+ // 5. returned_bits = Leftmost (requested_no_of_bits) bits of W.
+ private byte[] hashgen(byte[] input, int lengthInBits)
+ {
+ int digestSize = mDigest.GetDigestSize();
+ int m = (lengthInBits / 8) / digestSize;
+
+ byte[] data = new byte[input.Length];
+ Array.Copy(input, 0, data, 0, input.Length);
+
+ byte[] W = new byte[lengthInBits / 8];
+
+ byte[] dig = new byte[mDigest.GetDigestSize()];
+ for (int i = 0; i <= m; i++)
+ {
+ DoHash(data, dig);
+
+ int bytesToCopy = ((W.Length - i * dig.Length) > dig.Length)
+ ? dig.Length
+ : (W.Length - i * dig.Length);
+ Array.Copy(dig, 0, W, i * dig.Length, bytesToCopy);
+
+ AddTo(data, ONE);
+ }
+
+ return W;
+ }
+ }
+}
diff --git a/crypto/src/crypto/prng/drbg/ISP80090Drbg.cs b/crypto/src/crypto/prng/drbg/ISP80090Drbg.cs
new file mode 100644
index 000000000..0e398209e
--- /dev/null
+++ b/crypto/src/crypto/prng/drbg/ISP80090Drbg.cs
@@ -0,0 +1,35 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Prng.Drbg
+{
+ /**
+ * Interface to SP800-90A deterministic random bit generators.
+ */
+ public interface ISP80090Drbg
+ {
+ /**
+ * Return the block size of the DRBG.
+ *
+ * @return the block size (in bits) produced by each round of the DRBG.
+ */
+ int BlockSize { get; }
+
+ /**
+ * Populate a passed in array with random data.
+ *
+ * @param output output array for generated bits.
+ * @param additionalInput additional input to be added to the DRBG in this step.
+ * @param predictionResistant true if a reseed should be forced, false otherwise.
+ *
+ * @return number of bits generated, -1 if a reseed required.
+ */
+ int Generate(byte[] output, byte[] additionalInput, bool predictionResistant);
+
+ /**
+ * Reseed the DRBG.
+ *
+ * @param additionalInput additional input to be added to the DRBG in this step.
+ */
+ void Reseed(byte[] additionalInput);
+ }
+}
diff --git a/crypto/src/openpgp/PgpEncryptedData.cs b/crypto/src/openpgp/PgpEncryptedData.cs
index 0d237b56c..558e0b8a2 100644
--- a/crypto/src/openpgp/PgpEncryptedData.cs
+++ b/crypto/src/openpgp/PgpEncryptedData.cs
@@ -81,7 +81,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
Array.Copy(lookAhead, bufStart, buf, pos, len);
bufStart += len;
- return pos + len - off;;
+ return pos + len - off;
}
internal byte[] GetLookAhead()
diff --git a/crypto/src/openpgp/PgpPublicKeyRing.cs b/crypto/src/openpgp/PgpPublicKeyRing.cs
index 7b1ac93bf..92464d64f 100644
--- a/crypto/src/openpgp/PgpPublicKeyRing.cs
+++ b/crypto/src/openpgp/PgpPublicKeyRing.cs
@@ -45,7 +45,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
+ "tag 0x" + ((int)initialTag).ToString("X"));
}
- PublicKeyPacket pubPk = (PublicKeyPacket) bcpgInput.ReadPacket();;
+ PublicKeyPacket pubPk = (PublicKeyPacket) bcpgInput.ReadPacket();
TrustPacket trustPk = ReadOptionalTrustPacket(bcpgInput);
// direct signatures and revocations
diff --git a/crypto/src/security/SecureRandom.cs b/crypto/src/security/SecureRandom.cs
index 4894a93e6..875709e57 100644
--- a/crypto/src/security/SecureRandom.cs
+++ b/crypto/src/security/SecureRandom.cs
@@ -164,13 +164,7 @@ namespace Org.BouncyCastle.Security
public override int Next()
{
- for (;;)
- {
- int i = NextInt() & int.MaxValue;
-
- if (i != int.MaxValue)
- return i;
- }
+ return NextInt() & int.MaxValue;
}
public override int Next(int maxValue)
@@ -184,11 +178,9 @@ namespace Org.BouncyCastle.Security
}
// Test whether maxValue is a power of 2
- if ((maxValue & -maxValue) == maxValue)
+ if ((maxValue & (maxValue - 1)) == 0)
{
- int val = NextInt() & int.MaxValue;
- long lr = ((long) maxValue * (long) val) >> 31;
- return (int) lr;
+ return NextInt() & (maxValue - 1);
}
int bits, result;
@@ -244,16 +236,17 @@ namespace Org.BouncyCastle.Security
public virtual int NextInt()
{
- byte[] intBytes = new byte[4];
- NextBytes(intBytes);
-
- int result = 0;
- for (int i = 0; i < 4; i++)
- {
- result = (result << 8) + (intBytes[i] & 0xff);
- }
-
- return result;
+ byte[] bytes = new byte[4];
+ NextBytes(bytes);
+
+ uint result = bytes[0];
+ result <<= 8;
+ result |= bytes[1];
+ result <<= 8;
+ result |= bytes[2];
+ result <<= 8;
+ result |= bytes[3];
+ return (int)result;
}
public virtual long NextLong()
diff --git a/crypto/src/util/Arrays.cs b/crypto/src/util/Arrays.cs
index 1f9711555..df9b4e7ee 100644
--- a/crypto/src/util/Arrays.cs
+++ b/crypto/src/util/Arrays.cs
@@ -591,6 +591,35 @@ namespace Org.BouncyCastle.Utilities
return rv;
}
+ public static byte[] ConcatenateAll(params byte[][] vs)
+ {
+ byte[][] nonNull = new byte[vs.Length][];
+ int count = 0;
+ int totalLength = 0;
+
+ for (int i = 0; i < vs.Length; ++i)
+ {
+ byte[] v = vs[i];
+ if (v != null)
+ {
+ nonNull[count++] = v;
+ totalLength += v.Length;
+ }
+ }
+
+ byte[] result = new byte[totalLength];
+ int pos = 0;
+
+ for (int j = 0; j < count; ++j)
+ {
+ byte[] v = nonNull[j];
+ Array.Copy(v, 0, result, pos, v.Length);
+ pos += v.Length;
+ }
+
+ return result;
+ }
+
public static int[] Concatenate(int[] a, int[] b)
{
if (a == null)
diff --git a/crypto/test/src/crypto/prng/test/CtrDrbgTest.cs b/crypto/test/src/crypto/prng/test/CtrDrbgTest.cs
new file mode 100644
index 000000000..44b08f3a6
--- /dev/null
+++ b/crypto/test/src/crypto/prng/test/CtrDrbgTest.cs
@@ -0,0 +1,526 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Prng.Drbg;
+using Org.BouncyCastle.Utilities.Test;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Prng.Test
+{
+ /**
+ * CTR DRBG Test
+ */
+ [TestFixture]
+ public class CtrDrbgTest
+ : SimpleTest
+ {
+ public override string Name
+ {
+ get { return "CTRDRBGTest"; }
+ }
+
+ public static void Main(string[] args)
+ {
+ RunTest(new CtrDrbgTest());
+ }
+
+ [Test]
+ public void TestFunction()
+ {
+ string resultText = Perform().ToString();
+
+ Assert.AreEqual(Name + ": Okay", resultText);
+ }
+
+ private DrbgTestVector[] CreateTestVectorData()
+ {
+ return new DrbgTestVector[]
+ {
+ new DrbgTestVector(
+ new DesEdeEngine(), 168,
+ new Bit232EntropyProvider().Get(232),
+ false,
+ "20212223242526",
+ 112,
+ new string[]
+ {
+ "ABC88224514D0316EA3D48AEE3C9A2B4",
+ "D3D3F372E43E7ABDC4FA293743EED076"
+ }
+ ),
+ new DrbgTestVector(
+ new DesEdeEngine(), 168,
+ new Bit232EntropyProvider().Get(232),
+ false,
+ "20212223242526",
+ 112,
+ new string[]
+ {
+ "D4564EE072ACA5BD279536E14F94CB12",
+ "1CCD9AFEF15A9679BA75E35225585DEA"
+ }
+ )
+ .AddAdditionalInput("606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C")
+ .AddAdditionalInput("A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBC"),
+ new DrbgTestVector(
+ new DesEdeEngine(), 168,
+ new Bit232EntropyProvider().Get(232),
+ false,
+ "20212223242526",
+ 112,
+ new string[]
+ {
+ "760BED7D92B083B10AF31CF0656081EB",
+ "FD1AC41482384D823CF3FD6F0E6C88B3"
+ }
+ )
+ .SetPersonalizationString("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C"),
+ new DrbgTestVector(
+ new DesEdeEngine(), 168,
+ new Bit232EntropyProvider().Get(232),
+ false,
+ "20212223242526",
+ 112,
+ new string[]
+ {
+ "7A4C1D7ADC8A67FDB50100ED23583A2C",
+ "43044D311C0E07541CA5C8B0916976B2"
+ }
+ )
+ .SetPersonalizationString("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C")
+ .AddAdditionalInput("606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C")
+ .AddAdditionalInput("A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBC"),
+ new DrbgTestVector(
+ new DesEdeEngine(), 168,
+ new Bit232EntropyProvider().Get(232),
+ true,
+ "20212223242526",
+ 112,
+ new string[]
+ {
+ "8FB78ABCA75C9F284E974E36141866BC",
+ "9D9745FF31C42A4488CBB771B13B5D86"
+ }
+ ),
+ new DrbgTestVector(
+ new DesEdeEngine(), 168,
+ new Bit232EntropyProvider().Get(232),
+ true,
+ "20212223242526",
+ 112,
+ new string[]
+ {
+ "0E389920A09B485AA4ABD0CA7E60D89C",
+ "F4478EC6659A0D3577625B0C73A211DD"
+ }
+ )
+ .AddAdditionalInput("606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C")
+ .AddAdditionalInput("A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBC"),
+ new DrbgTestVector(
+ new DesEdeEngine(), 168,
+ new Bit232EntropyProvider().Get(232),
+ true,
+ "20212223242526",
+ 112,
+ new string[]
+ {
+ "64983055D014550B39DE699E43130B64",
+ "035FDDA8582A2214EC722C410A8D95D3"
+ }
+ )
+ .SetPersonalizationString("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C"),
+ new DrbgTestVector(
+ new DesEdeEngine(), 168,
+ new Bit232EntropyProvider().Get(232),
+ true,
+ "20212223242526",
+ 112,
+ new string[]
+ {
+ "A29C1A8C42FBC562D7D1DBA7DC541FFE",
+ "0BDA66B049429061C013E4228C2F44C6"
+ }
+ )
+ .SetPersonalizationString("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C")
+ .AddAdditionalInput("606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C")
+ .AddAdditionalInput("A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBC"),
+ new DrbgTestVector(
+ new AesFastEngine(), 128,
+ new Bit256EntropyProvider().Get(256),
+ false,
+ "2021222324252627",
+ 128,
+ new string[]
+ {
+ "8CF59C8CF6888B96EB1C1E3E79D82387AF08A9E5FF75E23F1FBCD4559B6B997E",
+ "69CDEF912C692D61B1DA4C05146B52EB7B8849BD87937835328254EC25A9180E"
+ }
+ ),
+ new DrbgTestVector(
+ new AesFastEngine(), 128,
+ new Bit256EntropyProvider().Get(256),
+ false,
+ "2021222324252627",
+ 128,
+ new string[]
+ {
+ "E8C74A4B7BFFB53BEB80E78CA86BB6DF70E2032AEB473E0DD54D2339CEFCE9D0",
+ "26B3F823B4DBAFC23B141375E10B3AEB7A0B5DEF1C7D760B6F827D01ECD17AC7"
+ }
+ )
+ .AddAdditionalInput("606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F")
+ .AddAdditionalInput("A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF"),
+ new DrbgTestVector(
+ new AesFastEngine(), 128,
+ new Bit256EntropyProvider().Get(256),
+ false,
+ "2021222324252627",
+ 128,
+ new string[]
+ {
+ "18FDEFBDC43D7A36D5D6D862205765D1D701C9F237007030DF1B8E70EE4EEE29",
+ "9888F1D38BB1CCE31B363AA1BD9B39616876C30DEE1FF0B7BD8C4C441715C833"
+ }
+ )
+ .SetPersonalizationString("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F"),
+ new DrbgTestVector(
+ new AesFastEngine(), 128,
+ new Bit256EntropyProvider().Get(256),
+ true,
+ "2021222324252627",
+ 128,
+ new string[]
+ {
+ "BFF4B85D68C84529F24F69F9ACF1756E29BA648DDEB825C225FA32BA490EF4A9",
+ "9BD2635137A52AF7D0FCBEFEFB97EA93A0F4C438BD98956C0DACB04F15EE25B3"
+ }
+ ),
+ new DrbgTestVector(
+ new AesFastEngine(), 128,
+ new Bit256EntropyProvider().Get(256),
+ true,
+ "2021222324252627",
+ 128,
+ new string[]
+ {
+ "4573AC8BBB33D7CC4DBEF3EEDF6EAE748B536C3A1082CEE4948CDB51C83A7F9C",
+ "99C628CDD87BD8C2F1FE443AA7F761DA16886436326323354DA6311FFF5BC678"
+ }
+ )
+ .AddAdditionalInput("606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F")
+ .AddAdditionalInput("A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF"),
+ new DrbgTestVector(
+ new AesFastEngine(), 128,
+ new Bit256EntropyProvider().Get(256),
+ true,
+ "2021222324252627",
+ 128,
+ new string[]
+ {
+ "F324104E2FA14F79D8AA60DF06B93B3BC157324958F0A7EE1E193677A70E0250",
+ "78F4C840134F40DC001BFAD3A90B5EF4DEBDBFAC3CFDF0CD69A89DC4FD34713F"
+ }
+ )
+ .SetPersonalizationString("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F"),
+ new DrbgTestVector(
+ new AesFastEngine(), 192,
+ new Bit320EntropyProvider().Get(320),
+ false,
+ "202122232425262728292A2B",
+ 192,
+ new string[]
+ {
+ "E231244B3235B085C81604424357E85201E3828B5C45568679A5555F867AAC8C",
+ "DDD0F7BCCADADAA31A67652259CE569A271DD85CF66C3D6A7E9FAED61F38D219"
+ }
+ )
+ .SetPersonalizationString("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F6061626364656667"),
+ new DrbgTestVector(
+ new AesFastEngine(), 192,
+ new Bit320EntropyProvider().Get(320),
+ true,
+ "202122232425262728292A2B",
+ 192,
+ new string[]
+ {
+ "F780D4A2C25CF8EE7407D948EC0B724A4235D8B20E65081392755CA7912AD7C0",
+ "BA14617F915BA964CB79276BDADC840C14B631BBD1A59097054FA6DFF863B238"
+ }
+ )
+ .SetPersonalizationString("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F6061626364656667"),
+ new DrbgTestVector(
+ new AesFastEngine(), 256,
+ new Bit384EntropyProvider().Get(384),
+ false,
+ "202122232425262728292A2B2C2D2E2F",
+ 256,
+ new string[]
+ {
+ "47111E146562E9AA2FB2A1B095D37A8165AF8FC7CA611D632BE7D4C145C83900",
+ "98A28E3B1BA363C9DAF0F6887A1CF52B833D3354D77A7C10837DD63DD2E645F8"
+ }
+ )
+ .SetPersonalizationString("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F")
+ .AddAdditionalInput("606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F")
+ .AddAdditionalInput("A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECF"),
+ new DrbgTestVector(
+ new AesFastEngine(), 256,
+ new Bit384EntropyProvider().Get(384),
+ true,
+ "202122232425262728292A2B2C2D2E2F",
+ 256,
+ new string[]
+ {
+ "71BB3F9C9CEAF4E6C92A83EB4C7225010EE150AC75E23F5F77AD5073EF24D88A",
+ "386DEBBBF091BBF0502957B0329938FB836B82E594A2F5FDD5EB28D4E35528F4"
+ }
+ )
+ .AddAdditionalInput("606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F")
+ .AddAdditionalInput("A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECF"),
+ new DrbgTestVector(
+ new AesFastEngine(), 256,
+ new Bit384EntropyProvider().Get(384),
+ true,
+ "202122232425262728292A2B2C2D2E2F",
+ 256,
+ new string[]
+ {
+ "1A2E3FEE9056E98D375525FDC2B63B95B47CE51FCF594D804BD5A17F2E01139B",
+ "601F95384F0D85946301D1EACE8F645A825CE38F1E2565B0C0C439448E9CA8AC"
+ }
+ )
+ .SetPersonalizationString("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F"),
+ new DrbgTestVector(
+ new AesFastEngine(), 256,
+ new Bit384EntropyProvider().Get(384),
+ true,
+ "202122232425262728292A2B2C2D2E2F",
+ 256,
+ new string[]
+ {
+ "EAE6BCE781807E524D26605EA198077932D01EEB445B9AC6C5D99C101D29F46E",
+ "738E99C95AF59519AAD37FF3D5180986ADEBAB6E95836725097E50A8D1D0BD28"
+ }
+ )
+ .SetPersonalizationString("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F")
+ .AddAdditionalInput("606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F")
+ .AddAdditionalInput("A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECF"),
+ new DrbgTestVector(
+ new AesFastEngine(), 256,
+ new Bit384EntropyProvider().Get(384),
+ true,
+ "202122232425262728292A2B2C2D2E2F",
+ 256,
+ new string[]
+ {
+ "eae6bce781807e524d26605ea198077932d01eeb445b9ac6c5d99c101d29f46e30b27377",
+ "ec51b55b49904c3ff9e13939f1cf27398993e1b3acb2b0be0be8761261428f0aa8ba2657"
+ }
+ )
+ .SetPersonalizationString("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F")
+ .AddAdditionalInput("606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F")
+ .AddAdditionalInput("A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECF")
+ };
+ }
+
+ public override void PerformTest()
+ {
+ DrbgTestVector[] tests = CreateTestVectorData();
+ ISP80090Drbg d;
+ DrbgTestVector tv;
+ byte[] output;
+
+ for (int i = 0; i != tests.Length; i++)
+ {
+ tv = tests[i];
+
+ byte[] nonce = tv.GetNonce();
+ byte[] personalisationString = tv.GetPersonalizationString();
+
+ d = new CtrSP800Drbg(tv.Cipher, tv.KeySizeInBits, tv.SecurityStrength, tv.EntropySource, personalisationString, nonce);
+
+ output = new byte[tv.GetExpectedValue(0).Length];
+
+ d.Generate(output, tv.GetAdditionalInput(0), tv.PredictionResistance);
+
+ byte[] expected = tv.GetExpectedValue(0);
+
+ if (!AreEqual(expected, output))
+ {
+ Fail("Test #" + (i + 1) + ".1 failed, expected " + Hex.ToHexString(tv.GetExpectedValue(0)) + " got " + Hex.ToHexString(output));
+ }
+
+ output = new byte[tv.GetExpectedValue(0).Length];
+
+ d.Generate(output, tv.GetAdditionalInput(1), tv.PredictionResistance);
+
+ expected = tv.GetExpectedValue(1);
+ if (!AreEqual(expected, output))
+ {
+ Fail("Test #" + (i + 1) + ".2 failed, expected " + Hex.ToHexString(tv.GetExpectedValue(1)) + " got " + Hex.ToHexString(output));
+ }
+ }
+
+ // DESede/TDEA key parity test
+ tv = tests[0];
+
+ ISP80090Drbg drbg = new CtrSP800Drbg(new KeyParityCipher(tv.Cipher), tv.KeySizeInBits, tv.SecurityStrength, tv.EntropySource,
+ tv.GetPersonalizationString(), tv.GetNonce());
+
+ output = new byte[tv.GetExpectedValue(0).Length];
+
+ drbg.Generate(output, tv.GetAdditionalInput(0), tv.PredictionResistance);
+
+ // Exception tests
+ try
+ {
+ d = new CtrSP800Drbg(new AesEngine(), 256, 256, new Bit232EntropyProvider().Get(128), null, null);
+ Fail("no exception thrown");
+ }
+ catch (ArgumentException e)
+ {
+ if (!e.Message.Equals("Not enough entropy for security strength required"))
+ {
+ Fail("Wrong exception", e);
+ }
+ }
+
+ try
+ {
+ d = new CtrSP800Drbg(new DesEdeEngine(), 256, 256, new Bit232EntropyProvider().Get(232), null, null);
+ Fail("no exception thrown");
+ }
+ catch (ArgumentException e)
+ {
+ if (!e.Message.Equals("Requested security strength is not supported by block cipher and key size"))
+ {
+ Fail("Wrong exception", e);
+ }
+ }
+
+ try
+ {
+ d = new CtrSP800Drbg(new DesEdeEngine(), 168, 256, new Bit232EntropyProvider().Get(232), null, null);
+ Fail("no exception thrown");
+ }
+ catch (ArgumentException e)
+ {
+ if (!e.Message.Equals("Requested security strength is not supported by block cipher and key size"))
+ {
+ Fail("Wrong exception", e);
+ }
+ }
+
+ try
+ {
+ d = new CtrSP800Drbg(new AesEngine(), 192, 256, new Bit232EntropyProvider().Get(232), null, null);
+ Fail("no exception thrown");
+ }
+ catch (ArgumentException e)
+ {
+ if (!e.Message.Equals("Requested security strength is not supported by block cipher and key size"))
+ {
+ Fail("Wrong exception", e);
+ }
+ }
+ }
+
+ internal class Bit232EntropyProvider : TestEntropySourceProvider
+ {
+ internal Bit232EntropyProvider() : base(Hex.Decode(
+ "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C" +
+ "808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C" +
+ "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDC"), true)
+ { }
+ }
+
+ internal class Bit256EntropyProvider : TestEntropySourceProvider
+ {
+ internal Bit256EntropyProvider(): base(Hex.Decode(
+ "0001020304050607" +
+ "08090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F" +
+ "8081828384858687" +
+ "88898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F" +
+ "C0C1C2C3C4C5C6C7" +
+ "C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF"), true)
+ { }
+ }
+
+ internal class Bit320EntropyProvider : TestEntropySourceProvider
+ {
+ internal Bit320EntropyProvider() : base(Hex.Decode(
+ "000102030405060708090A0B0C0D0E0F" +
+ "101112131415161718191A1B1C1D1E1F2021222324252627" +
+ "808182838485868788898A8B8C8D8E8F" +
+ "909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7" +
+ "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF" +
+ "D0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7"), true)
+ { }
+ }
+
+ internal class Bit384EntropyProvider : TestEntropySourceProvider
+ {
+ internal Bit384EntropyProvider() : base(Hex.Decode(
+ "000102030405060708090A0B0C0D0E0F1011121314151617" +
+ "18191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F" +
+ "808182838485868788898A8B8C8D8E8F9091929394959697" +
+ "98999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAF" +
+ "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7" +
+ "D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF"), true)
+ { }
+ }
+
+ internal class KeyParityCipher : IBlockCipher
+ {
+ private IBlockCipher cipher;
+
+ internal KeyParityCipher(IBlockCipher cipher)
+ {
+ this.cipher = cipher;
+ }
+
+ public void Init(bool forEncryption, ICipherParameters parameters)
+ {
+ byte[] k = Arrays.Clone(((KeyParameter)parameters).GetKey());
+
+ DesEdeParameters.SetOddParity(k);
+
+ if (!Arrays.AreEqual(((KeyParameter)parameters).GetKey(), k))
+ {
+ throw new ArgumentException("key not odd parity");
+ }
+
+ cipher.Init(forEncryption, parameters);
+ }
+
+ public String AlgorithmName
+ {
+ get { return cipher.AlgorithmName; }
+ }
+
+ public bool IsPartialBlockOkay
+ {
+ get { return false; }
+ }
+
+ public int GetBlockSize()
+ {
+ return cipher.GetBlockSize();
+ }
+
+ public int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
+ {
+ return cipher.ProcessBlock(input, inOff, output, outOff);
+ }
+
+ public void Reset()
+ {
+ cipher.Reset();
+ }
+ }
+ }
+}
diff --git a/crypto/test/src/crypto/prng/test/DrbgTestVector.cs b/crypto/test/src/crypto/prng/test/DrbgTestVector.cs
new file mode 100644
index 000000000..e0a8eeaf5
--- /dev/null
+++ b/crypto/test/src/crypto/prng/test/DrbgTestVector.cs
@@ -0,0 +1,111 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Crypto.Prng.Test
+{
+ public class DrbgTestVector
+ {
+ private IDigest _digest;
+ private IBlockCipher _cipher;
+ private int _keySizeInBits;
+ private IEntropySource _eSource;
+ private bool _pr;
+ private string _nonce;
+ private string _personalisation;
+ private int _ss;
+ private String[] _ev;
+ private IList _ai = new ArrayList();
+
+ public DrbgTestVector(IDigest digest, IEntropySource eSource, bool predictionResistance, string nonce,
+ int securityStrength, string[] expected)
+ {
+ _digest = digest;
+ _eSource = eSource;
+ _pr = predictionResistance;
+ _nonce = nonce;
+ _ss = securityStrength;
+ _ev = expected;
+ _personalisation = null;
+ }
+
+ public DrbgTestVector(IBlockCipher cipher, int keySizeInBits, IEntropySource eSource, bool predictionResistance,
+ string nonce, int securityStrength, string[] expected)
+ {
+ _cipher = cipher;
+ _keySizeInBits = keySizeInBits;
+ _eSource = eSource;
+ _pr = predictionResistance;
+ _nonce = nonce;
+ _ss = securityStrength;
+ _ev = expected;
+ _personalisation = null;
+ }
+
+ public IDigest Digest
+ {
+ get { return _digest; }
+ }
+
+ public IBlockCipher Cipher
+ {
+ get { return _cipher; }
+ }
+
+ public int KeySizeInBits
+ {
+ get { return _keySizeInBits; }
+ }
+
+ public DrbgTestVector AddAdditionalInput(string input)
+ {
+ _ai.Add(input);
+ return this;
+ }
+
+ public DrbgTestVector SetPersonalizationString(string p)
+ {
+ _personalisation = p;
+ return this;
+ }
+
+ public IEntropySource EntropySource
+ {
+ get { return _eSource; }
+ }
+
+ public bool PredictionResistance
+ {
+ get { return _pr; }
+ }
+
+ public byte[] GetNonce()
+ {
+ return _nonce == null ? null : Hex.Decode(_nonce);
+ }
+
+ public byte[] GetPersonalizationString()
+ {
+ return _personalisation == null ? null : Hex.Decode(_personalisation);
+ }
+
+ public int SecurityStrength
+ {
+ get { return _ss; }
+ }
+
+ public byte[] GetExpectedValue(int index)
+ {
+ return Hex.Decode(_ev[index]);
+ }
+
+ public byte[] GetAdditionalInput(int position)
+ {
+ if (position >= _ai.Count)
+ return null;
+
+ return Hex.Decode((string)_ai[position]);
+ }
+ }
+}
diff --git a/crypto/test/src/crypto/prng/test/HMacDrbgTest.cs b/crypto/test/src/crypto/prng/test/HMacDrbgTest.cs
new file mode 100644
index 000000000..a5ca30836
--- /dev/null
+++ b/crypto/test/src/crypto/prng/test/HMacDrbgTest.cs
@@ -0,0 +1,524 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Crypto.Prng.Drbg;
+using Org.BouncyCastle.Utilities.Test;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Crypto.Prng.Test
+{
+ /**
+ * HMAC SP800-90 DRBG
+ */
+ [TestFixture]
+ public class HMacDrbgTest
+ : SimpleTest
+ {
+ public override string Name
+ {
+ get { return "HMacDRBG"; }
+ }
+
+ public static void Main(string[] args)
+ {
+ RunTest(new HMacDrbgTest());
+ }
+
+ [Test]
+ public void TestFunction()
+ {
+ string resultText = Perform().ToString();
+
+ Assert.AreEqual(Name + ": Okay", resultText);
+ }
+
+ private DrbgTestVector[] CreateTestVectorData()
+ {
+ return new DrbgTestVector[]
+ {
+ new DrbgTestVector(
+ new Sha1Digest(),
+ new SHA1EntropyProvider().Get(440),
+ false,
+ "2021222324",
+ 80,
+ new string[]
+ {
+ "5A7D3B449F481CB38DF79AD2B1FCC01E57F8135E8C0B22CD0630BFB0127FB5408C8EFC17A929896E",
+ "82cf772ec3e84b00fc74f5df104efbfb2428554e9ce367d03aeade37827fa8e9cb6a08196115d948"
+ }),
+ new DrbgTestVector(
+ new Sha1Digest(),
+ new SHA1EntropyProvider().Get(440),
+ false,
+ "2021222324",
+ 80,
+ new string[]
+ {
+ "B3BD05246CBA12A64735A4E3FDE599BC1BE30F439BD060208EEA7D71F9D123DF47B3CE069D98EDE6",
+ "B5DADA380E2872DF935BCA55B882C8C9376902AB639765472B71ACEBE2EA8B1B6B49629CB67317E0"
+ })
+ .SetPersonalizationString("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F70717273747576"),
+ new DrbgTestVector(
+ new Sha1Digest(),
+ new SHA1EntropyProvider().Get(440),
+ false,
+ "2021222324",
+ 80,
+ new string[]
+ {
+ "C7AAAC583C6EF6300714C2CC5D06C148CFFB40449AD0BB26FAC0497B5C57E161E36681BCC930CE80",
+ "6EBD2B7B5E0A2AD7A24B1BF9A1DBA47D43271719B9C37B7FE81BA94045A14A7CB514B446666EA5A7"
+ })
+ .AddAdditionalInput("606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F90919293949596")
+ .AddAdditionalInput("A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6"),
+ new DrbgTestVector(
+ new Sha1Digest(),
+ new SHA1EntropyProvider().Get(440),
+ true,
+ "2021222324",
+ 80,
+ new string[]
+ {
+ "FEC4597F06A3A8CC8529D59557B9E661053809C0BC0EFC282ABD87605CC90CBA9B8633DCB1DAE02E",
+ "84ADD5E2D2041C01723A4DE4335B13EFDF16B0E51A0AD39BD15E862E644F31E4A2D7D843E57C5968"
+ }),
+ new DrbgTestVector(
+ new Sha1Digest(),
+ new SHA1EntropyProvider().Get(440),
+ true,
+ "2021222324",
+ 80,
+ new string[]
+ {
+ "6C37FDD729AA40F80BC6AB08CA7CC649794F6998B57081E4220F22C5C283E2C91B8E305AB869C625",
+ "CAF57DCFEA393B9236BF691FA456FEA7FDF1DF8361482CA54D5FA723F4C88B4FA504BF03277FA783"
+ })
+ .SetPersonalizationString("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F70717273747576"),
+ new DrbgTestVector(
+ new Sha1Digest(),
+ new SHA1EntropyProvider().Get(440),
+ true,
+ "2021222324",
+ 80,
+ new string[]
+ {
+ "A1BA8FA58BB5013F43F7B6ED52B4539FA16DC77957AEE815B9C07004C7E992EB8C7E591964AFEEA2",
+ "84264A73A818C95C2F424B37D3CC990B046FB50C2DC64A164211889A010F2471A0912FFEA1BF0195"
+ })
+ .AddAdditionalInput("606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F90919293949596")
+ .AddAdditionalInput("A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6"),
+ new DrbgTestVector(
+ new Sha256Digest(),
+ new SHA256EntropyProvider().Get(440),
+ false,
+ "2021222324252627",
+ 128,
+ new string[]
+ {
+ "D67B8C1734F46FA3F763CF57C6F9F4F2" +
+ "DC1089BD8BC1F6F023950BFC5617635208C8501238AD7A44" +
+ "00DEFEE46C640B61AF77C2D1A3BFAA90EDE5D207406E5403",
+ "8FDAEC20F8B421407059E3588920DA7E" +
+ "DA9DCE3CF8274DFA1C59C108C1D0AA9B0FA38DA5C792037C" +
+ "4D33CD070CA7CD0C5608DBA8B885654639DE2187B74CB263"
+ }),
+ new DrbgTestVector(
+ new Sha256Digest(),
+ new SHA256EntropyProvider().Get(440),
+ true,
+ "2021222324252627",
+ 128,
+ new string[]
+ {
+ "FABD0AE25C69DC2EFDEFB7F20C5A31B5" +
+ "7AC938AB771AA19BF8F5F1468F665C938C9A1A5DF0628A56" +
+ "90F15A1AD8A613F31BBD65EEAD5457D5D26947F29FE91AA7",
+ "6BD925B0E1C232EFD67CCD84F722E927" +
+ "ECB46AB2B740014777AF14BA0BBF53A45BDBB62B3F7D0B9C" +
+ "8EEAD057C0EC754EF8B53E60A1F434F05946A8B686AFBC7A"
+ }),
+ new DrbgTestVector(
+ new Sha384Digest(),
+ new SHA384EntropyProvider().Get(888),
+ false,
+ "202122232425262728292A2B",
+ 192,
+ new string[]
+ {
+ "03AB8BCE4D1DBBB636C5C5B7E1C58499FEB1C619CDD11D35" +
+ "CD6CF6BB8F20EF27B6F5F9054FF900DB9EBF7BF30ED4DCBB" +
+ "BC8D5B51C965EA226FFEE2CA5AB2EFD00754DC32F357BF7A" +
+ "E42275E0F7704DC44E50A5220AD05AB698A22640AC634829",
+ "B907E77144FD55A54E9BA1A6A0EED0AAC780020C41A15DD8" +
+ "9A6C163830BA1D094E6A17100FF71EE30A96E1EE04D2A966" +
+ "03832A4E404F1966C2B5F4CB61B9927E8D12AC1E1A24CF23" +
+ "88C14E8EC96C35181EAEE32AAA46330DEAAFE5E7CE783C74"
+ })
+ .SetPersonalizationString(
+ "404142434445464748494A4B4C4D4E" +
+ "4F505152535455565758595A5B5C5D5E5F60616263646566" +
+ "6768696A6B6C6D6E6F707172737475767778797A7B7C7D7E" +
+ "7F808182838485868788898A8B8C8D8E8F90919293949596" +
+ "9798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAE"),
+ new DrbgTestVector(
+ new Sha384Digest(),
+ new SHA384EntropyProvider().Get(888),
+ true,
+ "202122232425262728292A2B",
+ 192,
+ new string[]
+ {
+ "804A3AD720F4FCE8738D0632514FEF16430CB7D63A8DF1A5" +
+ "F02A3CE3BD7ED6A668B69E63E2BB93F096EE753D6194A0F1" +
+ "A32711063653009636337D22167CC4402D019AC216FA574F" +
+ "091CF6EA283568D737A77BE38E8F09382C69E76B142ABC3A",
+ "73B8E55C753202176A17B9B9754A9FE6F23B01861FCD4059" +
+ "6AEAA301AF1AEF8AF0EAF22FBF34541EFFAB1431666ACACC" +
+ "759338C7E28672819D53CFEF10A3E19DAFBD53295F1980A9" +
+ "F491504A2725506784B7AC826D92C838A8668171CAAA86E7"
+ })
+ .SetPersonalizationString(
+ "404142434445464748494A4B4C4D4E" +
+ "4F505152535455565758595A5B5C5D5E5F60616263646566" +
+ "6768696A6B6C6D6E6F707172737475767778797A7B7C7D7E" +
+ "7F808182838485868788898A8B8C8D8E8F90919293949596" +
+ "9798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAE"),
+ new DrbgTestVector(
+ new Sha512Digest(),
+ new SHA512EntropyProvider().Get(888),
+ false,
+ "202122232425262728292A2B2C2D2E2F",
+ 256,
+ new string[]
+ {
+ "2A5FF6520C20F66E" +
+ "D5EA431BD4AEAC58F975EEC9A015137D5C94B73AA09CB8B5" +
+ "9D611DDEECEB34A52BB999424009EB9EAC5353F92A6699D2" +
+ "0A02164EEBBC6492941E10426323898465DFD731C7E04730" +
+ "60A5AA8973841FDF3446FB6E72A58DA8BDA2A57A36F3DD98" +
+ "6DF85C8A5C6FF31CDE660BF8A841B21DD6AA9D3AC356B87B",
+ "0EDC8D7D7CEEC7FE" +
+ "36333FB30C0A9A4B27AA0BECBF075568B006C1C3693B1C29" +
+ "0F84769C213F98EB5880909EDF068FDA6BFC43503987BBBD" +
+ "4FC23AFBE982FE4B4B007910CC4874EEC217405421C8D8A1" +
+ "BA87EC684D0AF9A6101D9DB787AE82C3A6A25ED478DF1B12" +
+ "212CEC325466F3AC7C48A56166DD0B119C8673A1A9D54F67"
+ })
+ .SetPersonalizationString(
+ "404142434445464748494A4B4C4D4E" +
+ "4F505152535455565758595A5B5C5D5E5F60616263646566" +
+ "6768696A6B6C6D6E6F707172737475767778797A7B7C7D7E" +
+ "7F808182838485868788898A8B8C8D8E8F90919293949596" +
+ "9798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAE"),
+ new DrbgTestVector(
+ new Sha512Digest(),
+ new SHA512EntropyProvider().Get(888),
+ true,
+ "202122232425262728292A2B2C2D2E2F",
+ 256,
+ new string[]
+ {
+ "AAE4DC3C9ECC74D9" +
+ "061DD527117EF3D29E1E52B26853C539D6CA797E8DA3D0BB" +
+ "171D8E30B8B194D8C28F7F6BE3B986B88506DC6A01B294A7" +
+ "165DD1C3470F7BE7B396AA0DB7D50C4051E7C7E1C8A7D21A" +
+ "2B5878C0BCB163CAA79366E7A1162FDC88429616CD3E6977" +
+ "8D327520A6BBBF71D8AA2E03EC4A9DAA0E77CF93E1EE30D2 ",
+ "129FF6D31A23FFBC" +
+ "870632B35EE477C2280DDD2ECDABEDB900C78418BE2D243B" +
+ "B9D8E5093ECE7B6BF48638D8F704D134ADDEB7F4E9D5C142" +
+ "CD05683E72B516486AF24AEC15D61E81E270DD4EBED91B62" +
+ "12EB8896A6250D5C8BC3A4A12F7E3068FBDF856F47EB23D3" +
+ "79F82C1EBCD1585FB260B9C0C42625FBCEE68CAD773CD5B1"
+ })
+ .SetPersonalizationString(
+ "404142434445464748494A4B4C4D4E" +
+ "4F505152535455565758595A5B5C5D5E5F60616263646566" +
+ "6768696A6B6C6D6E6F707172737475767778797A7B7C7D7E" +
+ "7F808182838485868788898A8B8C8D8E8F90919293949596" +
+ "9798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAE"),
+ new DrbgTestVector(
+ new Sha512Digest(),
+ new SHA512EntropyProvider().Get(888),
+ false,
+ "202122232425262728292A2B2C2D2E2F",
+ 256,
+ new string[]
+ {
+ "7AE31A2DEC31075F" +
+ "E5972660C16D22ECC0D415C5693001BE5A468B590BC1AE2C" +
+ "43F647F8D681AEEA0D87B79B0B4E5D089CA2C9D327534234" +
+ "0254E6B04690D77A71A294DA9568479EEF8BB2A2110F18B6" +
+ "22F60F35235DE0E8F9D7E98105D84AA24AF0757AF005DFD5" +
+ "2FA51DE3F44FCE0C5F3A27FCE8B0F6E4A3F7C7B53CE34A3D",
+ "D83A8084630F286D" +
+ "A4DB49B9F6F608C8993F7F1397EA0D6F4A72CF3EF2733A11" +
+ "AB823C29F2EBDEC3EDE962F93D920A1DB59C84E1E879C29F" +
+ "5F9995FC3A6A3AF9B587CA7C13EA197D423E81E1D6469942" +
+ "B6E2CA83A97E91F6B298266AC148A1809776C26AF5E239A5" +
+ "5A2BEB9E752203A694E1F3FE2B3E6A0C9C314421CDB55FBD "
+ })
+ .SetPersonalizationString(
+ "404142434445464748494A4B4C4D4E" +
+ "4F505152535455565758595A5B5C5D5E5F60616263646566" +
+ "6768696A6B6C6D6E6F707172737475767778797A7B7C7D7E" +
+ "7F808182838485868788898A8B8C8D8E8F90919293949596" +
+ "9798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAE")
+ .AddAdditionalInput(
+ "606162636465666768696A6B6C6D6E" +
+ "6F707172737475767778797A7B7C7D7E7F80818283848586" +
+ "8788898A8B8C8D8E8F909192939495969798999A9B9C9D9E" +
+ "9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6" +
+ "B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCE")
+ .AddAdditionalInput(
+ "A0A1A2A3A4A5A6A7A8A9AAABACADAE" +
+ "AFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6" +
+ "C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDE" +
+ "DFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6" +
+ "F7F8F9FAFBFCFDFEFF000102030405060708090A0B0C0D0E"),
+ new DrbgTestVector(
+ new Sha512Digest(),
+ new SHA512EntropyProvider().Get(888),
+ true,
+ "202122232425262728292A2B2C2D2E2F",
+ 256,
+ new string[]
+ {
+ "28FD6060C4F35F4D" +
+ "317AB2060EE32019E0DAA330F3F5650BBCA57CB67EE6AF1C" +
+ "6F25D1B01F3601EDA85DC2ED29A9B2BA4C85CF491CE7185F" +
+ "1A2BD9378AE3C655BD1CEC2EE108AE7FC382989F6D4FEA8A" +
+ "B01499697C2F07945CE02C5ED617D04287FEAF3BA638A4CE" +
+ "F3BB6B827E40AF16279580FCF1FDAD830930F7FDE341E2AF",
+ "C0B1601AFE39338B" +
+ "58DC2BE7C256AEBE3C21C5A939BEEC7E97B3528AC420F0C6" +
+ "341847187666E0FF578A8EB0A37809F877365A28DF2FA0F0" +
+ "6354A6F02496747369375B9A9D6B756FDC4A8FB308E08256" +
+ "9D79A85BB960F747256626389A3B45B0ABE7ECBC39D5CD7B" +
+ "2C18DF2E5FDE8C9B8D43474C54B6F9839468445929B438C7"
+ }),
+ new DrbgTestVector(
+ new Sha512Digest(),
+ new SHA512EntropyProvider().Get(888),
+ true,
+ "202122232425262728292A2B2C2D2E2F",
+ 256,
+ new string[]
+ {
+ "72691D2103FB567C" +
+ "CD30370715B36666F63430087B1C688281CA0974DB456BDB" +
+ "A7EB5C48CFF62EA05F9508F3B530CE995A272B11EC079C13" +
+ "923EEF8E011A93C19B58CC6716BC7CB8BD886CAA60C14D85" +
+ "C023348BD77738C475D6C7E1D9BFF4B12C43D8CC73F838DC" +
+ "4F8BD476CF8328EEB71B3D873D6B7B859C9B21065638FF95",
+ "8570DA3D47E1E160" +
+ "5CF3E44B8D328B995EFC64107B6292D1B1036B5F88CE3160" +
+ "2F12BEB71D801C0942E7C0864B3DB67A9356DB203490D881" +
+ "24FE86BCE38AC2269B4FDA6ABAA884039DF80A0336A24D79" +
+ "1EB3067C8F5F0CF0F18DD73B66A7B316FB19E02835CC6293" +
+ "65FCD1D3BE640178ED9093B91B36E1D68135F2785BFF505C"
+ })
+ .AddAdditionalInput(
+ "606162636465666768696A6B6C6D6E" +
+ "6F707172737475767778797A7B7C7D7E7F80818283848586" +
+ "8788898A8B8C8D8E8F909192939495969798999A9B9C9D9E" +
+ "9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6" +
+ "B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCE")
+ .AddAdditionalInput(
+ "A0A1A2A3A4A5A6A7A8A9AAABACADAE" +
+ "AFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6" +
+ "C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDE" +
+ "DFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6" +
+ "F7F8F9FAFBFCFDFEFF000102030405060708090A0B0C0D0E"),
+ new DrbgTestVector(
+ new Sha512Digest(),
+ new SHA512EntropyProvider().Get(888),
+ true,
+ "202122232425262728292A2B2C2D2E2F",
+ 256,
+ new string[]
+ {
+ "AAE4DC3C9ECC74D9" +
+ "061DD527117EF3D29E1E52B26853C539D6CA797E8DA3D0BB" +
+ "171D8E30B8B194D8C28F7F6BE3B986B88506DC6A01B294A7" +
+ "165DD1C3470F7BE7B396AA0DB7D50C4051E7C7E1C8A7D21A" +
+ "2B5878C0BCB163CAA79366E7A1162FDC88429616CD3E6977" +
+ "8D327520A6BBBF71D8AA2E03EC4A9DAA0E77CF93E1EE30D2 ",
+ "129FF6D31A23FFBC" +
+ "870632B35EE477C2280DDD2ECDABEDB900C78418BE2D243B" +
+ "B9D8E5093ECE7B6BF48638D8F704D134ADDEB7F4E9D5C142" +
+ "CD05683E72B516486AF24AEC15D61E81E270DD4EBED91B62" +
+ "12EB8896A6250D5C8BC3A4A12F7E3068FBDF856F47EB23D3" +
+ "79F82C1EBCD1585FB260B9C0C42625FBCEE68CAD773CD5B1"
+ })
+ .SetPersonalizationString(
+ "404142434445464748494A4B4C4D4E" +
+ "4F505152535455565758595A5B5C5D5E5F60616263646566" +
+ "6768696A6B6C6D6E6F707172737475767778797A7B7C7D7E" +
+ "7F808182838485868788898A8B8C8D8E8F90919293949596" +
+ "9798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAE"),
+ new DrbgTestVector(
+ new Sha512Digest(),
+ new SHA512EntropyProvider().Get(888),
+ true,
+ "202122232425262728292A2B2C2D2E2F",
+ 256,
+ new string[]
+ {
+ "B8E827652175E6E0" +
+ "6E513C7BE94B5810C14ED94AD903647940CAEB7EE014C848" +
+ "8DCBBE6D4D6616D06656A3DC707CDAC4F02EE6D8408C065F" +
+ "CB068C0760DA47C5D60E5D70D09DC3929B6979615D117F7B" +
+ "EDCC661A98514B3A1F55B2CBABDCA59F11823E4838065F1F" +
+ "8431CBF28A577738234AF3F188C7190CC19739E72E9BBFFF",
+ "7ED41B9CFDC8C256" +
+ "83BBB4C553CC2DC61F690E62ABC9F038A16B8C519690CABE" +
+ "BD1B5C196C57CF759BB9871BE0C163A57315EA96F615136D" +
+ "064572F09F26D659D24211F9610FFCDFFDA8CE23FFA96735" +
+ "7595182660877766035EED800B05364CE324A75EB63FD9B3" +
+ "EED956D147480B1D0A42DF8AA990BB628666F6F61D60CBE2"
+ })
+ .SetPersonalizationString(
+ "404142434445464748494A4B4C4D4E" +
+ "4F505152535455565758595A5B5C5D5E5F60616263646566" +
+ "6768696A6B6C6D6E6F707172737475767778797A7B7C7D7E" +
+ "7F808182838485868788898A8B8C8D8E8F90919293949596" +
+ "9798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAE")
+ .AddAdditionalInput(
+ "606162636465666768696A6B6C6D6E" +
+ "6F707172737475767778797A7B7C7D7E7F80818283848586" +
+ "8788898A8B8C8D8E8F909192939495969798999A9B9C9D9E" +
+ "9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6" +
+ "B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCE")
+ .AddAdditionalInput(
+ "A0A1A2A3A4A5A6A7A8A9AAABACADAE" +
+ "AFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6" +
+ "C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDE" +
+ "DFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6" +
+ "F7F8F9FAFBFCFDFEFF000102030405060708090A0B0C0D0E")
+ };
+ }
+
+ public override void PerformTest()
+ {
+ DrbgTestVector[] tests = CreateTestVectorData();
+ ISP80090Drbg d;
+
+ for (int i = 0; i != tests.Length; i++)
+ {
+ DrbgTestVector tv = tests[i];
+
+ byte[] nonce = tv.GetNonce();
+ byte[] personalisationString = tv.GetPersonalizationString();
+
+ d = new HMacSP800Drbg(new HMac(tv.Digest), tv.SecurityStrength, tv.EntropySource, personalisationString, nonce);
+
+ byte[] output = new byte[tv.GetExpectedValue(0).Length];
+
+ d.Generate(output, tv.GetAdditionalInput(0), tv.PredictionResistance);
+
+ byte[] expected = tv.GetExpectedValue(0);
+
+ if (!AreEqual(expected, output))
+ {
+ Fail("Test #" + (i + 1) + ".1 failed, expected " + Hex.ToHexString(tv.GetExpectedValue(0)) + " got " + Hex.ToHexString(output));
+ }
+
+ output = new byte[tv.GetExpectedValue(0).Length];
+
+ d.Generate(output, tv.GetAdditionalInput(1), tv.PredictionResistance);
+
+ expected = tv.GetExpectedValue(1);
+ if (!AreEqual(expected, output))
+ {
+ Fail("Test #" + (i + 1) + ".2 failed, expected " + Hex.ToHexString(tv.GetExpectedValue(1)) + " got " + Hex.ToHexString(output));
+ }
+ }
+
+ // Exception tests
+ //
+ try
+ {
+ d = new HMacSP800Drbg(new HMac(new Sha256Digest()), 256, new SHA256EntropyProvider().Get(128), null, null);
+ Fail("no exception thrown");
+ }
+ catch (ArgumentException e)
+ {
+ if (!e.Message.Equals("Not enough entropy for security strength required"))
+ {
+ Fail("Wrong exception", e);
+ }
+ }
+ }
+
+ private class SHA1EntropyProvider : TestEntropySourceProvider
+ {
+ internal SHA1EntropyProvider() : base(Hex.Decode(
+ "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F30313233343536" +
+ "808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6" +
+ "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6"), true)
+ {
+ }
+ }
+
+ internal class SHA256EntropyProvider : TestEntropySourceProvider
+ {
+ internal SHA256EntropyProvider() : base(Hex.Decode(
+ "00010203040506" +
+ "0708090A0B0C0D0E0F101112131415161718191A1B1C1D1E" +
+ "1F202122232425262728292A2B2C2D2E2F30313233343536" +
+ "80818283848586" +
+ "8788898A8B8C8D8E8F909192939495969798999A9B9C9D9E" +
+ "9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6" +
+ "C0C1C2C3C4C5C6" +
+ "C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDE" +
+ "DFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6"), true)
+ {
+ }
+ }
+
+ internal class SHA384EntropyProvider : TestEntropySourceProvider
+ {
+ internal SHA384EntropyProvider() : base(Hex.Decode(
+ "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F20212223242526" +
+ "2728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F50515253545556" +
+ "5758595A5B5C5D5E5F606162636465666768696A6B6C6D6E" +
+ "808182838485868788898A8B8C8D8E" +
+ "8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6" +
+ "A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBE" +
+ "BFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6" +
+ "D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEE" +
+ "C0C1C2C3C4C5C6C7C8C9CACBCCCDCE" +
+ "CFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6" +
+ "E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFE" +
+ "FF000102030405060708090A0B0C0D0E0F10111213141516" +
+ "1718191A1B1C1D1E1F202122232425262728292A2B2C2D2E"), true)
+ { }
+ }
+
+ internal class SHA512EntropyProvider : TestEntropySourceProvider
+ {
+ internal SHA512EntropyProvider() : base(Hex.Decode(
+ "000102030405060708090A0B0C0D0E" +
+ "0F101112131415161718191A1B1C1D1E1F20212223242526" +
+ "2728292A2B2C2D2E2F303132333435363738393A3B3C3D3E" +
+ "3F404142434445464748494A4B4C4D4E4F50515253545556" +
+ "5758595A5B5C5D5E5F606162636465666768696A6B6C6D6E" +
+ "808182838485868788898A8B8C8D8E" +
+ "8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6" +
+ "A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBE" +
+ "BFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6" +
+ "D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEE" +
+ "C0C1C2C3C4C5C6C7C8C9CACBCCCDCE" +
+ "CFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6" +
+ "E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFE" +
+ "FF000102030405060708090A0B0C0D0E0F10111213141516" +
+ "1718191A1B1C1D1E1F202122232425262728292A2B2C2D2E"), true)
+ { }
+ }
+ }
+}
diff --git a/crypto/test/src/crypto/prng/test/HashDrbgTest.cs b/crypto/test/src/crypto/prng/test/HashDrbgTest.cs
new file mode 100644
index 000000000..892ca74da
--- /dev/null
+++ b/crypto/test/src/crypto/prng/test/HashDrbgTest.cs
@@ -0,0 +1,477 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Prng.Drbg;
+using Org.BouncyCastle.Utilities.Test;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Crypto.Prng.Test
+{
+ /**
+ * DRBG Test
+ */
+ [TestFixture]
+ public class HashDrbgTest
+ : SimpleTest
+ {
+ public override string Name
+ {
+ get { return "HashDRBG"; }
+ }
+
+ public static void Main(string[] args)
+ {
+ RunTest(new HashDrbgTest());
+ }
+
+ [Test]
+ public void TestFunction()
+ {
+ string resultText = Perform().ToString();
+
+ Assert.AreEqual(Name + ": Okay", resultText);
+ }
+
+ private DrbgTestVector[] CreateTestVectorData()
+ {
+ return new DrbgTestVector[]
+ {
+ new DrbgTestVector(
+ new Sha1Digest(),
+ new SHA1EntropyProvider().Get(440),
+ false,
+ "2021222324",
+ 80,
+ new string[]
+ {
+ "9F7CFF1ECA23E750F66326969F11800F12088BA68E441D15D888B3FE12BF66FE057494F4546DE2F1",
+ "B77AA5C0CD55BBCEED7574AF223AFD988C7EEC8EFF4A94E5E89D26A04F58FA79F5E0D3702D7A9A6A"
+ }
+ ),
+ new DrbgTestVector(
+ new Sha1Digest(),
+ new SHA1EntropyProvider().Get(440),
+ false,
+ "2021222324",
+ 80,
+ new string[]
+ {
+ "AB438BD3B01A0AF85CFEE29F7D7B71621C4908B909124D430E7B406FB1086EA994C582E0D656D989",
+ "29D9098F987E7005314A0F51B3DD2B8122F4AED706735DE6AD5DDBF223177C1E5F3AEBC52FAB90B9"
+ })
+ .SetPersonalizationString("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F70717273747576"),
+ new DrbgTestVector(
+ new Sha1Digest(),
+ new SHA1EntropyProvider().Get(440),
+ false,
+ "2021222324",
+ 80,
+ new string[]
+ {
+ "E76B4EDD5C865BC8AFD809A59B69B429AC7F4352A579BCF3F75E56249A3491F87C3CA6848B0FAB25",
+ "6577B6B4F87A93240B199FE51A3B335313683103DECE171E3256FB7E803586CA4E45DD242EB01F70"
+ })
+ .AddAdditionalInput("606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F90919293949596")
+ .AddAdditionalInput("A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6"),
+ new DrbgTestVector(
+ new Sha1Digest(),
+ new SHA1EntropyProvider().Get(440),
+ true,
+ "2021222324",
+ 80,
+ new string[]
+ {
+ "56EF4913373994D5539F4D7D17AFE7448CDF5E72416CC6A71A340059FA0D5AE526B23250C46C0944",
+ "575B37A2739814F966C63B60A2C4F149CA9ACC84FC4B25493289B085C67B2E30F5F0B99A2C349E2A"
+ }),
+ new DrbgTestVector(
+ new Sha1Digest(),
+ new SHA1EntropyProvider().Get(440),
+ true,
+ "2021222324",
+ 80,
+ new string[]
+ {
+ "532CA1165DCFF21C55592687639884AF4BC4B057DF8F41DE653AB44E2ADEC7C9303E75ABE277EDBF",
+ "73C2C67C696D686D0C4DBCEB5C2AF7DDF6F020B6874FAE4390F102117ECAAFF54418529A367005A0"
+ })
+ .SetPersonalizationString("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F70717273747576"),
+ new DrbgTestVector(
+ new Sha1Digest(),
+ new SHA1EntropyProvider().Get(440),
+ true,
+ "2021222324",
+ 80,
+ new string[]
+ {
+ "183C242A1430E46C4ED70B4DBE1BF9AB0AB8721CDCA2A2D1820AD6F6C956858543B2AA191D8D1287",
+ "F196F9BD021C745CBD5AC7BFCE48EAAF0D0E7C091FBF436940E63A198EE770D9A4F0718669AF2BC9"
+ })
+ .AddAdditionalInput("606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F90919293949596")
+ .AddAdditionalInput("A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6"),
+ new DrbgTestVector(
+ new Sha256Digest(),
+ new SHA256EntropyProvider().Get(440),
+ false,
+ "2021222324252627",
+ 128,
+ new string[]
+ {
+ "77E05A0E7DC78AB5D8934D5E93E82C06" +
+ "A07C04CEE6C9C53045EEB485872777CF3B3E35C474F976B8" +
+ "94BF301A86FA651F463970E89D4A0534B2ECAD29EC044E7E",
+ "5FF4BA493C40CFFF3B01E472C575668C" +
+ "CE3880B9290B05BFEDE5EC96ED5E9B2898508B09BC800EEE" +
+ "099A3C90602ABD4B1D4F343D497C6055C87BB956D53BF351"
+ }
+ ),
+ new DrbgTestVector(
+ new Sha256Digest(),
+ new SHA256EntropyProvider().Get(440),
+ true,
+ "2021222324252627",
+ 128,
+ new string[]
+ {
+ "92275523C70E567BCF9B35EC50B933F8" +
+ "12616DF586B7F72EE1BC7735A5C2654373CBBC72316DFF84" +
+ "20A33BF02B97AC8D1952583F270ACD7005CC027F4CF1187E",
+ "681A46B2AA8694A0FE4DEEA720927A84" +
+ "EAAA985E59C19F8BE0984D8CBEF8C69B754167641946E040" +
+ "EE2043E1CCB29DCF063C0A50830E428E6DCA262ECD77C542"
+ }),
+ new DrbgTestVector(
+ new Sha384Digest(),
+ new SHA384EntropyProvider().Get(888),
+ false,
+ "202122232425262728292A2B",
+ 192,
+ new string[]
+ {
+ "04FF23AD15E78790ADD36B438BBC097C7A11747CC2CCEEDE" +
+ "2C978B23B3DC63B732C953061D7764990ABFEFC47A581B92" +
+ "1BC0428C4F12212460E406A0F0651E7F0CB9A90ABFDB07B5" +
+ "25565C74F0AA085082F6CF213AAFAD0C0646895078F1E1FE",
+ "4F35B85F95DEE3E873054905CFD02341653E18F529930CBE" +
+ "14D909F37FEAF2C790D22FAE7516B4590BE35D53E2FE1A35" +
+ "AFE4B6607CB358589C3B4D094A1D81FE0717F1DF5BDDEB3E" +
+ "114F130BB781E66C22B5B770E8AE115FF39F8ADAF66DEEDF"
+ }
+ ),
+ new DrbgTestVector(
+ new Sha384Digest(),
+ new SHA384EntropyProvider().Get(888),
+ true,
+ "202122232425262728292A2B",
+ 192,
+ new string[]
+ {
+ "97993B78F7C31C0E876DC92EB7D6C408E09D608AD6B99D0E" +
+ "A2229B05A578C426334FCC8A1C7E676ED2D89A5B4CDF5B3F" +
+ "4ADF11936BF14F4E10909DBA9C24F4FDFFDE72351DA8E2CC" +
+ "3B135A395373899E5F1A5955B880CA9B9E9DD4C9CA7FA4D4",
+ "F5983946320E36C64EF283CA1F65D197CF81624EC6778E77" +
+ "0E78949D84EF21A45CDD62D1DB76920D4C2836FC6AE5299F" +
+ "AF1357D9701FAD10FBD88D1E2832239436D76EB271BDC3CA" +
+ "04425EC88BC0E89A4D5C37FFCE7C6C3ABDE9C413AE6D3FEA"
+ }
+ ),
+ new DrbgTestVector(
+ new Sha512Digest(),
+ new SHA512EntropyProvider().Get(888),
+ false,
+ "202122232425262728292A2B2C2D2E2F",
+ 256,
+ new string[]
+ {
+ "DA126CF95C6BF97E" +
+ "2F731F2137A907ACC70FD7AC9EBACD1C6E31C74029B052E3" +
+ "AABC48F3B00993F2B2381F7650A55322A968C86E05DE88E6" +
+ "367F6EF89A601DB4342E9086C7AC13B5E56C32E9E668040B" +
+ "73847893C5BFD38A1CF44F348B4EEE4CD68ADB7E7B8C837F" +
+ "19BC4F902761F7CFF24AB1D704FD11C4E929D8553753B55D",
+ "400B977CE8A2BB6A" +
+ "84C6FD1CF901459685ABF5408CFF4588CEDF52E2D2DC300A" +
+ "A9B4FAED8CD0161C2172B1FD269253195883D6EBF21020F2" +
+ "C20E5F2C81AE60C8595B834A229B1F5B726C1125717E6207" +
+ "8886EF38E61E32707AD5F8116C6393DFB6E7C7AE0E8E92BB" +
+ "D7E0C3D04BBA02F5169F2F569A58158915FEE4C9D28D45DB"
+ }
+ )
+ .SetPersonalizationString(
+ "404142434445464748494A4B4C4D4E" +
+ "4F505152535455565758595A5B5C5D5E5F60616263646566" +
+ "6768696A6B6C6D6E6F707172737475767778797A7B7C7D7E" +
+ "7F808182838485868788898A8B8C8D8E8F90919293949596" +
+ "9798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAE")
+ .AddAdditionalInput(
+ "606162636465666768696A6B6C6D6E" +
+ "6F707172737475767778797A7B7C7D7E7F80818283848586" +
+ "8788898A8B8C8D8E8F909192939495969798999A9B9C9D9E" +
+ "9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6" +
+ "B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCE")
+ .AddAdditionalInput(
+ "A0A1A2A3A4A5A6A7A8A9AAABACADAE" +
+ "AFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6" +
+ "C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDE" +
+ "DFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6" +
+ "F7F8F9FAFBFCFDFEFF000102030405060708090A0B0C0D0E"),
+ new DrbgTestVector(
+ new Sha512Digest(),
+ new SHA512EntropyProvider().Get(888),
+ true,
+ "202122232425262728292A2B2C2D2E2F",
+ 256,
+ new string[]
+ {
+ "F93CA6855590A77F" +
+ "07354097E90E026648B6115DF008FFEDBD9D9811F54E8286" +
+ "EF00FDD6BA1E58DF2535E3FBDD9A9BA3754A97F36EE83322" +
+ "1582060A1F37FCE4EE8826636B28EAD589593F4CA8B64738" +
+ "8F24EB3F0A34796968D21BDEE6F81FD5DF93536F935937B8" +
+ "025EC8CBF57DDB0C61F2E41463CC1516D657DA2829C6BF90",
+ "4817618F48C60FB1" +
+ "CE5BFBDA0CAF4591882A31F6EE3FE0F78779992A06EC60F3" +
+ "7FB9A8D6108C231F0A927754B0599FA4FA27A4E25E065EF0" +
+ "3085B892979DC0E7A1080883CAEBFDFD3665A8F2D061C521" +
+ "F7D6E3DA2AF8B97B6B43B6EC831AF515070A83BBB9AC95ED" +
+ "4EF49B756A2377A5F0833D847E27A88DDB0C2CE4AD782E7B "
+ }
+ ),
+ new DrbgTestVector(
+ new Sha512Digest(),
+ new SHA512EntropyProvider().Get(888),
+ true,
+ "202122232425262728292A2B2C2D2E2F",
+ 256,
+ new string[]
+ {
+ "0455DD4AD7DBACB2" +
+ "410BE58DF7248D765A4547ABAEE1743B0BCAD37EBD06DA7C" +
+ "F7CE5E2216E525327E9E2005EBEF2CE53BD733B18128627D" +
+ "3FD6153089373AF2606A1584646A0EA488BFEF45228699A0" +
+ "89CEA8AEC44502D86D9591F3552C688B7F7B45FCB0C3C2B9" +
+ "43C1CD8A6FC63DF4D81C3DA543C9CF2843855EA84E4F959C",
+ "C047D46D7F614E4E" +
+ "4A7952C79A451F8F7ACA379967E2977C401C626A2ED70D74" +
+ "A63660579A354115BC8C8C8CC3AEA3050686A0CFCDB6FA9C" +
+ "F78D4C2165BAF851C6F9B1CD16A2E14C15C6DAAC56C16E75" +
+ "FC84A14D58B41622E88B0F1B1995587FD8BAA999CBA98025" +
+ "4C8AB9A9691DF7B84D88B639A9A3106DEABEB63748B99C09"
+ }
+ )
+ .AddAdditionalInput(
+ "606162636465666768696A6B6C6D6E" +
+ "6F707172737475767778797A7B7C7D7E7F80818283848586" +
+ "8788898A8B8C8D8E8F909192939495969798999A9B9C9D9E" +
+ "9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6" +
+ "B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCE")
+ .AddAdditionalInput(
+ "A0A1A2A3A4A5A6A7A8A9AAABACADAE" +
+ "AFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6" +
+ "C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDE" +
+ "DFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6" +
+ "F7F8F9FAFBFCFDFEFF000102030405060708090A0B0C0D0E"),
+ new DrbgTestVector(
+ new Sha512Digest(),
+ new SHA512EntropyProvider().Get(888),
+ true,
+ "202122232425262728292A2B2C2D2E2F",
+ 256,
+ new string[]
+ {
+ "22EB93A67911DA73" +
+ "85D9180C78127DE1A04FF713114C07C9C615F7CC5EF72744" +
+ "A2DDCD7C3CB85E65DED8EF5F240FBDCBEBBDE2BAAC8ECF7D" +
+ "CBC8AC333E54607AD41DC495D83DF72A05EF55B127C1441C" +
+ "9A0EFFDA2C7954DB6C2D04342EB812E5E0B11D6C395F41ED" +
+ "A2702ECE5BA479E2DFA18F953097492636C12FE30CE5C968",
+ "E66698CFBF1B3F2E" +
+ "919C03036E584EAA81CF1C6666240AF05F70637043733954" +
+ "D8A1E5A66A04C53C6900FDC145D4A3A80A31F5868ACE9AC9" +
+ "4E14E2051F624A05EEA1F8B684AA5410BCE315E76EA07C71" +
+ "5D6F34731320FF0DCF78D795E6EFA2DF92B98BE636CDFBA2" +
+ "9008DD392112AEC202F2E481CB9D83F987FEA69CD1B368BB"
+ }
+ )
+ .SetPersonalizationString(
+ "404142434445464748494A4B4C4D4E" +
+ "4F505152535455565758595A5B5C5D5E5F60616263646566" +
+ "6768696A6B6C6D6E6F707172737475767778797A7B7C7D7E" +
+ "7F808182838485868788898A8B8C8D8E8F90919293949596" +
+ "9798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAE"),
+ new DrbgTestVector(
+ new Sha512Digest(),
+ new SHA512EntropyProvider().Get(888),
+ true,
+ "202122232425262728292A2B2C2D2E2F",
+ 256,
+ new string[]
+ {
+ "7596A76372308BD5" +
+ "A5613439934678B35521A94D81ABFE63A21ACF61ABB88B61" +
+ "E86A12C37F308F2BBBE32BE4B38D03AE808386494D70EF52" +
+ "E9E1365DD18B7784CAB826F31D47579E4D57F69D8BF3152B" +
+ "95741946CEBE58571DF58ED39980D9AF44E69F01E8989759" +
+ "8E40171101A0E3302838E0AD9E849C01988993CF9F6E5263",
+ "DBE5EE36FCD85301" +
+ "303E1C3617C1AC5E23C08885D0BEFAAD0C85A0D89F85B9F1" +
+ "6ECE3D88A24EB96504F2F13EFA7049621782F5DE2C416A0D" +
+ "294CCFE53545C4E309C48E1E285A2B829A574B72B3C2FBE1" +
+ "34D01E3706B486F2401B9820E17298A342666918E15B8462" +
+ "87F8C5AF2D96B20FAF3D0BB392E15F4A06CDB0DECD1B6AD7"
+ }
+ )
+ .SetPersonalizationString(
+ "404142434445464748494A4B4C4D4E" +
+ "4F505152535455565758595A5B5C5D5E5F60616263646566" +
+ "6768696A6B6C6D6E6F707172737475767778797A7B7C7D7E" +
+ "7F808182838485868788898A8B8C8D8E8F90919293949596" +
+ "9798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAE")
+ .AddAdditionalInput(
+ "606162636465666768696A6B6C6D6E" +
+ "6F707172737475767778797A7B7C7D7E7F80818283848586" +
+ "8788898A8B8C8D8E8F909192939495969798999A9B9C9D9E" +
+ "9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6" +
+ "B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCE")
+ .AddAdditionalInput(
+ "A0A1A2A3A4A5A6A7A8A9AAABACADAE" +
+ "AFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6" +
+ "C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDE" +
+ "DFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6" +
+ "F7F8F9FAFBFCFDFEFF000102030405060708090A0B0C0D0E")
+ };
+ }
+
+ public override void PerformTest()
+ {
+ DrbgTestVector[] tests = CreateTestVectorData();
+ ISP80090Drbg d;
+
+ for (int i = 0; i != tests.Length; i++)
+ {
+ DrbgTestVector tv = tests[i];
+
+ byte[] nonce = tv.GetNonce();
+ byte[] personalisationString = tv.GetPersonalizationString();
+
+ d = new HashSP800Drbg(tv.Digest, tv.SecurityStrength, tv.EntropySource, personalisationString, nonce);
+
+ byte[] output = new byte[tv.GetExpectedValue(0).Length];
+
+ d.Generate(output, tv.GetAdditionalInput(0), tv.PredictionResistance);
+
+ byte[] expected = tv.GetExpectedValue(0);
+
+ if (!AreEqual(expected, output))
+ {
+ Fail("Test #" + (i + 1) + ".1 failed, expected " + Hex.ToHexString(tv.GetExpectedValue(0)) + " got " + Hex.ToHexString(output));
+ }
+
+ output = new byte[tv.GetExpectedValue(0).Length];
+
+ d.Generate(output, tv.GetAdditionalInput(1), tv.PredictionResistance);
+
+ expected = tv.GetExpectedValue(1);
+ if (!AreEqual(expected, output))
+ {
+ Fail("Test #" + (i + 1) + ".2 failed, expected " + Hex.ToHexString(tv.GetExpectedValue(1)) + " got " + Hex.ToHexString(output));
+ }
+ }
+
+ // Exception tests
+ //
+ try
+ {
+ d = new HashSP800Drbg(new Sha256Digest(), 256, new SHA256EntropyProvider().Get(128), null, null);
+ Fail("no exception thrown");
+ }
+ catch (ArgumentException e)
+ {
+ if (!e.Message.Equals("Not enough entropy for security strength required"))
+ {
+ Fail("Wrong exception", e);
+ }
+ }
+
+ try
+ {
+ d = new HashSP800Drbg(new Sha1Digest(), 256, new SHA256EntropyProvider().Get(256), null, null);
+ Fail("no exception thrown");
+ }
+ catch (ArgumentException e)
+ {
+ if (!e.Message.Equals("Requested security strength is not supported by the derivation function"))
+ {
+ Fail("Wrong exception", e);
+ }
+ }
+ }
+
+ internal class SHA1EntropyProvider : TestEntropySourceProvider
+ {
+ internal SHA1EntropyProvider() : base(Hex.Decode(
+ "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F30313233343536" +
+ "808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6" +
+ "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6"), true)
+ {}
+ }
+
+ internal class SHA256EntropyProvider : TestEntropySourceProvider
+ {
+ internal SHA256EntropyProvider() : base(Hex.Decode(
+ "00010203040506" +
+ "0708090A0B0C0D0E0F101112131415161718191A1B1C1D1E" +
+ "1F202122232425262728292A2B2C2D2E2F30313233343536" +
+ "80818283848586" +
+ "8788898A8B8C8D8E8F909192939495969798999A9B9C9D9E" +
+ "9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6" +
+ "C0C1C2C3C4C5C6" +
+ "C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDE" +
+ "DFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6"), true)
+ { }
+ }
+
+ internal class SHA384EntropyProvider : TestEntropySourceProvider
+ {
+ internal SHA384EntropyProvider() : base(Hex.Decode(
+ "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F20212223242526" +
+ "2728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F50515253545556" +
+ "5758595A5B5C5D5E5F606162636465666768696A6B6C6D6E" +
+ "808182838485868788898A8B8C8D8E" +
+ "8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6" +
+ "A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBE" +
+ "BFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6" +
+ "D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEE" +
+ "C0C1C2C3C4C5C6C7C8C9CACBCCCDCE" +
+ "CFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6" +
+ "E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFE" +
+ "FF000102030405060708090A0B0C0D0E0F10111213141516" +
+ "1718191A1B1C1D1E1F202122232425262728292A2B2C2D2E"), true)
+ {}
+ }
+
+ internal class SHA512EntropyProvider : TestEntropySourceProvider
+ {
+ internal SHA512EntropyProvider() : base(Hex.Decode(
+ "000102030405060708090A0B0C0D0E" +
+ "0F101112131415161718191A1B1C1D1E1F20212223242526" +
+ "2728292A2B2C2D2E2F303132333435363738393A3B3C3D3E" +
+ "3F404142434445464748494A4B4C4D4E4F50515253545556" +
+ "5758595A5B5C5D5E5F606162636465666768696A6B6C6D6E" +
+ "808182838485868788898A8B8C8D8E" +
+ "8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6" +
+ "A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBE" +
+ "BFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6" +
+ "D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEE" +
+ "C0C1C2C3C4C5C6C7C8C9CACBCCCDCE" +
+ "CFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6" +
+ "E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFE" +
+ "FF000102030405060708090A0B0C0D0E0F10111213141516" +
+ "1718191A1B1C1D1E1F202122232425262728292A2B2C2D2E"), true)
+ { }
+ }
+ }
+}
diff --git a/crypto/test/src/crypto/prng/test/TestEntropySourceProvider.cs b/crypto/test/src/crypto/prng/test/TestEntropySourceProvider.cs
new file mode 100644
index 000000000..647799630
--- /dev/null
+++ b/crypto/test/src/crypto/prng/test/TestEntropySourceProvider.cs
@@ -0,0 +1,57 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Prng.Test
+{
+ public class TestEntropySourceProvider
+ : IEntropySourceProvider
+ {
+ private readonly byte[] data;
+ private readonly bool isPredictionResistant;
+
+ internal TestEntropySourceProvider(byte[] data, bool isPredictionResistant)
+ {
+ this.data = data;
+ this.isPredictionResistant = isPredictionResistant;
+ }
+
+ public IEntropySource Get(int bitsRequired)
+ {
+ return new EntropySource(bitsRequired, data, isPredictionResistant);
+ }
+
+ internal class EntropySource
+ : IEntropySource
+ {
+ private readonly int bitsRequired;
+ private readonly byte[] data;
+ private readonly bool isPredictionResistant;
+
+ int index = 0;
+
+ internal EntropySource(int bitsRequired, byte[] data, bool isPredictionResistant)
+ {
+ this.bitsRequired = bitsRequired;
+ this.data = data;
+ this.isPredictionResistant = isPredictionResistant;
+ }
+
+ public bool IsPredictionResistant
+ {
+ get { return isPredictionResistant; }
+ }
+
+ public byte[] GetEntropy()
+ {
+ byte[] rv = new byte[bitsRequired / 8];
+ Array.Copy(data, index, rv, 0, rv.Length);
+ index += bitsRequired / 8;
+ return rv;
+ }
+
+ public int EntropySize
+ {
+ get { return bitsRequired; }
+ }
+ }
+ }
+}
diff --git a/crypto/test/src/crypto/prng/test/X931Test.cs b/crypto/test/src/crypto/prng/test/X931Test.cs
new file mode 100644
index 000000000..1132ea34a
--- /dev/null
+++ b/crypto/test/src/crypto/prng/test/X931Test.cs
@@ -0,0 +1,137 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Prng.Test
+{
+ /**
+ * HMAC SP800-90 DRBG
+ */
+ [TestFixture]
+ public class X931Test
+ : SimpleTest
+ {
+ public override string Name
+ {
+ get { return "X931"; }
+ }
+
+ public static void Main(string[] args)
+ {
+ RunTest(new X931Test());
+ }
+
+ [Test]
+ public void TestFunction()
+ {
+ string resultText = Perform().ToString();
+
+ Assert.AreEqual(Name + ": Okay", resultText);
+ }
+
+ private X931TestVector[] CreateTestVectorData()
+ {
+ return new X931TestVector[]
+ {
+ new X931TestVector(
+ new AesEngine(),
+ new Aes128EntropyProvider(),
+ "f7d36762b9915f1ed585eb8e91700eb2",
+ "259e67249288597a4d61e7c0e690afae",
+ false,
+ new string[]
+ {
+ "15f013af5a8e9df9a8e37500edaeac43",
+ "a9d74bb1c90a222adc398546d64879cf",
+ "0379e404042d58180764fb9e6c5d94bb",
+ "3c74603e036d28c79947ffb56fee4e51",
+ "e872101a4df81ebbe1e632fc87195d52",
+ "26a6b3d33b8e7e68b75d9630ec036314"
+ }),
+ new X931TestVector(
+ new DesEdeEngine(),
+ new TDesEntropyProvider(),
+ "ef16ec643e5db5892cbc6eabba310b3410e6f8759e3e382c",
+ "55df103deaf68dc4",
+ false,
+ new string[]
+ {
+ "9c960bb9662ce6de",
+ "d9d0e527fd0931da",
+ "3e2db9994e9e6995",
+ "0e3868aef8218cf7",
+ "7b0b0ca137f8fd81",
+ "f657df270ad12265"
+ })
+ };
+ }
+
+ public override void PerformTest()
+ {
+ X931TestVector[] vectors = CreateTestVectorData();
+
+ for (int i = 0; i != vectors.Length; i++)
+ {
+ X931TestVector tv = vectors[i];
+ X931SecureRandomBuilder bld = new X931SecureRandomBuilder(tv.EntropyProvider);
+
+ bld.SetDateTimeVector(Hex.Decode(tv.DateTimeVector));
+
+ SecureRandom rand = bld.Build(tv.Engine, new KeyParameter(Hex.Decode(tv.Key)), tv.IsPredictionResistant);
+
+ for (int j = 0; j != tv.Expected.Length - 1; j++)
+ {
+ byte[] expected = Hex.Decode(tv.Expected[j]);
+ byte[] res = new byte[expected.Length];
+
+ rand.NextBytes(res);
+
+ if (!Arrays.AreEqual(expected, res))
+ {
+ Fail("expected output wrong [" + j + "] got : " + Strings.FromByteArray(Hex.Encode(res)));
+ }
+ }
+
+ {
+ byte[] expected = Hex.Decode(tv.Expected[tv.Expected.Length - 1]);
+ byte[] res = new byte[expected.Length];
+
+ for (int j = tv.Expected.Length - 1; j != 10000; j++)
+ {
+ rand.NextBytes(res);
+ }
+
+ if (!Arrays.AreEqual(expected, res))
+ {
+ Fail("expected output wrong [" + 10000 + "] got : " + Strings.FromByteArray(Hex.Encode(res)));
+ }
+ }
+ }
+ }
+
+ private class Aes128EntropyProvider
+ : TestEntropySourceProvider
+ {
+ internal Aes128EntropyProvider()
+ : base(Hex.Decode("35cc0ea481fc8a4f5f05c7d4667233b2"), true)
+ {
+ }
+ }
+
+ private class TDesEntropyProvider
+ : TestEntropySourceProvider
+ {
+ internal TDesEntropyProvider()
+ : base(Hex.Decode("96d872b9122c5e74"), true)
+ {
+ }
+ }
+ }
+}
diff --git a/crypto/test/src/crypto/prng/test/X931TestVector.cs b/crypto/test/src/crypto/prng/test/X931TestVector.cs
new file mode 100644
index 000000000..e641b0a66
--- /dev/null
+++ b/crypto/test/src/crypto/prng/test/X931TestVector.cs
@@ -0,0 +1,55 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Prng.Test
+{
+ public class X931TestVector
+ {
+ private readonly IBlockCipher engine;
+ private readonly IEntropySourceProvider entropyProvider;
+ private readonly string key;
+ private readonly string dateTimeVector;
+ private readonly bool predictionResistant;
+ private readonly string[] expected;
+
+ public X931TestVector(IBlockCipher engine, IEntropySourceProvider entropyProvider, string key, string dateTimeVector,
+ bool predictionResistant, string[] expected)
+ {
+ this.engine = engine;
+ this.entropyProvider = entropyProvider;
+ this.key = key;
+ this.dateTimeVector = dateTimeVector;
+ this.predictionResistant = predictionResistant;
+ this.expected = expected;
+ }
+
+ public string DateTimeVector
+ {
+ get { return dateTimeVector; }
+ }
+
+ public IBlockCipher Engine
+ {
+ get { return engine; }
+ }
+
+ public IEntropySourceProvider EntropyProvider
+ {
+ get { return entropyProvider; }
+ }
+
+ public string[] Expected
+ {
+ get { return expected; }
+ }
+
+ public string Key
+ {
+ get { return key; }
+ }
+
+ public bool IsPredictionResistant
+ {
+ get { return predictionResistant; }
+ }
+ }
+}
|