summary refs log tree commit diff
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2015-11-17 18:59:43 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2015-11-17 18:59:43 +0700
commitce020967b052d0d1764002003e173aec746208b8 (patch)
tree0ee9654b2f71f05e84773300c63340b9d7a3b446
parentMerge branch 'master' of git.bouncycastle.org:bc-csharp into pcl (diff)
parentImprove usage/behaviour of SecureRandom.GenerateSeed (diff)
downloadBouncyCastle.NET-ed25519-ce020967b052d0d1764002003e173aec746208b8.tar.xz
Merge branch 'master' of git.bouncycastle.org:bc-csharp into pcl
-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/generators/DesEdeKeyGenerator.cs8
-rw-r--r--crypto/src/crypto/generators/DesKeyGenerator.cs8
-rw-r--r--crypto/src/crypto/parameters/DesEdeParameters.cs45
-rw-r--r--crypto/src/crypto/parameters/DesParameters.cs35
-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/crypto/prng/drbg/CtrSP800Drbg.cs13
-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
18 files changed, 254 insertions, 64 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/generators/DesEdeKeyGenerator.cs b/crypto/src/crypto/generators/DesEdeKeyGenerator.cs
index 5902643fd..904cc71f1 100644
--- a/crypto/src/crypto/generators/DesEdeKeyGenerator.cs
+++ b/crypto/src/crypto/generators/DesEdeKeyGenerator.cs
@@ -52,14 +52,14 @@ namespace Org.BouncyCastle.Crypto.Generators
 
         protected override byte[] engineGenerateKey()
         {
-            byte[] newKey;
+            byte[] newKey = new byte[strength];
 
-			do
+            do
             {
-                newKey = random.GenerateSeed(strength);
+                random.NextBytes(newKey);
                 DesEdeParameters.SetOddParity(newKey);
             }
-            while (DesEdeParameters.IsWeakKey(newKey, 0, newKey.Length));
+            while (DesEdeParameters.IsWeakKey(newKey, 0, newKey.Length) || !DesEdeParameters.IsRealEdeKey(newKey, 0));
 
             return newKey;
         }
diff --git a/crypto/src/crypto/generators/DesKeyGenerator.cs b/crypto/src/crypto/generators/DesKeyGenerator.cs
index 154e3471a..4c2051d89 100644
--- a/crypto/src/crypto/generators/DesKeyGenerator.cs
+++ b/crypto/src/crypto/generators/DesKeyGenerator.cs
@@ -42,12 +42,12 @@ namespace Org.BouncyCastle.Crypto.Generators
 
 		protected override byte[] engineGenerateKey()
         {
-            byte[] newKey;
+            byte[] newKey = new byte[DesParameters.DesKeyLength];
 
-			do
+            do
             {
-				newKey = random.GenerateSeed(DesParameters.DesKeyLength);
-				DesParameters.SetOddParity(newKey);
+                random.NextBytes(newKey);
+                DesParameters.SetOddParity(newKey);
             }
             while (DesParameters.IsWeakKey(newKey, 0));
 
diff --git a/crypto/src/crypto/parameters/DesEdeParameters.cs b/crypto/src/crypto/parameters/DesEdeParameters.cs
index 420aaecea..6be56fb2c 100644
--- a/crypto/src/crypto/parameters/DesEdeParameters.cs
+++ b/crypto/src/crypto/parameters/DesEdeParameters.cs
@@ -91,5 +91,50 @@ namespace Org.BouncyCastle.Crypto.Parameters
 		{
 			return IsWeakKey(key, 0, key.Length);
 		}
+
+        /**
+         * return true if the passed in key is a real 2/3 part DES-EDE key.
+         *
+         * @param key bytes making up the key
+         * @param offset offset into the byte array the key starts at
+         */
+        public static bool IsRealEdeKey(byte[] key, int offset)
+        {
+            return key.Length == 16 ? IsReal2Key(key, offset) : IsReal3Key(key, offset);
+        }
+
+        /**
+         * return true if the passed in key is a real 2 part DES-EDE key.
+         *
+         * @param key bytes making up the key
+         * @param offset offset into the byte array the key starts at
+         */
+        public static bool IsReal2Key(byte[] key, int offset)
+        {
+            bool isValid = false;
+            for (int i = offset; i != offset + 8; i++)
+            {
+                isValid |= (key[i] != key[i + 8]);
+            }
+            return isValid;
+        }
+
+        /**
+         * return true if the passed in key is a real 3 part DES-EDE key.
+         *
+         * @param key bytes making up the key
+         * @param offset offset into the byte array the key starts at
+         */
+        public static bool IsReal3Key(byte[] key, int offset)
+        {
+            bool diff12 = false, diff13 = false, diff23 = false;
+            for (int i = offset; i != offset + 8; i++)
+            {
+                diff12 |= (key[i] != key[i + 8]);
+                diff13 |= (key[i] != key[i + 16]);
+                diff23 |= (key[i + 8] != key[i + 16]);
+            }
+            return diff12 && diff13 && diff23;
+        }
     }
 }
diff --git a/crypto/src/crypto/parameters/DesParameters.cs b/crypto/src/crypto/parameters/DesParameters.cs
index ee37cd861..a1f67e2b1 100644
--- a/crypto/src/crypto/parameters/DesParameters.cs
+++ b/crypto/src/crypto/parameters/DesParameters.cs
@@ -103,28 +103,37 @@ namespace Org.BouncyCastle.Crypto.Parameters
 			return IsWeakKey(key, 0);
 		}
 
-		/**
+        public static byte SetOddParity(byte b)
+        {
+            uint parity = b ^ 1U;
+            parity ^= (parity >> 4);
+            parity ^= (parity >> 2);
+            parity ^= (parity >> 1);
+            parity &= 1U;
+
+            return (byte)(b ^ parity);
+        }
+
+        /**
         * DES Keys use the LSB as the odd parity bit.  This can
         * be used to check for corrupt keys.
         *
         * @param bytes the byte array to set the parity on.
         */
-        public static void SetOddParity(
-            byte[] bytes)
+        public static void SetOddParity(byte[] bytes)
         {
             for (int i = 0; i < bytes.Length; i++)
             {
-                int b = bytes[i];
-                bytes[i] = (byte)((b & 0xfe) |
-                                ((((b >> 1) ^
-                                (b >> 2) ^
-                                (b >> 3) ^
-                                (b >> 4) ^
-                                (b >> 5) ^
-                                (b >> 6) ^
-                                (b >> 7)) ^ 0x01) & 0x01));
+                bytes[i] = SetOddParity(bytes[i]);
             }
         }
-    }
 
+        public static void SetOddParity(byte[] bytes, int off, int len)
+        {
+            for (int i = 0; i < len; i++)
+            {
+                bytes[off + i] = SetOddParity(bytes[off + i]);
+            }
+        }
+    }
 }
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/crypto/prng/drbg/CtrSP800Drbg.cs b/crypto/src/crypto/prng/drbg/CtrSP800Drbg.cs
index 2e4fbe4ed..eca1821d3 100644
--- a/crypto/src/crypto/prng/drbg/CtrSP800Drbg.cs
+++ b/crypto/src/crypto/prng/drbg/CtrSP800Drbg.cs
@@ -460,18 +460,7 @@ namespace Org.BouncyCastle.Crypto.Prng.Drbg
 	        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);
-	        }
+            DesParameters.SetOddParity(tmp, tmpOff, 8);
 	    }
 	}
 }
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);