summary refs log tree commit diff
path: root/crypto
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2015-11-17 18:57:14 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2015-11-17 18:57:14 +0700
commitced92a086526c85e31842aaa60ede4c4b8e0fdb9 (patch)
tree15b6cba6381bb5ee611fd5873c46b3ee37163889 /crypto
parentPort some DES/DESEDE changes from Java (diff)
downloadBouncyCastle.NET-ed25519-ced92a086526c85e31842aaa60ede4c4b8e0fdb9.tar.xz
Improve usage/behaviour of SecureRandom.GenerateSeed
Diffstat (limited to 'crypto')
-rw-r--r--crypto/crypto.csproj10
-rw-r--r--crypto/src/crypto/CipherKeyGenerator.cs4
-rw-r--r--crypto/src/crypto/encodings/OaepEncoding.cs2
-rw-r--r--crypto/src/crypto/prng/CryptoApiEntropySourceProvider.cs70
-rw-r--r--crypto/src/crypto/prng/DigestRandomGenerator.cs12
-rw-r--r--crypto/src/crypto/prng/EntropyUtilities.cs30
-rw-r--r--crypto/src/crypto/prng/SP800SecureRandom.cs4
-rw-r--r--crypto/src/crypto/prng/X931Rng.cs2
-rw-r--r--crypto/src/crypto/prng/X931SecureRandom.cs4
-rw-r--r--crypto/src/security/SecureRandom.cs21
-rw-r--r--crypto/test/src/security/test/SecureRandomTest.cs41
-rw-r--r--crypto/test/src/test/BlockCipherTest.cs2
-rw-r--r--crypto/test/src/util/test/FixedSecureRandom.cs7
13 files changed, 178 insertions, 31 deletions
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);