if (offset >= blob.Length)
throw new ArgumentException ("blob is too small.");
+ RSAParameters rsap = new RSAParameters ();
try {
if ((blob [offset] != 0x07) || // PRIVATEKEYBLOB (0x07)
(blob [offset+1] != 0x02) || // Version (0x02)
int bitLen = ToInt32LE (blob, offset+12);
// DWORD public exponent
- RSAParameters rsap = new RSAParameters ();
byte[] exp = new byte [4];
Buffer.BlockCopy (blob, offset+16, exp, 0, 4);
Array.Reverse (exp);
Buffer.BlockCopy (blob, pos, rsap.D, 0, byteLen);
Array.Reverse (rsap.D);
}
+ }
+ catch (Exception e) {
+ throw new CryptographicException ("Invalid blob.", e);
+ }
- RSA rsa = null;
+ RSA rsa = null;
+ try {
+ rsa = RSA.Create ();
+ rsa.ImportParameters (rsap);
+ }
+ catch (CryptographicException ce) {
+ // this may cause problem when this code is run under
+ // the SYSTEM identity on Windows (e.g. ASP.NET). See
+ // http://bugzilla.ximian.com/show_bug.cgi?id=77559
try {
- rsa = RSA.Create ();
- rsa.ImportParameters (rsap);
- }
- catch (CryptographicException) {
- // this may cause problem when this code is run under
- // the SYSTEM identity on Windows (e.g. ASP.NET). See
- // http://bugzilla.ximian.com/show_bug.cgi?id=77559
CspParameters csp = new CspParameters ();
csp.Flags = CspProviderFlags.UseMachineKeyStore;
rsa = new RSACryptoServiceProvider (csp);
rsa.ImportParameters (rsap);
}
- return rsa;
- }
- catch (Exception e) {
- throw new CryptographicException ("Invalid blob.", e);
+ catch {
+ // rethrow original, not the later, exception if this fails
+ throw ce;
+ }
}
+ return rsa;
}
static public DSA FromCapiPrivateKeyBlobDSA (byte[] blob)
if (offset >= blob.Length)
throw new ArgumentException ("blob is too small.");
+ DSAParameters dsap = new DSAParameters ();
try {
if ((blob [offset] != 0x07) || // PRIVATEKEYBLOB (0x07)
(blob [offset + 1] != 0x02) || // Version (0x02)
throw new CryptographicException ("Invalid blob header");
int bitlen = ToInt32LE (blob, offset + 12);
- DSAParameters dsap = new DSAParameters ();
int bytelen = bitlen >> 3;
int pos = offset + 16;
Buffer.BlockCopy (blob, pos, dsap.Seed, 0, 20);
Array.Reverse (dsap.Seed);
pos += 20;
-
- DSA dsa = (DSA)DSA.Create ();
- dsa.ImportParameters (dsap);
- return dsa;
}
catch (Exception e) {
throw new CryptographicException ("Invalid blob.", e);
}
+
+ DSA dsa = null;
+ try {
+ dsa = (DSA)DSA.Create ();
+ dsa.ImportParameters (dsap);
+ }
+ catch (CryptographicException ce) {
+ // this may cause problem when this code is run under
+ // the SYSTEM identity on Windows (e.g. ASP.NET). See
+ // http://bugzilla.ximian.com/show_bug.cgi?id=77559
+ try {
+ CspParameters csp = new CspParameters ();
+ csp.Flags = CspProviderFlags.UseMachineKeyStore;
+ dsa = new DSACryptoServiceProvider (csp);
+ dsa.ImportParameters (dsap);
+ }
+ catch {
+ // rethrow original, not the later, exception if this fails
+ throw ce;
+ }
+ }
+ return dsa;
}
static public byte[] ToCapiPrivateKeyBlob (RSA rsa)
// 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);
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)