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 // 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:
27 // The above copyright notice and this permission notice shall be
28 // included in all copies or substantial portions of the Software.
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.
40 using System
.Security
.Cryptography
;
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
{
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;
70 private BigInteger dp
;
71 private BigInteger dq
;
72 private BigInteger qInv
;
73 private BigInteger n
; // modulus
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);
89 // Zeroize private key
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;
101 // generate p, prime and (p-1) relatively prime to e
103 p
= BigInteger
.GeneratePseudoPrime (pbitlength
);
107 // generate a modulus of the required length
109 // generate q, prime and (q-1) relatively prime to e,
110 // and not equal to p
112 q
= BigInteger
.GeneratePseudoPrime (qbitlength
);
113 if ((q
% uint_e
!= 1) && (p
!= q
))
117 // calculate the modulus
119 if (n
.BitCount () == KeySize
)
122 // if we get here our primes aren't big enough, make the largest
123 // of the two p and try again
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
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
{
151 // in case keypair hasn't been (yet) generated
152 if (keypairGenerated
) {
153 int ks
= n
.BitCount ();
155 ks
= ks
+ (8 - (ks
& 7));
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
)
179 throw new ObjectDisposedException ("private key");
181 // decrypt operation is used for signature
182 if (!keypairGenerated
)
185 BigInteger input
= new BigInteger (rgb
);
187 // decrypt (which uses the private key) can be
188 // optimized by using CRT (Chinese Remainder Theorem)
191 BigInteger m1
= input
.ModPow (dp
, p
);
193 BigInteger m2
= input
.ModPow (dq
, q
);
197 h
= p
- ((m2
- m1
) * qInv
% p
);
201 // h = (m1 - m2) * qInv mod p
202 h
= (m1
- m2
) * qInv
% p
;
209 output
= input
.ModPow (d
, n
);
211 byte[] result
= output
.GetBytes ();
218 public override byte[] EncryptValue (byte[] rgb
)
221 throw new ObjectDisposedException ("public key");
223 if (!keypairGenerated
)
226 BigInteger input
= new BigInteger (rgb
);
227 BigInteger output
= input
.ModPow (e
, n
);
228 byte[] result
= output
.GetBytes ();
235 public override RSAParameters
ExportParameters (bool includePrivateParameters
)
238 throw new ObjectDisposedException ("");
240 if (!keypairGenerated
)
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 ();
270 public override void ImportParameters (RSAParameters parameters
)
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
)
305 // Always zeroize private key
344 // no need as they all are abstract before us
348 public delegate void KeyGeneratedEventHandler (object sender
, EventArgs e
);
350 public event KeyGeneratedEventHandler KeyGenerated
;