diff options
author | Peter Dettman <peter.dettman@bouncycastle.org> | 2015-11-17 18:59:43 +0700 |
---|---|---|
committer | Peter Dettman <peter.dettman@bouncycastle.org> | 2015-11-17 18:59:43 +0700 |
commit | ce020967b052d0d1764002003e173aec746208b8 (patch) | |
tree | 0ee9654b2f71f05e84773300c63340b9d7a3b446 | |
parent | Merge branch 'master' of git.bouncycastle.org:bc-csharp into pcl (diff) | |
parent | Improve usage/behaviour of SecureRandom.GenerateSeed (diff) | |
download | BouncyCastle.NET-ed25519-ce020967b052d0d1764002003e173aec746208b8.tar.xz |
Merge branch 'master' of git.bouncycastle.org:bc-csharp into pcl
-rw-r--r-- | crypto/crypto.csproj | 10 | ||||
-rw-r--r-- | crypto/src/crypto/CipherKeyGenerator.cs | 4 | ||||
-rw-r--r-- | crypto/src/crypto/encodings/OaepEncoding.cs | 2 | ||||
-rw-r--r-- | crypto/src/crypto/generators/DesEdeKeyGenerator.cs | 8 | ||||
-rw-r--r-- | crypto/src/crypto/generators/DesKeyGenerator.cs | 8 | ||||
-rw-r--r-- | crypto/src/crypto/parameters/DesEdeParameters.cs | 45 | ||||
-rw-r--r-- | crypto/src/crypto/parameters/DesParameters.cs | 35 | ||||
-rw-r--r-- | crypto/src/crypto/prng/CryptoApiEntropySourceProvider.cs | 70 | ||||
-rw-r--r-- | crypto/src/crypto/prng/DigestRandomGenerator.cs | 12 | ||||
-rw-r--r-- | crypto/src/crypto/prng/EntropyUtilities.cs | 30 | ||||
-rw-r--r-- | crypto/src/crypto/prng/SP800SecureRandom.cs | 4 | ||||
-rw-r--r-- | crypto/src/crypto/prng/X931Rng.cs | 2 | ||||
-rw-r--r-- | crypto/src/crypto/prng/X931SecureRandom.cs | 4 | ||||
-rw-r--r-- | crypto/src/crypto/prng/drbg/CtrSP800Drbg.cs | 13 | ||||
-rw-r--r-- | crypto/src/security/SecureRandom.cs | 21 | ||||
-rw-r--r-- | crypto/test/src/security/test/SecureRandomTest.cs | 41 | ||||
-rw-r--r-- | crypto/test/src/test/BlockCipherTest.cs | 2 | ||||
-rw-r--r-- | crypto/test/src/util/test/FixedSecureRandom.cs | 7 |
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); |