2 // RSAManaged.cs - Implements the RSA algorithm.
5 // Sebastien Pouliot (sebastien@ximian.com)
6 // Ben Maurer (bmaurer@users.sf.net)
8 // (C) 2002, 2003 Motus Technologies Inc. (http://www.motus.com)
9 // Portions (C) 2003 Ben Maurer
10 // (C) 2004 Novell (http://www.novell.com)
12 // Key generation translated from Bouncy Castle JCE (http://www.bouncycastle.org/)
13 // See bouncycastle.txt for license.
17 using System.Security.Cryptography;
21 // Big chunks of code are coming from the original RSACryptoServiceProvider class.
22 // The class was refactored to :
23 // a. ease integration of new hash algorithm (like MD2, RIPEMD160, ...);
24 // b. provide better support for the coming SSL implementation (requires
25 // EncryptValue/DecryptValue) with, or without, Mono runtime/corlib;
26 // c. provide an alternative RSA implementation for all Windows (like using
27 // OAEP without Windows XP).
29 namespace Mono.Security.Cryptography {
36 class RSAManaged : RSA {
38 private const int defaultKeySize = 1024;
40 private bool isCRTpossible = false;
41 private bool keypairGenerated = false;
42 private bool m_disposed = false;
47 private BigInteger dp;
48 private BigInteger dq;
49 private BigInteger qInv;
50 private BigInteger n; // modulus
53 public RSAManaged () : this (defaultKeySize) {}
55 public RSAManaged (int dwKeySize)
57 KeySizeValue = dwKeySize;
58 LegalKeySizesValue = new KeySizes [1];
59 LegalKeySizesValue [0] = new KeySizes (384, 16384, 8);
64 // Zeroize private key
68 private void GenerateKeyPair ()
70 // p and q values should have a length of half the strength in bits
71 int pbitlength = ((KeySize + 1) >> 1);
72 int qbitlength = (KeySize - pbitlength);
73 const uint uint_e = 17;
76 // generate p, prime and (p-1) relatively prime to e
78 p = BigInteger.genPseudoPrime (pbitlength);
82 // generate a modulus of the required length
84 // generate q, prime and (q-1) relatively prime to e,
87 q = BigInteger.genPseudoPrime (qbitlength);
88 if ((q % uint_e != 1) && (p != q))
92 // calculate the modulus
94 if (n.bitCount () == KeySize)
97 // if we get here our primes aren't big enough, make the largest
98 // of the two p and try again
103 BigInteger pSub1 = (p - 1);
104 BigInteger qSub1 = (q - 1);
105 BigInteger phi = pSub1 * qSub1;
107 // calculate the private exponent
108 d = e.modInverse (phi);
110 // calculate the CRT factors
113 qInv = q.modInverse (p);
115 keypairGenerated = true;
116 isCRTpossible = true;
118 if (KeyGenerated != null)
122 // overrides from RSA class
124 public override int KeySize {
126 // in case keypair hasn't been (yet) generated
127 if (keypairGenerated)
128 return n.bitCount ();
133 public override string KeyExchangeAlgorithm {
134 get { return "RSA-PKCS1-KeyEx"; }
137 // note: this property will exist in RSACryptoServiceProvider in
138 // version 1.2 of the framework
139 public bool PublicOnly {
140 get { return ((d == null) || (n == null)); }
143 public override string SignatureAlgorithm {
144 get { return "http://www.w3.org/2000/09/xmldsig#rsa-sha1"; }
147 public override byte[] DecryptValue (byte[] rgb)
150 throw new ObjectDisposedException ("private key");
152 // decrypt operation is used for signature
153 if (!keypairGenerated)
156 BigInteger input = new BigInteger (rgb);
158 // decrypt (which uses the private key) can be
159 // optimized by using CRT (Chinese Remainder Theorem)
162 BigInteger m1 = input.modPow (dp, p);
164 BigInteger m2 = input.modPow (dq, q);
168 h = p - ((m2 - m1) * qInv % p);
172 // h = (m1 - m2) * qInv mod p
173 h = (m1 - m2) * qInv % p;
180 output = input.modPow (d, n);
182 byte[] result = output.getBytes ();
189 public override byte[] EncryptValue (byte[] rgb)
192 throw new ObjectDisposedException ("public key");
194 if (!keypairGenerated)
197 BigInteger input = new BigInteger (rgb);
198 BigInteger output = input.modPow (e, n);
199 byte[] result = output.getBytes ();
206 public override RSAParameters ExportParameters (bool includePrivateParameters)
209 throw new ObjectDisposedException ("");
211 if (!keypairGenerated)
214 RSAParameters param = new RSAParameters ();
215 param.Exponent = e.getBytes ();
216 param.Modulus = n.getBytes ();
217 if (includePrivateParameters) {
218 // some parameters are required for exporting the private key
219 if ((d == null) || (p == null) || (q == null))
220 throw new CryptographicException ("Missing private key");
221 param.D = d.getBytes ();
222 param.P = p.getBytes ();
223 param.Q = q.getBytes ();
224 // but CRT parameters are optionals
225 if ((dp != null) && (dq != null) && (qInv != null)) {
226 // and we include them only if we have them all
227 param.DP = dp.getBytes ();
228 param.DQ = dq.getBytes ();
229 param.InverseQ = qInv.getBytes ();
235 public override void ImportParameters (RSAParameters parameters)
238 throw new ObjectDisposedException ("");
240 // if missing "mandatory" parameters
241 if (parameters.Exponent == null)
242 throw new CryptographicException ("Missing Exponent");
243 if (parameters.Modulus == null)
244 throw new CryptographicException ("Missing Modulus");
246 e = new BigInteger (parameters.Exponent);
247 n = new BigInteger (parameters.Modulus);
248 // only if the private key is present
249 if (parameters.D != null)
250 d = new BigInteger (parameters.D);
251 if (parameters.DP != null)
252 dp = new BigInteger (parameters.DP);
253 if (parameters.DQ != null)
254 dq = new BigInteger (parameters.DQ);
255 if (parameters.InverseQ != null)
256 qInv = new BigInteger (parameters.InverseQ);
257 if (parameters.P != null)
258 p = new BigInteger (parameters.P);
259 if (parameters.Q != null)
260 q = new BigInteger (parameters.Q);
262 // we now have a keypair
263 keypairGenerated = true;
264 isCRTpossible = ((p != null) && (q != null) && (dp != null) && (dq != null) && (qInv != null));
267 protected override void Dispose (bool disposing)
270 // Always zeroize private key
309 // no need as they all are abstract before us
313 public delegate void KeyGeneratedEventHandler (object sender);
315 public event KeyGeneratedEventHandler KeyGenerated;