summary refs log tree commit diff
path: root/Crypto/src/crypto/generators
diff options
context:
space:
mode:
Diffstat (limited to 'Crypto/src/crypto/generators')
-rw-r--r--Crypto/src/crypto/generators/BaseKdfBytesGenerator.cs141
-rw-r--r--Crypto/src/crypto/generators/DHBasicKeyPairGenerator.cs38
-rw-r--r--Crypto/src/crypto/generators/DHKeyGeneratorHelper.cs53
-rw-r--r--Crypto/src/crypto/generators/DHKeyPairGenerator.cs38
-rw-r--r--Crypto/src/crypto/generators/DHParametersGenerator.cs45
-rw-r--r--Crypto/src/crypto/generators/DHParametersHelper.cs234
-rw-r--r--Crypto/src/crypto/generators/DesEdeKeyGenerator.cs67
-rw-r--r--Crypto/src/crypto/generators/DesKeyGenerator.cs57
-rw-r--r--Crypto/src/crypto/generators/DsaKeyPairGenerator.cs61
-rw-r--r--Crypto/src/crypto/generators/DsaParametersGenerator.cs355
-rw-r--r--Crypto/src/crypto/generators/ECKeyPairGenerator.cs174
-rw-r--r--Crypto/src/crypto/generators/ElGamalKeyPairGenerator.cs40
-rw-r--r--Crypto/src/crypto/generators/ElGamalParametersGenerator.cs46
-rw-r--r--Crypto/src/crypto/generators/GOST3410KeyPairGenerator.cs73
-rw-r--r--Crypto/src/crypto/generators/GOST3410ParametersGenerator.cs530
-rw-r--r--Crypto/src/crypto/generators/Kdf1BytesGenerator.cs27
-rw-r--r--Crypto/src/crypto/generators/Kdf2BytesGenerator.cs28
-rw-r--r--Crypto/src/crypto/generators/Mgf1BytesGenerator.cs117
-rw-r--r--Crypto/src/crypto/generators/NaccacheSternKeyPairGenerator.cs333
-rw-r--r--Crypto/src/crypto/generators/OpenSSLPBEParametersGenerator.cs167
-rw-r--r--Crypto/src/crypto/generators/Pkcs12ParametersGenerator.cs245
-rw-r--r--Crypto/src/crypto/generators/Pkcs5S1ParametersGenerator.cs162
-rw-r--r--Crypto/src/crypto/generators/Pkcs5S2ParametersGenerator.cs172
-rw-r--r--Crypto/src/crypto/generators/RSABlindingFactorGenerator.cs69
-rw-r--r--Crypto/src/crypto/generators/RsaKeyPairGenerator.cs139
-rw-r--r--Crypto/src/crypto/generators/SCrypt.cs140
26 files changed, 3551 insertions, 0 deletions
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);
+			}
+		}
+	}
+}