public static void DoPrivate(RSAPrivateKey sk, byte[] x, int off, int len) { /* * Check that the source array has the proper length * (identical to the length of the modulus). */ if (len != sk.N.Length) { throw new CryptoException( "Invalid source length for RSA private"); } /* * Reduce the source value to the proper range. */ ModInt mx = new ModInt(sk.N); mx.DecodeReduce(x, off, len); /* * Compute m1 = x^dp mod p. */ ModInt m1 = new ModInt(sk.P); m1.Set(mx); m1.Pow(sk.DP); /* * Compute m2 = x^dq mod q. */ ModInt m2 = new ModInt(sk.Q); m2.Set(mx); m2.Pow(sk.DQ); /* * Compute h = (m1 - m2) / q mod p. * (Result goes in m1.) */ ModInt m3 = m1.Dup(); m3.Set(m2); m1.Sub(m3); m3.Decode(sk.IQ); m1.ToMonty(); m1.MontyMul(m3); /* * Compute m_2 + q*h. This works on plain integers, but * we have efficient and constant-time code for modular * integers, so we will do it modulo n. */ m3 = mx; m3.Set(m1); m1 = m3.Dup(); m1.Decode(sk.Q); m1.ToMonty(); m3.MontyMul(m1); m1.Set(m2); m3.Add(m1); /* * Write result back in x[]. */ m3.Encode(x, off, len); }
public static bool VerifyRaw(ECPublicKey pk, byte[] hash, int hashOff, int hashLen, byte[] sig, int sigOff, int sigLen) { try { /* * Get the curve. */ ECCurve curve = pk.Curve; /* * Get r and s from signature. This also verifies * that they do not exceed the subgroup order. */ if (sigLen == 0 || (sigLen & 1) != 0) { return(false); } int tlen = sigLen >> 1; ModInt oneQ = new ModInt(curve.SubgroupOrder); oneQ.Set(1); ModInt r = oneQ.Dup(); ModInt s = oneQ.Dup(); r.Decode(sig, sigOff, tlen); s.Decode(sig, sigOff + tlen, tlen); /* * If either r or s was too large, it got set to * zero. We also don't want real zeros. */ if (r.IsZero || s.IsZero) { return(false); } /* * Convert the hash value to an integer modulo q. * As per FIPS 186-4, if the hash value is larger * than q, then we keep the qlen leftmost bits of * the hash value. */ int qBitLength = oneQ.ModBitLength; int hBitLength = hashLen << 3; byte[] hv; if (hBitLength <= qBitLength) { hv = new byte[hashLen]; Array.Copy(hash, hashOff, hv, 0, hashLen); } else { int qlen = (qBitLength + 7) >> 3; hv = new byte[qlen]; Array.Copy(hash, hashOff, hv, 0, qlen); int rs = (8 - (qBitLength & 7)) & 7; BigInt.RShift(hv, rs); } ModInt z = oneQ.Dup(); z.DecodeReduce(hv); /* * Apply the verification algorithm: * w = 1/s mod q * u = z*w mod q * v = r*w mod q * T = u*G + v*Pub * test whether T.x mod q == r. */ /* * w = 1/s mod q */ ModInt w = s.Dup(); w.Invert(); /* * u = z*w mod q */ w.ToMonty(); ModInt u = w.Dup(); u.MontyMul(z); /* * v = r*w mod q */ ModInt v = w.Dup(); v.MontyMul(r); /* * Compute u*G */ MutableECPoint T = curve.MakeGenerator(); uint good = T.MulSpecCT(u.Encode()); /* * Compute v*iPub */ MutableECPoint M = pk.iPub.Dup(); good &= M.MulSpecCT(v.Encode()); /* * Compute T = u*G+v*iPub */ uint nd = T.AddCT(M); M.DoubleCT(); T.Set(M, ~nd); good &= ~T.IsInfinityCT; /* * Get T.x, reduced modulo q. * Signature is valid if and only if we get * the same value as r (and we did not encounter * an error previously). */ s.DecodeReduce(T.X); return((good & r.EqCT(s)) != 0); } catch (CryptoException) { /* * Exceptions may occur if the key or signature * have invalid values (non invertible, out of * range...). Any such occurrence means that the * signature is not valid. */ return(false); } }