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)
57 public RSAManaged (int keySize)
59 KeySizeValue = keySize;
60 LegalKeySizesValue = new KeySizes [1];
61 LegalKeySizesValue [0] = new KeySizes (384, 16384, 8);
66 // Zeroize private key
70 private void GenerateKeyPair ()
72 // p and q values should have a length of half the strength in bits
73 int pbitlength = ((KeySize + 1) >> 1);
74 int qbitlength = (KeySize - pbitlength);
75 const uint uint_e = 17;
78 // generate p, prime and (p-1) relatively prime to e
80 p = BigInteger.GeneratePseudoPrime (pbitlength);
84 // generate a modulus of the required length
86 // generate q, prime and (q-1) relatively prime to e,
89 q = BigInteger.GeneratePseudoPrime (qbitlength);
90 if ((q % uint_e != 1) && (p != q))
94 // calculate the modulus
96 if (n.BitCount () == KeySize)
99 // if we get here our primes aren't big enough, make the largest
100 // of the two p and try again
105 BigInteger pSub1 = (p - 1);
106 BigInteger qSub1 = (q - 1);
107 BigInteger phi = pSub1 * qSub1;
109 // calculate the private exponent
110 d = e.ModInverse (phi);
112 // calculate the CRT factors
115 qInv = q.ModInverse (p);
117 keypairGenerated = true;
118 isCRTpossible = true;
120 if (KeyGenerated != null)
121 KeyGenerated (this, null);
124 // overrides from RSA class
126 public override int KeySize {
128 // in case keypair hasn't been (yet) generated
129 if (keypairGenerated)
130 return n.BitCount ();
135 public override string KeyExchangeAlgorithm {
136 get { return "RSA-PKCS1-KeyEx"; }
139 // note: this property will exist in RSACryptoServiceProvider in
140 // version 1.2 of the framework
141 public bool PublicOnly {
142 get { return ((d == null) || (n == null)); }
145 public override string SignatureAlgorithm {
146 get { return "http://www.w3.org/2000/09/xmldsig#rsa-sha1"; }
149 public override byte[] DecryptValue (byte[] rgb)
152 throw new ObjectDisposedException ("private key");
154 // decrypt operation is used for signature
155 if (!keypairGenerated)
158 BigInteger input = new BigInteger (rgb);
160 // decrypt (which uses the private key) can be
161 // optimized by using CRT (Chinese Remainder Theorem)
164 BigInteger m1 = input.ModPow (dp, p);
166 BigInteger m2 = input.ModPow (dq, q);
170 h = p - ((m2 - m1) * qInv % p);
174 // h = (m1 - m2) * qInv mod p
175 h = (m1 - m2) * qInv % p;
182 output = input.ModPow (d, n);
184 byte[] result = output.GetBytes ();
191 public override byte[] EncryptValue (byte[] rgb)
194 throw new ObjectDisposedException ("public key");
196 if (!keypairGenerated)
199 BigInteger input = new BigInteger (rgb);
200 BigInteger output = input.ModPow (e, n);
201 byte[] result = output.GetBytes ();
208 public override RSAParameters ExportParameters (bool includePrivateParameters)
211 throw new ObjectDisposedException ("");
213 if (!keypairGenerated)
216 RSAParameters param = new RSAParameters ();
217 param.Exponent = e.GetBytes ();
218 param.Modulus = n.GetBytes ();
219 if (includePrivateParameters) {
220 // some parameters are required for exporting the private key
221 if ((d == null) || (p == null) || (q == null))
222 throw new CryptographicException ("Missing private key");
223 param.D = d.GetBytes ();
224 // hack for bugzilla #57941 where D wasn't provided
225 if (param.D.Length != param.Modulus.Length) {
226 byte[] normalizedD = new byte [param.Modulus.Length];
227 Buffer.BlockCopy (param.D, 0, normalizedD, (normalizedD.Length - param.D.Length), param.D.Length);
228 param.D = normalizedD;
230 param.P = p.GetBytes ();
231 param.Q = q.GetBytes ();
232 // but CRT parameters are optionals
233 if ((dp != null) && (dq != null) && (qInv != null)) {
234 // and we include them only if we have them all
235 param.DP = dp.GetBytes ();
236 param.DQ = dq.GetBytes ();
237 param.InverseQ = qInv.GetBytes ();
243 public override void ImportParameters (RSAParameters parameters)
246 throw new ObjectDisposedException ("");
248 // if missing "mandatory" parameters
249 if (parameters.Exponent == null)
250 throw new CryptographicException ("Missing Exponent");
251 if (parameters.Modulus == null)
252 throw new CryptographicException ("Missing Modulus");
254 e = new BigInteger (parameters.Exponent);
255 n = new BigInteger (parameters.Modulus);
256 // only if the private key is present
257 if (parameters.D != null)
258 d = new BigInteger (parameters.D);
259 if (parameters.DP != null)
260 dp = new BigInteger (parameters.DP);
261 if (parameters.DQ != null)
262 dq = new BigInteger (parameters.DQ);
263 if (parameters.InverseQ != null)
264 qInv = new BigInteger (parameters.InverseQ);
265 if (parameters.P != null)
266 p = new BigInteger (parameters.P);
267 if (parameters.Q != null)
268 q = new BigInteger (parameters.Q);
270 // we now have a keypair
271 keypairGenerated = true;
272 isCRTpossible = ((p != null) && (q != null) && (dp != null) && (dq != null) && (qInv != null));
275 protected override void Dispose (bool disposing)
278 // Always zeroize private key
317 // no need as they all are abstract before us
321 public delegate void KeyGeneratedEventHandler (object sender, EventArgs e);
323 public event KeyGeneratedEventHandler KeyGenerated;