示例#1
0
        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;
        }