// Apply the private key to a value. private byte[] ApplyPrivate(byte[] value) { if (rsaParams.P != null) { // Use the Chinese Remainder Theorem exponents. // Based on the description in PKCS #1. byte[] m1 = CryptoMethods.NumPow(value, rsaParams.DP, rsaParams.P); byte[] m2 = CryptoMethods.NumPow(value, rsaParams.DQ, rsaParams.Q); byte[] diff = CryptoMethods.NumSub(m1, m2, null); byte[] h = CryptoMethods.NumMul(diff, rsaParams.InverseQ, rsaParams.P); byte[] prod = CryptoMethods.NumMul(rsaParams.Q, h, null); byte[] m = CryptoMethods.NumAdd(m2, prod, null); // Clear all temporary values. Array.Clear(m1, 0, m1.Length); Array.Clear(m2, 0, m2.Length); Array.Clear(diff, 0, diff.Length); Array.Clear(h, 0, h.Length); Array.Clear(prod, 0, prod.Length); // Return the decrypted message. return(m); } else if (rsaParams.D != null) { // Use the private exponent directly. return(CryptoMethods.NumPow(value, rsaParams.D, rsaParams.Modulus)); } else { // Insufficient parameters for private key operations. throw new CryptographicException (_("Crypto_RSAParamsNotSet")); } }
// Verify a DSA signature. public override bool VerifySignature(byte[] rgbHash, byte[] rgbSignature) { // Validate the parameters. if (rgbHash == null) { throw new ArgumentNullException("rgbHash"); } if (rgbSignature == null) { throw new ArgumentNullException("rgbSignature"); } // Make sure that we have sufficient parameters to verify. if (dsaParams.G == null) { throw new CryptographicException (_("Crypto_DSAParamsNotSet")); } // Unpack the signature blob to get R and S. ASN1Parser parser; parser = (new ASN1Parser(rgbSignature)).GetSequence(); byte[] R = parser.GetBigInt(); byte[] S = parser.GetBigInt(); parser.AtEnd(); // Compute W = (S^-1 mod Q) byte[] W = CryptoMethods.NumInv(S, dsaParams.Q); // Compute U1 = ((hash * W) mod Q) byte[] U1 = CryptoMethods.NumMul(rgbHash, W, dsaParams.Q); // Compute U2 = ((R * W) mod Q) byte[] U2 = CryptoMethods.NumMul(R, W, dsaParams.Q); // Compute V = (((G^U1 * Y^U2) mod P) mod Q) byte[] temp1 = CryptoMethods.NumPow (dsaParams.G, U1, dsaParams.P); byte[] temp2 = CryptoMethods.NumPow (dsaParams.Y, U2, dsaParams.P); byte[] temp3 = CryptoMethods.NumMul(temp1, temp2, dsaParams.P); byte[] V = CryptoMethods.NumMod(temp3, dsaParams.Q); // Determine if we have a signature match. bool result = CryptoMethods.NumEq(V, R); // Clear sensitive values. Array.Clear(R, 0, R.Length); Array.Clear(S, 0, S.Length); Array.Clear(W, 0, W.Length); Array.Clear(U1, 0, U1.Length); Array.Clear(U2, 0, U2.Length); Array.Clear(temp1, 0, temp1.Length); Array.Clear(temp2, 0, temp2.Length); Array.Clear(temp3, 0, temp3.Length); Array.Clear(V, 0, V.Length); // Done. return(result); }
// Create a DSA signature for the specified data. public override byte[] CreateSignature(byte[] rgbHash) { // Validate the parameter. if (rgbHash == null) { throw new ArgumentNullException("rgbHash"); } // Check that we have sufficient DSA parameters to sign. if (dsaParams.G == null) { throw new CryptographicException (_("Crypto_DSAParamsNotSet")); } else if (dsaParams.X == null) { throw new CryptographicException (_("Crypto_CannotSignWithPublic")); } // Generate a random K less than Q to use in // signature generation. We guarantee less than // by setting the high byte of K to at least one // less than the high byte of Q. int len = dsaParams.Q.Length; byte[] K = new byte [len]; CryptoMethods.GenerateRandom(K, 1, K.Length - 1); int index = 0; while (index < len && K[index] >= dsaParams.Q[index]) { if (dsaParams.Q[index] == 0) { K[index] = (byte)0; ++index; } else { K[index] = (byte)(dsaParams.Q[index] - 1); break; } } // Compute R = ((G^K mod P) mod Q) byte[] temp1 = CryptoMethods.NumPow (dsaParams.G, K, dsaParams.P); byte[] R = CryptoMethods.NumMod(temp1, dsaParams.Q); Array.Clear(temp1, 0, temp1.Length); // Compute S = ((K^-1 * (hash + X * R)) mod Q) temp1 = CryptoMethods.NumInv(K, dsaParams.Q); byte[] temp2 = CryptoMethods.NumMul (dsaParams.X, R, dsaParams.Q); byte[] temp3 = CryptoMethods.NumAdd (rgbHash, temp2, dsaParams.Q); byte[] S = CryptoMethods.NumMul(temp1, temp3, dsaParams.Q); Array.Clear(temp1, 0, temp1.Length); Array.Clear(temp2, 0, temp2.Length); Array.Clear(temp3, 0, temp3.Length); Array.Clear(K, 0, K.Length); // Pack R and S into a signature blob and return it. ASN1Builder builder = new ASN1Builder(); builder.AddBigInt(R); builder.AddBigInt(S); byte[] sig = builder.ToByteArray(); Array.Clear(R, 0, R.Length); Array.Clear(S, 0, S.Length); return(sig); }