diff --git a/crypto/src/crypto/prng/BasicEntropySourceProvider.cs b/crypto/src/crypto/prng/BasicEntropySourceProvider.cs
new file mode 100644
index 000000000..0e929e0fd
--- /dev/null
+++ b/crypto/src/crypto/prng/BasicEntropySourceProvider.cs
@@ -0,0 +1,70 @@
+using System;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Prng
+{
+ /**
+ * An EntropySourceProvider where entropy generation is based on a SecureRandom output using SecureRandom.generateSeed().
+ */
+ public class BasicEntropySourceProvider
+ : IEntropySourceProvider
+ {
+ private readonly SecureRandom mSecureRandom;
+ private readonly bool mPredictionResistant;
+
+ /**
+ * Create a entropy source provider based on the passed in SecureRandom.
+ *
+ * @param secureRandom the SecureRandom to base EntropySource construction on.
+ * @param isPredictionResistant boolean indicating if the SecureRandom is based on prediction resistant entropy or not (true if it is).
+ */
+ public BasicEntropySourceProvider(SecureRandom secureRandom, bool isPredictionResistant)
+ {
+ mSecureRandom = secureRandom;
+ mPredictionResistant = isPredictionResistant;
+ }
+
+ /**
+ * Return an entropy source that will create bitsRequired bits of entropy on
+ * each invocation of getEntropy().
+ *
+ * @param bitsRequired size (in bits) of entropy to be created by the provided source.
+ * @return an EntropySource that generates bitsRequired bits of entropy on each call to its getEntropy() method.
+ */
+ public IEntropySource Get(int bitsRequired)
+ {
+ return new BasicEntropySource(mSecureRandom, mPredictionResistant, bitsRequired);
+ }
+
+ private class BasicEntropySource
+ : IEntropySource
+ {
+ private readonly SecureRandom mSecureRandom;
+ private readonly bool mPredictionResistant;
+ private readonly int mEntropySize;
+
+ internal BasicEntropySource(SecureRandom secureRandom, bool predictionResistant, int entropySize)
+ {
+ this.mSecureRandom = secureRandom;
+ this.mPredictionResistant = predictionResistant;
+ this.mEntropySize = entropySize;
+ }
+
+ bool IEntropySource.IsPredictionResistant
+ {
+ get { return mPredictionResistant; }
+ }
+
+ byte[] IEntropySource.GetEntropy()
+ {
+ return mSecureRandom.GenerateSeed((mEntropySize + 7) / 8);
+ }
+
+ int IEntropySource.EntropySize
+ {
+ get { return mEntropySize; }
+ }
+ }
+ }
+}
diff --git a/crypto/src/crypto/prng/IDrbgProvider.cs b/crypto/src/crypto/prng/IDrbgProvider.cs
new file mode 100644
index 000000000..5ebf5fd8d
--- /dev/null
+++ b/crypto/src/crypto/prng/IDrbgProvider.cs
@@ -0,0 +1,11 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Prng.Drbg;
+
+namespace Org.BouncyCastle.Crypto.Prng
+{
+ internal interface IDrbgProvider
+ {
+ ISP80090Drbg Get(IEntropySource entropySource);
+ }
+}
diff --git a/crypto/src/crypto/prng/IEntropySource.cs b/crypto/src/crypto/prng/IEntropySource.cs
index 33ce1b801..90b9e61af 100644
--- a/crypto/src/crypto/prng/IEntropySource.cs
+++ b/crypto/src/crypto/prng/IEntropySource.cs
@@ -1,9 +1,9 @@
using System;
-namespace Org.BouncyCastle.Crypto
+namespace Org.BouncyCastle.Crypto.Prng
{
/// <summary>
- /// Base interface describing an entropy source for a DRGB.
+ /// Base interface describing an entropy source for a DRBG.
/// </summary>
public interface IEntropySource
{
diff --git a/crypto/src/crypto/prng/IEntropySourceProvider.cs b/crypto/src/crypto/prng/IEntropySourceProvider.cs
index 990c6497b..643f92ef8 100644
--- a/crypto/src/crypto/prng/IEntropySourceProvider.cs
+++ b/crypto/src/crypto/prng/IEntropySourceProvider.cs
@@ -1,8 +1,6 @@
using System;
-using System.Collections.Generic;
-using System.Text;
-namespace Org.BouncyCastle.Crypto
+namespace Org.BouncyCastle.Crypto.Prng
{
/// <summary>
/// Base interface describing a provider of entropy sources.
diff --git a/crypto/src/crypto/prng/SP800SecureRandom.cs b/crypto/src/crypto/prng/SP800SecureRandom.cs
new file mode 100644
index 000000000..996ba0846
--- /dev/null
+++ b/crypto/src/crypto/prng/SP800SecureRandom.cs
@@ -0,0 +1,82 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Prng.Drbg;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Prng
+{
+ public class SP800SecureRandom
+ : SecureRandom
+ {
+ private readonly IDrbgProvider mDrbgProvider;
+ private readonly bool mPredictionResistant;
+ private readonly SecureRandom mRandomSource;
+ private readonly IEntropySource mEntropySource;
+
+ private ISP80090Drbg mDrbg;
+
+ internal SP800SecureRandom(SecureRandom randomSource, IEntropySource entropySource, IDrbgProvider drbgProvider, bool predictionResistant)
+ : base((IRandomGenerator)null)
+ {
+ this.mRandomSource = randomSource;
+ this.mEntropySource = entropySource;
+ this.mDrbgProvider = drbgProvider;
+ this.mPredictionResistant = predictionResistant;
+ }
+
+ public override void SetSeed(byte[] seed)
+ {
+ lock (this)
+ {
+ if (mRandomSource != null)
+ {
+ this.mRandomSource.SetSeed(seed);
+ }
+ }
+ }
+
+ public override void SetSeed(long seed)
+ {
+ lock (this)
+ {
+ // this will happen when SecureRandom() is created
+ if (mRandomSource != null)
+ {
+ this.mRandomSource.SetSeed(seed);
+ }
+ }
+ }
+
+ public override void NextBytes(byte[] bytes)
+ {
+ lock (this)
+ {
+ if (mDrbg == null)
+ {
+ mDrbg = mDrbgProvider.Get(mEntropySource);
+ }
+
+ // check if a reseed is required...
+ if (mDrbg.Generate(bytes, null, mPredictionResistant) < 0)
+ {
+ mDrbg.Reseed(null);
+ mDrbg.Generate(bytes, null, mPredictionResistant);
+ }
+ }
+ }
+
+ public override void NextBytes(byte[] buf, int off, int len)
+ {
+ byte[] bytes = new byte[len];
+ NextBytes(bytes);
+ Array.Copy(bytes, 0, buf, off, len);
+ }
+
+ public override byte[] GenerateSeed(int numBytes)
+ {
+ byte[] bytes = new byte[numBytes];
+ NextBytes(bytes);
+ return bytes;
+ }
+ }
+}
diff --git a/crypto/src/crypto/prng/SP800SecureRandomBuilder.cs b/crypto/src/crypto/prng/SP800SecureRandomBuilder.cs
new file mode 100644
index 000000000..7199f1ae7
--- /dev/null
+++ b/crypto/src/crypto/prng/SP800SecureRandomBuilder.cs
@@ -0,0 +1,208 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Prng.Drbg;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Prng
+{
+ /**
+ * Builder class for making SecureRandom objects based on SP 800-90A Deterministic Random Bit Generators (DRBG).
+ */
+ public class SP800SecureRandomBuilder
+ {
+ private readonly SecureRandom mRandom;
+ private readonly IEntropySourceProvider mEntropySourceProvider;
+
+ private byte[] mPersonalizationString = null;
+ private int mSecurityStrength = 256;
+ private int mEntropyBitsRequired = 256;
+
+ /**
+ * Basic constructor, creates a builder using an EntropySourceProvider based on the default SecureRandom with
+ * predictionResistant set to false.
+ * <p>
+ * Any SecureRandom created from a builder constructed like this will make use of input passed to SecureRandom.setSeed() if
+ * the default SecureRandom does for its generateSeed() call.
+ * </p>
+ */
+ public SP800SecureRandomBuilder()
+ : this(new SecureRandom(), false)
+ {
+ }
+
+ /**
+ * Construct a builder with an EntropySourceProvider based on the passed in SecureRandom and the passed in value
+ * for prediction resistance.
+ * <p>
+ * Any SecureRandom created from a builder constructed like this will make use of input passed to SecureRandom.setSeed() if
+ * the passed in SecureRandom does for its generateSeed() call.
+ * </p>
+ * @param entropySource
+ * @param predictionResistant
+ */
+ public SP800SecureRandomBuilder(SecureRandom entropySource, bool predictionResistant)
+ {
+ this.mRandom = entropySource;
+ this.mEntropySourceProvider = new BasicEntropySourceProvider(entropySource, predictionResistant);
+ }
+
+ /**
+ * Create a builder which makes creates the SecureRandom objects from a specified entropy source provider.
+ * <p>
+ * <b>Note:</b> If this constructor is used any calls to setSeed() in the resulting SecureRandom will be ignored.
+ * </p>
+ * @param entropySourceProvider a provider of EntropySource objects.
+ */
+ public SP800SecureRandomBuilder(IEntropySourceProvider entropySourceProvider)
+ {
+ this.mRandom = null;
+ this.mEntropySourceProvider = entropySourceProvider;
+ }
+
+ /**
+ * Set the personalization string for DRBG SecureRandoms created by this builder
+ * @param personalizationString the personalisation string for the underlying DRBG.
+ * @return the current builder.
+ */
+ public SP800SecureRandomBuilder SetPersonalizationString(byte[] personalizationString)
+ {
+ this.mPersonalizationString = personalizationString;
+ return this;
+ }
+
+ /**
+ * Set the security strength required for DRBGs used in building SecureRandom objects.
+ *
+ * @param securityStrength the security strength (in bits)
+ * @return the current builder.
+ */
+ public SP800SecureRandomBuilder SetSecurityStrength(int securityStrength)
+ {
+ this.mSecurityStrength = securityStrength;
+ return this;
+ }
+
+ /**
+ * Set the amount of entropy bits required for seeding and reseeding DRBGs used in building SecureRandom objects.
+ *
+ * @param entropyBitsRequired the number of bits of entropy to be requested from the entropy source on each seed/reseed.
+ * @return the current builder.
+ */
+ public SP800SecureRandomBuilder SetEntropyBitsRequired(int entropyBitsRequired)
+ {
+ this.mEntropyBitsRequired = entropyBitsRequired;
+ return this;
+ }
+
+ /**
+ * Build a SecureRandom based on a SP 800-90A Hash DRBG.
+ *
+ * @param digest digest algorithm to use in the DRBG underneath the SecureRandom.
+ * @param nonce nonce value to use in DRBG construction.
+ * @param predictionResistant specify whether the underlying DRBG in the resulting SecureRandom should reseed on each request for bytes.
+ * @return a SecureRandom supported by a Hash DRBG.
+ */
+ public SP800SecureRandom BuildHash(IDigest digest, byte[] nonce, bool predictionResistant)
+ {
+ return new SP800SecureRandom(mRandom, mEntropySourceProvider.Get(mEntropyBitsRequired),
+ new HashDrbgProvider(digest, nonce, mPersonalizationString, mSecurityStrength), predictionResistant);
+ }
+
+ /**
+ * Build a SecureRandom based on a SP 800-90A CTR DRBG.
+ *
+ * @param cipher the block cipher to base the DRBG on.
+ * @param keySizeInBits key size in bits to be used with the block cipher.
+ * @param nonce nonce value to use in DRBG construction.
+ * @param predictionResistant specify whether the underlying DRBG in the resulting SecureRandom should reseed on each request for bytes.
+ * @return a SecureRandom supported by a CTR DRBG.
+ */
+ public SP800SecureRandom BuildCtr(IBlockCipher cipher, int keySizeInBits, byte[] nonce, bool predictionResistant)
+ {
+ return new SP800SecureRandom(mRandom, mEntropySourceProvider.Get(mEntropyBitsRequired),
+ new CtrDrbgProvider(cipher, keySizeInBits, nonce, mPersonalizationString, mSecurityStrength), predictionResistant);
+ }
+
+ /**
+ * Build a SecureRandom based on a SP 800-90A HMAC DRBG.
+ *
+ * @param hMac HMAC algorithm to use in the DRBG underneath the SecureRandom.
+ * @param nonce nonce value to use in DRBG construction.
+ * @param predictionResistant specify whether the underlying DRBG in the resulting SecureRandom should reseed on each request for bytes.
+ * @return a SecureRandom supported by a HMAC DRBG.
+ */
+ public SP800SecureRandom BuildHMac(IMac hMac, byte[] nonce, bool predictionResistant)
+ {
+ return new SP800SecureRandom(mRandom, mEntropySourceProvider.Get(mEntropyBitsRequired),
+ new HMacDrbgProvider(hMac, nonce, mPersonalizationString, mSecurityStrength), predictionResistant);
+ }
+
+ private class HashDrbgProvider
+ : IDrbgProvider
+ {
+ private readonly IDigest mDigest;
+ private readonly byte[] mNonce;
+ private readonly byte[] mPersonalizationString;
+ private readonly int mSecurityStrength;
+
+ public HashDrbgProvider(IDigest digest, byte[] nonce, byte[] personalizationString, int securityStrength)
+ {
+ this.mDigest = digest;
+ this.mNonce = nonce;
+ this.mPersonalizationString = personalizationString;
+ this.mSecurityStrength = securityStrength;
+ }
+
+ public ISP80090Drbg Get(IEntropySource entropySource)
+ {
+ return new HashSP800Drbg(mDigest, mSecurityStrength, entropySource, mPersonalizationString, mNonce);
+ }
+ }
+
+ private class HMacDrbgProvider
+ : IDrbgProvider
+ {
+ private readonly IMac mHMac;
+ private readonly byte[] mNonce;
+ private readonly byte[] mPersonalizationString;
+ private readonly int mSecurityStrength;
+
+ public HMacDrbgProvider(IMac hMac, byte[] nonce, byte[] personalizationString, int securityStrength)
+ {
+ this.mHMac = hMac;
+ this.mNonce = nonce;
+ this.mPersonalizationString = personalizationString;
+ this.mSecurityStrength = securityStrength;
+ }
+
+ public ISP80090Drbg Get(IEntropySource entropySource)
+ {
+ return new HMacSP800Drbg(mHMac, mSecurityStrength, entropySource, mPersonalizationString, mNonce);
+ }
+ }
+
+ private class CtrDrbgProvider
+ : IDrbgProvider
+ {
+ private readonly IBlockCipher mBlockCipher;
+ private readonly int mKeySizeInBits;
+ private readonly byte[] mNonce;
+ private readonly byte[] mPersonalizationString;
+ private readonly int mSecurityStrength;
+
+ public CtrDrbgProvider(IBlockCipher blockCipher, int keySizeInBits, byte[] nonce, byte[] personalizationString, int securityStrength)
+ {
+ this.mBlockCipher = blockCipher;
+ this.mKeySizeInBits = keySizeInBits;
+ this.mNonce = nonce;
+ this.mPersonalizationString = personalizationString;
+ this.mSecurityStrength = securityStrength;
+ }
+
+ public ISP80090Drbg Get(IEntropySource entropySource)
+ {
+ return new CtrSP800Drbg(mBlockCipher, mKeySizeInBits, mSecurityStrength, entropySource, mPersonalizationString, mNonce);
+ }
+ }
+ }
+}
diff --git a/crypto/src/crypto/prng/X931Rng.cs b/crypto/src/crypto/prng/X931Rng.cs
new file mode 100644
index 000000000..d09cc6618
--- /dev/null
+++ b/crypto/src/crypto/prng/X931Rng.cs
@@ -0,0 +1,141 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Prng
+{
+ internal class X931Rng
+ {
+ private const long BLOCK64_RESEED_MAX = 1L << (16 - 1);
+ private const long BLOCK128_RESEED_MAX = 1L << (24 - 1);
+ private const int BLOCK64_MAX_BITS_REQUEST = 1 << (13 - 1);
+ private const int BLOCK128_MAX_BITS_REQUEST = 1 << (19 - 1);
+
+ private readonly IBlockCipher mEngine;
+ private readonly IEntropySource mEntropySource;
+
+ private readonly byte[] mDT;
+ private readonly byte[] mI;
+ private readonly byte[] mR;
+
+ private byte[] mV;
+
+ private long mReseedCounter = 1;
+
+ /**
+ *
+ * @param engine
+ * @param entropySource
+ */
+ internal X931Rng(IBlockCipher engine, byte[] dateTimeVector, IEntropySource entropySource)
+ {
+ this.mEngine = engine;
+ this.mEntropySource = entropySource;
+
+ this.mDT = new byte[engine.GetBlockSize()];
+
+ Array.Copy(dateTimeVector, 0, mDT, 0, mDT.Length);
+
+ this.mI = new byte[engine.GetBlockSize()];
+ this.mR = new byte[engine.GetBlockSize()];
+ }
+
+ /**
+ * Populate a passed in array with random data.
+ *
+ * @param output output array for generated bits.
+ * @param predictionResistant true if a reseed should be forced, false otherwise.
+ *
+ * @return number of bits generated, -1 if a reseed required.
+ */
+ internal int Generate(byte[] output, bool predictionResistant)
+ {
+ if (mR.Length == 8) // 64 bit block size
+ {
+ if (mReseedCounter > BLOCK64_RESEED_MAX)
+ return -1;
+
+ if (IsTooLarge(output, BLOCK64_MAX_BITS_REQUEST / 8))
+ throw new ArgumentException("Number of bits per request limited to " + BLOCK64_MAX_BITS_REQUEST, "output");
+ }
+ else
+ {
+ if (mReseedCounter > BLOCK128_RESEED_MAX)
+ return -1;
+
+ if (IsTooLarge(output, BLOCK128_MAX_BITS_REQUEST / 8))
+ throw new ArgumentException("Number of bits per request limited to " + BLOCK128_MAX_BITS_REQUEST, "output");
+ }
+
+ if (predictionResistant || mV == null)
+ {
+ mV = mEntropySource.GetEntropy();
+ if (mV.Length != mEngine.GetBlockSize())
+ throw new InvalidOperationException("Insufficient entropy returned");
+ }
+
+ int m = output.Length / mR.Length;
+
+ for (int i = 0; i < m; i++)
+ {
+ mEngine.ProcessBlock(mDT, 0, mI, 0);
+ Process(mR, mI, mV);
+ Process(mV, mR, mI);
+
+ Array.Copy(mR, 0, output, i * mR.Length, mR.Length);
+
+ Increment(mDT);
+ }
+
+ int bytesToCopy = (output.Length - m * mR.Length);
+
+ if (bytesToCopy > 0)
+ {
+ mEngine.ProcessBlock(mDT, 0, mI, 0);
+ Process(mR, mI, mV);
+ Process(mV, mR, mI);
+
+ Array.Copy(mR, 0, output, m * mR.Length, bytesToCopy);
+
+ Increment(mDT);
+ }
+
+ mReseedCounter++;
+
+ return output.Length;
+ }
+
+ /**
+ * Reseed the RNG.
+ */
+ internal void Reseed()
+ {
+ mV = mEntropySource.GetEntropy();
+ if (mV.Length != mEngine.GetBlockSize())
+ throw new InvalidOperationException("Insufficient entropy returned");
+ mReseedCounter = 1;
+ }
+
+ private void Process(byte[] res, byte[] a, byte[] b)
+ {
+ for (int i = 0; i != res.Length; i++)
+ {
+ res[i] = (byte)(a[i] ^ b[i]);
+ }
+
+ mEngine.ProcessBlock(res, 0, res, 0);
+ }
+
+ private void Increment(byte[] val)
+ {
+ for (int i = val.Length - 1; i >= 0; i--)
+ {
+ if (++val[i] != 0)
+ break;
+ }
+ }
+
+ private static bool IsTooLarge(byte[] bytes, int maxBytes)
+ {
+ return bytes != null && bytes.Length > maxBytes;
+ }
+ }
+}
diff --git a/crypto/src/crypto/prng/X931SecureRandom.cs b/crypto/src/crypto/prng/X931SecureRandom.cs
new file mode 100644
index 000000000..a87bf1567
--- /dev/null
+++ b/crypto/src/crypto/prng/X931SecureRandom.cs
@@ -0,0 +1,72 @@
+using System;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Prng
+{
+ public class X931SecureRandom
+ : SecureRandom
+ {
+ private readonly bool mPredictionResistant;
+ private readonly SecureRandom mRandomSource;
+ private readonly X931Rng mDrbg;
+
+ internal X931SecureRandom(SecureRandom randomSource, X931Rng drbg, bool predictionResistant)
+ : base((IRandomGenerator)null)
+ {
+ this.mRandomSource = randomSource;
+ this.mDrbg = drbg;
+ this.mPredictionResistant = predictionResistant;
+ }
+
+ public override void SetSeed(byte[] seed)
+ {
+ lock (this)
+ {
+ if (mRandomSource != null)
+ {
+ this.mRandomSource.SetSeed(seed);
+ }
+ }
+ }
+
+ public override void SetSeed(long seed)
+ {
+ lock (this)
+ {
+ // this will happen when SecureRandom() is created
+ if (mRandomSource != null)
+ {
+ this.mRandomSource.SetSeed(seed);
+ }
+ }
+ }
+
+ public override void NextBytes(byte[] bytes)
+ {
+ lock (this)
+ {
+ // check if a reseed is required...
+ if (mDrbg.Generate(bytes, mPredictionResistant) < 0)
+ {
+ mDrbg.Reseed();
+ mDrbg.Generate(bytes, mPredictionResistant);
+ }
+ }
+ }
+
+ public override void NextBytes(byte[] buf, int off, int len)
+ {
+ byte[] bytes = new byte[len];
+ NextBytes(bytes);
+ Array.Copy(bytes, 0, buf, off, len);
+ }
+
+ public override byte[] GenerateSeed(int numBytes)
+ {
+ byte[] bytes = new byte[numBytes];
+ NextBytes(bytes);
+ return bytes;
+ }
+ }
+}
diff --git a/crypto/src/crypto/prng/X931SecureRandomBuilder.cs b/crypto/src/crypto/prng/X931SecureRandomBuilder.cs
new file mode 100644
index 000000000..31e94312e
--- /dev/null
+++ b/crypto/src/crypto/prng/X931SecureRandomBuilder.cs
@@ -0,0 +1,87 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Date;
+
+namespace Org.BouncyCastle.Crypto.Prng
+{
+ public class X931SecureRandomBuilder
+ {
+ private readonly SecureRandom mRandom; // JDK 1.1 complains on final.
+
+ private IEntropySourceProvider mEntropySourceProvider;
+ private byte[] mDateTimeVector;
+
+ /**
+ * Basic constructor, creates a builder using an EntropySourceProvider based on the default SecureRandom with
+ * predictionResistant set to false.
+ * <p>
+ * Any SecureRandom created from a builder constructed like this will make use of input passed to SecureRandom.setSeed() if
+ * the default SecureRandom does for its generateSeed() call.
+ * </p>
+ */
+ public X931SecureRandomBuilder()
+ : this(new SecureRandom(), false)
+ {
+ }
+
+ /**
+ * Construct a builder with an EntropySourceProvider based on the passed in SecureRandom and the passed in value
+ * for prediction resistance.
+ * <p>
+ * Any SecureRandom created from a builder constructed like this will make use of input passed to SecureRandom.setSeed() if
+ * the passed in SecureRandom does for its generateSeed() call.
+ * </p>
+ * @param entropySource
+ * @param predictionResistant
+ */
+ public X931SecureRandomBuilder(SecureRandom entropySource, bool predictionResistant)
+ {
+ this.mRandom = entropySource;
+ this.mEntropySourceProvider = new BasicEntropySourceProvider(mRandom, predictionResistant);
+ }
+
+ /**
+ * Create a builder which makes creates the SecureRandom objects from a specified entropy source provider.
+ * <p>
+ * <b>Note:</b> If this constructor is used any calls to setSeed() in the resulting SecureRandom will be ignored.
+ * </p>
+ * @param entropySourceProvider a provider of EntropySource objects.
+ */
+ public X931SecureRandomBuilder(IEntropySourceProvider entropySourceProvider)
+ {
+ this.mRandom = null;
+ this.mEntropySourceProvider = entropySourceProvider;
+ }
+
+ public X931SecureRandomBuilder SetDateTimeVector(byte[] dateTimeVector)
+ {
+ this.mDateTimeVector = dateTimeVector;
+ return this;
+ }
+
+ /**
+ * Construct a X9.31 secure random generator using the passed in engine and key. If predictionResistant is true the
+ * generator will be reseeded on each request.
+ *
+ * @param engine a block cipher to use as the operator.
+ * @param key the block cipher key to initialise engine with.
+ * @param predictionResistant true if engine to be reseeded on each use, false otherwise.
+ * @return a SecureRandom.
+ */
+ public X931SecureRandom Build(IBlockCipher engine, KeyParameter key, bool predictionResistant)
+ {
+ if (mDateTimeVector == null)
+ {
+ mDateTimeVector = new byte[engine.GetBlockSize()];
+ Pack.UInt64_To_BE((ulong)DateTimeUtilities.CurrentUnixMs(), mDateTimeVector, 0);
+ }
+
+ engine.Init(true, key);
+
+ return new X931SecureRandom(mRandom, new X931Rng(engine, mDateTimeVector, mEntropySourceProvider.Get(engine.GetBlockSize() * 8)), predictionResistant);
+ }
+ }
+}
diff --git a/crypto/src/crypto/prng/drbg/CtrSP800Drbg.cs b/crypto/src/crypto/prng/drbg/CtrSP800Drbg.cs
index d9595d530..2e4fbe4ed 100644
--- a/crypto/src/crypto/prng/drbg/CtrSP800Drbg.cs
+++ b/crypto/src/crypto/prng/drbg/CtrSP800Drbg.cs
@@ -1,5 +1,6 @@
using System;
+using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Utilities;
using Org.BouncyCastle.Utilities.Encoders;
@@ -8,24 +9,25 @@ namespace Org.BouncyCastle.Crypto.Prng.Drbg
/**
* A SP800-90A CTR DRBG.
*/
- public class CTRSP800Drbg: SP80090Drbg
+ public class CtrSP800Drbg
+ : ISP80090Drbg
{
- private static readonly long TDEA_RESEED_MAX = 1L << (32 - 1);
- private static readonly long AES_RESEED_MAX = 1L << (48 - 1);
- private static readonly int TDEA_MAX_BITS_REQUEST = 1 << (13 - 1);
- private static readonly int AES_MAX_BITS_REQUEST = 1 << (19 - 1);
-
- private IEntropySource _entropySource;
- private IBlockCipher _engine;
- private int _keySizeInBits;
- private int _seedLength;
- private int _securityStrength;
-
- // internal state
- private byte[] _Key;
- private byte[] _V;
- private long _reseedCounter = 0;
- private bool _isTDEA = false;
+ private static readonly long TDEA_RESEED_MAX = 1L << (32 - 1);
+ private static readonly long AES_RESEED_MAX = 1L << (48 - 1);
+ private static readonly int TDEA_MAX_BITS_REQUEST = 1 << (13 - 1);
+ private static readonly int AES_MAX_BITS_REQUEST = 1 << (19 - 1);
+
+ private readonly IEntropySource mEntropySource;
+ private readonly IBlockCipher mEngine;
+ private readonly int mKeySizeInBits;
+ private readonly int mSeedLength;
+ private readonly int mSecurityStrength;
+
+ // internal state
+ private byte[] mKey;
+ private byte[] mV;
+ private long mReseedCounter = 0;
+ private bool mIsTdea = false;
/**
* Construct a SP800-90A CTR DRBG.
@@ -39,66 +41,58 @@ namespace Org.BouncyCastle.Crypto.Prng.Drbg
* @param personalizationString personalization string to distinguish this DRBG (may be null).
* @param nonce nonce to further distinguish this DRBG (may be null).
*/
- public CTRSP800Drbg(IBlockCipher engine, int keySizeInBits, int securityStrength, IEntropySource entropySource, byte[] personalizationString, byte[] nonce)
+ public CtrSP800Drbg(IBlockCipher engine, int keySizeInBits, int securityStrength, IEntropySource entropySource,
+ byte[] personalizationString, byte[] nonce)
{
- _entropySource = entropySource;
- _engine = engine;
-
- _keySizeInBits = keySizeInBits;
- _securityStrength = securityStrength;
- _seedLength = keySizeInBits + engine.getBlockSize() * 8;
- _isTDEA = isTDEA(engine);
-
if (securityStrength > 256)
- {
throw new ArgumentException("Requested security strength is not supported by the derivation function");
- }
-
- if (getMaxSecurityStrength(engine, keySizeInBits) < securityStrength)
- {
+ if (GetMaxSecurityStrength(engine, keySizeInBits) < securityStrength)
throw new ArgumentException("Requested security strength is not supported by block cipher and key size");
- }
-
if (entropySource.EntropySize < securityStrength)
- {
throw new ArgumentException("Not enough entropy for security strength required");
- }
- byte[] entropy = getEntropy(); // Get_entropy_input
+ mEntropySource = entropySource;
+ mEngine = engine;
+
+ mKeySizeInBits = keySizeInBits;
+ mSecurityStrength = securityStrength;
+ mSeedLength = keySizeInBits + engine.GetBlockSize() * 8;
+ mIsTdea = IsTdea(engine);
+
+ byte[] entropy = GetEntropy(); // Get_entropy_input
- CTR_DRBG_Instantiate_algorithm(entropy, nonce, personalizationString);
+ CTR_DRBG_Instantiate_algorithm(entropy, nonce, personalizationString);
}
- private void CTR_DRBG_Instantiate_algorithm(byte[] entropy, byte[] nonce,
- byte[] personalisationString)
+ private void CTR_DRBG_Instantiate_algorithm(byte[] entropy, byte[] nonce, byte[] personalisationString)
{
- byte[] seedMaterial = Arrays.Concatenate(entropy, nonce, personalisationString);
- byte[] seed = Block_Cipher_df(seedMaterial, _seedLength);
+ byte[] seedMaterial = Arrays.ConcatenateAll(entropy, nonce, personalisationString);
+ byte[] seed = Block_Cipher_df(seedMaterial, mSeedLength);
- int outlen = _engine.getBlockSize();
+ int outlen = mEngine.GetBlockSize();
- _Key = new byte[(_keySizeInBits + 7) / 8];
- _V = new byte[outlen];
+ mKey = new byte[(mKeySizeInBits + 7) / 8];
+ mV = new byte[outlen];
- // _Key & _V are modified by this call
- CTR_DRBG_Update(seed, _Key, _V);
+ // mKey & mV are modified by this call
+ CTR_DRBG_Update(seed, mKey, mV);
- _reseedCounter = 1;
+ mReseedCounter = 1;
}
- private void CTR_DRBG_Update(byte[] seed, byte[] key, byte[] v)
+ private void CTR_DRBG_Update(byte[] seed, byte[] key, byte[] v)
{
byte[] temp = new byte[seed.Length];
- byte[] outputBlock = new byte[_engine.getBlockSize()];
-
- int i=0;
- int outLen = _engine.getBlockSize();
+ byte[] outputBlock = new byte[mEngine.GetBlockSize()];
+
+ int i = 0;
+ int outLen = mEngine.GetBlockSize();
- _engine.init(true, new KeyParameter(expandKey(key)));
+ mEngine.Init(true, new KeyParameter(ExpandKey(key)));
while (i*outLen < seed.Length)
{
- addOneTo(v);
- _engine.processBlock(v, 0, outputBlock, 0);
+ AddOneTo(v);
+ mEngine.ProcessBlock(v, 0, outputBlock, 0);
int bytesToCopy = ((temp.Length - i * outLen) > outLen)
? outLen : (temp.Length - i * outLen);
@@ -115,49 +109,48 @@ namespace Org.BouncyCastle.Crypto.Prng.Drbg
private void CTR_DRBG_Reseed_algorithm(byte[] additionalInput)
{
- byte[] seedMaterial = Arrays.Concatenate(getEntropy(), additionalInput);
+ byte[] seedMaterial = Arrays.Concatenate(GetEntropy(), additionalInput);
- seedMaterial = Block_Cipher_df(seedMaterial, _seedLength);
+ seedMaterial = Block_Cipher_df(seedMaterial, mSeedLength);
- CTR_DRBG_Update(seedMaterial, _Key, _V);
+ CTR_DRBG_Update(seedMaterial, mKey, mV);
- _reseedCounter = 1;
+ mReseedCounter = 1;
}
- private void XOR(byte[] output, byte[] a, byte[] b, int bOff)
+ private void XOR(byte[] output, byte[] a, byte[] b, int bOff)
{
- for (int i=0; i< output.Length; i++)
+ for (int i = 0; i < output.Length; i++)
{
- output[i] = (byte)(a[i] ^ b[i+bOff]);
+ output[i] = (byte)(a[i] ^ b[bOff + i]);
}
}
-
- private void addOneTo(byte[] longer)
+
+ private void AddOneTo(byte[] longer)
{
- int carry = 1;
- for (int i = 1; i <= longer.Length; i++) // warning
- {
- int res = (longer[longer.Length - i] & 0xff) + carry;
- carry = (res > 0xff) ? 1 : 0;
- longer[longer.Length - i] = (byte)res;
- }
+ uint carry = 1;
+ int i = longer.Length;
+ while (--i >= 0)
+ {
+ carry += longer[i];
+ longer[i] = (byte)carry;
+ carry >>= 8;
+ }
}
- private byte[] getEntropy()
+ private byte[] GetEntropy()
{
- byte[] entropy = _entropySource.getEntropy();
- if (entropy.Length < (_securityStrength + 7) / 8)
- {
- throw new IllegalStateException("Insufficient entropy provided by entropy source");
- }
+ byte[] entropy = mEntropySource.GetEntropy();
+ if (entropy.Length < (mSecurityStrength + 7) / 8)
+ throw new InvalidOperationException("Insufficient entropy provided by entropy source");
return entropy;
}
// -- Internal state migration ---
-
- private static final byte[] K_BITS = Hex.decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F");
- // 1. If (number_of_bits_to_return > max_number_of_bits), then return an
+ private static readonly byte[] K_BITS = Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F");
+
+ // 1. If (number_of_bits_to_return > max_number_of_bits), then return an
// ERROR_FLAG.
// 2. L = len (input_string)/8.
// 3. N = number_of_bits_to_return/8.
@@ -219,7 +212,7 @@ namespace Org.BouncyCastle.Crypto.Prng.Drbg
// 15. Return SUCCESS and requested_bits.
private byte[] Block_Cipher_df(byte[] inputString, int bitLength)
{
- int outLen = _engine.getBlockSize();
+ int outLen = mEngine.GetBlockSize();
int L = inputString.Length; // already in bytes
int N = bitLength / 8;
// 4 S = L || N || inputstring || 0x80
@@ -232,16 +225,16 @@ namespace Org.BouncyCastle.Crypto.Prng.Drbg
S[8 + L] = (byte)0x80;
// S already padded with zeros
- byte[] temp = new byte[_keySizeInBits / 8 + outLen];
+ byte[] temp = new byte[mKeySizeInBits / 8 + outLen];
byte[] bccOut = new byte[outLen];
byte[] IV = new byte[outLen];
int i = 0;
- byte[] K = new byte[_keySizeInBits / 8];
+ byte[] K = new byte[mKeySizeInBits / 8];
Array.Copy(K_BITS, 0, K, 0, K.Length);
- while (i*outLen*8 < _keySizeInBits + outLen *8)
+ while (i*outLen*8 < mKeySizeInBits + outLen *8)
{
copyIntToByteArray(IV, i, 0);
BCC(bccOut, K, IV, S);
@@ -261,11 +254,11 @@ namespace Org.BouncyCastle.Crypto.Prng.Drbg
temp = new byte[bitLength / 2];
i = 0;
- _engine.init(true, new KeyParameter(expandKey(K)));
+ mEngine.Init(true, new KeyParameter(ExpandKey(K)));
while (i * outLen < temp.Length)
{
- _engine.processBlock(X, 0, X, 0);
+ mEngine.ProcessBlock(X, 0, X, 0);
int bytesToCopy = ((temp.Length - i * outLen) > outLen)
? outLen
@@ -292,23 +285,23 @@ namespace Org.BouncyCastle.Crypto.Prng.Drbg
*/
private void BCC(byte[] bccOut, byte[] k, byte[] iV, byte[] data)
{
- int outlen = _engine.getBlockSize();
+ int outlen = mEngine.GetBlockSize();
byte[] chainingValue = new byte[outlen]; // initial values = 0
int n = data.Length / outlen;
byte[] inputBlock = new byte[outlen];
- _engine.init(true, new KeyParameter(expandKey(k)));
+ mEngine.Init(true, new KeyParameter(ExpandKey(k)));
- _engine.processBlock(iV, 0, chainingValue, 0);
+ mEngine.ProcessBlock(iV, 0, chainingValue, 0);
- for (int i = 0; i < n; i++)
+ for (int i = 0; i < n; i++)
{
XOR(inputBlock, chainingValue, data, i*outlen);
- _engine.processBlock(inputBlock, 0, chainingValue, 0);
+ mEngine.ProcessBlock(inputBlock, 0, chainingValue, 0);
}
- Array.Copy(chainingValue, 0, bccOut, 0, bccOut.Length);
+ Array.Copy(chainingValue, 0, bccOut, 0, bccOut.Length);
}
private void copyIntToByteArray(byte[] buf, int value, int offSet)
@@ -326,9 +319,7 @@ namespace Org.BouncyCastle.Crypto.Prng.Drbg
*/
public int BlockSize
{
- get {
- return _V.Length * 8;
- }
+ get { return mV.Length * 8; }
}
/**
@@ -342,32 +333,24 @@ namespace Org.BouncyCastle.Crypto.Prng.Drbg
*/
public int Generate(byte[] output, byte[] additionalInput, bool predictionResistant)
{
- if (_isTDEA)
+ if (mIsTdea)
{
- if (_reseedCounter > TDEA_RESEED_MAX)
- {
+ if (mReseedCounter > TDEA_RESEED_MAX)
return -1;
- }
- if (Utils.isTooLarge(output, TDEA_MAX_BITS_REQUEST / 8))
- {
- throw new ArgumentException("Number of bits per request limited to " + TDEA_MAX_BITS_REQUEST);
- }
+ if (DrbgUtilities.IsTooLarge(output, TDEA_MAX_BITS_REQUEST / 8))
+ throw new ArgumentException("Number of bits per request limited to " + TDEA_MAX_BITS_REQUEST, "output");
}
else
{
- if (_reseedCounter > AES_RESEED_MAX)
- {
+ if (mReseedCounter > AES_RESEED_MAX)
return -1;
- }
- if (Utils.isTooLarge(output, AES_MAX_BITS_REQUEST / 8))
- {
- throw new ArgumentException("Number of bits per request limited to " + AES_MAX_BITS_REQUEST);
- }
+ if (DrbgUtilities.IsTooLarge(output, AES_MAX_BITS_REQUEST / 8))
+ throw new ArgumentException("Number of bits per request limited to " + AES_MAX_BITS_REQUEST, "output");
}
- if (predictionResistant)
+ if (predictionResistant)
{
CTR_DRBG_Reseed_algorithm(additionalInput);
additionalInput = null;
@@ -375,39 +358,39 @@ namespace Org.BouncyCastle.Crypto.Prng.Drbg
if (additionalInput != null)
{
- additionalInput = Block_Cipher_df(additionalInput, _seedLength);
- CTR_DRBG_Update(additionalInput, _Key, _V);
+ additionalInput = Block_Cipher_df(additionalInput, mSeedLength);
+ CTR_DRBG_Update(additionalInput, mKey, mV);
}
else
{
- additionalInput = new byte[_seedLength];
+ additionalInput = new byte[mSeedLength];
}
- byte[] tmp = new byte[_V.Length];
+ byte[] tmp = new byte[mV.Length];
- _engine.init(true, new KeyParameter(expandKey(_Key)));
+ mEngine.Init(true, new KeyParameter(ExpandKey(mKey)));
- for (int i = 0; i <= output.Length / tmp.Length; i++)
+ for (int i = 0; i <= output.Length / tmp.Length; i++)
{
- int bytesToCopy = ((output.Length - i * tmp.Length) > tmp.Length)
- ? tmp.Length
- : (output.Length - i * _V.Length);
+ int bytesToCopy = ((output.Length - i * tmp.Length) > tmp.Length)
+ ? tmp.Length
+ : (output.Length - i * mV.Length);
- if (bytesToCopy != 0)
+ if (bytesToCopy != 0)
{
- addOneTo(_V);
+ AddOneTo(mV);
- _engine.processBlock(_V, 0, tmp, 0);
+ mEngine.ProcessBlock(mV, 0, tmp, 0);
- Array.Copy(tmp, 0, output, i * tmp.Length, bytesToCopy);
+ Array.Copy(tmp, 0, output, i * tmp.Length, bytesToCopy);
}
}
- CTR_DRBG_Update(additionalInput, _Key, _V);
+ CTR_DRBG_Update(additionalInput, mKey, mV);
- _reseedCounter++;
+ mReseedCounter++;
- return output.Length * 8;
+ return output.Length * 8;
}
/**
@@ -420,14 +403,14 @@ namespace Org.BouncyCastle.Crypto.Prng.Drbg
CTR_DRBG_Reseed_algorithm(additionalInput);
}
- private boolean isTDEA(BlockCipher cipher)
+ private bool IsTdea(IBlockCipher cipher)
{
return cipher.AlgorithmName.Equals("DESede") || cipher.AlgorithmName.Equals("TDEA");
}
- private int getMaxSecurityStrength(BlockCipher cipher, int keySizeInBits)
+ private int GetMaxSecurityStrength(IBlockCipher cipher, int keySizeInBits)
{
- if (isTDEA(cipher) && keySizeInBits == 168)
+ if (IsTdea(cipher) && keySizeInBits == 168)
{
return 112;
}
@@ -436,19 +419,19 @@ namespace Org.BouncyCastle.Crypto.Prng.Drbg
return keySizeInBits;
}
- return -1;
+ return -1;
}
- byte[] expandKey(byte[] key)
+ private byte[] ExpandKey(byte[] key)
{
- if (_isTDEA)
+ if (mIsTdea)
{
// expand key to 192 bits.
byte[] tmp = new byte[24];
- padKey(key, 0, tmp, 0);
- padKey(key, 7, tmp, 8);
- padKey(key, 14, tmp, 16);
+ PadKey(key, 0, tmp, 0);
+ PadKey(key, 7, tmp, 8);
+ PadKey(key, 14, tmp, 16);
return tmp;
}
@@ -466,7 +449,7 @@ namespace Org.BouncyCastle.Crypto.Prng.Drbg
* @param tmp
* @param tmpOff
*/
- private void padKey(byte[] keyMaster, int keyOff, byte[] tmp, int tmpOff)
+ private void PadKey(byte[] keyMaster, int keyOff, byte[] tmp, int tmpOff)
{
tmp[tmpOff + 0] = (byte)(keyMaster[keyOff + 0] & 0xfe);
tmp[tmpOff + 1] = (byte)((keyMaster[keyOff + 0] << 7) | ((keyMaster[keyOff + 1] & 0xfc) >> 1));
@@ -479,15 +462,15 @@ namespace Org.BouncyCastle.Crypto.Prng.Drbg
for (int i = tmpOff; i <= tmpOff + 7; i++)
{
- int b = tmp[i];
- tmp[i] = (byte)((b & 0xfe) |
- ((((b >> 1) ^
- (b >> 2) ^
- (b >> 3) ^
- (b >> 4) ^
- (b >> 5) ^
- (b >> 6) ^
- (b >> 7)) ^ 0x01) & 0x01));
+ uint b = tmp[i];
+
+ uint parity = b ^ 1U;
+ parity ^= (parity >> 4);
+ parity ^= (parity >> 2);
+ parity ^= (parity >> 1);
+ parity &= 1U;
+
+ tmp[i] = (byte)(b ^ parity);
}
}
}
diff --git a/crypto/src/crypto/prng/drbg/DrbgUtilities.cs b/crypto/src/crypto/prng/drbg/DrbgUtilities.cs
index b5f3b5830..d9a1c439c 100644
--- a/crypto/src/crypto/prng/drbg/DrbgUtilities.cs
+++ b/crypto/src/crypto/prng/drbg/DrbgUtilities.cs
@@ -5,39 +5,39 @@ using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Prng.Drbg
{
- internal class Utils
+ internal class DrbgUtilities
{
private static readonly IDictionary maxSecurityStrengths = Platform.CreateHashtable();
- static Utils()
+ static DrbgUtilities()
{
- maxSecurityStrengths.put("SHA-1", 128);
+ maxSecurityStrengths.Add("SHA-1", 128);
- maxSecurityStrengths.put("SHA-224", 192);
- maxSecurityStrengths.put("SHA-256", 256);
- maxSecurityStrengths.put("SHA-384", 256);
- maxSecurityStrengths.put("SHA-512", 256);
+ maxSecurityStrengths.Add("SHA-224", 192);
+ maxSecurityStrengths.Add("SHA-256", 256);
+ maxSecurityStrengths.Add("SHA-384", 256);
+ maxSecurityStrengths.Add("SHA-512", 256);
- maxSecurityStrengths.put("SHA-512/224", 192);
- maxSecurityStrengths.put("SHA-512/256", 256);
+ maxSecurityStrengths.Add("SHA-512/224", 192);
+ maxSecurityStrengths.Add("SHA-512/256", 256);
}
- internal static int getMaxSecurityStrength(IDigest d)
+ internal static int GetMaxSecurityStrength(IDigest d)
{
return (int)maxSecurityStrengths[d.AlgorithmName];
}
- internal static int getMaxSecurityStrength(IMac m)
+ internal static int GetMaxSecurityStrength(IMac m)
{
- String name = m.getAlgorithmName();
+ string name = m.AlgorithmName;
- return (int)maxSecurityStrengths[name.substring(0, name.indexOf("/"))];
+ return (int)maxSecurityStrengths[name.Substring(0, name.IndexOf("/"))];
}
/**
* Used by both Dual EC and Hash.
*/
- internal static byte[] hash_df(Digest digest, byte[] seedMaterial, int seedLength)
+ internal static byte[] HashDF(IDigest digest, byte[] seedMaterial, int seedLength)
{
// 1. temp = the Null string.
// 2. .
@@ -52,10 +52,10 @@ namespace Org.BouncyCastle.Crypto.Prng.Drbg
// 6. Return SUCCESS and requested_bits.
byte[] temp = new byte[(seedLength + 7) / 8];
- int len = temp.Length / digest.getDigestSize();
+ int len = temp.Length / digest.GetDigestSize();
int counter = 1;
- byte[] dig = new byte[digest.getDigestSize()];
+ byte[] dig = new byte[digest.GetDigestSize()];
for (int i = 0; i <= len; i++)
{
@@ -82,20 +82,20 @@ namespace Org.BouncyCastle.Crypto.Prng.Drbg
if (seedLength % 8 != 0)
{
int shift = 8 - (seedLength % 8);
- int carry = 0;
+ uint carry = 0;
- for (int i = 0; i != temp.Length; i++)
+ for (int i = 0; i != temp.Length; i++)
{
- uint b = temp[i] & 0xff;
+ uint b = temp[i];
temp[i] = (byte)((b >> shift) | (carry << (8 - shift)));
carry = b;
}
}
- return temp;
+ return temp;
}
- internal static boolean isTooLarge(byte[] bytes, int maxBytes)
+ internal static bool IsTooLarge(byte[] bytes, int maxBytes)
{
return bytes != null && bytes.Length > maxBytes;
}
diff --git a/crypto/src/crypto/prng/drbg/HMacSP800Drbg.cs b/crypto/src/crypto/prng/drbg/HMacSP800Drbg.cs
index 78a710097..78331705e 100644
--- a/crypto/src/crypto/prng/drbg/HMacSP800Drbg.cs
+++ b/crypto/src/crypto/prng/drbg/HMacSP800Drbg.cs
@@ -8,19 +8,21 @@ namespace Org.BouncyCastle.Crypto.Prng.Drbg
/**
* A SP800-90A HMAC DRBG.
*/
- public class HMacSP800Drbg: SP80090Drbg
+ public class HMacSP800Drbg
+ : ISP80090Drbg
{
- private readonly static long RESEED_MAX = 1L << (48 - 1);
- private readonly static int MAX_BITS_REQUEST = 1 << (19 - 1);
+ private readonly static long RESEED_MAX = 1L << (48 - 1);
+ private readonly static int MAX_BITS_REQUEST = 1 << (19 - 1);
- private byte[] _K;
- private byte[] _V;
- private long _reseedCounter;
- private EntropySource _entropySource;
- private Mac _hMac;
- private int _securityStrength;
+ private readonly byte[] mK;
+ private readonly byte[] mV;
+ private readonly IEntropySource mEntropySource;
+ private readonly IMac mHMac;
+ private readonly int mSecurityStrength;
- /**
+ private long mReseedCounter;
+
+ /**
* Construct a SP800-90A Hash DRBG.
* <p>
* Minimum entropy requirement is the security strength requested.
@@ -33,33 +35,28 @@ namespace Org.BouncyCastle.Crypto.Prng.Drbg
*/
public HMacSP800Drbg(IMac hMac, int securityStrength, IEntropySource entropySource, byte[] personalizationString, byte[] nonce)
{
- if (securityStrength > Utils.getMaxSecurityStrength(hMac))
- {
+ if (securityStrength > DrbgUtilities.GetMaxSecurityStrength(hMac))
throw new ArgumentException("Requested security strength is not supported by the derivation function");
- }
-
if (entropySource.EntropySize < securityStrength)
- {
throw new ArgumentException("Not enough entropy for security strength required");
- }
- _securityStrength = securityStrength;
- _entropySource = entropySource;
- _hMac = hMac;
+ mHMac = hMac;
+ mSecurityStrength = securityStrength;
+ mEntropySource = entropySource;
- byte[] entropy = getEntropy();
- byte[] seedMaterial = Arrays.Concatenate(entropy, nonce, personalizationString);
+ byte[] entropy = GetEntropy();
+ byte[] seedMaterial = Arrays.ConcatenateAll(entropy, nonce, personalizationString);
- _K = new byte[hMac.GetMacSize()];
- _V = new byte[_K.Length];
- Arrays.fill(_V, (byte)1);
+ mK = new byte[hMac.GetMacSize()];
+ mV = new byte[mK.Length];
+ Arrays.Fill(mV, (byte)1);
- hmac_DRBG_Update(seedMaterial);
+ hmac_DRBG_Update(seedMaterial);
- _reseedCounter = 1;
+ mReseedCounter = 1;
}
- private void hmac_DRBG_Update(byte[] seedMaterial)
+ private void hmac_DRBG_Update(byte[] seedMaterial)
{
hmac_DRBG_Update_Func(seedMaterial, (byte)0x00);
if (seedMaterial != null)
@@ -70,22 +67,22 @@ namespace Org.BouncyCastle.Crypto.Prng.Drbg
private void hmac_DRBG_Update_Func(byte[] seedMaterial, byte vValue)
{
- _hMac.Init(new KeyParameter(_K));
+ mHMac.Init(new KeyParameter(mK));
- _hMac.BlockUpdate(_V, 0, _V.Length);
- _hMac.Update(vValue);
+ mHMac.BlockUpdate(mV, 0, mV.Length);
+ mHMac.Update(vValue);
if (seedMaterial != null)
{
- _hMac.update(seedMaterial, 0, seedMaterial.Length);
+ mHMac.BlockUpdate(seedMaterial, 0, seedMaterial.Length);
}
- _hMac.DoFinal(_K, 0);
+ mHMac.DoFinal(mK, 0);
- _hMac.Init(new KeyParameter(_K));
- _hMac.BlockUpdate(_V, 0, _V.Length);
+ mHMac.Init(new KeyParameter(mK));
+ mHMac.BlockUpdate(mV, 0, mV.Length);
- _hMac.DoFinal(_V, 0);
+ mHMac.DoFinal(mV, 0);
}
/**
@@ -95,9 +92,7 @@ namespace Org.BouncyCastle.Crypto.Prng.Drbg
*/
public int BlockSize
{
- get {
- return _V.Length * 8;
- }
+ get { return mV.Length * 8; }
}
/**
@@ -109,23 +104,21 @@ namespace Org.BouncyCastle.Crypto.Prng.Drbg
*
* @return number of bits generated, -1 if a reseed required.
*/
- public int Generate(byte[] output, byte[] additionalInput, boolean predictionResistant)
+ public int Generate(byte[] output, byte[] additionalInput, bool predictionResistant)
{
int numberOfBits = output.Length * 8;
- if (numberOfBits > MAX_BITS_REQUEST)
- {
- throw new IllegalArgumentException("Number of bits per request limited to " + MAX_BITS_REQUEST);
- }
+ if (numberOfBits > MAX_BITS_REQUEST)
+ throw new ArgumentException("Number of bits per request limited to " + MAX_BITS_REQUEST, "output");
- if (_reseedCounter > RESEED_MAX)
+ if (mReseedCounter > RESEED_MAX)
{
return -1;
}
- if (predictionResistant)
+ if (predictionResistant)
{
- reseed(additionalInput);
+ Reseed(additionalInput);
additionalInput = null;
}
@@ -135,36 +128,36 @@ namespace Org.BouncyCastle.Crypto.Prng.Drbg
hmac_DRBG_Update(additionalInput);
}
- // 3.
+ // 3.
byte[] rv = new byte[output.Length];
- int m = output.Length / _V.Length;
+ int m = output.Length / mV.Length;
- _hMac.Init(new KeyParameter(_K));
+ mHMac.Init(new KeyParameter(mK));
for (int i = 0; i < m; i++)
{
- _hMac.BlockUpdate(_V, 0, _V.Length);
- _hMac.DoFinal(_V, 0);
+ mHMac.BlockUpdate(mV, 0, mV.Length);
+ mHMac.DoFinal(mV, 0);
- Array.Copy(_V, 0, rv, i * _V.Length, _V.Length);
+ Array.Copy(mV, 0, rv, i * mV.Length, mV.Length);
}
- if (m * _V.Length < rv.Length)
+ if (m * mV.Length < rv.Length)
{
- _hMac.BlockUpdate(_V, 0, _V.Length);
- _hMac.DoFinal(_V, 0);
+ mHMac.BlockUpdate(mV, 0, mV.Length);
+ mHMac.DoFinal(mV, 0);
- Array.Copy(_V, 0, rv, m * _V.Length, rv.Length - (m * _V.Length));
+ Array.Copy(mV, 0, rv, m * mV.Length, rv.Length - (m * mV.Length));
}
- hmac_DRBG_Update(additionalInput);
+ hmac_DRBG_Update(additionalInput);
- _reseedCounter++;
+ mReseedCounter++;
Array.Copy(rv, 0, output, 0, output.Length);
- return numberOfBits;
+ return numberOfBits;
}
/**
@@ -174,22 +167,19 @@ namespace Org.BouncyCastle.Crypto.Prng.Drbg
*/
public void Reseed(byte[] additionalInput)
{
- byte[] entropy = getEntropy();
+ byte[] entropy = GetEntropy();
byte[] seedMaterial = Arrays.Concatenate(entropy, additionalInput);
hmac_DRBG_Update(seedMaterial);
- _reseedCounter = 1;
+ mReseedCounter = 1;
}
- private byte[] getEntropy()
+ private byte[] GetEntropy()
{
- byte[] entropy = _entropySource.GetEntropy();
-
- if (entropy.Length < (_securityStrength + 7) / 8)
- {
- throw new IllegalStateException("Insufficient entropy provided by entropy source");
- }
+ byte[] entropy = mEntropySource.GetEntropy();
+ if (entropy.Length < (mSecurityStrength + 7) / 8)
+ throw new InvalidOperationException("Insufficient entropy provided by entropy source");
return entropy;
}
}
diff --git a/crypto/src/crypto/prng/drbg/HashSP800Drbg.cs b/crypto/src/crypto/prng/drbg/HashSP800Drbg.cs
index 868778817..493da5a75 100644
--- a/crypto/src/crypto/prng/drbg/HashSP800Drbg.cs
+++ b/crypto/src/crypto/prng/drbg/HashSP800Drbg.cs
@@ -8,36 +8,37 @@ namespace Org.BouncyCastle.Crypto.Prng.Drbg
/**
* A SP800-90A Hash DRBG.
*/
- public class HashSP800Drbg: SP80090Drbg
+ public class HashSP800Drbg
+ : ISP80090Drbg
{
- private readonly static byte[] ONE = { 0x01 };
+ private readonly static byte[] ONE = { 0x01 };
- private readonly static long RESEED_MAX = 1L << (48 - 1);
- private readonly static int MAX_BITS_REQUEST = 1 << (19 - 1);
+ private readonly static long RESEED_MAX = 1L << (48 - 1);
+ private readonly static int MAX_BITS_REQUEST = 1 << (19 - 1);
private static readonly IDictionary seedlens = Platform.CreateHashtable();
static HashSP800Drbg()
{
- seedlens.Add("SHA-1", 440);
- seedlens.Add("SHA-224", 440);
- seedlens.Add("SHA-256", 440);
- seedlens.Add("SHA-512/256", 440);
- seedlens.Add("SHA-512/224", 440);
- seedlens.Add("SHA-384", 888);
- seedlens.Add("SHA-512", 888);
-
+ seedlens.Add("SHA-1", 440);
+ seedlens.Add("SHA-224", 440);
+ seedlens.Add("SHA-256", 440);
+ seedlens.Add("SHA-512/256", 440);
+ seedlens.Add("SHA-512/224", 440);
+ seedlens.Add("SHA-384", 888);
+ seedlens.Add("SHA-512", 888);
}
- private IDigest _digest;
- private byte[] _V;
- private byte[] _C;
- private long _reseedCounter;
- private IEntropySource _entropySource;
- private int _securityStrength;
- private int _seedLength;
+ private readonly IDigest mDigest;
+ private readonly IEntropySource mEntropySource;
+ private readonly int mSecurityStrength;
+ private readonly int mSeedLength;
- /**
+ private byte[] mV;
+ private byte[] mC;
+ private long mReseedCounter;
+
+ /**
* Construct a SP800-90A Hash DRBG.
* <p>
* Minimum entropy requirement is the security strength requested.
@@ -50,22 +51,17 @@ namespace Org.BouncyCastle.Crypto.Prng.Drbg
*/
public HashSP800Drbg(IDigest digest, int securityStrength, IEntropySource entropySource, byte[] personalizationString, byte[] nonce)
{
- if (securityStrength > Utils.getMaxSecurityStrength(digest))
- {
+ if (securityStrength > DrbgUtilities.GetMaxSecurityStrength(digest))
throw new ArgumentException("Requested security strength is not supported by the derivation function");
- }
-
if (entropySource.EntropySize < securityStrength)
- {
throw new ArgumentException("Not enough entropy for security strength required");
- }
- _digest = digest;
- _entropySource = entropySource;
- _securityStrength = securityStrength;
- _seedLength = ((Integer)seedlens.get(digest.getAlgorithmName())).intValue();
+ mDigest = digest;
+ mEntropySource = entropySource;
+ mSecurityStrength = securityStrength;
+ mSeedLength = (int)seedlens[digest.AlgorithmName];
- // 1. seed_material = entropy_input || nonce || personalization_string.
+ // 1. seed_material = entropy_input || nonce || personalization_string.
// 2. seed = Hash_df (seed_material, seedlen).
// 3. V = seed.
// 4. C = Hash_df ((0x00 || V), seedlen). Comment: Preceed V with a byte
@@ -73,16 +69,16 @@ namespace Org.BouncyCastle.Crypto.Prng.Drbg
// 5. reseed_counter = 1.
// 6. Return V, C, and reseed_counter as the initial_working_state
- byte[] entropy = getEntropy();
- byte[] seedMaterial = Arrays.Concatenate(entropy, nonce, personalizationString);
- byte[] seed = Utils.hash_df(_digest, seedMaterial, _seedLength);
+ byte[] entropy = GetEntropy();
+ byte[] seedMaterial = Arrays.ConcatenateAll(entropy, nonce, personalizationString);
+ byte[] seed = DrbgUtilities.HashDF(mDigest, seedMaterial, mSeedLength);
- _V = seed;
- byte[] subV = new byte[_V.Length + 1];
- Array.Copy(_V, 0, subV, 1, _V.Length);
- _C = Utils.hash_df(_digest, subV, _seedLength);
+ mV = seed;
+ byte[] subV = new byte[mV.Length + 1];
+ Array.Copy(mV, 0, subV, 1, mV.Length);
+ mC = DrbgUtilities.HashDF(mDigest, subV, mSeedLength);
- _reseedCounter = 1;
+ mReseedCounter = 1;
}
/**
@@ -92,9 +88,7 @@ namespace Org.BouncyCastle.Crypto.Prng.Drbg
*/
public int BlockSize
{
- get {
- return _digest.GetDigestSize () * 8;
- }
+ get { return mDigest.GetDigestSize () * 8; }
}
/**
@@ -121,97 +115,95 @@ namespace Org.BouncyCastle.Crypto.Prng.Drbg
// 6. reseed_counter = reseed_counter + 1.
// 7. Return SUCCESS, returned_bits, and the new values of V, C, and
// reseed_counter for the new_working_state.
- int numberOfBits = output.Length*8;
+ int numberOfBits = output.Length * 8;
if (numberOfBits > MAX_BITS_REQUEST)
- {
- throw new ArgumentException("Number of bits per request limited to " + MAX_BITS_REQUEST);
- }
+ throw new ArgumentException("Number of bits per request limited to " + MAX_BITS_REQUEST, "output");
- if (_reseedCounter > RESEED_MAX)
- {
+ if (mReseedCounter > RESEED_MAX)
return -1;
- }
- if (predictionResistant)
+ if (predictionResistant)
{
- reseed(additionalInput);
+ Reseed(additionalInput);
additionalInput = null;
}
// 2.
if (additionalInput != null)
{
- byte[] newInput = new byte[1 + _V.Length + additionalInput.Length];
+ byte[] newInput = new byte[1 + mV.Length + additionalInput.Length];
newInput[0] = 0x02;
- Array.Copy(_V, 0, newInput, 1, _V.Length);
+ Array.Copy(mV, 0, newInput, 1, mV.Length);
// TODO: inOff / inLength
- Array.Copy(additionalInput, 0, newInput, 1 + _V.Length, additionalInput.Length);
- byte[] w = hash(newInput);
+ Array.Copy(additionalInput, 0, newInput, 1 + mV.Length, additionalInput.Length);
+ byte[] w = Hash(newInput);
- addTo(_V, w);
+ AddTo(mV, w);
}
-
- // 3.
- byte[] rv = hashgen(_V, numberOfBits);
-
- // 4.
- byte[] subH = new byte[_V.Length + 1];
- Array.Copy(_V, 0, subH, 1, _V.Length);
+
+ // 3.
+ byte[] rv = hashgen(mV, numberOfBits);
+
+ // 4.
+ byte[] subH = new byte[mV.Length + 1];
+ Array.Copy(mV, 0, subH, 1, mV.Length);
subH[0] = 0x03;
-
- byte[] H = hash(subH);
-
- // 5.
- addTo(_V, H);
- addTo(_V, _C);
+
+ byte[] H = Hash(subH);
+
+ // 5.
+ AddTo(mV, H);
+ AddTo(mV, mC);
byte[] c = new byte[4];
- c[0] = (byte)(_reseedCounter >> 24);
- c[1] = (byte)(_reseedCounter >> 16);
- c[2] = (byte)(_reseedCounter >> 8);
- c[3] = (byte)_reseedCounter;
-
- addTo(_V, c);
+ c[0] = (byte)(mReseedCounter >> 24);
+ c[1] = (byte)(mReseedCounter >> 16);
+ c[2] = (byte)(mReseedCounter >> 8);
+ c[3] = (byte)mReseedCounter;
+
+ AddTo(mV, c);
- _reseedCounter++;
+ mReseedCounter++;
Array.Copy(rv, 0, output, 0, output.Length);
return numberOfBits;
}
- private byte[] getEntropy()
+ private byte[] GetEntropy()
{
- byte[] entropy = _entropySource.getEntropy();
- if (entropy.Length < (_securityStrength + 7) / 8)
- {
- throw new IllegalStateException("Insufficient entropy provided by entropy source");
- }
+ byte[] entropy = mEntropySource.GetEntropy();
+ if (entropy.Length < (mSecurityStrength + 7) / 8)
+ throw new InvalidOperationException("Insufficient entropy provided by entropy source");
return entropy;
}
// this will always add the shorter length byte array mathematically to the
// longer length byte array.
// be careful....
- private void addTo(byte[] longer, byte[] shorter)
+ private void AddTo(byte[] longer, byte[] shorter)
{
- int carry = 0;
- for (int i=1;i <= shorter.Length; i++) // warning
- {
- int res = (longer[longer.Length-i] & 0xff) + (shorter[shorter.Length-i] & 0xff) + carry;
- carry = (res > 0xff) ? 1 : 0;
- longer[longer.Length-i] = (byte)res;
- }
-
- for (int i=shorter.Length+1;i <= longer.Length; i++) // warning
- {
- int res = (longer[longer.Length-i] & 0xff) + carry;
- carry = (res > 0xff) ? 1 : 0;
- longer[longer.Length-i] = (byte)res;
- }
+ int off = longer.Length - shorter.Length;
+
+ uint carry = 0;
+ int i = shorter.Length;
+ while (--i >= 0)
+ {
+ carry += (uint)longer[off + i] + (uint)shorter[i];
+ longer[off + i] = (byte)carry;
+ carry >>= 8;
+ }
+
+ i = off;
+ while (--i >= 0)
+ {
+ carry += longer[i];
+ longer[i] = (byte)carry;
+ carry >>= 8;
+ }
}
- /**
+ /**
* Reseed the DRBG.
*
* @param additionalInput additional input to be added to the DRBG in this step.
@@ -231,33 +223,33 @@ namespace Org.BouncyCastle.Crypto.Prng.Drbg
// 6. Return V, C, and reseed_counter for the new_working_state.
//
// Comment: Precede with a byte of all zeros.
- byte[] entropy = getEntropy();
- byte[] seedMaterial = Arrays.Concatenate(ONE, _V, entropy, additionalInput);
- byte[] seed = Utils.hash_df(_digest, seedMaterial, _seedLength);
+ byte[] entropy = GetEntropy();
+ byte[] seedMaterial = Arrays.ConcatenateAll(ONE, mV, entropy, additionalInput);
+ byte[] seed = DrbgUtilities.HashDF(mDigest, seedMaterial, mSeedLength);
- _V = seed;
- byte[] subV = new byte[_V.Length + 1];
+ mV = seed;
+ byte[] subV = new byte[mV.Length + 1];
subV[0] = 0x00;
- Array.Copy(_V, 0, subV, 1, _V.Length);
- _C = Utils.hash_df(_digest, subV, _seedLength);
+ Array.Copy(mV, 0, subV, 1, mV.Length);
+ mC = DrbgUtilities.HashDF(mDigest, subV, mSeedLength);
- _reseedCounter = 1;
- }
-
- private byte[] hash(byte[] input)
- {
- byte[] hash = new byte[_digest.GetDigestSize()];
- doHash(input, hash);
- return hash;
+ mReseedCounter = 1;
}
- private void doHash(byte[] input, byte[] output)
- {
- _digest.BlockUpdate(input, 0, input.Length);
- _digest.DoFinal(output, 0);
- }
+ private byte[] Hash(byte[] input)
+ {
+ byte[] hash = new byte[mDigest.GetDigestSize()];
+ DoHash(input, hash);
+ return hash;
+ }
+
+ private void DoHash(byte[] input, byte[] output)
+ {
+ mDigest.BlockUpdate(input, 0, input.Length);
+ mDigest.DoFinal(output, 0);
+ }
- // 1. m = [requested_number_of_bits / outlen]
+ // 1. m = [requested_number_of_bits / outlen]
// 2. data = V.
// 3. W = the Null string.
// 4. For i = 1 to m
@@ -268,25 +260,25 @@ namespace Org.BouncyCastle.Crypto.Prng.Drbg
// 5. returned_bits = Leftmost (requested_no_of_bits) bits of W.
private byte[] hashgen(byte[] input, int lengthInBits)
{
- int digestSize = _digest.GetDigestSize();
+ int digestSize = mDigest.GetDigestSize();
int m = (lengthInBits / 8) / digestSize;
- byte[] data = new byte[input.Length];
+ byte[] data = new byte[input.Length];
Array.Copy(input, 0, data, 0, input.Length);
byte[] W = new byte[lengthInBits / 8];
- byte[] dig = new byte[_digest.GetDigestSize()];
+ byte[] dig = new byte[mDigest.GetDigestSize()];
for (int i = 0; i <= m; i++)
{
- doHash(data, dig);
+ DoHash(data, dig);
int bytesToCopy = ((W.Length - i * dig.Length) > dig.Length)
? dig.Length
: (W.Length - i * dig.Length);
Array.Copy(dig, 0, W, i * dig.Length, bytesToCopy);
- addTo(data, ONE);
+ AddTo(data, ONE);
}
return W;
diff --git a/crypto/src/crypto/prng/drbg/ISP80090Drbg.cs b/crypto/src/crypto/prng/drbg/ISP80090Drbg.cs
index c39cf365f..0e398209e 100644
--- a/crypto/src/crypto/prng/drbg/ISP80090Drbg.cs
+++ b/crypto/src/crypto/prng/drbg/ISP80090Drbg.cs
@@ -1,9 +1,11 @@
+using System;
+
namespace Org.BouncyCastle.Crypto.Prng.Drbg
{
/**
* Interface to SP800-90A deterministic random bit generators.
*/
- public interface SP80090Drbg
+ public interface ISP80090Drbg
{
/**
* Return the block size of the DRBG.
diff --git a/crypto/src/security/SecureRandom.cs b/crypto/src/security/SecureRandom.cs
index 4894a93e6..875709e57 100644
--- a/crypto/src/security/SecureRandom.cs
+++ b/crypto/src/security/SecureRandom.cs
@@ -164,13 +164,7 @@ namespace Org.BouncyCastle.Security
public override int Next()
{
- for (;;)
- {
- int i = NextInt() & int.MaxValue;
-
- if (i != int.MaxValue)
- return i;
- }
+ return NextInt() & int.MaxValue;
}
public override int Next(int maxValue)
@@ -184,11 +178,9 @@ namespace Org.BouncyCastle.Security
}
// Test whether maxValue is a power of 2
- if ((maxValue & -maxValue) == maxValue)
+ if ((maxValue & (maxValue - 1)) == 0)
{
- int val = NextInt() & int.MaxValue;
- long lr = ((long) maxValue * (long) val) >> 31;
- return (int) lr;
+ return NextInt() & (maxValue - 1);
}
int bits, result;
@@ -244,16 +236,17 @@ namespace Org.BouncyCastle.Security
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;
+ byte[] bytes = new byte[4];
+ NextBytes(bytes);
+
+ uint result = bytes[0];
+ result <<= 8;
+ result |= bytes[1];
+ result <<= 8;
+ result |= bytes[2];
+ result <<= 8;
+ result |= bytes[3];
+ return (int)result;
}
public virtual long NextLong()
diff --git a/crypto/src/util/Arrays.cs b/crypto/src/util/Arrays.cs
index 32c56b8b5..df9b4e7ee 100644
--- a/crypto/src/util/Arrays.cs
+++ b/crypto/src/util/Arrays.cs
@@ -591,57 +591,33 @@ namespace Org.BouncyCastle.Utilities
return rv;
}
- public static byte[] Concatenate(byte[] a, byte[] b, byte[] c)
+ public static byte[] ConcatenateAll(params byte[][] vs)
{
- if (a != null && b != null && c != null)
- {
- byte[] rv = new byte[a.Length + b.Length + c.Length];
-
- Array.Copy(a, 0, rv, 0, a.Length);
- Array.Copy(b, 0, rv, a.Length, b.Length);
- Array.Copy(c, 0, rv, a.Length + b.Length, c.Length);
+ byte[][] nonNull = new byte[vs.Length][];
+ int count = 0;
+ int totalLength = 0;
- return rv;
- }
- else if (b == null)
- {
- return Concatenate(a, c);
- }
- else
+ for (int i = 0; i < vs.Length; ++i)
+ {
+ byte[] v = vs[i];
+ if (v != null)
{
- return Concatenate(a, b);
+ nonNull[count++] = v;
+ totalLength += v.Length;
}
- }
+ }
- public static byte[] Concatenate(byte[] a, byte[] b, byte[] c, byte[] d)
- {
- if (a != null && b != null && c != null && d != null)
- {
- byte[] rv = new byte[a.Length + b.Length + c.Length + d.Length];
+ byte[] result = new byte[totalLength];
+ int pos = 0;
- Array.Copy(a, 0, rv, 0, a.Length);
- Array.Copy(b, 0, rv, a.Length, b.Length);
- Array.Copy(c, 0, rv, a.Length + b.Length, c.Length);
- Array.Copy(d, 0, rv, a.Length + b.Length + c.Length, d.Length);
+ for (int j = 0; j < count; ++j)
+ {
+ byte[] v = nonNull[j];
+ Array.Copy(v, 0, result, pos, v.Length);
+ pos += v.Length;
+ }
- return rv;
- }
- else if (d == null)
- {
- return Concatenate(a, b, c);
- }
- else if (c == null)
- {
- return Concatenate(a, b, d);
- }
- else if (b == null)
- {
- return Concatenate(a, c, d);
- }
- else
- {
- return Concatenate(b, c, d);
- }
+ return result;
}
public static int[] Concatenate(int[] a, int[] b)
|