**** Merged from MCS ****
[mono-project.git] / mcs / class / corlib / Mono.Security.Cryptography / RSAManaged.cs
blob82b16f6b291ec3ac5983b6f196be95545548c3ea
1 //
2 // RSAManaged.cs - Implements the RSA algorithm.
3 //
4 // Authors:
5 // Sebastien Pouliot (sebastien@ximian.com)
6 // Ben Maurer (bmaurer@users.sf.net)
7 //
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 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
19 // Permission is hereby granted, free of charge, to any person obtaining
20 // a copy of this software and associated documentation files (the
21 // "Software"), to deal in the Software without restriction, including
22 // without limitation the rights to use, copy, modify, merge, publish,
23 // distribute, sublicense, and/or sell copies of the Software, and to
24 // permit persons to whom the Software is furnished to do so, subject to
25 // the following conditions:
26 //
27 // The above copyright notice and this permission notice shall be
28 // included in all copies or substantial portions of the Software.
29 //
30 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
31 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
32 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
33 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
34 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
35 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
36 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
39 using System;
40 using System.Security.Cryptography;
42 using Mono.Math;
44 // Big chunks of code are coming from the original RSACryptoServiceProvider class.
45 // The class was refactored to :
46 // a. ease integration of new hash algorithm (like MD2, RIPEMD160, ...);
47 // b. provide better support for the coming SSL implementation (requires
48 // EncryptValue/DecryptValue) with, or without, Mono runtime/corlib;
49 // c. provide an alternative RSA implementation for all Windows (like using
50 // OAEP without Windows XP).
52 namespace Mono.Security.Cryptography {
54 #if INSIDE_CORLIB
55 internal
56 #else
57 public
58 #endif
59 class RSAManaged : RSA {
61 private const int defaultKeySize = 1024;
63 private bool isCRTpossible = false;
64 private bool keypairGenerated = false;
65 private bool m_disposed = false;
67 private BigInteger d;
68 private BigInteger p;
69 private BigInteger q;
70 private BigInteger dp;
71 private BigInteger dq;
72 private BigInteger qInv;
73 private BigInteger n; // modulus
74 private BigInteger e;
76 public RSAManaged () : this (defaultKeySize)
80 public RSAManaged (int keySize)
82 KeySizeValue = keySize;
83 LegalKeySizesValue = new KeySizes [1];
84 LegalKeySizesValue [0] = new KeySizes (384, 16384, 8);
87 ~RSAManaged ()
89 // Zeroize private key
90 Dispose (false);
93 private void GenerateKeyPair ()
95 // p and q values should have a length of half the strength in bits
96 int pbitlength = ((KeySize + 1) >> 1);
97 int qbitlength = (KeySize - pbitlength);
98 const uint uint_e = 17;
99 e = uint_e; // fixed
101 // generate p, prime and (p-1) relatively prime to e
102 for (;;) {
103 p = BigInteger.GeneratePseudoPrime (pbitlength);
104 if (p % uint_e != 1)
105 break;
107 // generate a modulus of the required length
108 for (;;) {
109 // generate q, prime and (q-1) relatively prime to e,
110 // and not equal to p
111 for (;;) {
112 q = BigInteger.GeneratePseudoPrime (qbitlength);
113 if ((q % uint_e != 1) && (p != q))
114 break;
117 // calculate the modulus
118 n = p * q;
119 if (n.BitCount () == KeySize)
120 break;
122 // if we get here our primes aren't big enough, make the largest
123 // of the two p and try again
124 if (p < q)
125 p = q;
128 BigInteger pSub1 = (p - 1);
129 BigInteger qSub1 = (q - 1);
130 BigInteger phi = pSub1 * qSub1;
132 // calculate the private exponent
133 d = e.ModInverse (phi);
135 // calculate the CRT factors
136 dp = d % pSub1;
137 dq = d % qSub1;
138 qInv = q.ModInverse (p);
140 keypairGenerated = true;
141 isCRTpossible = true;
143 if (KeyGenerated != null)
144 KeyGenerated (this, null);
147 // overrides from RSA class
149 public override int KeySize {
150 get {
151 // in case keypair hasn't been (yet) generated
152 if (keypairGenerated) {
153 int ks = n.BitCount ();
154 if ((ks & 7) != 0)
155 ks = ks + (8 - (ks & 7));
156 return ks;
158 else
159 return base.KeySize;
162 public override string KeyExchangeAlgorithm {
163 get { return "RSA-PKCS1-KeyEx"; }
166 // note: this property will exist in RSACryptoServiceProvider in
167 // version 1.2 of the framework
168 public bool PublicOnly {
169 get { return ((d == null) || (n == null)); }
172 public override string SignatureAlgorithm {
173 get { return "http://www.w3.org/2000/09/xmldsig#rsa-sha1"; }
176 public override byte[] DecryptValue (byte[] rgb)
178 if (m_disposed)
179 throw new ObjectDisposedException ("private key");
181 // decrypt operation is used for signature
182 if (!keypairGenerated)
183 GenerateKeyPair ();
185 BigInteger input = new BigInteger (rgb);
186 BigInteger output;
187 // decrypt (which uses the private key) can be
188 // optimized by using CRT (Chinese Remainder Theorem)
189 if (isCRTpossible) {
190 // m1 = c^dp mod p
191 BigInteger m1 = input.ModPow (dp, p);
192 // m2 = c^dq mod q
193 BigInteger m2 = input.ModPow (dq, q);
194 BigInteger h;
195 if (m2 > m1) {
196 // thanks to benm!
197 h = p - ((m2 - m1) * qInv % p);
198 output = m2 + q * h;
200 else {
201 // h = (m1 - m2) * qInv mod p
202 h = (m1 - m2) * qInv % p;
203 // m = m2 + q * h;
204 output = m2 + q * h;
207 else {
208 // m = c^d mod n
209 output = input.ModPow (d, n);
211 byte[] result = output.GetBytes ();
212 // zeroize value
213 input.Clear ();
214 output.Clear ();
215 return result;
218 public override byte[] EncryptValue (byte[] rgb)
220 if (m_disposed)
221 throw new ObjectDisposedException ("public key");
223 if (!keypairGenerated)
224 GenerateKeyPair ();
226 BigInteger input = new BigInteger (rgb);
227 BigInteger output = input.ModPow (e, n);
228 byte[] result = output.GetBytes ();
229 // zeroize value
230 input.Clear ();
231 output.Clear ();
232 return result;
235 public override RSAParameters ExportParameters (bool includePrivateParameters)
237 if (m_disposed)
238 throw new ObjectDisposedException ("");
240 if (!keypairGenerated)
241 GenerateKeyPair ();
243 RSAParameters param = new RSAParameters ();
244 param.Exponent = e.GetBytes ();
245 param.Modulus = n.GetBytes ();
246 if (includePrivateParameters) {
247 // some parameters are required for exporting the private key
248 if ((d == null) || (p == null) || (q == null))
249 throw new CryptographicException ("Missing private key");
250 param.D = d.GetBytes ();
251 // hack for bugzilla #57941 where D wasn't provided
252 if (param.D.Length != param.Modulus.Length) {
253 byte[] normalizedD = new byte [param.Modulus.Length];
254 Buffer.BlockCopy (param.D, 0, normalizedD, (normalizedD.Length - param.D.Length), param.D.Length);
255 param.D = normalizedD;
257 param.P = p.GetBytes ();
258 param.Q = q.GetBytes ();
259 // but CRT parameters are optionals
260 if ((dp != null) && (dq != null) && (qInv != null)) {
261 // and we include them only if we have them all
262 param.DP = dp.GetBytes ();
263 param.DQ = dq.GetBytes ();
264 param.InverseQ = qInv.GetBytes ();
267 return param;
270 public override void ImportParameters (RSAParameters parameters)
272 if (m_disposed)
273 throw new ObjectDisposedException ("");
275 // if missing "mandatory" parameters
276 if (parameters.Exponent == null)
277 throw new CryptographicException ("Missing Exponent");
278 if (parameters.Modulus == null)
279 throw new CryptographicException ("Missing Modulus");
281 e = new BigInteger (parameters.Exponent);
282 n = new BigInteger (parameters.Modulus);
283 // only if the private key is present
284 if (parameters.D != null)
285 d = new BigInteger (parameters.D);
286 if (parameters.DP != null)
287 dp = new BigInteger (parameters.DP);
288 if (parameters.DQ != null)
289 dq = new BigInteger (parameters.DQ);
290 if (parameters.InverseQ != null)
291 qInv = new BigInteger (parameters.InverseQ);
292 if (parameters.P != null)
293 p = new BigInteger (parameters.P);
294 if (parameters.Q != null)
295 q = new BigInteger (parameters.Q);
297 // we now have a keypair
298 keypairGenerated = true;
299 isCRTpossible = ((p != null) && (q != null) && (dp != null) && (dq != null) && (qInv != null));
302 protected override void Dispose (bool disposing)
304 if (!m_disposed) {
305 // Always zeroize private key
306 if (d != null) {
307 d.Clear ();
308 d = null;
310 if (p != null) {
311 p.Clear ();
312 p = null;
314 if (q != null) {
315 q.Clear ();
316 q = null;
318 if (dp != null) {
319 dp.Clear ();
320 dp = null;
322 if (dq != null) {
323 dq.Clear ();
324 dq = null;
326 if (qInv != null) {
327 qInv.Clear ();
328 qInv = null;
331 if (disposing) {
332 // clear public key
333 if (e != null) {
334 e.Clear ();
335 e = null;
337 if (n != null) {
338 n.Clear ();
339 n = null;
343 // call base class
344 // no need as they all are abstract before us
345 m_disposed = true;
348 public delegate void KeyGeneratedEventHandler (object sender, EventArgs e);
350 public event KeyGeneratedEventHandler KeyGenerated;