public static bool?VerifySignatureCng(byte[] pkParameters, byte[] pkKey, byte[] hash, byte[] signature) { #if !__MonoCS__ EllipticCurve curve = null; var ecsngHeader = new byte[8] { (byte)'E', (byte)'C', (byte)'S', 0, 0, 0, 0, 0 }; curve = GetCurveFromParameters(pkParameters); if (curve == null) { return(null); } if (curve == EllipticCurve.P256) { ecsngHeader[3] = (byte)'1'; } else if (curve == EllipticCurve.P384) { ecsngHeader[3] = (byte)'3'; } else // P512 { ecsngHeader[3] = (byte)'5'; } ecsngHeader[4] = (byte)curve.curveByteLen; var pubKeyBlob = new byte[8 + curve.curveByteLen * 2]; Buffer.BlockCopy(ecsngHeader, 0, pubKeyBlob, 0, 8); Buffer.BlockCopy(pkKey, 1, pubKeyBlob, 8, curve.curveByteLen * 2); var ecdsa = new ECDsaCng(CngKey.Import(pubKeyBlob, CngKeyBlobFormat.EccPublicBlob)); // We must decode the signature from DER format to raw format (to coordinates on the curve) var decodedSignature = Utils.DecodeDERSignature(signature, 0, signature.Length, curve.curveByteLen); bool ok = ecdsa.VerifyHash(hash, decodedSignature); return(ok); #else throw new NotSupportedException(); #endif }
public static bool?VerifySignature(byte[] pkParameters, byte[] pkKey, byte[] hash, byte[] signature) { EllipticCurve curve = GetCurveFromParameters(pkParameters); if (curve == null) { return(null); } // We must decode the signature from DER format to raw format (to coordinates on the curve) int offset = 1; // Skip tag 0x30 Utils.GetASNLength(signature, ref offset); // P521 requires 2 bytes to specify the length offset += 1; // 0x02 int len1 = Utils.GetASNLength(signature, ref offset); var rBytes = new byte[len1]; for (var i = 0; i < len1; i++) { rBytes[i] = signature[offset + len1 - 1 - i]; } offset += len1; offset += 1; // 0x02 int len2 = Utils.GetASNLength(signature, ref offset); var sBytes = new byte[len2]; for (var i = 0; i < len2; i++) { sBytes[i] = signature[offset + len2 - 1 - i]; } var r = new BigInteger(rBytes); var s = new BigInteger(sBytes); // Verify that r, s are in [1, q - 1] and Qa lies on the curve if (r == 0 || s == 0) { return(false); } if (r >= curve.q || s >= curve.q) { return(false); } BigInt Qax = new BigInt(pkKey, 1, curve.curveByteLen), Qay = new BigInt(pkKey, 1 + curve.curveByteLen, curve.curveByteLen); BigInteger QaxBi = Qax.ExportToBigInteger(), QayBi = Qay.ExportToBigInteger(); var pBi = curve.p.ExportToBigInteger(); if (QaxBi >= pBi || QayBi >= pBi) { return(false); } if ((QaxBi * QaxBi * QaxBi - 3 * QaxBi + curve.b + pBi * 3) % pBi != QayBi * QayBi % pBi) { return(false); } // Data points are ok, now start verify the signature var hashLen = hash.Length; byte[] hash2 = null; if (hash[0] >= 128) { hash2 = new byte[hash.Length + 1]; hash2[hash.Length] = 0; for (var i = 0; i < hash.Length; i++) { hash2[i] = hash[hash.Length - 1 - i]; } } else { Array.Reverse(hash); hash2 = hash; } var z = new BigInteger(hash2); if (hashLen * 8 > curve.curveLen) // Should be compared to order length, but p length is the same for NIST curves { var excessBits = hashLen * 8 - curve.curveLen; z >>= excessBits; } var w = BigInteger.ModPow(s, curve.q - 2, curve.q); var u1 = z * w % curve.q; var u2 = r * w % curve.q; var mul = curve.EcTwinMult(new BigInt(u1, (curve.curveByteLen + 3) / 4), new Projective() { x = curve.xg, y = curve.yg, z = new BigInt(1, (curve.curveByteLen + 3) / 4) }, new BigInt(u2, (curve.curveByteLen + 3) / 4), new Projective() { x = Qax, y = Qay, z = new BigInt(1, (curve.curveByteLen + 3) / 4) }); var res = curve.EcAffinify(mul).x.ExportToBigInteger(); if (res >= curve.q) { res -= curve.q; } bool ok = res == r; return(ok); }