1 files changed, 228 insertions, 0 deletions
diff --git a/Crypto/src/security/SecureRandom.cs b/Crypto/src/security/SecureRandom.cs
new file mode 100644
index 000000000..866a2cf0d
--- /dev/null
+++ b/Crypto/src/security/SecureRandom.cs
@@ -0,0 +1,228 @@
+using System;
+using System.Globalization;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Prng;
+
+namespace Org.BouncyCastle.Security
+{
+ public class SecureRandom
+ : Random
+ {
+ // Note: all objects of this class should be deriving their random data from
+ // a single generator appropriate to the digest being used.
+ private static readonly IRandomGenerator sha1Generator = new DigestRandomGenerator(new Sha1Digest());
+ private static readonly IRandomGenerator sha256Generator = new DigestRandomGenerator(new Sha256Digest());
+
+ private static readonly SecureRandom[] master = { null };
+ private static SecureRandom Master
+ {
+ get
+ {
+ if (master[0] == null)
+ {
+ IRandomGenerator gen = sha256Generator;
+ gen = new ReversedWindowGenerator(gen, 32);
+ SecureRandom sr = master[0] = new SecureRandom(gen);
+
+ sr.SetSeed(DateTime.Now.Ticks);
+ sr.SetSeed(new ThreadedSeedGenerator().GenerateSeed(24, true));
+ sr.GenerateSeed(1 + sr.Next(32));
+ }
+
+ return master[0];
+ }
+ }
+
+ public static SecureRandom GetInstance(
+ string algorithm)
+ {
+ // TODO Compared to JDK, we don't auto-seed if the client forgets - problem?
+
+ // TODO Support all digests more generally, by stripping PRNG and calling DigestUtilities?
+ string drgName = algorithm.ToUpperInvariant();
+
+ IRandomGenerator drg = null;
+ if (drgName == "SHA1PRNG")
+ {
+ drg = sha1Generator;
+ }
+ else if (drgName == "SHA256PRNG")
+ {
+ drg = sha256Generator;
+ }
+
+ if (drg != null)
+ {
+ return new SecureRandom(drg);
+ }
+
+ throw new ArgumentException("Unrecognised PRNG algorithm: " + algorithm, "algorithm");
+ }
+
+ public static byte[] GetSeed(
+ int length)
+ {
+ return Master.GenerateSeed(length);
+ }
+
+ protected IRandomGenerator generator;
+
+ public SecureRandom()
+ : this(sha1Generator)
+ {
+ SetSeed(GetSeed(8));
+ }
+
+ public SecureRandom(
+ byte[] inSeed)
+ : this(sha1Generator)
+ {
+ SetSeed(inSeed);
+ }
+
+ /// <summary>Use the specified instance of IRandomGenerator as random source.</summary>
+ /// <remarks>
+ /// This constructor performs no seeding of either the <c>IRandomGenerator</c> or the
+ /// constructed <c>SecureRandom</c>. It is the responsibility of the client to provide
+ /// proper seed material as necessary/appropriate for the given <c>IRandomGenerator</c>
+ /// implementation.
+ /// </remarks>
+ /// <param name="generator">The source to generate all random bytes from.</param>
+ public SecureRandom(
+ IRandomGenerator generator)
+ : base(0)
+ {
+ this.generator = generator;
+ }
+
+ public virtual byte[] GenerateSeed(
+ int length)
+ {
+ SetSeed(DateTime.Now.Ticks);
+
+ byte[] rv = new byte[length];
+ NextBytes(rv);
+ return rv;
+ }
+
+ public virtual void SetSeed(
+ byte[] inSeed)
+ {
+ generator.AddSeedMaterial(inSeed);
+ }
+
+ public virtual void SetSeed(
+ long seed)
+ {
+ generator.AddSeedMaterial(seed);
+ }
+
+ public override int Next()
+ {
+ for (;;)
+ {
+ int i = NextInt() & int.MaxValue;
+
+ if (i != int.MaxValue)
+ return i;
+ }
+ }
+
+ public override int Next(
+ int maxValue)
+ {
+ if (maxValue < 2)
+ {
+ if (maxValue < 0)
+ throw new ArgumentOutOfRangeException("maxValue < 0");
+
+ return 0;
+ }
+
+ // Test whether maxValue is a power of 2
+ if ((maxValue & -maxValue) == maxValue)
+ {
+ int val = NextInt() & int.MaxValue;
+ long lr = ((long) maxValue * (long) val) >> 31;
+ return (int) lr;
+ }
+
+ int bits, result;
+ do
+ {
+ bits = NextInt() & int.MaxValue;
+ result = bits % maxValue;
+ }
+ while (bits - result + (maxValue - 1) < 0); // Ignore results near overflow
+
+ return result;
+ }
+
+ public override int Next(
+ int minValue,
+ int maxValue)
+ {
+ if (maxValue <= minValue)
+ {
+ if (maxValue == minValue)
+ return minValue;
+
+ throw new ArgumentException("maxValue cannot be less than minValue");
+ }
+
+ int diff = maxValue - minValue;
+ if (diff > 0)
+ return minValue + Next(diff);
+
+ for (;;)
+ {
+ int i = NextInt();
+
+ if (i >= minValue && i < maxValue)
+ return i;
+ }
+ }
+
+ public override void NextBytes(
+ byte[] buffer)
+ {
+ generator.NextBytes(buffer);
+ }
+
+ public virtual void NextBytes(
+ byte[] buffer,
+ int start,
+ int length)
+ {
+ generator.NextBytes(buffer, start, length);
+ }
+
+ private static readonly double DoubleScale = System.Math.Pow(2.0, 64.0);
+
+ public override double NextDouble()
+ {
+ return Convert.ToDouble((ulong) NextLong()) / DoubleScale;
+ }
+
+ public virtual int NextInt()
+ {
+ byte[] intBytes = new byte[4];
+ NextBytes(intBytes);
+
+ int result = 0;
+ for (int i = 0; i < 4; i++)
+ {
+ result = (result << 8) + (intBytes[i] & 0xff);
+ }
+
+ return result;
+ }
+
+ public virtual long NextLong()
+ {
+ return ((long)(uint) NextInt() << 32) | (long)(uint) NextInt();
+ }
+ }
+}
|