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);
|