diff --git a/Crypto/src/crypto/generators/BaseKdfBytesGenerator.cs b/Crypto/src/crypto/generators/BaseKdfBytesGenerator.cs
new file mode 100644
index 000000000..0366401d1
--- /dev/null
+++ b/Crypto/src/crypto/generators/BaseKdfBytesGenerator.cs
@@ -0,0 +1,141 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ /**
+ * Basic KDF generator for derived keys and ivs as defined by IEEE P1363a/ISO 18033
+ * <br/>
+ * This implementation is based on ISO 18033/P1363a.
+ */
+ public class BaseKdfBytesGenerator
+ : IDerivationFunction
+ {
+ private int counterStart;
+ private IDigest digest;
+ private byte[] shared;
+ private byte[] iv;
+
+ /**
+ * Construct a KDF Parameters generator.
+ *
+ * @param counterStart value of counter.
+ * @param digest the digest to be used as the source of derived keys.
+ */
+ protected BaseKdfBytesGenerator(
+ int counterStart,
+ IDigest digest)
+ {
+ this.counterStart = counterStart;
+ this.digest = digest;
+ }
+
+ public void Init(
+ IDerivationParameters parameters)
+ {
+ if (parameters is KdfParameters)
+ {
+ KdfParameters p = (KdfParameters)parameters;
+
+ shared = p.GetSharedSecret();
+ iv = p.GetIV();
+ }
+ else if (parameters is Iso18033KdfParameters)
+ {
+ Iso18033KdfParameters p = (Iso18033KdfParameters)parameters;
+
+ shared = p.GetSeed();
+ iv = null;
+ }
+ else
+ {
+ throw new ArgumentException("KDF parameters required for KDF Generator");
+ }
+ }
+
+ /**
+ * return the underlying digest.
+ */
+ public IDigest Digest
+ {
+ get
+ {
+ return digest;
+ }
+ }
+
+ /**
+ * fill len bytes of the output buffer with bytes generated from
+ * the derivation function.
+ *
+ * @throws ArgumentException if the size of the request will cause an overflow.
+ * @throws DataLengthException if the out buffer is too small.
+ */
+ public int GenerateBytes(
+ byte[] output,
+ int outOff,
+ int length)
+ {
+ if ((output.Length - length) < outOff)
+ {
+ throw new DataLengthException("output buffer too small");
+ }
+
+ long oBytes = length;
+ int outLen = digest.GetDigestSize();
+
+ //
+ // this is at odds with the standard implementation, the
+ // maximum value should be hBits * (2^32 - 1) where hBits
+ // is the digest output size in bits. We can't have an
+ // array with a long index at the moment...
+ //
+ if (oBytes > ((2L << 32) - 1))
+ {
+ throw new ArgumentException("Output length too large");
+ }
+
+ int cThreshold = (int)((oBytes + outLen - 1) / outLen);
+
+ byte[] dig = new byte[digest.GetDigestSize()];
+
+ int counter = counterStart;
+
+ for (int i = 0; i < cThreshold; i++)
+ {
+ digest.BlockUpdate(shared, 0, shared.Length);
+
+ digest.Update((byte)(counter >> 24));
+ digest.Update((byte)(counter >> 16));
+ digest.Update((byte)(counter >> 8));
+ digest.Update((byte)counter);
+
+ if (iv != null)
+ {
+ digest.BlockUpdate(iv, 0, iv.Length);
+ }
+
+ digest.DoFinal(dig, 0);
+
+ if (length > outLen)
+ {
+ Array.Copy(dig, 0, output, outOff, outLen);
+ outOff += outLen;
+ length -= outLen;
+ }
+ else
+ {
+ Array.Copy(dig, 0, output, outOff, length);
+ }
+
+ counter++;
+ }
+
+ digest.Reset();
+
+ return (int)oBytes;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Crypto/src/crypto/generators/DHBasicKeyPairGenerator.cs b/Crypto/src/crypto/generators/DHBasicKeyPairGenerator.cs
new file mode 100644
index 000000000..51b3af687
--- /dev/null
+++ b/Crypto/src/crypto/generators/DHBasicKeyPairGenerator.cs
@@ -0,0 +1,38 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ /**
+ * a basic Diffie-Hellman key pair generator.
+ *
+ * This generates keys consistent for use with the basic algorithm for
+ * Diffie-Hellman.
+ */
+ public class DHBasicKeyPairGenerator
+ : IAsymmetricCipherKeyPairGenerator
+ {
+ private DHKeyGenerationParameters param;
+
+ public virtual void Init(
+ KeyGenerationParameters parameters)
+ {
+ this.param = (DHKeyGenerationParameters)parameters;
+ }
+
+ public virtual AsymmetricCipherKeyPair GenerateKeyPair()
+ {
+ DHKeyGeneratorHelper helper = DHKeyGeneratorHelper.Instance;
+ DHParameters dhp = param.Parameters;
+
+ BigInteger x = helper.CalculatePrivate(dhp, param.Random);
+ BigInteger y = helper.CalculatePublic(dhp, x);
+
+ return new AsymmetricCipherKeyPair(
+ new DHPublicKeyParameters(y, dhp),
+ new DHPrivateKeyParameters(x, dhp));
+ }
+ }
+}
diff --git a/Crypto/src/crypto/generators/DHKeyGeneratorHelper.cs b/Crypto/src/crypto/generators/DHKeyGeneratorHelper.cs
new file mode 100644
index 000000000..756e8482a
--- /dev/null
+++ b/Crypto/src/crypto/generators/DHKeyGeneratorHelper.cs
@@ -0,0 +1,53 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ class DHKeyGeneratorHelper
+ {
+ internal static readonly DHKeyGeneratorHelper Instance = new DHKeyGeneratorHelper();
+
+ private DHKeyGeneratorHelper()
+ {
+ }
+
+ internal BigInteger CalculatePrivate(
+ DHParameters dhParams,
+ SecureRandom random)
+ {
+ int limit = dhParams.L;
+
+ if (limit != 0)
+ {
+ return new BigInteger(limit, random).SetBit(limit - 1);
+ }
+
+ BigInteger min = BigInteger.Two;
+ int m = dhParams.M;
+ if (m != 0)
+ {
+ min = BigInteger.One.ShiftLeft(m - 1);
+ }
+
+ BigInteger max = dhParams.P.Subtract(BigInteger.Two);
+ BigInteger q = dhParams.Q;
+ if (q != null)
+ {
+ max = q.Subtract(BigInteger.Two);
+ }
+
+ return BigIntegers.CreateRandomInRange(min, max, random);
+ }
+
+ internal BigInteger CalculatePublic(
+ DHParameters dhParams,
+ BigInteger x)
+ {
+ return dhParams.G.ModPow(x, dhParams.P);
+ }
+ }
+}
diff --git a/Crypto/src/crypto/generators/DHKeyPairGenerator.cs b/Crypto/src/crypto/generators/DHKeyPairGenerator.cs
new file mode 100644
index 000000000..3bf58ba1b
--- /dev/null
+++ b/Crypto/src/crypto/generators/DHKeyPairGenerator.cs
@@ -0,0 +1,38 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ /**
+ * a Diffie-Hellman key pair generator.
+ *
+ * This generates keys consistent for use in the MTI/A0 key agreement protocol
+ * as described in "Handbook of Applied Cryptography", Pages 516-519.
+ */
+ public class DHKeyPairGenerator
+ : IAsymmetricCipherKeyPairGenerator
+ {
+ private DHKeyGenerationParameters param;
+
+ public virtual void Init(
+ KeyGenerationParameters parameters)
+ {
+ this.param = (DHKeyGenerationParameters)parameters;
+ }
+
+ public virtual AsymmetricCipherKeyPair GenerateKeyPair()
+ {
+ DHKeyGeneratorHelper helper = DHKeyGeneratorHelper.Instance;
+ DHParameters dhp = param.Parameters;
+
+ BigInteger x = helper.CalculatePrivate(dhp, param.Random);
+ BigInteger y = helper.CalculatePublic(dhp, x);
+
+ return new AsymmetricCipherKeyPair(
+ new DHPublicKeyParameters(y, dhp),
+ new DHPrivateKeyParameters(x, dhp));
+ }
+ }
+}
diff --git a/Crypto/src/crypto/generators/DHParametersGenerator.cs b/Crypto/src/crypto/generators/DHParametersGenerator.cs
new file mode 100644
index 000000000..e752c8456
--- /dev/null
+++ b/Crypto/src/crypto/generators/DHParametersGenerator.cs
@@ -0,0 +1,45 @@
+using System;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ public class DHParametersGenerator
+ {
+ private int size;
+ private int certainty;
+ private SecureRandom random;
+
+ public virtual void Init(
+ int size,
+ int certainty,
+ SecureRandom random)
+ {
+ this.size = size;
+ this.certainty = certainty;
+ this.random = random;
+ }
+
+ /**
+ * which Generates the p and g values from the given parameters,
+ * returning the DHParameters object.
+ * <p>
+ * Note: can take a while...</p>
+ */
+ public virtual DHParameters GenerateParameters()
+ {
+ //
+ // find a safe prime p where p = 2*q + 1, where p and q are prime.
+ //
+ BigInteger[] safePrimes = DHParametersHelper.GenerateSafePrimes(size, certainty, random);
+
+ BigInteger p = safePrimes[0];
+ BigInteger q = safePrimes[1];
+ BigInteger g = DHParametersHelper.SelectGenerator(p, q, random);
+
+ return new DHParameters(p, g, q, BigInteger.Two, null);
+ }
+ }
+}
diff --git a/Crypto/src/crypto/generators/DHParametersHelper.cs b/Crypto/src/crypto/generators/DHParametersHelper.cs
new file mode 100644
index 000000000..7860cbe33
--- /dev/null
+++ b/Crypto/src/crypto/generators/DHParametersHelper.cs
@@ -0,0 +1,234 @@
+using System;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ internal class DHParametersHelper
+ {
+ // The primes b/w 2 and ~2^10
+ /*
+ 3 5 7 11 13 17 19 23 29
+ 31 37 41 43 47 53 59 61 67 71
+ 73 79 83 89 97 101 103 107 109 113
+ 127 131 137 139 149 151 157 163 167 173
+ 179 181 191 193 197 199 211 223 227 229
+ 233 239 241 251 257 263 269 271 277 281
+ 283 293 307 311 313 317 331 337 347 349
+ 353 359 367 373 379 383 389 397 401 409
+ 419 421 431 433 439 443 449 457 461 463
+ 467 479 487 491 499 503 509 521 523 541
+ 547 557 563 569 571 577 587 593 599 601
+ 607 613 617 619 631 641 643 647 653 659
+ 661 673 677 683 691 701 709 719 727 733
+ 739 743 751 757 761 769 773 787 797 809
+ 811 821 823 827 829 839 853 857 859 863
+ 877 881 883 887 907 911 919 929 937 941
+ 947 953 967 971 977 983 991 997
+ 1009 1013 1019 1021 1031
+ */
+
+ // Each list has a product < 2^31
+ private static readonly int[][] primeLists = new int[][]
+ {
+ new int[]{ 3, 5, 7, 11, 13, 17, 19, 23 },
+ new int[]{ 29, 31, 37, 41, 43 },
+ new int[]{ 47, 53, 59, 61, 67 },
+ new int[]{ 71, 73, 79, 83 },
+ new int[]{ 89, 97, 101, 103 },
+
+ new int[]{ 107, 109, 113, 127 },
+ new int[]{ 131, 137, 139, 149 },
+ new int[]{ 151, 157, 163, 167 },
+ new int[]{ 173, 179, 181, 191 },
+ new int[]{ 193, 197, 199, 211 },
+
+ new int[]{ 223, 227, 229 },
+ new int[]{ 233, 239, 241 },
+ new int[]{ 251, 257, 263 },
+ new int[]{ 269, 271, 277 },
+ new int[]{ 281, 283, 293 },
+
+ new int[]{ 307, 311, 313 },
+ new int[]{ 317, 331, 337 },
+ new int[]{ 347, 349, 353 },
+ new int[]{ 359, 367, 373 },
+ new int[]{ 379, 383, 389 },
+
+ new int[]{ 397, 401, 409 },
+ new int[]{ 419, 421, 431 },
+ new int[]{ 433, 439, 443 },
+ new int[]{ 449, 457, 461 },
+ new int[]{ 463, 467, 479 },
+
+ new int[]{ 487, 491, 499 },
+ new int[]{ 503, 509, 521 },
+ new int[]{ 523, 541, 547 },
+ new int[]{ 557, 563, 569 },
+ new int[]{ 571, 577, 587 },
+
+ new int[]{ 593, 599, 601 },
+ new int[]{ 607, 613, 617 },
+ new int[]{ 619, 631, 641 },
+ new int[]{ 643, 647, 653 },
+ new int[]{ 659, 661, 673 },
+
+ new int[]{ 677, 683, 691 },
+ new int[]{ 701, 709, 719 },
+ new int[]{ 727, 733, 739 },
+ new int[]{ 743, 751, 757 },
+ new int[]{ 761, 769, 773 },
+
+ new int[]{ 787, 797, 809 },
+ new int[]{ 811, 821, 823 },
+ new int[]{ 827, 829, 839 },
+ new int[]{ 853, 857, 859 },
+ new int[]{ 863, 877, 881 },
+
+ new int[]{ 883, 887, 907 },
+ new int[]{ 911, 919, 929 },
+ new int[]{ 937, 941, 947 },
+ new int[]{ 953, 967, 971 },
+ new int[]{ 977, 983, 991 },
+
+ new int[]{ 997, 1009, 1013 },
+ new int[]{ 1019, 1021, 1031 },
+ };
+
+ private static readonly BigInteger Six = BigInteger.ValueOf(6);
+
+ private static readonly int[] primeProducts;
+ private static readonly BigInteger[] PrimeProducts;
+
+ static DHParametersHelper()
+ {
+ primeProducts = new int[primeLists.Length];
+ PrimeProducts = new BigInteger[primeLists.Length];
+
+ for (int i = 0; i < primeLists.Length; ++i)
+ {
+ int[] primeList = primeLists[i];
+ int product = 1;
+ for (int j = 0; j < primeList.Length; ++j)
+ {
+ product *= primeList[j];
+ }
+ primeProducts[i] = product;
+ PrimeProducts[i] = BigInteger.ValueOf(product);
+ }
+ }
+
+ /*
+ * Finds a pair of prime BigInteger's {p, q: p = 2q + 1}
+ *
+ * (see: Handbook of Applied Cryptography 4.86)
+ */
+ internal static BigInteger[] GenerateSafePrimes(int size, int certainty, SecureRandom random)
+ {
+ BigInteger p, q;
+ int qLength = size - 1;
+
+ if (size <= 32)
+ {
+ for (;;)
+ {
+ q = new BigInteger(qLength, 2, random);
+
+ p = q.ShiftLeft(1).Add(BigInteger.One);
+
+ if (p.IsProbablePrime(certainty)
+ && (certainty <= 2 || q.IsProbablePrime(certainty)))
+ break;
+ }
+ }
+ else
+ {
+ // Note: Modified from Java version for speed
+ for (;;)
+ {
+ q = new BigInteger(qLength, 0, random);
+
+ retry:
+ for (int i = 0; i < primeLists.Length; ++i)
+ {
+ int test = q.Remainder(PrimeProducts[i]).IntValue;
+
+ if (i == 0)
+ {
+ int rem3 = test % 3;
+ if (rem3 != 2)
+ {
+ int diff = 2 * rem3 + 2;
+ q = q.Add(BigInteger.ValueOf(diff));
+ test = (test + diff) % primeProducts[i];
+ }
+ }
+
+ int[] primeList = primeLists[i];
+ for (int j = 0; j < primeList.Length; ++j)
+ {
+ int prime = primeList[j];
+ int qRem = test % prime;
+ if (qRem == 0 || qRem == (prime >> 1))
+ {
+ q = q.Add(Six);
+ goto retry;
+ }
+ }
+ }
+
+
+ if (q.BitLength != qLength)
+ continue;
+
+ if (!q.RabinMillerTest(2, random))
+ continue;
+
+ p = q.ShiftLeft(1).Add(BigInteger.One);
+
+ if (p.RabinMillerTest(certainty, random)
+ && (certainty <= 2 || q.RabinMillerTest(certainty - 2, random)))
+ break;
+ }
+ }
+
+ return new BigInteger[] { p, q };
+ }
+
+ /*
+ * Select a high order element of the multiplicative group Zp*
+ *
+ * p and q must be s.t. p = 2*q + 1, where p and q are prime (see generateSafePrimes)
+ */
+ internal static BigInteger SelectGenerator(BigInteger p, BigInteger q, SecureRandom random)
+ {
+ BigInteger pMinusTwo = p.Subtract(BigInteger.Two);
+ BigInteger g;
+
+ /*
+ * (see: Handbook of Applied Cryptography 4.80)
+ */
+// do
+// {
+// g = BigIntegers.CreateRandomInRange(BigInteger.Two, pMinusTwo, random);
+// }
+// while (g.ModPow(BigInteger.Two, p).Equals(BigInteger.One)
+// || g.ModPow(q, p).Equals(BigInteger.One));
+
+ /*
+ * RFC 2631 2.2.1.2 (and see: Handbook of Applied Cryptography 4.81)
+ */
+ do
+ {
+ BigInteger h = BigIntegers.CreateRandomInRange(BigInteger.Two, pMinusTwo, random);
+
+ g = h.ModPow(BigInteger.Two, p);
+ }
+ while (g.Equals(BigInteger.One));
+
+ return g;
+ }
+ }
+}
diff --git a/Crypto/src/crypto/generators/DesEdeKeyGenerator.cs b/Crypto/src/crypto/generators/DesEdeKeyGenerator.cs
new file mode 100644
index 000000000..5902643fd
--- /dev/null
+++ b/Crypto/src/crypto/generators/DesEdeKeyGenerator.cs
@@ -0,0 +1,67 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ public class DesEdeKeyGenerator
+ : DesKeyGenerator
+ {
+ public DesEdeKeyGenerator()
+ {
+ }
+
+ internal DesEdeKeyGenerator(
+ int defaultStrength)
+ : base(defaultStrength)
+ {
+ }
+
+ /**
+ * initialise the key generator - if strength is set to zero
+ * the key Generated will be 192 bits in size, otherwise
+ * strength can be 128 or 192 (or 112 or 168 if you don't count
+ * parity bits), depending on whether you wish to do 2-key or 3-key
+ * triple DES.
+ *
+ * @param param the parameters to be used for key generation
+ */
+ protected override void engineInit(
+ KeyGenerationParameters parameters)
+ {
+ this.random = parameters.Random;
+ this.strength = (parameters.Strength + 7) / 8;
+
+ if (strength == 0 || strength == (168 / 8))
+ {
+ strength = DesEdeParameters.DesEdeKeyLength;
+ }
+ else if (strength == (112 / 8))
+ {
+ strength = 2 * DesEdeParameters.DesKeyLength;
+ }
+ else if (strength != DesEdeParameters.DesEdeKeyLength
+ && strength != (2 * DesEdeParameters.DesKeyLength))
+ {
+ throw new ArgumentException("DESede key must be "
+ + (DesEdeParameters.DesEdeKeyLength * 8) + " or "
+ + (2 * 8 * DesEdeParameters.DesKeyLength)
+ + " bits long.");
+ }
+ }
+
+ protected override byte[] engineGenerateKey()
+ {
+ byte[] newKey;
+
+ do
+ {
+ newKey = random.GenerateSeed(strength);
+ DesEdeParameters.SetOddParity(newKey);
+ }
+ while (DesEdeParameters.IsWeakKey(newKey, 0, newKey.Length));
+
+ return newKey;
+ }
+ }
+}
diff --git a/Crypto/src/crypto/generators/DesKeyGenerator.cs b/Crypto/src/crypto/generators/DesKeyGenerator.cs
new file mode 100644
index 000000000..154e3471a
--- /dev/null
+++ b/Crypto/src/crypto/generators/DesKeyGenerator.cs
@@ -0,0 +1,57 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ public class DesKeyGenerator
+ : CipherKeyGenerator
+ {
+ public DesKeyGenerator()
+ {
+ }
+
+ internal DesKeyGenerator(
+ int defaultStrength)
+ : base(defaultStrength)
+ {
+ }
+
+ /**
+ * initialise the key generator - if strength is set to zero
+ * the key generated will be 64 bits in size, otherwise
+ * strength can be 64 or 56 bits (if you don't count the parity bits).
+ *
+ * @param param the parameters to be used for key generation
+ */
+ protected override void engineInit(
+ KeyGenerationParameters parameters)
+ {
+ base.engineInit(parameters);
+
+ if (strength == 0 || strength == (56 / 8))
+ {
+ strength = DesParameters.DesKeyLength;
+ }
+ else if (strength != DesParameters.DesKeyLength)
+ {
+ throw new ArgumentException(
+ "DES key must be " + (DesParameters.DesKeyLength * 8) + " bits long.");
+ }
+ }
+
+ protected override byte[] engineGenerateKey()
+ {
+ byte[] newKey;
+
+ do
+ {
+ newKey = random.GenerateSeed(DesParameters.DesKeyLength);
+ DesParameters.SetOddParity(newKey);
+ }
+ while (DesParameters.IsWeakKey(newKey, 0));
+
+ return newKey;
+ }
+ }
+}
diff --git a/Crypto/src/crypto/generators/DsaKeyPairGenerator.cs b/Crypto/src/crypto/generators/DsaKeyPairGenerator.cs
new file mode 100644
index 000000000..bb8ec591b
--- /dev/null
+++ b/Crypto/src/crypto/generators/DsaKeyPairGenerator.cs
@@ -0,0 +1,61 @@
+using System;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ /**
+ * a DSA key pair generator.
+ *
+ * This Generates DSA keys in line with the method described
+ * in <i>FIPS 186-3 B.1 FFC Key Pair Generation</i>.
+ */
+ public class DsaKeyPairGenerator
+ : IAsymmetricCipherKeyPairGenerator
+ {
+ private DsaKeyGenerationParameters param;
+
+ public void Init(
+ KeyGenerationParameters parameters)
+ {
+ if (parameters == null)
+ throw new ArgumentNullException("parameters");
+
+ // Note: If we start accepting instances of KeyGenerationParameters,
+ // must apply constraint checking on strength (see DsaParametersGenerator.Init)
+
+ this.param = (DsaKeyGenerationParameters) parameters;
+ }
+
+ public AsymmetricCipherKeyPair GenerateKeyPair()
+ {
+ DsaParameters dsaParams = param.Parameters;
+
+ BigInteger x = GeneratePrivateKey(dsaParams.Q, param.Random);
+ BigInteger y = CalculatePublicKey(dsaParams.P, dsaParams.G, x);
+
+ return new AsymmetricCipherKeyPair(
+ new DsaPublicKeyParameters(y, dsaParams),
+ new DsaPrivateKeyParameters(x, dsaParams));
+ }
+
+ private static BigInteger GeneratePrivateKey(BigInteger q, SecureRandom random)
+ {
+ // TODO Prefer this method? (change test cases that used fixed random)
+ // B.1.1 Key Pair Generation Using Extra Random Bits
+// BigInteger c = new BigInteger(q.BitLength + 64, random);
+// return c.Mod(q.Subtract(BigInteger.One)).Add(BigInteger.One);
+
+ // B.1.2 Key Pair Generation by Testing Candidates
+ return BigIntegers.CreateRandomInRange(BigInteger.One, q.Subtract(BigInteger.One), random);
+ }
+
+ private static BigInteger CalculatePublicKey(BigInteger p, BigInteger g, BigInteger x)
+ {
+ return g.ModPow(x, p);
+ }
+ }
+}
diff --git a/Crypto/src/crypto/generators/DsaParametersGenerator.cs b/Crypto/src/crypto/generators/DsaParametersGenerator.cs
new file mode 100644
index 000000000..3e9d4f021
--- /dev/null
+++ b/Crypto/src/crypto/generators/DsaParametersGenerator.cs
@@ -0,0 +1,355 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ // TODO Update docs to mention FIPS 186-3 when done
+ /**
+ * Generate suitable parameters for DSA, in line with FIPS 186-2.
+ */
+ public class DsaParametersGenerator
+ {
+ private int L, N;
+ private int certainty;
+ private SecureRandom random;
+
+ /**
+ * initialise the key generator.
+ *
+ * @param size size of the key (range 2^512 -> 2^1024 - 64 bit increments)
+ * @param certainty measure of robustness of prime (for FIPS 186-2 compliance this should be at least 80).
+ * @param random random byte source.
+ */
+ public void Init(
+ int size,
+ int certainty,
+ SecureRandom random)
+ {
+ if (!IsValidDsaStrength(size))
+ throw new ArgumentException("size must be from 512 - 1024 and a multiple of 64", "size");
+
+ Init(size, GetDefaultN(size), certainty, random);
+ }
+
+ // TODO Make public to enable support for DSA keys > 1024 bits
+ private void Init(
+ int L,
+ int N,
+ int certainty,
+ SecureRandom random)
+ {
+ // TODO Check that the (L, N) pair is in the list of acceptable (L, N pairs) (see Section 4.2)
+ // TODO Should we enforce the minimum 'certainty' values as per C.3 Table C.1?
+
+ this.L = L;
+ this.N = N;
+ this.certainty = certainty;
+ this.random = random;
+ }
+
+// /**
+// * add value to b, returning the result in a. The a value is treated
+// * as a BigInteger of length (a.Length * 8) bits. The result is
+// * modulo 2^a.Length in case of overflow.
+// */
+// private static void Add(
+// byte[] a,
+// byte[] b,
+// int value)
+// {
+// int x = (b[b.Length - 1] & 0xff) + value;
+//
+// a[b.Length - 1] = (byte)x;
+// x = (int) ((uint) x >>8);
+//
+// for (int i = b.Length - 2; i >= 0; i--)
+// {
+// x += (b[i] & 0xff);
+// a[i] = (byte)x;
+// x = (int) ((uint) x >>8);
+// }
+// }
+
+ /**
+ * which Generates the p and g values from the given parameters,
+ * returning the DsaParameters object.
+ * <p>
+ * Note: can take a while...</p>
+ */
+ public DsaParameters GenerateParameters()
+ {
+ return L > 1024
+ ? GenerateParameters_FIPS186_3()
+ : GenerateParameters_FIPS186_2();
+ }
+
+ private DsaParameters GenerateParameters_FIPS186_2()
+ {
+ byte[] seed = new byte[20];
+ byte[] part1 = new byte[20];
+ byte[] part2 = new byte[20];
+ byte[] u = new byte[20];
+ Sha1Digest sha1 = new Sha1Digest();
+ int n = (L - 1) / 160;
+ byte[] w = new byte[L / 8];
+
+ for (;;)
+ {
+ random.NextBytes(seed);
+
+ Hash(sha1, seed, part1);
+ Array.Copy(seed, 0, part2, 0, seed.Length);
+ Inc(part2);
+ Hash(sha1, part2, part2);
+
+ for (int i = 0; i != u.Length; i++)
+ {
+ u[i] = (byte)(part1[i] ^ part2[i]);
+ }
+
+ u[0] |= (byte)0x80;
+ u[19] |= (byte)0x01;
+
+ BigInteger q = new BigInteger(1, u);
+
+ if (!q.IsProbablePrime(certainty))
+ continue;
+
+ byte[] offset = Arrays.Clone(seed);
+ Inc(offset);
+
+ for (int counter = 0; counter < 4096; ++counter)
+ {
+ for (int k = 0; k < n; k++)
+ {
+ Inc(offset);
+ Hash(sha1, offset, part1);
+ Array.Copy(part1, 0, w, w.Length - (k + 1) * part1.Length, part1.Length);
+ }
+
+ Inc(offset);
+ Hash(sha1, offset, part1);
+ Array.Copy(part1, part1.Length - ((w.Length - (n) * part1.Length)), w, 0, w.Length - n * part1.Length);
+
+ w[0] |= (byte)0x80;
+
+ BigInteger x = new BigInteger(1, w);
+
+ BigInteger c = x.Mod(q.ShiftLeft(1));
+
+ BigInteger p = x.Subtract(c.Subtract(BigInteger.One));
+
+ if (p.BitLength != L)
+ continue;
+
+ if (p.IsProbablePrime(certainty))
+ {
+ BigInteger g = CalculateGenerator_FIPS186_2(p, q, random);
+
+ return new DsaParameters(p, q, g, new DsaValidationParameters(seed, counter));
+ }
+ }
+ }
+ }
+
+ private static BigInteger CalculateGenerator_FIPS186_2(BigInteger p, BigInteger q, SecureRandom r)
+ {
+ BigInteger e = p.Subtract(BigInteger.One).Divide(q);
+ BigInteger pSub2 = p.Subtract(BigInteger.Two);
+
+ for (;;)
+ {
+ BigInteger h = BigIntegers.CreateRandomInRange(BigInteger.Two, pSub2, r);
+ BigInteger g = h.ModPow(e, p);
+
+ if (g.BitLength > 1)
+ return g;
+ }
+ }
+
+ /**
+ * generate suitable parameters for DSA, in line with
+ * <i>FIPS 186-3 A.1 Generation of the FFC Primes p and q</i>.
+ */
+ private DsaParameters GenerateParameters_FIPS186_3()
+ {
+// A.1.1.2 Generation of the Probable Primes p and q Using an Approved Hash Function
+ // FIXME This should be configurable (digest size in bits must be >= N)
+ IDigest d = new Sha256Digest();
+ int outlen = d.GetDigestSize() * 8;
+
+// 1. Check that the (L, N) pair is in the list of acceptable (L, N pairs) (see Section 4.2). If
+// the pair is not in the list, then return INVALID.
+ // Note: checked at initialisation
+
+// 2. If (seedlen < N), then return INVALID.
+ // FIXME This should be configurable (must be >= N)
+ int seedlen = N;
+ byte[] seed = new byte[seedlen / 8];
+
+// 3. n = ceiling(L ⁄ outlen) – 1.
+ int n = (L - 1) / outlen;
+
+// 4. b = L – 1 – (n ∗ outlen).
+ int b = (L - 1) % outlen;
+
+ byte[] output = new byte[d.GetDigestSize()];
+ for (;;)
+ {
+// 5. Get an arbitrary sequence of seedlen bits as the domain_parameter_seed.
+ random.NextBytes(seed);
+
+// 6. U = Hash (domain_parameter_seed) mod 2^(N–1).
+ Hash(d, seed, output);
+ BigInteger U = new BigInteger(1, output).Mod(BigInteger.One.ShiftLeft(N - 1));
+
+// 7. q = 2^(N–1) + U + 1 – ( U mod 2).
+ BigInteger q = BigInteger.One.ShiftLeft(N - 1).Add(U).Add(BigInteger.One).Subtract(
+ U.Mod(BigInteger.Two));
+
+// 8. Test whether or not q is prime as specified in Appendix C.3.
+ // TODO Review C.3 for primality checking
+ if (!q.IsProbablePrime(certainty))
+ {
+// 9. If q is not a prime, then go to step 5.
+ continue;
+ }
+
+// 10. offset = 1.
+ // Note: 'offset' value managed incrementally
+ byte[] offset = Arrays.Clone(seed);
+
+// 11. For counter = 0 to (4L – 1) do
+ int counterLimit = 4 * L;
+ for (int counter = 0; counter < counterLimit; ++counter)
+ {
+// 11.1 For j = 0 to n do
+// Vj = Hash ((domain_parameter_seed + offset + j) mod 2^seedlen).
+// 11.2 W = V0 + (V1 ∗ 2^outlen) + ... + (V^(n–1) ∗ 2^((n–1) ∗ outlen)) + ((Vn mod 2^b) ∗ 2^(n ∗ outlen)).
+ // TODO Assemble w as a byte array
+ BigInteger W = BigInteger.Zero;
+ for (int j = 0, exp = 0; j <= n; ++j, exp += outlen)
+ {
+ Inc(offset);
+ Hash(d, offset, output);
+
+ BigInteger Vj = new BigInteger(1, output);
+ if (j == n)
+ {
+ Vj = Vj.Mod(BigInteger.One.ShiftLeft(b));
+ }
+
+ W = W.Add(Vj.ShiftLeft(exp));
+ }
+
+// 11.3 X = W + 2^(L–1). Comment: 0 ≤ W < 2L–1; hence, 2L–1 ≤ X < 2L.
+ BigInteger X = W.Add(BigInteger.One.ShiftLeft(L - 1));
+
+// 11.4 c = X mod 2q.
+ BigInteger c = X.Mod(q.ShiftLeft(1));
+
+// 11.5 p = X - (c - 1). Comment: p ≡ 1 (mod 2q).
+ BigInteger p = X.Subtract(c.Subtract(BigInteger.One));
+
+ // 11.6 If (p < 2^(L - 1)), then go to step 11.9
+ if (p.BitLength != L)
+ continue;
+
+// 11.7 Test whether or not p is prime as specified in Appendix C.3.
+ // TODO Review C.3 for primality checking
+ if (p.IsProbablePrime(certainty))
+ {
+// 11.8 If p is determined to be prime, then return VALID and the values of p, q and
+// (optionally) the values of domain_parameter_seed and counter.
+ // TODO Make configurable (8-bit unsigned)?
+// int index = 1;
+// BigInteger g = CalculateGenerator_FIPS186_3_Verifiable(d, p, q, seed, index);
+// if (g != null)
+// {
+// // TODO Should 'index' be a part of the validation parameters?
+// return new DsaParameters(p, q, g, new DsaValidationParameters(seed, counter));
+// }
+
+ BigInteger g = CalculateGenerator_FIPS186_3_Unverifiable(p, q, random);
+ return new DsaParameters(p, q, g, new DsaValidationParameters(seed, counter));
+ }
+
+// 11.9 offset = offset + n + 1. Comment: Increment offset; then, as part of
+// the loop in step 11, increment counter; if
+// counter < 4L, repeat steps 11.1 through 11.8.
+ // Note: 'offset' value already incremented in inner loop
+ }
+// 12. Go to step 5.
+ }
+ }
+
+ private static BigInteger CalculateGenerator_FIPS186_3_Unverifiable(BigInteger p, BigInteger q,
+ SecureRandom r)
+ {
+ return CalculateGenerator_FIPS186_2(p, q, r);
+ }
+
+ private static BigInteger CalculateGenerator_FIPS186_3_Verifiable(IDigest d, BigInteger p, BigInteger q,
+ byte[] seed, int index)
+ {
+ // A.2.3 Verifiable Canonical Generation of the Generator g
+ BigInteger e = p.Subtract(BigInteger.One).Divide(q);
+ byte[] ggen = Hex.Decode("6767656E");
+
+ // 7. U = domain_parameter_seed || "ggen" || index || count.
+ byte[] U = new byte[seed.Length + ggen.Length + 1 + 2];
+ Array.Copy(seed, 0, U, 0, seed.Length);
+ Array.Copy(ggen, 0, U, seed.Length, ggen.Length);
+ U[U.Length - 3] = (byte)index;
+
+ byte[] w = new byte[d.GetDigestSize()];
+ for (int count = 1; count < (1 << 16); ++count)
+ {
+ Inc(U);
+ Hash(d, U, w);
+ BigInteger W = new BigInteger(1, w);
+ BigInteger g = W.ModPow(e, p);
+
+ if (g.CompareTo(BigInteger.Two) >= 0)
+ return g;
+ }
+
+ return null;
+ }
+
+ private static bool IsValidDsaStrength(
+ int strength)
+ {
+ return strength >= 512 && strength <= 1024 && strength % 64 == 0;
+ }
+
+ private static void Hash(IDigest d, byte[] input, byte[] output)
+ {
+ d.BlockUpdate(input, 0, input.Length);
+ d.DoFinal(output, 0);
+ }
+
+ private static int GetDefaultN(int L)
+ {
+ return L > 1024 ? 256 : 160;
+ }
+
+ private static void Inc(byte[] buf)
+ {
+ for (int i = buf.Length - 1; i >= 0; --i)
+ {
+ byte b = (byte)(buf[i] + 1);
+ buf[i] = b;
+
+ if (b != 0)
+ break;
+ }
+ }
+ }
+}
diff --git a/Crypto/src/crypto/generators/ECKeyPairGenerator.cs b/Crypto/src/crypto/generators/ECKeyPairGenerator.cs
new file mode 100644
index 000000000..d1e4b7cf6
--- /dev/null
+++ b/Crypto/src/crypto/generators/ECKeyPairGenerator.cs
@@ -0,0 +1,174 @@
+using System;
+using System.Globalization;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Sec;
+using Org.BouncyCastle.Asn1.TeleTrust;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ public class ECKeyPairGenerator
+ : IAsymmetricCipherKeyPairGenerator
+ {
+ private readonly string algorithm;
+
+ private ECDomainParameters parameters;
+ private DerObjectIdentifier publicKeyParamSet;
+ private SecureRandom random;
+
+ public ECKeyPairGenerator()
+ : this("EC")
+ {
+ }
+
+ public ECKeyPairGenerator(
+ string algorithm)
+ {
+ if (algorithm == null)
+ throw new ArgumentNullException("algorithm");
+
+ this.algorithm = VerifyAlgorithmName(algorithm);
+ }
+
+ public void Init(
+ KeyGenerationParameters parameters)
+ {
+ if (parameters is ECKeyGenerationParameters)
+ {
+ ECKeyGenerationParameters ecP = (ECKeyGenerationParameters) parameters;
+
+ this.publicKeyParamSet = ecP.PublicKeyParamSet;
+ this.parameters = ecP.DomainParameters;
+ }
+ else
+ {
+ DerObjectIdentifier oid;
+ switch (parameters.Strength)
+ {
+ case 192:
+ oid = X9ObjectIdentifiers.Prime192v1;
+ break;
+ case 224:
+ oid = SecObjectIdentifiers.SecP224r1;
+ break;
+ case 239:
+ oid = X9ObjectIdentifiers.Prime239v1;
+ break;
+ case 256:
+ oid = X9ObjectIdentifiers.Prime256v1;
+ break;
+ case 384:
+ oid = SecObjectIdentifiers.SecP384r1;
+ break;
+ case 521:
+ oid = SecObjectIdentifiers.SecP521r1;
+ break;
+ default:
+ throw new InvalidParameterException("unknown key size.");
+ }
+
+ X9ECParameters ecps = FindECCurveByOid(oid);
+
+ this.parameters = new ECDomainParameters(
+ ecps.Curve, ecps.G, ecps.N, ecps.H, ecps.GetSeed());
+ }
+
+ this.random = parameters.Random;
+ }
+
+ /**
+ * Given the domain parameters this routine Generates an EC key
+ * pair in accordance with X9.62 section 5.2.1 pages 26, 27.
+ */
+ public AsymmetricCipherKeyPair GenerateKeyPair()
+ {
+ BigInteger n = parameters.N;
+ BigInteger d;
+
+ do
+ {
+ d = new BigInteger(n.BitLength, random);
+ }
+ while (d.SignValue == 0 || (d.CompareTo(n) >= 0));
+
+ ECPoint q = parameters.G.Multiply(d);
+
+ if (publicKeyParamSet != null)
+ {
+ return new AsymmetricCipherKeyPair(
+ new ECPublicKeyParameters(algorithm, q, publicKeyParamSet),
+ new ECPrivateKeyParameters(algorithm, d, publicKeyParamSet));
+ }
+
+ return new AsymmetricCipherKeyPair(
+ new ECPublicKeyParameters(algorithm, q, parameters),
+ new ECPrivateKeyParameters(algorithm, d, parameters));
+ }
+
+ private string VerifyAlgorithmName(
+ string algorithm)
+ {
+ string upper = algorithm.ToUpperInvariant();
+
+ switch (upper)
+ {
+ case "EC":
+ case "ECDSA":
+ case "ECDH":
+ case "ECDHC":
+ case "ECGOST3410":
+ case "ECMQV":
+ break;
+ default:
+ throw new ArgumentException("unrecognised algorithm: " + algorithm, "algorithm");
+ }
+
+ return upper;
+ }
+
+ internal static X9ECParameters FindECCurveByOid(DerObjectIdentifier oid)
+ {
+ // TODO ECGost3410NamedCurves support (returns ECDomainParameters though)
+
+ X9ECParameters ecP = X962NamedCurves.GetByOid(oid);
+
+ if (ecP == null)
+ {
+ ecP = SecNamedCurves.GetByOid(oid);
+
+ if (ecP == null)
+ {
+ ecP = NistNamedCurves.GetByOid(oid);
+
+ if (ecP == null)
+ {
+ ecP = TeleTrusTNamedCurves.GetByOid(oid);
+ }
+ }
+ }
+
+ return ecP;
+ }
+
+ internal static ECPublicKeyParameters GetCorrespondingPublicKey(
+ ECPrivateKeyParameters privKey)
+ {
+ ECDomainParameters parameters = privKey.Parameters;
+ ECPoint q = parameters.G.Multiply(privKey.D);
+
+ if (privKey.PublicKeyParamSet != null)
+ {
+ return new ECPublicKeyParameters(privKey.AlgorithmName, q, privKey.PublicKeyParamSet);
+ }
+
+ return new ECPublicKeyParameters(privKey.AlgorithmName, q, parameters);
+ }
+ }
+}
diff --git a/Crypto/src/crypto/generators/ElGamalKeyPairGenerator.cs b/Crypto/src/crypto/generators/ElGamalKeyPairGenerator.cs
new file mode 100644
index 000000000..227e7fe94
--- /dev/null
+++ b/Crypto/src/crypto/generators/ElGamalKeyPairGenerator.cs
@@ -0,0 +1,40 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ /**
+ * a ElGamal key pair generator.
+ * <p>
+ * This Generates keys consistent for use with ElGamal as described in
+ * page 164 of "Handbook of Applied Cryptography".</p>
+ */
+ public class ElGamalKeyPairGenerator
+ : IAsymmetricCipherKeyPairGenerator
+ {
+ private ElGamalKeyGenerationParameters param;
+
+ public void Init(
+ KeyGenerationParameters parameters)
+ {
+ this.param = (ElGamalKeyGenerationParameters) parameters;
+ }
+
+ public AsymmetricCipherKeyPair GenerateKeyPair()
+ {
+ DHKeyGeneratorHelper helper = DHKeyGeneratorHelper.Instance;
+ ElGamalParameters egp = param.Parameters;
+ DHParameters dhp = new DHParameters(egp.P, egp.G, null, 0, egp.L);
+
+ BigInteger x = helper.CalculatePrivate(dhp, param.Random);
+ BigInteger y = helper.CalculatePublic(dhp, x);
+
+ return new AsymmetricCipherKeyPair(
+ new ElGamalPublicKeyParameters(y, egp),
+ new ElGamalPrivateKeyParameters(x, egp));
+ }
+ }
+
+}
diff --git a/Crypto/src/crypto/generators/ElGamalParametersGenerator.cs b/Crypto/src/crypto/generators/ElGamalParametersGenerator.cs
new file mode 100644
index 000000000..8443bb00e
--- /dev/null
+++ b/Crypto/src/crypto/generators/ElGamalParametersGenerator.cs
@@ -0,0 +1,46 @@
+using System;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ public class ElGamalParametersGenerator
+ {
+ private int size;
+ private int certainty;
+ private SecureRandom random;
+
+ public void Init(
+ int size,
+ int certainty,
+ SecureRandom random)
+ {
+ this.size = size;
+ this.certainty = certainty;
+ this.random = random;
+ }
+
+ /**
+ * which Generates the p and g values from the given parameters,
+ * returning the ElGamalParameters object.
+ * <p>
+ * Note: can take a while...
+ * </p>
+ */
+ public ElGamalParameters GenerateParameters()
+ {
+ //
+ // find a safe prime p where p = 2*q + 1, where p and q are prime.
+ //
+ BigInteger[] safePrimes = DHParametersHelper.GenerateSafePrimes(size, certainty, random);
+
+ BigInteger p = safePrimes[0];
+ BigInteger q = safePrimes[1];
+ BigInteger g = DHParametersHelper.SelectGenerator(p, q, random);
+
+ return new ElGamalParameters(p, g);
+ }
+ }
+}
diff --git a/Crypto/src/crypto/generators/GOST3410KeyPairGenerator.cs b/Crypto/src/crypto/generators/GOST3410KeyPairGenerator.cs
new file mode 100644
index 000000000..5878da64b
--- /dev/null
+++ b/Crypto/src/crypto/generators/GOST3410KeyPairGenerator.cs
@@ -0,0 +1,73 @@
+using System;
+
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ /**
+ * a GOST3410 key pair generator.
+ * This generates GOST3410 keys in line with the method described
+ * in GOST R 34.10-94.
+ */
+ public class Gost3410KeyPairGenerator
+ : IAsymmetricCipherKeyPairGenerator
+ {
+ private Gost3410KeyGenerationParameters param;
+
+ public void Init(
+ KeyGenerationParameters parameters)
+ {
+ if (parameters is Gost3410KeyGenerationParameters)
+ {
+ this.param = (Gost3410KeyGenerationParameters) parameters;
+ }
+ else
+ {
+ Gost3410KeyGenerationParameters kgp = new Gost3410KeyGenerationParameters(
+ parameters.Random,
+ CryptoProObjectIdentifiers.GostR3410x94CryptoProA);
+
+ if (parameters.Strength != kgp.Parameters.P.BitLength - 1)
+ {
+ // TODO Should we complain?
+ }
+
+ this.param = kgp;
+ }
+ }
+
+ public AsymmetricCipherKeyPair GenerateKeyPair()
+ {
+ SecureRandom random = param.Random;
+ Gost3410Parameters gost3410Params = param.Parameters;
+
+ BigInteger q = gost3410Params.Q;
+ BigInteger x;
+ do
+ {
+ x = new BigInteger(256, random);
+ }
+ while (x.SignValue < 1 || x.CompareTo(q) >= 0);
+
+ BigInteger p = gost3410Params.P;
+ BigInteger a = gost3410Params.A;
+
+ // calculate the public key.
+ BigInteger y = a.ModPow(x, p);
+
+ if (param.PublicKeyParamSet != null)
+ {
+ return new AsymmetricCipherKeyPair(
+ new Gost3410PublicKeyParameters(y, param.PublicKeyParamSet),
+ new Gost3410PrivateKeyParameters(x, param.PublicKeyParamSet));
+ }
+
+ return new AsymmetricCipherKeyPair(
+ new Gost3410PublicKeyParameters(y, gost3410Params),
+ new Gost3410PrivateKeyParameters(x, gost3410Params));
+ }
+ }
+}
diff --git a/Crypto/src/crypto/generators/GOST3410ParametersGenerator.cs b/Crypto/src/crypto/generators/GOST3410ParametersGenerator.cs
new file mode 100644
index 000000000..52a9f5a82
--- /dev/null
+++ b/Crypto/src/crypto/generators/GOST3410ParametersGenerator.cs
@@ -0,0 +1,530 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ /**
+ * generate suitable parameters for GOST3410.
+ */
+ public class Gost3410ParametersGenerator
+ {
+ private int size;
+ private int typeproc;
+ private SecureRandom init_random;
+
+ /**
+ * initialise the key generator.
+ *
+ * @param size size of the key
+ * @param typeProcedure type procedure A,B = 1; A',B' - else
+ * @param random random byte source.
+ */
+ public void Init(
+ int size,
+ int typeProcedure,
+ SecureRandom random)
+ {
+ this.size = size;
+ this.typeproc = typeProcedure;
+ this.init_random = random;
+ }
+
+ //Procedure A
+ private int procedure_A(int x0, int c, BigInteger[] pq, int size)
+ {
+ //Verify and perform condition: 0<x<2^16; 0<c<2^16; c - odd.
+ while(x0<0 || x0>65536)
+ {
+ x0 = init_random.NextInt()/32768;
+ }
+
+ while((c<0 || c>65536) || (c/2==0))
+ {
+ c = init_random.NextInt()/32768 + 1;
+ }
+
+ BigInteger C = BigInteger.ValueOf(c);
+ BigInteger constA16 = BigInteger.ValueOf(19381);
+
+ //step1
+ BigInteger[] y = new BigInteger[1]; // begin length = 1
+ y[0] = BigInteger.ValueOf(x0);
+
+ //step 2
+ int[] t = new int[1]; // t - orders; begin length = 1
+ t[0] = size;
+ int s = 0;
+ for (int i=0; t[i]>=17; i++)
+ {
+ // extension array t
+ int[] tmp_t = new int[t.Length + 1]; ///////////////
+ Array.Copy(t,0,tmp_t,0,t.Length); // extension
+ t = new int[tmp_t.Length]; // array t
+ Array.Copy(tmp_t, 0, t, 0, tmp_t.Length); ///////////////
+
+ t[i+1] = t[i]/2;
+ s = i+1;
+ }
+
+ //step3
+ BigInteger[] p = new BigInteger[s+1];
+ p[s] = new BigInteger("8003",16); //set min prime number length 16 bit
+
+ int m = s-1; //step4
+
+ for (int i=0; i<s; i++)
+ {
+ int rm = t[m]/16; //step5
+
+ step6: for(;;)
+ {
+ //step 6
+ BigInteger[] tmp_y = new BigInteger[y.Length]; ////////////////
+ Array.Copy(y,0,tmp_y,0,y.Length); // extension
+ y = new BigInteger[rm+1]; // array y
+ Array.Copy(tmp_y,0,y,0,tmp_y.Length); ////////////////
+
+ for (int j=0; j<rm; j++)
+ {
+ y[j+1] = (y[j].Multiply(constA16).Add(C)).Mod(BigInteger.Two.Pow(16));
+ }
+
+ //step 7
+ BigInteger Ym = BigInteger.Zero;
+ for (int j=0; j<rm; j++)
+ {
+ Ym = Ym.Add(y[j].ShiftLeft(16*j));
+ }
+
+ y[0] = y[rm]; //step 8
+
+ //step 9
+ BigInteger N = BigInteger.One.ShiftLeft(t[m]-1).Divide(p[m+1]).Add(
+ Ym.ShiftLeft(t[m]-1).Divide(p[m+1].ShiftLeft(16*rm)));
+
+ if (N.TestBit(0))
+ {
+ N = N.Add(BigInteger.One);
+ }
+
+ //step 10
+
+ for(;;)
+ {
+ //step 11
+ BigInteger NByLastP = N.Multiply(p[m+1]);
+
+ if (NByLastP.BitLength > t[m])
+ {
+ goto step6; //step 12
+ }
+
+ p[m] = NByLastP.Add(BigInteger.One);
+
+ //step13
+ if (BigInteger.Two.ModPow(NByLastP, p[m]).CompareTo(BigInteger.One) == 0
+ && BigInteger.Two.ModPow(N, p[m]).CompareTo(BigInteger.One) != 0)
+ {
+ break;
+ }
+
+ N = N.Add(BigInteger.Two);
+ }
+
+ if (--m < 0)
+ {
+ pq[0] = p[0];
+ pq[1] = p[1];
+ return y[0].IntValue; //return for procedure B step 2
+ }
+
+ break; //step 14
+ }
+ }
+ return y[0].IntValue;
+ }
+
+ //Procedure A'
+ private long procedure_Aa(long x0, long c, BigInteger[] pq, int size)
+ {
+ //Verify and perform condition: 0<x<2^32; 0<c<2^32; c - odd.
+ while(x0<0 || x0>4294967296L)
+ {
+ x0 = init_random.NextInt()*2;
+ }
+
+ while((c<0 || c>4294967296L) || (c/2==0))
+ {
+ c = init_random.NextInt()*2+1;
+ }
+
+ BigInteger C = BigInteger.ValueOf(c);
+ BigInteger constA32 = BigInteger.ValueOf(97781173);
+
+ //step1
+ BigInteger[] y = new BigInteger[1]; // begin length = 1
+ y[0] = BigInteger.ValueOf(x0);
+
+ //step 2
+ int[] t = new int[1]; // t - orders; begin length = 1
+ t[0] = size;
+ int s = 0;
+ for (int i=0; t[i]>=33; i++)
+ {
+ // extension array t
+ int[] tmp_t = new int[t.Length + 1]; ///////////////
+ Array.Copy(t,0,tmp_t,0,t.Length); // extension
+ t = new int[tmp_t.Length]; // array t
+ Array.Copy(tmp_t, 0, t, 0, tmp_t.Length); ///////////////
+
+ t[i+1] = t[i]/2;
+ s = i+1;
+ }
+
+ //step3
+ BigInteger[] p = new BigInteger[s+1];
+ p[s] = new BigInteger("8000000B",16); //set min prime number length 32 bit
+
+ int m = s-1; //step4
+
+ for (int i=0; i<s; i++)
+ {
+ int rm = t[m]/32; //step5
+
+ step6: for(;;)
+ {
+ //step 6
+ BigInteger[] tmp_y = new BigInteger[y.Length]; ////////////////
+ Array.Copy(y,0,tmp_y,0,y.Length); // extension
+ y = new BigInteger[rm+1]; // array y
+ Array.Copy(tmp_y,0,y,0,tmp_y.Length); ////////////////
+
+ for (int j=0; j<rm; j++)
+ {
+ y[j+1] = (y[j].Multiply(constA32).Add(C)).Mod(BigInteger.Two.Pow(32));
+ }
+
+ //step 7
+ BigInteger Ym = BigInteger.Zero;
+ for (int j=0; j<rm; j++)
+ {
+ Ym = Ym.Add(y[j].ShiftLeft(32*j));
+ }
+
+ y[0] = y[rm]; //step 8
+
+ //step 9
+ BigInteger N = BigInteger.One.ShiftLeft(t[m]-1).Divide(p[m+1]).Add(
+ Ym.ShiftLeft(t[m]-1).Divide(p[m+1].ShiftLeft(32*rm)));
+
+ if (N.TestBit(0))
+ {
+ N = N.Add(BigInteger.One);
+ }
+
+ //step 10
+
+ for(;;)
+ {
+ //step 11
+ BigInteger NByLastP = N.Multiply(p[m+1]);
+
+ if (NByLastP.BitLength > t[m])
+ {
+ goto step6; //step 12
+ }
+
+ p[m] = NByLastP.Add(BigInteger.One);
+
+ //step13
+ if (BigInteger.Two.ModPow(NByLastP, p[m]).CompareTo(BigInteger.One) == 0
+ && BigInteger.Two.ModPow(N, p[m]).CompareTo(BigInteger.One) != 0)
+ {
+ break;
+ }
+
+ N = N.Add(BigInteger.Two);
+ }
+
+ if (--m < 0)
+ {
+ pq[0] = p[0];
+ pq[1] = p[1];
+ return y[0].LongValue; //return for procedure B' step 2
+ }
+
+ break; //step 14
+ }
+ }
+ return y[0].LongValue;
+ }
+
+ //Procedure B
+ private void procedure_B(int x0, int c, BigInteger[] pq)
+ {
+ //Verify and perform condition: 0<x<2^16; 0<c<2^16; c - odd.
+ while(x0<0 || x0>65536)
+ {
+ x0 = init_random.NextInt()/32768;
+ }
+
+ while((c<0 || c>65536) || (c/2==0))
+ {
+ c = init_random.NextInt()/32768 + 1;
+ }
+
+ BigInteger [] qp = new BigInteger[2];
+ BigInteger q = null, Q = null, p = null;
+ BigInteger C = BigInteger.ValueOf(c);
+ BigInteger constA16 = BigInteger.ValueOf(19381);
+
+ //step1
+ x0 = procedure_A(x0, c, qp, 256);
+ q = qp[0];
+
+ //step2
+ x0 = procedure_A(x0, c, qp, 512);
+ Q = qp[0];
+
+ BigInteger[] y = new BigInteger[65];
+ y[0] = BigInteger.ValueOf(x0);
+
+ const int tp = 1024;
+
+ BigInteger qQ = q.Multiply(Q);
+
+step3:
+ for(;;)
+ {
+ //step 3
+ for (int j=0; j<64; j++)
+ {
+ y[j+1] = (y[j].Multiply(constA16).Add(C)).Mod(BigInteger.Two.Pow(16));
+ }
+
+ //step 4
+ BigInteger Y = BigInteger.Zero;
+
+ for (int j=0; j<64; j++)
+ {
+ Y = Y.Add(y[j].ShiftLeft(16*j));
+ }
+
+ y[0] = y[64]; //step 5
+
+ //step 6
+ BigInteger N = BigInteger.One.ShiftLeft(tp-1).Divide(qQ).Add(
+ Y.ShiftLeft(tp-1).Divide(qQ.ShiftLeft(1024)));
+
+ if (N.TestBit(0))
+ {
+ N = N.Add(BigInteger.One);
+ }
+
+ //step 7
+
+ for(;;)
+ {
+ //step 11
+ BigInteger qQN = qQ.Multiply(N);
+
+ if (qQN.BitLength > tp)
+ {
+ goto step3; //step 9
+ }
+
+ p = qQN.Add(BigInteger.One);
+
+ //step10
+ if (BigInteger.Two.ModPow(qQN, p).CompareTo(BigInteger.One) == 0
+ && BigInteger.Two.ModPow(q.Multiply(N), p).CompareTo(BigInteger.One) != 0)
+ {
+ pq[0] = p;
+ pq[1] = q;
+ return;
+ }
+
+ N = N.Add(BigInteger.Two);
+ }
+ }
+ }
+
+ //Procedure B'
+ private void procedure_Bb(long x0, long c, BigInteger[] pq)
+ {
+ //Verify and perform condition: 0<x<2^32; 0<c<2^32; c - odd.
+ while(x0<0 || x0>4294967296L)
+ {
+ x0 = init_random.NextInt()*2;
+ }
+
+ while((c<0 || c>4294967296L) || (c/2==0))
+ {
+ c = init_random.NextInt()*2+1;
+ }
+
+ BigInteger [] qp = new BigInteger[2];
+ BigInteger q = null, Q = null, p = null;
+ BigInteger C = BigInteger.ValueOf(c);
+ BigInteger constA32 = BigInteger.ValueOf(97781173);
+
+ //step1
+ x0 = procedure_Aa(x0, c, qp, 256);
+ q = qp[0];
+
+ //step2
+ x0 = procedure_Aa(x0, c, qp, 512);
+ Q = qp[0];
+
+ BigInteger[] y = new BigInteger[33];
+ y[0] = BigInteger.ValueOf(x0);
+
+ const int tp = 1024;
+
+ BigInteger qQ = q.Multiply(Q);
+
+step3:
+ for(;;)
+ {
+ //step 3
+ for (int j=0; j<32; j++)
+ {
+ y[j+1] = (y[j].Multiply(constA32).Add(C)).Mod(BigInteger.Two.Pow(32));
+ }
+
+ //step 4
+ BigInteger Y = BigInteger.Zero;
+ for (int j=0; j<32; j++)
+ {
+ Y = Y.Add(y[j].ShiftLeft(32*j));
+ }
+
+ y[0] = y[32]; //step 5
+
+ //step 6
+ BigInteger N = BigInteger.One.ShiftLeft(tp-1).Divide(qQ).Add(
+ Y.ShiftLeft(tp-1).Divide(qQ.ShiftLeft(1024)));
+
+ if (N.TestBit(0))
+ {
+ N = N.Add(BigInteger.One);
+ }
+
+ //step 7
+
+ for(;;)
+ {
+ //step 11
+ BigInteger qQN = qQ.Multiply(N);
+
+ if (qQN.BitLength > tp)
+ {
+ goto step3; //step 9
+ }
+
+ p = qQN.Add(BigInteger.One);
+
+ //step10
+ if (BigInteger.Two.ModPow(qQN, p).CompareTo(BigInteger.One) == 0
+ && BigInteger.Two.ModPow(q.Multiply(N), p).CompareTo(BigInteger.One) != 0)
+ {
+ pq[0] = p;
+ pq[1] = q;
+ return;
+ }
+
+ N = N.Add(BigInteger.Two);
+ }
+ }
+ }
+
+
+ /**
+ * Procedure C
+ * procedure generates the a value from the given p,q,
+ * returning the a value.
+ */
+ private BigInteger procedure_C(BigInteger p, BigInteger q)
+ {
+ BigInteger pSub1 = p.Subtract(BigInteger.One);
+ BigInteger pSub1Divq = pSub1.Divide(q);
+
+ for(;;)
+ {
+ BigInteger d = new BigInteger(p.BitLength, init_random);
+
+ // 1 < d < p-1
+ if (d.CompareTo(BigInteger.One) > 0 && d.CompareTo(pSub1) < 0)
+ {
+ BigInteger a = d.ModPow(pSub1Divq, p);
+
+ if (a.CompareTo(BigInteger.One) != 0)
+ {
+ return a;
+ }
+ }
+ }
+ }
+
+ /**
+ * which generates the p , q and a values from the given parameters,
+ * returning the Gost3410Parameters object.
+ */
+ public Gost3410Parameters GenerateParameters()
+ {
+ BigInteger [] pq = new BigInteger[2];
+ BigInteger q = null, p = null, a = null;
+
+ int x0, c;
+ long x0L, cL;
+
+ if (typeproc==1)
+ {
+ x0 = init_random.NextInt();
+ c = init_random.NextInt();
+
+ switch(size)
+ {
+ case 512:
+ procedure_A(x0, c, pq, 512);
+ break;
+ case 1024:
+ procedure_B(x0, c, pq);
+ break;
+ default:
+ throw new ArgumentException("Ooops! key size 512 or 1024 bit.");
+ }
+ p = pq[0]; q = pq[1];
+ a = procedure_C(p, q);
+ //System.out.println("p:"+p.toString(16)+"\n"+"q:"+q.toString(16)+"\n"+"a:"+a.toString(16));
+ //System.out.println("p:"+p+"\n"+"q:"+q+"\n"+"a:"+a);
+ return new Gost3410Parameters(p, q, a, new Gost3410ValidationParameters(x0, c));
+ }
+ else
+ {
+ x0L = init_random.NextLong();
+ cL = init_random.NextLong();
+
+ switch(size)
+ {
+ case 512:
+ procedure_Aa(x0L, cL, pq, 512);
+ break;
+ case 1024:
+ procedure_Bb(x0L, cL, pq);
+ break;
+ default:
+ throw new InvalidOperationException("Ooops! key size 512 or 1024 bit.");
+ }
+ p = pq[0]; q = pq[1];
+ a = procedure_C(p, q);
+ //System.out.println("p:"+p.toString(16)+"\n"+"q:"+q.toString(16)+"\n"+"a:"+a.toString(16));
+ //System.out.println("p:"+p+"\n"+"q:"+q+"\n"+"a:"+a);
+ return new Gost3410Parameters(p, q, a, new Gost3410ValidationParameters(x0L, cL));
+ }
+ }
+ }
+}
diff --git a/Crypto/src/crypto/generators/Kdf1BytesGenerator.cs b/Crypto/src/crypto/generators/Kdf1BytesGenerator.cs
new file mode 100644
index 000000000..2b4fb7efd
--- /dev/null
+++ b/Crypto/src/crypto/generators/Kdf1BytesGenerator.cs
@@ -0,0 +1,27 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ /**
+ * KFD2 generator for derived keys and ivs as defined by IEEE P1363a/ISO 18033
+ * <br/>
+ * This implementation is based on IEEE P1363/ISO 18033.
+ */
+ public class Kdf1BytesGenerator
+ : BaseKdfBytesGenerator
+ {
+ /**
+ * Construct a KDF1 byte generator.
+ *
+ * @param digest the digest to be used as the source of derived keys.
+ */
+ public Kdf1BytesGenerator(
+ IDigest digest)
+ : base(0, digest)
+ {
+ }
+ }
+}
diff --git a/Crypto/src/crypto/generators/Kdf2BytesGenerator.cs b/Crypto/src/crypto/generators/Kdf2BytesGenerator.cs
new file mode 100644
index 000000000..be1cd158e
--- /dev/null
+++ b/Crypto/src/crypto/generators/Kdf2BytesGenerator.cs
@@ -0,0 +1,28 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ /**
+ * KDF2 generator for derived keys and ivs as defined by IEEE P1363a/ISO 18033
+ * <br/>
+ * This implementation is based on IEEE P1363/ISO 18033.
+ */
+ public class Kdf2BytesGenerator
+ : BaseKdfBytesGenerator
+ {
+ /**
+ * Construct a KDF2 bytes generator. Generates key material
+ * according to IEEE P1363 or ISO 18033 depending on the initialisation.
+ *
+ * @param digest the digest to be used as the source of derived keys.
+ */
+ public Kdf2BytesGenerator(
+ IDigest digest)
+ : base(1, digest)
+ {
+ }
+ }
+}
diff --git a/Crypto/src/crypto/generators/Mgf1BytesGenerator.cs b/Crypto/src/crypto/generators/Mgf1BytesGenerator.cs
new file mode 100644
index 000000000..23a3aca25
--- /dev/null
+++ b/Crypto/src/crypto/generators/Mgf1BytesGenerator.cs
@@ -0,0 +1,117 @@
+using System;
+//using Org.BouncyCastle.Math;
+//using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ /**
+ * Generator for MGF1 as defined in Pkcs 1v2
+ */
+ public class Mgf1BytesGenerator : IDerivationFunction
+ {
+ private IDigest digest;
+ private byte[] seed;
+ private int hLen;
+
+ /**
+ * @param digest the digest to be used as the source of Generated bytes
+ */
+ public Mgf1BytesGenerator(
+ IDigest digest)
+ {
+ this.digest = digest;
+ this.hLen = digest.GetDigestSize();
+ }
+
+ public void Init(
+ IDerivationParameters parameters)
+ {
+ if (!(typeof(MgfParameters).IsInstanceOfType(parameters)))
+ {
+ throw new ArgumentException("MGF parameters required for MGF1Generator");
+ }
+
+ MgfParameters p = (MgfParameters)parameters;
+
+ seed = p.GetSeed();
+ }
+
+ /**
+ * return the underlying digest.
+ */
+ public IDigest Digest
+ {
+ get
+ {
+ return digest;
+ }
+ }
+
+ /**
+ * int to octet string.
+ */
+ private void ItoOSP(
+ int i,
+ byte[] sp)
+ {
+ sp[0] = (byte)((uint) i >> 24);
+ sp[1] = (byte)((uint) i >> 16);
+ sp[2] = (byte)((uint) i >> 8);
+ sp[3] = (byte)((uint) i >> 0);
+ }
+
+ /**
+ * fill len bytes of the output buffer with bytes Generated from
+ * the derivation function.
+ *
+ * @throws DataLengthException if the out buffer is too small.
+ */
+ public int GenerateBytes(
+ byte[] output,
+ int outOff,
+ int length)
+ {
+ if ((output.Length - length) < outOff)
+ {
+ throw new DataLengthException("output buffer too small");
+ }
+
+ byte[] hashBuf = new byte[hLen];
+ byte[] C = new byte[4];
+ int counter = 0;
+
+ digest.Reset();
+
+ if (length > hLen)
+ {
+ do
+ {
+ ItoOSP(counter, C);
+
+ digest.BlockUpdate(seed, 0, seed.Length);
+ digest.BlockUpdate(C, 0, C.Length);
+ digest.DoFinal(hashBuf, 0);
+
+ Array.Copy(hashBuf, 0, output, outOff + counter * hLen, hLen);
+ }
+ while (++counter < (length / hLen));
+ }
+
+ if ((counter * hLen) < length)
+ {
+ ItoOSP(counter, C);
+
+ digest.BlockUpdate(seed, 0, seed.Length);
+ digest.BlockUpdate(C, 0, C.Length);
+ digest.DoFinal(hashBuf, 0);
+
+ Array.Copy(hashBuf, 0, output, outOff + counter * hLen, length - (counter * hLen));
+ }
+
+ return length;
+ }
+ }
+
+}
diff --git a/Crypto/src/crypto/generators/NaccacheSternKeyPairGenerator.cs b/Crypto/src/crypto/generators/NaccacheSternKeyPairGenerator.cs
new file mode 100644
index 000000000..a00a6c8a6
--- /dev/null
+++ b/Crypto/src/crypto/generators/NaccacheSternKeyPairGenerator.cs
@@ -0,0 +1,333 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ /**
+ * Key generation parameters for NaccacheStern cipher. For details on this cipher, please see
+ *
+ * http://www.gemplus.com/smart/rd/publications/pdf/NS98pkcs.pdf
+ */
+ public class NaccacheSternKeyPairGenerator
+ : IAsymmetricCipherKeyPairGenerator
+ {
+ private static readonly int[] smallPrimes =
+ {
+ 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67,
+ 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149,
+ 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233,
+ 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331,
+ 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431,
+ 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523,
+ 541, 547, 557
+ };
+
+ private NaccacheSternKeyGenerationParameters param;
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator#init(org.bouncycastle.crypto.KeyGenerationParameters)
+ */
+ public void Init(KeyGenerationParameters parameters)
+ {
+ this.param = (NaccacheSternKeyGenerationParameters)parameters;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator#generateKeyPair()
+ */
+ public AsymmetricCipherKeyPair GenerateKeyPair()
+ {
+ int strength = param.Strength;
+ SecureRandom rand = param.Random;
+ int certainty = param.Certainty;
+ bool debug = param.IsDebug;
+
+ if (debug)
+ {
+ System.Diagnostics.Debug.WriteLine("Fetching first " + param.CountSmallPrimes + " primes.");
+ }
+
+ IList smallPrimes = findFirstPrimes(param.CountSmallPrimes);
+
+ smallPrimes = permuteList(smallPrimes, rand);
+
+ BigInteger u = BigInteger.One;
+ BigInteger v = BigInteger.One;
+
+ for (int i = 0; i < smallPrimes.Count / 2; i++)
+ {
+ u = u.Multiply((BigInteger)smallPrimes[i]);
+ }
+ for (int i = smallPrimes.Count / 2; i < smallPrimes.Count; i++)
+ {
+ v = v.Multiply((BigInteger)smallPrimes[i]);
+ }
+
+ BigInteger sigma = u.Multiply(v);
+
+ // n = (2 a u _p + 1 ) ( 2 b v _q + 1)
+ // -> |n| = strength
+ // |2| = 1 in bits
+ // -> |a| * |b| = |n| - |u| - |v| - |_p| - |_q| - |2| -|2|
+ // remainingStrength = strength - sigma.bitLength() - _p.bitLength() -
+ // _q.bitLength() - 1 -1
+ int remainingStrength = strength - sigma.BitLength - 48;
+ BigInteger a = generatePrime(remainingStrength / 2 + 1, certainty, rand);
+ BigInteger b = generatePrime(remainingStrength / 2 + 1, certainty, rand);
+
+ BigInteger _p;
+ BigInteger _q;
+ BigInteger p;
+ BigInteger q;
+
+ long tries = 0;
+ if (debug)
+ {
+ System.Diagnostics.Debug.WriteLine("generating p and q");
+ }
+
+ BigInteger _2au = a.Multiply(u).ShiftLeft(1);
+ BigInteger _2bv = b.Multiply(v).ShiftLeft(1);
+
+ for (;;)
+ {
+ tries++;
+
+ _p = generatePrime(24, certainty, rand);
+
+ p = _p.Multiply(_2au).Add(BigInteger.One);
+
+ if (!p.IsProbablePrime(certainty))
+ continue;
+
+ for (;;)
+ {
+ _q = generatePrime(24, certainty, rand);
+
+ if (_p.Equals(_q))
+ continue;
+
+ q = _q.Multiply(_2bv).Add(BigInteger.One);
+
+ if (q.IsProbablePrime(certainty))
+ break;
+ }
+
+ if (!sigma.Gcd(_p.Multiply(_q)).Equals(BigInteger.One))
+ {
+ System.Diagnostics.Debug.WriteLine("sigma.gcd(_p.mult(_q)) != 1!\n _p: " + _p + "\n _q: " + _q);
+ continue;
+ }
+
+ if (p.Multiply(q).BitLength < strength)
+ {
+ if (debug)
+ {
+ System.Diagnostics.Debug.WriteLine("key size too small. Should be " + strength + " but is actually "
+ + p.Multiply(q).BitLength);
+ }
+ continue;
+ }
+ break;
+ }
+
+ if (debug)
+ {
+ System.Diagnostics.Debug.WriteLine("needed " + tries + " tries to generate p and q.");
+ }
+
+ BigInteger n = p.Multiply(q);
+ BigInteger phi_n = p.Subtract(BigInteger.One).Multiply(q.Subtract(BigInteger.One));
+ BigInteger g;
+ tries = 0;
+ if (debug)
+ {
+ System.Diagnostics.Debug.WriteLine("generating g");
+ }
+ for (;;)
+ {
+ // TODO After the first loop, just regenerate one randomly-selected gPart each time?
+ IList gParts = Platform.CreateArrayList();
+ for (int ind = 0; ind != smallPrimes.Count; ind++)
+ {
+ BigInteger i = (BigInteger)smallPrimes[ind];
+ BigInteger e = phi_n.Divide(i);
+
+ for (;;)
+ {
+ tries++;
+
+ g = generatePrime(strength, certainty, rand);
+
+ if (!g.ModPow(e, n).Equals(BigInteger.One))
+ {
+ gParts.Add(g);
+ break;
+ }
+ }
+ }
+ g = BigInteger.One;
+ for (int i = 0; i < smallPrimes.Count; i++)
+ {
+ BigInteger gPart = (BigInteger) gParts[i];
+ BigInteger smallPrime = (BigInteger) smallPrimes[i];
+ g = g.Multiply(gPart.ModPow(sigma.Divide(smallPrime), n)).Mod(n);
+ }
+
+ // make sure that g is not divisible by p_i or q_i
+ bool divisible = false;
+ for (int i = 0; i < smallPrimes.Count; i++)
+ {
+ if (g.ModPow(phi_n.Divide((BigInteger)smallPrimes[i]), n).Equals(BigInteger.One))
+ {
+ if (debug)
+ {
+ System.Diagnostics.Debug.WriteLine("g has order phi(n)/" + smallPrimes[i] + "\n g: " + g);
+ }
+ divisible = true;
+ break;
+ }
+ }
+
+ if (divisible)
+ {
+ continue;
+ }
+
+ // make sure that g has order > phi_n/4
+
+ //if (g.ModPow(phi_n.Divide(BigInteger.ValueOf(4)), n).Equals(BigInteger.One))
+ if (g.ModPow(phi_n.ShiftRight(2), n).Equals(BigInteger.One))
+ {
+ if (debug)
+ {
+ System.Diagnostics.Debug.WriteLine("g has order phi(n)/4\n g:" + g);
+ }
+ continue;
+ }
+
+ if (g.ModPow(phi_n.Divide(_p), n).Equals(BigInteger.One))
+ {
+ if (debug)
+ {
+ System.Diagnostics.Debug.WriteLine("g has order phi(n)/p'\n g: " + g);
+ }
+ continue;
+ }
+ if (g.ModPow(phi_n.Divide(_q), n).Equals(BigInteger.One))
+ {
+ if (debug)
+ {
+ System.Diagnostics.Debug.WriteLine("g has order phi(n)/q'\n g: " + g);
+ }
+ continue;
+ }
+ if (g.ModPow(phi_n.Divide(a), n).Equals(BigInteger.One))
+ {
+ if (debug)
+ {
+ System.Diagnostics.Debug.WriteLine("g has order phi(n)/a\n g: " + g);
+ }
+ continue;
+ }
+ if (g.ModPow(phi_n.Divide(b), n).Equals(BigInteger.One))
+ {
+ if (debug)
+ {
+ System.Diagnostics.Debug.WriteLine("g has order phi(n)/b\n g: " + g);
+ }
+ continue;
+ }
+ break;
+ }
+ if (debug)
+ {
+ System.Diagnostics.Debug.WriteLine("needed " + tries + " tries to generate g");
+ System.Diagnostics.Debug.WriteLine("");
+ System.Diagnostics.Debug.WriteLine("found new NaccacheStern cipher variables:");
+ System.Diagnostics.Debug.WriteLine("smallPrimes: " + CollectionUtilities.ToString(smallPrimes));
+ System.Diagnostics.Debug.WriteLine("sigma:...... " + sigma + " (" + sigma.BitLength + " bits)");
+ System.Diagnostics.Debug.WriteLine("a:.......... " + a);
+ System.Diagnostics.Debug.WriteLine("b:.......... " + b);
+ System.Diagnostics.Debug.WriteLine("p':......... " + _p);
+ System.Diagnostics.Debug.WriteLine("q':......... " + _q);
+ System.Diagnostics.Debug.WriteLine("p:.......... " + p);
+ System.Diagnostics.Debug.WriteLine("q:.......... " + q);
+ System.Diagnostics.Debug.WriteLine("n:.......... " + n);
+ System.Diagnostics.Debug.WriteLine("phi(n):..... " + phi_n);
+ System.Diagnostics.Debug.WriteLine("g:.......... " + g);
+ System.Diagnostics.Debug.WriteLine("");
+ }
+
+ return new AsymmetricCipherKeyPair(new NaccacheSternKeyParameters(false, g, n, sigma.BitLength),
+ new NaccacheSternPrivateKeyParameters(g, n, sigma.BitLength, smallPrimes, phi_n));
+ }
+
+ private static BigInteger generatePrime(
+ int bitLength,
+ int certainty,
+ SecureRandom rand)
+ {
+ return new BigInteger(bitLength, certainty, rand);
+ }
+
+ /**
+ * Generates a permuted ArrayList from the original one. The original List
+ * is not modified
+ *
+ * @param arr
+ * the ArrayList to be permuted
+ * @param rand
+ * the source of Randomness for permutation
+ * @return a new ArrayList with the permuted elements.
+ */
+ private static IList permuteList(
+ IList arr,
+ SecureRandom rand)
+ {
+ // TODO Create a utility method for generating permutation of first 'n' integers
+
+ IList retval = Platform.CreateArrayList(arr.Count);
+
+ foreach (object element in arr)
+ {
+ int index = rand.Next(retval.Count + 1);
+ retval.Insert(index, element);
+ }
+
+ return retval;
+ }
+
+ /**
+ * Finds the first 'count' primes starting with 3
+ *
+ * @param count
+ * the number of primes to find
+ * @return a vector containing the found primes as Integer
+ */
+ private static IList findFirstPrimes(
+ int count)
+ {
+ IList primes = Platform.CreateArrayList(count);
+
+ for (int i = 0; i != count; i++)
+ {
+ primes.Add(BigInteger.ValueOf(smallPrimes[i]));
+ }
+
+ return primes;
+ }
+
+ }
+}
diff --git a/Crypto/src/crypto/generators/OpenSSLPBEParametersGenerator.cs b/Crypto/src/crypto/generators/OpenSSLPBEParametersGenerator.cs
new file mode 100644
index 000000000..8da5d3ad1
--- /dev/null
+++ b/Crypto/src/crypto/generators/OpenSSLPBEParametersGenerator.cs
@@ -0,0 +1,167 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ /**
+ * Generator for PBE derived keys and ivs as usd by OpenSSL.
+ * <p>
+ * The scheme is a simple extension of PKCS 5 V2.0 Scheme 1 using MD5 with an
+ * iteration count of 1.
+ * </p>
+ */
+ public class OpenSslPbeParametersGenerator
+ : PbeParametersGenerator
+ {
+ private readonly IDigest digest = new MD5Digest();
+
+ /**
+ * Construct a OpenSSL Parameters generator.
+ */
+ public OpenSslPbeParametersGenerator()
+ {
+ }
+
+ public override void Init(
+ byte[] password,
+ byte[] salt,
+ int iterationCount)
+ {
+ // Ignore the provided iterationCount
+ base.Init(password, salt, 1);
+ }
+
+ /**
+ * Initialise - note the iteration count for this algorithm is fixed at 1.
+ *
+ * @param password password to use.
+ * @param salt salt to use.
+ */
+ public virtual void Init(
+ byte[] password,
+ byte[] salt)
+ {
+ base.Init(password, salt, 1);
+ }
+
+ /**
+ * the derived key function, the ith hash of the password and the salt.
+ */
+ private byte[] GenerateDerivedKey(
+ int bytesNeeded)
+ {
+ byte[] buf = new byte[digest.GetDigestSize()];
+ byte[] key = new byte[bytesNeeded];
+ int offset = 0;
+
+ for (;;)
+ {
+ digest.BlockUpdate(mPassword, 0, mPassword.Length);
+ digest.BlockUpdate(mSalt, 0, mSalt.Length);
+
+ digest.DoFinal(buf, 0);
+
+ int len = (bytesNeeded > buf.Length) ? buf.Length : bytesNeeded;
+ Array.Copy(buf, 0, key, offset, len);
+ offset += len;
+
+ // check if we need any more
+ bytesNeeded -= len;
+ if (bytesNeeded == 0)
+ {
+ break;
+ }
+
+ // do another round
+ digest.Reset();
+ digest.BlockUpdate(buf, 0, buf.Length);
+ }
+
+ return key;
+ }
+
+ /**
+ * Generate a key parameter derived from the password, salt, and iteration
+ * count we are currently initialised with.
+ *
+ * @param keySize the size of the key we want (in bits)
+ * @return a KeyParameter object.
+ * @exception ArgumentException if the key length larger than the base hash size.
+ */
+ [Obsolete("Use version with 'algorithm' parameter")]
+ public override ICipherParameters GenerateDerivedParameters(
+ int keySize)
+ {
+ return GenerateDerivedMacParameters(keySize);
+ }
+
+ public override ICipherParameters GenerateDerivedParameters(
+ string algorithm,
+ int keySize)
+ {
+ keySize /= 8;
+
+ byte[] dKey = GenerateDerivedKey(keySize);
+
+ return ParameterUtilities.CreateKeyParameter(algorithm, dKey, 0, keySize);
+ }
+
+ /**
+ * Generate a key with initialisation vector parameter derived from
+ * the password, salt, and iteration count we are currently initialised
+ * with.
+ *
+ * @param keySize the size of the key we want (in bits)
+ * @param ivSize the size of the iv we want (in bits)
+ * @return a ParametersWithIV object.
+ * @exception ArgumentException if keySize + ivSize is larger than the base hash size.
+ */
+ [Obsolete("Use version with 'algorithm' parameter")]
+ public override ICipherParameters GenerateDerivedParameters(
+ int keySize,
+ int ivSize)
+ {
+ keySize = keySize / 8;
+ ivSize = ivSize / 8;
+
+ byte[] dKey = GenerateDerivedKey(keySize + ivSize);
+
+ return new ParametersWithIV(new KeyParameter(dKey, 0, keySize), dKey, keySize, ivSize);
+ }
+
+ public override ICipherParameters GenerateDerivedParameters(
+ string algorithm,
+ int keySize,
+ int ivSize)
+ {
+ keySize /= 8;
+ ivSize /= 8;
+
+ byte[] dKey = GenerateDerivedKey(keySize + ivSize);
+ KeyParameter key = ParameterUtilities.CreateKeyParameter(algorithm, dKey, 0, keySize);
+
+ return new ParametersWithIV(key, dKey, keySize, ivSize);
+ }
+
+ /**
+ * Generate a key parameter for use with a MAC derived from the password,
+ * salt, and iteration count we are currently initialised with.
+ *
+ * @param keySize the size of the key we want (in bits)
+ * @return a KeyParameter object.
+ * @exception ArgumentException if the key length larger than the base hash size.
+ */
+ public override ICipherParameters GenerateDerivedMacParameters(
+ int keySize)
+ {
+ keySize = keySize / 8;
+
+ byte[] dKey = GenerateDerivedKey(keySize);
+
+ return new KeyParameter(dKey, 0, keySize);
+ }
+ }
+}
diff --git a/Crypto/src/crypto/generators/Pkcs12ParametersGenerator.cs b/Crypto/src/crypto/generators/Pkcs12ParametersGenerator.cs
new file mode 100644
index 000000000..d2da3f6fc
--- /dev/null
+++ b/Crypto/src/crypto/generators/Pkcs12ParametersGenerator.cs
@@ -0,0 +1,245 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ /**
+ * Generator for Pbe derived keys and ivs as defined by Pkcs 12 V1.0.
+ * <p>
+ * The document this implementation is based on can be found at
+ * <a href="http://www.rsasecurity.com/rsalabs/pkcs/pkcs-12/index.html">
+ * RSA's Pkcs12 Page</a>
+ * </p>
+ */
+ public class Pkcs12ParametersGenerator
+ : PbeParametersGenerator
+ {
+ public const int KeyMaterial = 1;
+ public const int IVMaterial = 2;
+ public const int MacMaterial = 3;
+
+ private readonly IDigest digest;
+
+ private readonly int u;
+ private readonly int v;
+
+ /**
+ * Construct a Pkcs 12 Parameters generator.
+ *
+ * @param digest the digest to be used as the source of derived keys.
+ * @exception ArgumentException if an unknown digest is passed in.
+ */
+ public Pkcs12ParametersGenerator(
+ IDigest digest)
+ {
+ this.digest = digest;
+
+ u = digest.GetDigestSize();
+ v = digest.GetByteLength();
+ }
+
+ /**
+ * add a + b + 1, returning the result in a. The a value is treated
+ * as a BigInteger of length (b.Length * 8) bits. The result is
+ * modulo 2^b.Length in case of overflow.
+ */
+ private void Adjust(
+ byte[] a,
+ int aOff,
+ byte[] b)
+ {
+ int x = (b[b.Length - 1] & 0xff) + (a[aOff + b.Length - 1] & 0xff) + 1;
+
+ a[aOff + b.Length - 1] = (byte)x;
+ x = (int) ((uint) x >> 8);
+
+ for (int i = b.Length - 2; i >= 0; i--)
+ {
+ x += (b[i] & 0xff) + (a[aOff + i] & 0xff);
+ a[aOff + i] = (byte)x;
+ x = (int) ((uint) x >> 8);
+ }
+ }
+
+ /**
+ * generation of a derived key ala Pkcs12 V1.0.
+ */
+ private byte[] GenerateDerivedKey(
+ int idByte,
+ int n)
+ {
+ byte[] D = new byte[v];
+ byte[] dKey = new byte[n];
+
+ for (int i = 0; i != D.Length; i++)
+ {
+ D[i] = (byte)idByte;
+ }
+
+ byte[] S;
+
+ if ((mSalt != null) && (mSalt.Length != 0))
+ {
+ S = new byte[v * ((mSalt.Length + v - 1) / v)];
+
+ for (int i = 0; i != S.Length; i++)
+ {
+ S[i] = mSalt[i % mSalt.Length];
+ }
+ }
+ else
+ {
+ S = new byte[0];
+ }
+
+ byte[] P;
+
+ if ((mPassword != null) && (mPassword.Length != 0))
+ {
+ P = new byte[v * ((mPassword.Length + v - 1) / v)];
+
+ for (int i = 0; i != P.Length; i++)
+ {
+ P[i] = mPassword[i % mPassword.Length];
+ }
+ }
+ else
+ {
+ P = new byte[0];
+ }
+
+ byte[] I = new byte[S.Length + P.Length];
+
+ Array.Copy(S, 0, I, 0, S.Length);
+ Array.Copy(P, 0, I, S.Length, P.Length);
+
+ byte[] B = new byte[v];
+ int c = (n + u - 1) / u;
+
+ for (int i = 1; i <= c; i++)
+ {
+ byte[] A = new byte[u];
+
+ digest.BlockUpdate(D, 0, D.Length);
+ digest.BlockUpdate(I, 0, I.Length);
+ digest.DoFinal(A, 0);
+ for (int j = 1; j != mIterationCount; j++)
+ {
+ digest.BlockUpdate(A, 0, A.Length);
+ digest.DoFinal(A, 0);
+ }
+
+ for (int j = 0; j != B.Length; j++)
+ {
+ B[j] = A[j % A.Length];
+ }
+
+ for (int j = 0; j != I.Length / v; j++)
+ {
+ Adjust(I, j * v, B);
+ }
+
+ if (i == c)
+ {
+ Array.Copy(A, 0, dKey, (i - 1) * u, dKey.Length - ((i - 1) * u));
+ }
+ else
+ {
+ Array.Copy(A, 0, dKey, (i - 1) * u, A.Length);
+ }
+ }
+
+ return dKey;
+ }
+
+ /**
+ * Generate a key parameter derived from the password, salt, and iteration
+ * count we are currently initialised with.
+ *
+ * @param keySize the size of the key we want (in bits)
+ * @return a KeyParameter object.
+ */
+ [Obsolete("Use version with 'algorithm' parameter")]
+ public override ICipherParameters GenerateDerivedParameters(
+ int keySize)
+ {
+ keySize /= 8;
+
+ byte[] dKey = GenerateDerivedKey(KeyMaterial, keySize);
+
+ return new KeyParameter(dKey, 0, keySize);
+ }
+
+ public override ICipherParameters GenerateDerivedParameters(
+ string algorithm,
+ int keySize)
+ {
+ keySize /= 8;
+
+ byte[] dKey = GenerateDerivedKey(KeyMaterial, keySize);
+
+ return ParameterUtilities.CreateKeyParameter(algorithm, dKey, 0, keySize);
+ }
+
+ /**
+ * Generate a key with initialisation vector parameter derived from
+ * the password, salt, and iteration count we are currently initialised
+ * with.
+ *
+ * @param keySize the size of the key we want (in bits)
+ * @param ivSize the size of the iv we want (in bits)
+ * @return a ParametersWithIV object.
+ */
+ [Obsolete("Use version with 'algorithm' parameter")]
+ public override ICipherParameters GenerateDerivedParameters(
+ int keySize,
+ int ivSize)
+ {
+ keySize /= 8;
+ ivSize /= 8;
+
+ byte[] dKey = GenerateDerivedKey(KeyMaterial, keySize);
+
+ byte[] iv = GenerateDerivedKey(IVMaterial, ivSize);
+
+ return new ParametersWithIV(new KeyParameter(dKey, 0, keySize), iv, 0, ivSize);
+ }
+
+ public override ICipherParameters GenerateDerivedParameters(
+ string algorithm,
+ int keySize,
+ int ivSize)
+ {
+ keySize /= 8;
+ ivSize /= 8;
+
+ byte[] dKey = GenerateDerivedKey(KeyMaterial, keySize);
+ KeyParameter key = ParameterUtilities.CreateKeyParameter(algorithm, dKey, 0, keySize);
+
+ byte[] iv = GenerateDerivedKey(IVMaterial, ivSize);
+
+ return new ParametersWithIV(key, iv, 0, ivSize);
+ }
+
+ /**
+ * Generate a key parameter for use with a MAC derived from the password,
+ * salt, and iteration count we are currently initialised with.
+ *
+ * @param keySize the size of the key we want (in bits)
+ * @return a KeyParameter object.
+ */
+ public override ICipherParameters GenerateDerivedMacParameters(
+ int keySize)
+ {
+ keySize /= 8;
+
+ byte[] dKey = GenerateDerivedKey(MacMaterial, keySize);
+
+ return new KeyParameter(dKey, 0, keySize);
+ }
+ }
+}
diff --git a/Crypto/src/crypto/generators/Pkcs5S1ParametersGenerator.cs b/Crypto/src/crypto/generators/Pkcs5S1ParametersGenerator.cs
new file mode 100644
index 000000000..8586e1ca9
--- /dev/null
+++ b/Crypto/src/crypto/generators/Pkcs5S1ParametersGenerator.cs
@@ -0,0 +1,162 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ /**
+ * Generator for Pbe derived keys and ivs as defined by Pkcs 5 V2.0 Scheme 1.
+ * Note this generator is limited to the size of the hash produced by the
+ * digest used to drive it.
+ * <p>
+ * The document this implementation is based on can be found at
+ * <a href="http://www.rsasecurity.com/rsalabs/pkcs/pkcs-5/index.html">
+ * RSA's Pkcs5 Page</a>
+ * </p>
+ */
+ public class Pkcs5S1ParametersGenerator
+ : PbeParametersGenerator
+ {
+ private readonly IDigest digest;
+
+ /**
+ * Construct a Pkcs 5 Scheme 1 Parameters generator.
+ *
+ * @param digest the digest to be used as the source of derived keys.
+ */
+ public Pkcs5S1ParametersGenerator(
+ IDigest digest)
+ {
+ this.digest = digest;
+ }
+
+ /**
+ * the derived key function, the ith hash of the mPassword and the mSalt.
+ */
+ private byte[] GenerateDerivedKey()
+ {
+ byte[] digestBytes = new byte[digest.GetDigestSize()];
+
+ digest.BlockUpdate(mPassword, 0, mPassword.Length);
+ digest.BlockUpdate(mSalt, 0, mSalt.Length);
+
+ digest.DoFinal(digestBytes, 0);
+ for (int i = 1; i < mIterationCount; i++)
+ {
+ digest.BlockUpdate(digestBytes, 0, digestBytes.Length);
+ digest.DoFinal(digestBytes, 0);
+ }
+
+ return digestBytes;
+ }
+
+ /**
+ * Generate a key parameter derived from the mPassword, mSalt, and iteration
+ * count we are currently initialised with.
+ *
+ * @param keySize the size of the key we want (in bits)
+ * @return a KeyParameter object.
+ * @exception ArgumentException if the key length larger than the base hash size.
+ */
+ [Obsolete("Use version with 'algorithm' parameter")]
+ public override ICipherParameters GenerateDerivedParameters(
+ int keySize)
+ {
+ return GenerateDerivedMacParameters(keySize);
+ }
+
+ public override ICipherParameters GenerateDerivedParameters(
+ string algorithm,
+ int keySize)
+ {
+ keySize /= 8;
+
+ if (keySize > digest.GetDigestSize())
+ {
+ throw new ArgumentException(
+ "Can't Generate a derived key " + keySize + " bytes long.");
+ }
+
+ byte[] dKey = GenerateDerivedKey();
+
+ return ParameterUtilities.CreateKeyParameter(algorithm, dKey, 0, keySize);
+ }
+
+ /**
+ * Generate a key with initialisation vector parameter derived from
+ * the mPassword, mSalt, and iteration count we are currently initialised
+ * with.
+ *
+ * @param keySize the size of the key we want (in bits)
+ * @param ivSize the size of the iv we want (in bits)
+ * @return a ParametersWithIV object.
+ * @exception ArgumentException if keySize + ivSize is larger than the base hash size.
+ */
+ [Obsolete("Use version with 'algorithm' parameter")]
+ public override ICipherParameters GenerateDerivedParameters(
+ int keySize,
+ int ivSize)
+ {
+ keySize /= 8;
+ ivSize /= 8;
+
+ if ((keySize + ivSize) > digest.GetDigestSize())
+ {
+ throw new ArgumentException(
+ "Can't Generate a derived key " + (keySize + ivSize) + " bytes long.");
+ }
+
+ byte[] dKey = GenerateDerivedKey();
+
+ return new ParametersWithIV(new KeyParameter(dKey, 0, keySize), dKey, keySize, ivSize);
+ }
+
+ public override ICipherParameters GenerateDerivedParameters(
+ string algorithm,
+ int keySize,
+ int ivSize)
+ {
+ keySize /= 8;
+ ivSize /= 8;
+
+ if ((keySize + ivSize) > digest.GetDigestSize())
+ {
+ throw new ArgumentException(
+ "Can't Generate a derived key " + (keySize + ivSize) + " bytes long.");
+ }
+
+ byte[] dKey = GenerateDerivedKey();
+ KeyParameter key = ParameterUtilities.CreateKeyParameter(algorithm, dKey, 0, keySize);
+
+ return new ParametersWithIV(key, dKey, keySize, ivSize);
+ }
+
+ /**
+ * Generate a key parameter for use with a MAC derived from the mPassword,
+ * mSalt, and iteration count we are currently initialised with.
+ *
+ * @param keySize the size of the key we want (in bits)
+ * @return a KeyParameter object.
+ * @exception ArgumentException if the key length larger than the base hash size.
+ */
+ public override ICipherParameters GenerateDerivedMacParameters(
+ int keySize)
+ {
+ keySize /= 8;
+
+ if (keySize > digest.GetDigestSize())
+ {
+ throw new ArgumentException(
+ "Can't Generate a derived key " + keySize + " bytes long.");
+ }
+
+ byte[] dKey = GenerateDerivedKey();
+
+ return new KeyParameter(dKey, 0, keySize);
+ }
+ }
+}
diff --git a/Crypto/src/crypto/generators/Pkcs5S2ParametersGenerator.cs b/Crypto/src/crypto/generators/Pkcs5S2ParametersGenerator.cs
new file mode 100644
index 000000000..58d7b5c37
--- /dev/null
+++ b/Crypto/src/crypto/generators/Pkcs5S2ParametersGenerator.cs
@@ -0,0 +1,172 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ /**
+ * Generator for Pbe derived keys and ivs as defined by Pkcs 5 V2.0 Scheme 2.
+ * This generator uses a SHA-1 HMac as the calculation function.
+ * <p>
+ * The document this implementation is based on can be found at
+ * <a href="http://www.rsasecurity.com/rsalabs/pkcs/pkcs-5/index.html">
+ * RSA's Pkcs5 Page</a></p>
+ */
+ public class Pkcs5S2ParametersGenerator
+ : PbeParametersGenerator
+ {
+ private readonly IMac hMac;
+
+ /**
+ * construct a Pkcs5 Scheme 2 Parameters generator.
+ */
+ public Pkcs5S2ParametersGenerator()
+ : this(new Sha1Digest())
+ {
+ }
+
+ public Pkcs5S2ParametersGenerator(IDigest digest)
+ {
+ hMac = new HMac(digest);
+ }
+
+ private void F(
+ byte[] P,
+ byte[] S,
+ int c,
+ byte[] iBuf,
+ byte[] outBytes,
+ int outOff)
+ {
+ byte[] state = new byte[hMac.GetMacSize()];
+ ICipherParameters param = new KeyParameter(P);
+
+ hMac.Init(param);
+
+ if (S != null)
+ {
+ hMac.BlockUpdate(S, 0, S.Length);
+ }
+
+ hMac.BlockUpdate(iBuf, 0, iBuf.Length);
+
+ hMac.DoFinal(state, 0);
+
+ Array.Copy(state, 0, outBytes, outOff, state.Length);
+
+ for (int count = 1; count != c; count++)
+ {
+ hMac.Init(param);
+ hMac.BlockUpdate(state, 0, state.Length);
+ hMac.DoFinal(state, 0);
+
+ for (int j = 0; j != state.Length; j++)
+ {
+ outBytes[outOff + j] ^= state[j];
+ }
+ }
+ }
+
+ private byte[] GenerateDerivedKey(
+ int dkLen)
+ {
+ int hLen = hMac.GetMacSize();
+ int l = (dkLen + hLen - 1) / hLen;
+ byte[] iBuf = new byte[4];
+ byte[] outBytes = new byte[l * hLen];
+
+ for (int i = 1; i <= l; i++)
+ {
+ Pack.UInt32_To_BE((uint)i, iBuf);
+
+ F(mPassword, mSalt, mIterationCount, iBuf, outBytes, (i - 1) * hLen);
+ }
+
+ return outBytes;
+ }
+
+ /**
+ * Generate a key parameter derived from the password, salt, and iteration
+ * count we are currently initialised with.
+ *
+ * @param keySize the size of the key we want (in bits)
+ * @return a KeyParameter object.
+ */
+ [Obsolete("Use version with 'algorithm' parameter")]
+ public override ICipherParameters GenerateDerivedParameters(
+ int keySize)
+ {
+ return GenerateDerivedMacParameters(keySize);
+ }
+
+ public override ICipherParameters GenerateDerivedParameters(
+ string algorithm,
+ int keySize)
+ {
+ keySize /= 8;
+
+ byte[] dKey = GenerateDerivedKey(keySize);
+
+ return ParameterUtilities.CreateKeyParameter(algorithm, dKey, 0, keySize);
+ }
+
+ /**
+ * Generate a key with initialisation vector parameter derived from
+ * the password, salt, and iteration count we are currently initialised
+ * with.
+ *
+ * @param keySize the size of the key we want (in bits)
+ * @param ivSize the size of the iv we want (in bits)
+ * @return a ParametersWithIV object.
+ */
+ [Obsolete("Use version with 'algorithm' parameter")]
+ public override ICipherParameters GenerateDerivedParameters(
+ int keySize,
+ int ivSize)
+ {
+ keySize /= 8;
+ ivSize /= 8;
+
+ byte[] dKey = GenerateDerivedKey(keySize + ivSize);
+
+ return new ParametersWithIV(new KeyParameter(dKey, 0, keySize), dKey, keySize, ivSize);
+ }
+
+ public override ICipherParameters GenerateDerivedParameters(
+ string algorithm,
+ int keySize,
+ int ivSize)
+ {
+ keySize /= 8;
+ ivSize /= 8;
+
+ byte[] dKey = GenerateDerivedKey(keySize + ivSize);
+ KeyParameter key = ParameterUtilities.CreateKeyParameter(algorithm, dKey, 0, keySize);
+
+ return new ParametersWithIV(key, dKey, keySize, ivSize);
+ }
+
+ /**
+ * Generate a key parameter for use with a MAC derived from the password,
+ * salt, and iteration count we are currently initialised with.
+ *
+ * @param keySize the size of the key we want (in bits)
+ * @return a KeyParameter object.
+ */
+ public override ICipherParameters GenerateDerivedMacParameters(
+ int keySize)
+ {
+ keySize /= 8;
+
+ byte[] dKey = GenerateDerivedKey(keySize);
+
+ return new KeyParameter(dKey, 0, keySize);
+ }
+ }
+}
diff --git a/Crypto/src/crypto/generators/RSABlindingFactorGenerator.cs b/Crypto/src/crypto/generators/RSABlindingFactorGenerator.cs
new file mode 100644
index 000000000..e2f63face
--- /dev/null
+++ b/Crypto/src/crypto/generators/RSABlindingFactorGenerator.cs
@@ -0,0 +1,69 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ /**
+ * Generate a random factor suitable for use with RSA blind signatures
+ * as outlined in Chaum's blinding and unblinding as outlined in
+ * "Handbook of Applied Cryptography", page 475.
+ */
+ public class RsaBlindingFactorGenerator
+ {
+ private RsaKeyParameters key;
+ private SecureRandom random;
+
+ /**
+ * Initialise the factor generator
+ *
+ * @param param the necessary RSA key parameters.
+ */
+ public void Init(
+ ICipherParameters param)
+ {
+ if (param is ParametersWithRandom)
+ {
+ ParametersWithRandom rParam = (ParametersWithRandom)param;
+
+ key = (RsaKeyParameters)rParam.Parameters;
+ random = rParam.Random;
+ }
+ else
+ {
+ key = (RsaKeyParameters)param;
+ random = new SecureRandom();
+ }
+
+ if (key.IsPrivate)
+ throw new ArgumentException("generator requires RSA public key");
+ }
+
+ /**
+ * Generate a suitable blind factor for the public key the generator was initialised with.
+ *
+ * @return a random blind factor
+ */
+ public BigInteger GenerateBlindingFactor()
+ {
+ if (key == null)
+ throw new InvalidOperationException("generator not initialised");
+
+ BigInteger m = key.Modulus;
+ int length = m.BitLength - 1; // must be less than m.BitLength
+ BigInteger factor;
+ BigInteger gcd;
+
+ do
+ {
+ factor = new BigInteger(length, random);
+ gcd = factor.Gcd(m);
+ }
+ while (factor.SignValue == 0 || factor.Equals(BigInteger.One) || !gcd.Equals(BigInteger.One));
+
+ return factor;
+ }
+ }
+}
diff --git a/Crypto/src/crypto/generators/RsaKeyPairGenerator.cs b/Crypto/src/crypto/generators/RsaKeyPairGenerator.cs
new file mode 100644
index 000000000..3074aed04
--- /dev/null
+++ b/Crypto/src/crypto/generators/RsaKeyPairGenerator.cs
@@ -0,0 +1,139 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ /**
+ * an RSA key pair generator.
+ */
+ public class RsaKeyPairGenerator
+ : IAsymmetricCipherKeyPairGenerator
+ {
+ private static readonly BigInteger DefaultPublicExponent = BigInteger.ValueOf(0x10001);
+ private const int DefaultTests = 12;
+
+ private RsaKeyGenerationParameters param;
+
+ public void Init(
+ KeyGenerationParameters parameters)
+ {
+ if (parameters is RsaKeyGenerationParameters)
+ {
+ this.param = (RsaKeyGenerationParameters)parameters;
+ }
+ else
+ {
+ this.param = new RsaKeyGenerationParameters(
+ DefaultPublicExponent, parameters.Random, parameters.Strength, DefaultTests);
+ }
+ }
+
+ public AsymmetricCipherKeyPair GenerateKeyPair()
+ {
+ BigInteger p, q, n, d, e, pSub1, qSub1, phi;
+
+ //
+ // p and q values should have a length of half the strength in bits
+ //
+ int strength = param.Strength;
+ int pbitlength = (strength + 1) / 2;
+ int qbitlength = (strength - pbitlength);
+ int mindiffbits = strength / 3;
+
+ e = param.PublicExponent;
+
+ // TODO Consider generating safe primes for p, q (see DHParametersHelper.generateSafePrimes)
+ // (then p-1 and q-1 will not consist of only small factors - see "Pollard's algorithm")
+
+ //
+ // Generate p, prime and (p-1) relatively prime to e
+ //
+ for (;;)
+ {
+ p = new BigInteger(pbitlength, 1, param.Random);
+
+ if (p.Mod(e).Equals(BigInteger.One))
+ continue;
+
+ if (!p.IsProbablePrime(param.Certainty))
+ continue;
+
+ if (e.Gcd(p.Subtract(BigInteger.One)).Equals(BigInteger.One))
+ break;
+ }
+
+ //
+ // Generate a modulus of the required length
+ //
+ for (;;)
+ {
+ // Generate q, prime and (q-1) relatively prime to e,
+ // and not equal to p
+ //
+ for (;;)
+ {
+ q = new BigInteger(qbitlength, 1, param.Random);
+
+ if (q.Subtract(p).Abs().BitLength < mindiffbits)
+ continue;
+
+ if (q.Mod(e).Equals(BigInteger.One))
+ continue;
+
+ if (!q.IsProbablePrime(param.Certainty))
+ continue;
+
+ if (e.Gcd(q.Subtract(BigInteger.One)).Equals(BigInteger.One))
+ break;
+ }
+
+ //
+ // calculate the modulus
+ //
+ n = p.Multiply(q);
+
+ if (n.BitLength == param.Strength)
+ break;
+
+ //
+ // if we Get here our primes aren't big enough, make the largest
+ // of the two p and try again
+ //
+ p = p.Max(q);
+ }
+
+ if (p.CompareTo(q) < 0)
+ {
+ phi = p;
+ p = q;
+ q = phi;
+ }
+
+ pSub1 = p.Subtract(BigInteger.One);
+ qSub1 = q.Subtract(BigInteger.One);
+ phi = pSub1.Multiply(qSub1);
+
+ //
+ // calculate the private exponent
+ //
+ d = e.ModInverse(phi);
+
+ //
+ // calculate the CRT factors
+ //
+ BigInteger dP, dQ, qInv;
+
+ dP = d.Remainder(pSub1);
+ dQ = d.Remainder(qSub1);
+ qInv = q.ModInverse(p);
+
+ return new AsymmetricCipherKeyPair(
+ new RsaKeyParameters(false, n, e),
+ new RsaPrivateCrtKeyParameters(n, e, d, p, q, dP, dQ, qInv));
+ }
+ }
+
+}
diff --git a/Crypto/src/crypto/generators/SCrypt.cs b/Crypto/src/crypto/generators/SCrypt.cs
new file mode 100644
index 000000000..efa74d735
--- /dev/null
+++ b/Crypto/src/crypto/generators/SCrypt.cs
@@ -0,0 +1,140 @@
+using System;
+using System.Threading;
+
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ public class SCrypt
+ {
+ // TODO Validate arguments
+ public static byte[] Generate(byte[] P, byte[] S, int N, int r, int p, int dkLen)
+ {
+ return MFcrypt(P, S, N, r, p, dkLen);
+ }
+
+ private static byte[] MFcrypt(byte[] P, byte[] S, int N, int r, int p, int dkLen)
+ {
+ int MFLenBytes = r * 128;
+ byte[] bytes = SingleIterationPBKDF2(P, S, p * MFLenBytes);
+
+ uint[] B = null;
+
+ try
+ {
+ int BLen = bytes.Length >> 2;
+ B = new uint[BLen];
+
+ Pack.LE_To_UInt32(bytes, 0, B);
+
+ int MFLenWords = MFLenBytes >> 2;
+ for (int BOff = 0; BOff < BLen; BOff += MFLenWords)
+ {
+ // TODO These can be done in parallel threads
+ SMix(B, BOff, N, r);
+ }
+
+ Pack.UInt32_To_LE(B, bytes, 0);
+
+ return SingleIterationPBKDF2(P, bytes, dkLen);
+ }
+ finally
+ {
+ ClearAll(bytes, B);
+ }
+ }
+
+ private static byte[] SingleIterationPBKDF2(byte[] P, byte[] S, int dkLen)
+ {
+ PbeParametersGenerator pGen = new Pkcs5S2ParametersGenerator(new Sha256Digest());
+ pGen.Init(P, S, 1);
+ KeyParameter key = (KeyParameter)pGen.GenerateDerivedMacParameters(dkLen * 8);
+ return key.GetKey();
+ }
+
+ private static void SMix(uint[] B, int BOff, int N, int r)
+ {
+ int BCount = r * 32;
+
+ uint[] blockX1 = new uint[16];
+ uint[] blockX2 = new uint[16];
+ uint[] blockY = new uint[BCount];
+
+ uint[] X = new uint[BCount];
+ uint[][] V = new uint[N][];
+
+ try
+ {
+ Array.Copy(B, BOff, X, 0, BCount);
+
+ for (int i = 0; i < N; ++i)
+ {
+ V[i] = (uint[])X.Clone();
+ BlockMix(X, blockX1, blockX2, blockY, r);
+ }
+
+ uint mask = (uint)N - 1;
+ for (int i = 0; i < N; ++i)
+ {
+ uint j = X[BCount - 16] & mask;
+ Xor(X, V[j], 0, X);
+ BlockMix(X, blockX1, blockX2, blockY, r);
+ }
+
+ Array.Copy(X, 0, B, BOff, BCount);
+ }
+ finally
+ {
+ ClearAll(V);
+ ClearAll(X, blockX1, blockX2, blockY);
+ }
+ }
+
+ private static void BlockMix(uint[] B, uint[] X1, uint[] X2, uint[] Y, int r)
+ {
+ Array.Copy(B, B.Length - 16, X1, 0, 16);
+
+ int BOff = 0, YOff = 0, halfLen = B.Length >> 1;
+
+ for (int i = 2 * r; i > 0; --i)
+ {
+ Xor(X1, B, BOff, X2);
+
+ Salsa20Engine.SalsaCore(8, X2, X1);
+ Array.Copy(X1, 0, Y, YOff, 16);
+
+ YOff = halfLen + BOff - YOff;
+ BOff += 16;
+ }
+
+ Array.Copy(Y, 0, B, 0, Y.Length);
+ }
+
+ private static void Xor(uint[] a, uint[] b, int bOff, uint[] output)
+ {
+ for (int i = output.Length - 1; i >= 0; --i)
+ {
+ output[i] = a[i] ^ b[bOff + i];
+ }
+ }
+
+ private static void Clear(Array array)
+ {
+ if (array != null)
+ {
+ Array.Clear(array, 0, array.Length);
+ }
+ }
+
+ private static void ClearAll(params Array[] arrays)
+ {
+ foreach (Array array in arrays)
+ {
+ Clear(array);
+ }
+ }
+ }
+}
|