/* * Checks enforced by the constructor: * -- modulus is odd and at least 80-bit long * -- subgroup order is odd and at least 30-bit long * -- parameters a[] and b[] are lower than modulus * -- coordinates gx and gy are lower than modulus * -- coordinates gx and gy match curve equation */ internal ECCurvePrime(string name, byte[] mod, byte[] a, byte[] b, byte[] gx, byte[] gy, byte[] subgroupOrder, byte[] cofactor) : base(subgroupOrder, cofactor) { this.mod = mod = BigInt.NormalizeBE(mod); int modLen = BigInt.BitLength(mod); if (modLen < 80) { throw new CryptoException( "Invalid curve: modulus is too small"); } if ((mod[mod.Length - 1] & 0x01) == 0) { throw new CryptoException( "Invalid curve: modulus is even"); } int sgLen = BigInt.BitLength(subgroupOrder); if (sgLen < 30) { throw new CryptoException( "Invalid curve: subgroup is too small"); } if ((subgroupOrder[subgroupOrder.Length - 1] & 0x01) == 0) { throw new CryptoException( "Invalid curve: subgroup order is even"); } mp = new ModInt(mod); flen = (modLen + 7) >> 3; pMod4 = mod[mod.Length - 1] & 3; this.a = a = BigInt.NormalizeBE(a); this.b = b = BigInt.NormalizeBE(b); if (BigInt.CompareCT(a, mod) >= 0 || BigInt.CompareCT(b, mod) >= 0) { throw new CryptoException( "Invalid curve: out-of-range parameter"); } ma = mp.Dup(); ma.Decode(a); ma.Add(3); aIsM3 = ma.IsZero; ma.Sub(3); mb = mp.Dup(); mb.Decode(b); this.gx = gx = BigInt.NormalizeBE(gx); this.gy = gy = BigInt.NormalizeBE(gy); if (BigInt.CompareCT(gx, mod) >= 0 || BigInt.CompareCT(gy, mod) >= 0) { throw new CryptoException( "Invalid curve: out-of-range coordinates"); } MutableECPointPrime G = new MutableECPointPrime(this); G.Set(gx, gy, true); hashCode = (int)(BigInt.HashInt(mod) ^ BigInt.HashInt(a) ^ BigInt.HashInt(b) ^ BigInt.HashInt(gx) ^ BigInt.HashInt(gy)); if (name == null) { name = string.Format("generic prime {0}/{1}", modLen, sgLen); } this.name = name; }
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); } }
/* * Generate a new EC key pair in the specified curve. */ public static ECPrivateKey Generate(ECCurve curve) { return(new ECPrivateKey(curve, BigInt.RandIntNZ(curve.SubgroupOrder))); }
/* * Create a new instance with the provided elements. Values are * in unsigned big-endian representation. * * n modulus * e public exponent * d private exponent * p first modulus factor * q second modulus factor * dp d mod (p-1) * dq d mod (q-1) * iq (1/q) mod p * * Rules verified by this constructor: * n must be odd and at least 512 bits * e must be odd * p must be odd * q must be odd * p and q are greater than 1 * n is equal to p*q * dp must be non-zero and lower than p-1 * dq must be non-zero and lower than q-1 * iq must be non-zero and lower than p * * This constructor does NOT verify that: * p and q are prime * d is equal to dp modulo p-1 * d is equal to dq modulo q-1 * dp is the inverse of e modulo p-1 * dq is the inverse of e modulo q-1 * iq is the inverse of q modulo p */ public RSAPrivateKey(byte[] n, byte[] e, byte[] d, byte[] p, byte[] q, byte[] dp, byte[] dq, byte[] iq) { n = BigInt.NormalizeBE(n); e = BigInt.NormalizeBE(e); d = BigInt.NormalizeBE(d); p = BigInt.NormalizeBE(p); q = BigInt.NormalizeBE(q); dp = BigInt.NormalizeBE(dp); dq = BigInt.NormalizeBE(dq); iq = BigInt.NormalizeBE(iq); if (n.Length < 64 || (n.Length == 64 && n[0] < 0x80)) { throw new CryptoException( "Invalid RSA private key (less than 512 bits)"); } if (!BigInt.IsOdd(n)) { throw new CryptoException( "Invalid RSA private key (even modulus)"); } if (!BigInt.IsOdd(e)) { throw new CryptoException( "Invalid RSA private key (even exponent)"); } if (!BigInt.IsOdd(p) || !BigInt.IsOdd(q)) { throw new CryptoException( "Invalid RSA private key (even factor)"); } if (BigInt.IsOne(p) || BigInt.IsOne(q)) { throw new CryptoException( "Invalid RSA private key (trivial factor)"); } if (BigInt.Compare(n, BigInt.Mul(p, q)) != 0) { throw new CryptoException( "Invalid RSA private key (bad factors)"); } if (dp.Length == 0 || dq.Length == 0) { throw new CryptoException( "Invalid RSA private key" + " (null reduced private exponent)"); } /* * We can temporarily modify p[] and q[] (to compute * p-1 and q-1) since these are freshly produced copies. */ p[p.Length - 1]--; q[q.Length - 1]--; if (BigInt.Compare(dp, p) >= 0 || BigInt.Compare(dq, q) >= 0) { throw new CryptoException( "Invalid RSA private key" + " (oversized reduced private exponent)"); } p[p.Length - 1]++; q[q.Length - 1]++; if (iq.Length == 0 || BigInt.Compare(iq, p) >= 0) { throw new CryptoException( "Invalid RSA private key" + " (out of range CRT coefficient)"); } this.n = n; this.e = e; this.d = d; this.p = p; this.q = q; this.dp = dp; this.dq = dq; this.iq = iq; }