diff --git a/crypto/crypto.csproj b/crypto/crypto.csproj
index 395ea08df..ecfdc7311 100644
--- a/crypto/crypto.csproj
+++ b/crypto/crypto.csproj
@@ -4319,6 +4319,11 @@
BuildAction = "Compile"
/>
<File
+ RelPath = "src\crypto\prng\CryptoApiEntropySourceProvider.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
RelPath = "src\crypto\prng\CryptoApiRandomGenerator.cs"
SubType = "Code"
BuildAction = "Compile"
@@ -4329,6 +4334,11 @@
BuildAction = "Compile"
/>
<File
+ RelPath = "src\crypto\prng\EntropyUtilities.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
RelPath = "src\crypto\prng\IDrbgProvider.cs"
SubType = "Code"
BuildAction = "Compile"
diff --git a/crypto/src/crypto/CipherKeyGenerator.cs b/crypto/src/crypto/CipherKeyGenerator.cs
index 5d00d34dd..d8d9b29b5 100644
--- a/crypto/src/crypto/CipherKeyGenerator.cs
+++ b/crypto/src/crypto/CipherKeyGenerator.cs
@@ -75,9 +75,9 @@ namespace Org.BouncyCastle.Crypto
return engineGenerateKey();
}
- protected virtual byte[] engineGenerateKey()
+ protected virtual byte[] engineGenerateKey()
{
- return random.GenerateSeed(strength);
+ return SecureRandom.GetNextBytes(random, strength);
}
}
}
diff --git a/crypto/src/crypto/encodings/OaepEncoding.cs b/crypto/src/crypto/encodings/OaepEncoding.cs
index a4d2f0e36..95814ef25 100644
--- a/crypto/src/crypto/encodings/OaepEncoding.cs
+++ b/crypto/src/crypto/encodings/OaepEncoding.cs
@@ -161,7 +161,7 @@ namespace Org.BouncyCastle.Crypto.Encodings
//
// generate the seed.
//
- byte[] seed = random.GenerateSeed(defHash.Length);
+ byte[] seed = SecureRandom.GetNextBytes(random, defHash.Length);
//
// mask the message block.
diff --git a/crypto/src/crypto/prng/CryptoApiEntropySourceProvider.cs b/crypto/src/crypto/prng/CryptoApiEntropySourceProvider.cs
new file mode 100644
index 000000000..68579aaf4
--- /dev/null
+++ b/crypto/src/crypto/prng/CryptoApiEntropySourceProvider.cs
@@ -0,0 +1,70 @@
+#if !(NETCF_1_0 || PORTABLE)
+using System;
+using System.Security.Cryptography;
+
+namespace Org.BouncyCastle.Crypto.Prng
+{
+ public class CryptoApiEntropySourceProvider
+ : IEntropySourceProvider
+ {
+ private readonly RandomNumberGenerator mRng;
+ private readonly bool mPredictionResistant;
+
+ public CryptoApiEntropySourceProvider()
+ : this(new RNGCryptoServiceProvider(), true)
+ {
+ }
+
+ public CryptoApiEntropySourceProvider(RandomNumberGenerator rng, bool isPredictionResistant)
+ {
+ if (rng == null)
+ throw new ArgumentNullException("rng");
+
+ mRng = rng;
+ mPredictionResistant = isPredictionResistant;
+ }
+
+ public IEntropySource Get(int bitsRequired)
+ {
+ return new CryptoApiEntropySource(mRng, mPredictionResistant, bitsRequired);
+ }
+
+ private class CryptoApiEntropySource
+ : IEntropySource
+ {
+ private readonly RandomNumberGenerator mRng;
+ private readonly bool mPredictionResistant;
+ private readonly int mEntropySize;
+
+ internal CryptoApiEntropySource(RandomNumberGenerator rng, bool predictionResistant, int entropySize)
+ {
+ this.mRng = rng;
+ this.mPredictionResistant = predictionResistant;
+ this.mEntropySize = entropySize;
+ }
+
+ #region IEntropySource Members
+
+ bool IEntropySource.IsPredictionResistant
+ {
+ get { return mPredictionResistant; }
+ }
+
+ byte[] IEntropySource.GetEntropy()
+ {
+ byte[] result = new byte[(mEntropySize + 7) / 8];
+ mRng.GetBytes(result);
+ return result;
+ }
+
+ int IEntropySource.EntropySize
+ {
+ get { return mEntropySize; }
+ }
+
+ #endregion
+ }
+ }
+}
+
+#endif
diff --git a/crypto/src/crypto/prng/DigestRandomGenerator.cs b/crypto/src/crypto/prng/DigestRandomGenerator.cs
index cbd2ef060..f5a29952a 100644
--- a/crypto/src/crypto/prng/DigestRandomGenerator.cs
+++ b/crypto/src/crypto/prng/DigestRandomGenerator.cs
@@ -1,6 +1,7 @@
using System;
using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Utilities;
namespace Org.BouncyCastle.Crypto.Prng
{
@@ -108,15 +109,12 @@ namespace Org.BouncyCastle.Crypto.Prng
private void DigestAddCounter(long seedVal)
{
- ulong seed = (ulong)seedVal;
- for (int i = 0; i != 8; i++)
- {
- digest.Update((byte)seed);
- seed >>= 8;
- }
+ byte[] bytes = new byte[8];
+ Pack.UInt64_To_LE((ulong)seedVal, bytes);
+ digest.BlockUpdate(bytes, 0, bytes.Length);
}
- private void DigestUpdate(byte[] inSeed)
+ private void DigestUpdate(byte[] inSeed)
{
digest.BlockUpdate(inSeed, 0, inSeed.Length);
}
diff --git a/crypto/src/crypto/prng/EntropyUtilities.cs b/crypto/src/crypto/prng/EntropyUtilities.cs
new file mode 100644
index 000000000..58c8703f4
--- /dev/null
+++ b/crypto/src/crypto/prng/EntropyUtilities.cs
@@ -0,0 +1,30 @@
+using System;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Prng
+{
+ public abstract class EntropyUtilities
+ {
+ /**
+ * Generate numBytes worth of entropy from the passed in entropy source.
+ *
+ * @param entropySource the entropy source to request the data from.
+ * @param numBytes the number of bytes of entropy requested.
+ * @return a byte array populated with the random data.
+ */
+ public static byte[] GenerateSeed(IEntropySource entropySource, int numBytes)
+ {
+ byte[] bytes = new byte[numBytes];
+ int count = 0;
+ while (count < numBytes)
+ {
+ byte[] entropy = entropySource.GetEntropy();
+ int toCopy = System.Math.Min(bytes.Length, numBytes - count);
+ Array.Copy(entropy, 0, bytes, count, toCopy);
+ count += toCopy;
+ }
+ return bytes;
+ }
+ }
+}
diff --git a/crypto/src/crypto/prng/SP800SecureRandom.cs b/crypto/src/crypto/prng/SP800SecureRandom.cs
index 996ba0846..5c5bda399 100644
--- a/crypto/src/crypto/prng/SP800SecureRandom.cs
+++ b/crypto/src/crypto/prng/SP800SecureRandom.cs
@@ -74,9 +74,7 @@ namespace Org.BouncyCastle.Crypto.Prng
public override byte[] GenerateSeed(int numBytes)
{
- byte[] bytes = new byte[numBytes];
- NextBytes(bytes);
- return bytes;
+ return EntropyUtilities.GenerateSeed(mEntropySource, numBytes);
}
}
}
diff --git a/crypto/src/crypto/prng/X931Rng.cs b/crypto/src/crypto/prng/X931Rng.cs
index d09cc6618..987379d4b 100644
--- a/crypto/src/crypto/prng/X931Rng.cs
+++ b/crypto/src/crypto/prng/X931Rng.cs
@@ -10,7 +10,7 @@ namespace Org.BouncyCastle.Crypto.Prng
private const int BLOCK128_MAX_BITS_REQUEST = 1 << (19 - 1);
private readonly IBlockCipher mEngine;
- private readonly IEntropySource mEntropySource;
+ internal readonly IEntropySource mEntropySource;
private readonly byte[] mDT;
private readonly byte[] mI;
diff --git a/crypto/src/crypto/prng/X931SecureRandom.cs b/crypto/src/crypto/prng/X931SecureRandom.cs
index a87bf1567..bce8d2cf1 100644
--- a/crypto/src/crypto/prng/X931SecureRandom.cs
+++ b/crypto/src/crypto/prng/X931SecureRandom.cs
@@ -64,9 +64,7 @@ namespace Org.BouncyCastle.Crypto.Prng
public override byte[] GenerateSeed(int numBytes)
{
- byte[] bytes = new byte[numBytes];
- NextBytes(bytes);
- return bytes;
+ return EntropyUtilities.GenerateSeed(mDrbg.mEntropySource, numBytes);
}
}
}
diff --git a/crypto/src/security/SecureRandom.cs b/crypto/src/security/SecureRandom.cs
index 8683b4729..cb831acc2 100644
--- a/crypto/src/security/SecureRandom.cs
+++ b/crypto/src/security/SecureRandom.cs
@@ -68,11 +68,18 @@ namespace Org.BouncyCastle.Security
if (autoSeed)
{
prng.AddSeedMaterial(NextCounterValue());
- prng.AddSeedMaterial(GetSeed(digest.GetDigestSize()));
+ prng.AddSeedMaterial(GetNextBytes(Master, digest.GetDigestSize()));
}
return prng;
}
+ public static byte[] GetNextBytes(SecureRandom secureRandom, int length)
+ {
+ byte[] result = new byte[length];
+ secureRandom.NextBytes(result);
+ return result;
+ }
+
/// <summary>
/// Create and auto-seed an instance based on the given algorithm.
/// </summary>
@@ -104,12 +111,10 @@ namespace Org.BouncyCastle.Security
throw new ArgumentException("Unrecognised PRNG algorithm: " + algorithm, "algorithm");
}
+ [Obsolete("Call GenerateSeed() on a SecureRandom instance instead")]
public static byte[] GetSeed(int length)
{
-#if NETCF_1_0 || PORTABLE
- lock (master)
-#endif
- return Master.GenerateSeed(length);
+ return GetNextBytes(Master, length);
}
protected readonly IRandomGenerator generator;
@@ -145,11 +150,7 @@ namespace Org.BouncyCastle.Security
public virtual byte[] GenerateSeed(int length)
{
- SetSeed(DateTime.Now.Ticks);
-
- byte[] rv = new byte[length];
- NextBytes(rv);
- return rv;
+ return GetNextBytes(Master, length);
}
public virtual void SetSeed(byte[] seed)
diff --git a/crypto/test/src/security/test/SecureRandomTest.cs b/crypto/test/src/security/test/SecureRandomTest.cs
index f93afc0aa..f1d83b29c 100644
--- a/crypto/test/src/security/test/SecureRandomTest.cs
+++ b/crypto/test/src/security/test/SecureRandomTest.cs
@@ -3,7 +3,12 @@ using System.Text;
using NUnit.Framework;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Macs;
using Org.BouncyCastle.Crypto.Prng;
+using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Security.Tests
@@ -61,6 +66,30 @@ namespace Org.BouncyCastle.Security.Tests
}
[Test]
+ public void TestSP800Ctr()
+ {
+ SecureRandom random = new SP800SecureRandomBuilder().BuildCtr(new AesFastEngine(), 256, new byte[32], false);
+
+ CheckSecureRandom(random);
+ }
+
+ [Test]
+ public void TestSP800Hash()
+ {
+ SecureRandom random = new SP800SecureRandomBuilder().BuildHash(new Sha256Digest(), new byte[32], false);
+
+ CheckSecureRandom(random);
+ }
+
+ [Test]
+ public void TestSP800HMac()
+ {
+ SecureRandom random = new SP800SecureRandomBuilder().BuildHMac(new HMac(new Sha256Digest()), new byte[32], false);
+
+ CheckSecureRandom(random);
+ }
+
+ [Test]
public void TestThreadedSeed()
{
SecureRandom random = SecureRandom.GetInstance("SHA1PRNG", false);
@@ -73,7 +102,15 @@ namespace Org.BouncyCastle.Security.Tests
public void TestVmpcPrng()
{
SecureRandom random = new SecureRandom(new VmpcRandomGenerator());
- random.SetSeed(SecureRandom.GetSeed(32));
+ random.SetSeed(random.GenerateSeed(32));
+
+ CheckSecureRandom(random);
+ }
+
+ [Test]
+ public void TestX931()
+ {
+ SecureRandom random = new X931SecureRandomBuilder().Build(new AesFastEngine(), new KeyParameter(new byte[16]), false);
CheckSecureRandom(random);
}
@@ -106,7 +143,7 @@ namespace Org.BouncyCastle.Security.Tests
private static double MeasureChiSquared(SecureRandom random, int rounds)
{
- byte[] opts = SecureRandom.GetSeed(2);
+ byte[] opts = random.GenerateSeed(2);
int[] counts = new int[256];
byte[] bs = new byte[256];
diff --git a/crypto/test/src/test/BlockCipherTest.cs b/crypto/test/src/test/BlockCipherTest.cs
index 93cf2b0a5..fc3a99f4e 100644
--- a/crypto/test/src/test/BlockCipherTest.cs
+++ b/crypto/test/src/test/BlockCipherTest.cs
@@ -410,7 +410,7 @@ namespace Org.BouncyCastle.Tests
else
{
// NB: rand always generates same values each test run
- iv = rand.GenerateSeed(ivLength);
+ iv = SecureRandom.GetNextBytes(rand, ivLength);
}
parameters = new ParametersWithIV(key, iv);
diff --git a/crypto/test/src/util/test/FixedSecureRandom.cs b/crypto/test/src/util/test/FixedSecureRandom.cs
index 15a2e9bb3..d8598ac24 100644
--- a/crypto/test/src/util/test/FixedSecureRandom.cs
+++ b/crypto/test/src/util/test/FixedSecureRandom.cs
@@ -38,7 +38,12 @@ namespace Org.BouncyCastle.Utilities.Test
return new FixedSecureRandom(bOut.ToArray());
}
- public override void NextBytes(
+ public override byte[] GenerateSeed(int numBytes)
+ {
+ return SecureRandom.GetNextBytes(this, numBytes);
+ }
+
+ public override void NextBytes(
byte[] buf)
{
Array.Copy(_data, _index, buf, 0, buf.Length);
|