X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fclass%2Fcorlib%2FMono.Security.Cryptography%2FRSAManaged.cs;h=29ee75a21ced7c9ee8d28fe8ce1b0a1fd1271057;hb=95dc3521c07b15316c0087fb5f088e65162077e4;hp=bc6b9fb045f4e5822028c41ff06b7b5647ebbe5d;hpb=d4b7a08a3a4ee0acdff92b44c370afb9afee42ed;p=mono.git diff --git a/mcs/class/corlib/Mono.Security.Cryptography/RSAManaged.cs b/mcs/class/corlib/Mono.Security.Cryptography/RSAManaged.cs index bc6b9fb045f..29ee75a21ce 100644 --- a/mcs/class/corlib/Mono.Security.Cryptography/RSAManaged.cs +++ b/mcs/class/corlib/Mono.Security.Cryptography/RSAManaged.cs @@ -7,7 +7,7 @@ // // (C) 2002, 2003 Motus Technologies Inc. (http://www.motus.com) // Portions (C) 2003 Ben Maurer -// Copyright (C) 2004 Novell, Inc (http://www.novell.com) +// Copyright (C) 2004,2006 Novell, Inc (http://www.novell.com) // // Key generation translated from Bouncy Castle JCE (http://www.bouncycastle.org/) // See bouncycastle.txt for license. @@ -161,10 +161,10 @@ namespace Mono.Security.Cryptography { get { return "RSA-PKCS1-KeyEx"; } } - // note: this property will exist in RSACryptoServiceProvider in - // version 2.0 of the framework + // note: when (if) we generate a keypair then it will have both + // the public and private keys public bool PublicOnly { - get { return ((d == null) || (n == null)); } + get { return (keypairGenerated && ((d == null) || (n == null))); } } public override string SignatureAlgorithm { @@ -210,9 +210,11 @@ namespace Mono.Security.Cryptography { // m = m2 + q * h; output = m2 + q * h; } - } else { + } else if (!PublicOnly) { // m = c^d mod n output = input.ModPow (d, n); + } else { + throw new CryptographicException (Locale.GetText ("Missing private key to decrypt value.")); } if (keyBlinding) { @@ -222,7 +224,9 @@ namespace Mono.Security.Cryptography { r.Clear (); } - byte[] result = output.GetBytes (); + // it's sometimes possible for the results to be a byte short + // and this can break some software (see #79502) so we 0x00 pad the result + byte[] result = GetPaddedValue (output, (KeySize >> 3)); // zeroize values input.Clear (); output.Clear (); @@ -239,17 +243,21 @@ namespace Mono.Security.Cryptography { BigInteger input = new BigInteger (rgb); BigInteger output = input.ModPow (e, n); - byte[] result = output.GetBytes (); + // it's sometimes possible for the results to be a byte short + // and this can break some software (see #79502) so we 0x00 pad the result + byte[] result = GetPaddedValue (output, (KeySize >> 3)); // zeroize value input.Clear (); output.Clear (); return result; } + + public override RSAParameters ExportParameters (bool includePrivateParameters) { if (m_disposed) - throw new ObjectDisposedException (""); + throw new ObjectDisposedException (Locale.GetText ("Keypair was disposed")); if (!keypairGenerated) GenerateKeyPair (); @@ -271,11 +279,12 @@ namespace Mono.Security.Cryptography { // but CRT parameters are optionals if ((p != null) && (q != null) && (dp != null) && (dq != null) && (qInv != null)) { // and we include them only if we have them all - param.P = p.GetBytes (); - param.Q = q.GetBytes (); - param.DP = dp.GetBytes (); - param.DQ = dq.GetBytes (); - param.InverseQ = qInv.GetBytes (); + int length = (KeySize >> 4); + param.P = GetPaddedValue (p, length); + param.Q = GetPaddedValue (q, length); + param.DP = GetPaddedValue (dp, length); + param.DQ = GetPaddedValue (dq, length); + param.InverseQ = GetPaddedValue (qInv, length); } } return param; @@ -284,13 +293,13 @@ namespace Mono.Security.Cryptography { public override void ImportParameters (RSAParameters parameters) { if (m_disposed) - throw new ObjectDisposedException (""); + throw new ObjectDisposedException (Locale.GetText ("Keypair was disposed")); // if missing "mandatory" parameters if (parameters.Exponent == null) - throw new CryptographicException ("Missing Exponent"); + throw new CryptographicException (Locale.GetText ("Missing Exponent")); if (parameters.Modulus == null) - throw new CryptographicException ("Missing Modulus"); + throw new CryptographicException (Locale.GetText ("Missing Modulus")); e = new BigInteger (parameters.Exponent); n = new BigInteger (parameters.Modulus); @@ -307,10 +316,44 @@ namespace Mono.Security.Cryptography { p = new BigInteger (parameters.P); if (parameters.Q != null) q = new BigInteger (parameters.Q); - + // we now have a keypair keypairGenerated = true; - isCRTpossible = ((p != null) && (q != null) && (dp != null) && (dq != null) && (qInv != null)); + bool privateKey = ((p != null) && (q != null) && (dp != null)); + isCRTpossible = (privateKey && (dq != null) && (qInv != null)); + + // check if the public/private keys match + // the way the check is made allows a bad D to work if CRT is available (like MS does, see unit tests) + if (!privateKey) + return; + + // always check n == p * q + bool ok = (n == (p * q)); + if (ok) { + // we now know that p and q are correct, so (p - 1), (q - 1) and phi will be ok too + BigInteger pSub1 = (p - 1); + BigInteger qSub1 = (q - 1); + BigInteger phi = pSub1 * qSub1; + // e is fairly static but anyway we can ensure it makes sense by recomputing d + BigInteger dcheck = e.ModInverse (phi); + + // now if our new d(check) is different than the d we're provided then we cannot + // be sure if 'd' or 'e' is invalid... (note that, from experience, 'd' is more + // likely to be invalid since it's twice as large as DP (or DQ) and sits at the + // end of the structure (e.g. truncation). + ok = (d == dcheck); + + // ... unless we have the pre-computed CRT parameters + if (!ok && isCRTpossible) { + // we can override the previous decision since Mono always prefer, for + // performance reasons, using the CRT algorithm + ok = (dp == (dcheck % pSub1)) && (dq == (dcheck % qSub1)) && + (qInv == q.ModInverse (p)); + } + } + + if (!ok) + throw new CryptographicException (Locale.GetText ("Private/public key mismatch")); } protected override void Dispose (bool disposing) @@ -455,5 +498,19 @@ namespace Mono.Security.Cryptography { // possible (in case the key was imported) get { return (!keypairGenerated || isCRTpossible); } } + + private byte[] GetPaddedValue (BigInteger value, int length) + { + byte[] result = value.GetBytes (); + if (result.Length >= length) + return result; + + // left-pad 0x00 value on the result (same integer, correct length) + byte[] padded = new byte[length]; + Buffer.BlockCopy (result, 0, padded, (length - result.Length), result.Length); + // temporary result may contain decrypted (plaintext) data, clear it + Array.Clear (result, 0, result.Length); + return padded; + } } }