public bool VerifySignature(byte[] message, byte[] signature, byte[] pubkey) { if (pubkey.Length == 33 && (pubkey[0] == 0x02 || pubkey[0] == 0x03)) { try { pubkey = ECPoint.DecodePoint(pubkey, ECCurve.Secp256r1).EncodePoint(false).Skip(1).ToArray(); } catch { return(false); } } else if (pubkey.Length == 65 && pubkey[0] == 0x04) { pubkey = pubkey.Skip(1).ToArray(); } else if (pubkey.Length != 64) { throw new ArgumentException(); } BigInteger x = new BigInteger(1, pubkey.Take(32).ToArray()); BigInteger y = new BigInteger(1, pubkey.Skip(32).ToArray()); X9ECParameters ecParams = NistNamedCurves.GetByName("P-256"); ECDomainParameters domainParameters = new ECDomainParameters(ecParams.Curve, ecParams.G, ecParams.N, ecParams.H, ecParams.GetSeed()); var G = ecParams.G; Org.BouncyCastle.Math.EC.ECCurve curve = ecParams.Curve; Org.BouncyCastle.Math.EC.ECPoint q = curve.CreatePoint(x, y); ECPublicKeyParameters pubkeyParam = new ECPublicKeyParameters(q, domainParameters); var verifier = SignerUtilities.GetSigner("SHA-256withECDSA"); verifier.Init(false, pubkeyParam); verifier.BlockUpdate(message, 0, message.Length); // expected format is SEQUENCE {INTEGER r, INTEGER s} var derSignature = new DerSequence( // first 32 bytes is "r" number new DerInteger(new BigInteger(1, signature.Take(32).ToArray())), // last 32 bytes is "s" number new DerInteger(new BigInteger(1, signature.Skip(32).ToArray()))) .GetDerEncoded(); ///old verify method /// /* * const int ECDSA_PUBLIC_P256_MAGIC = 0x31534345; * pubkey = BitConverter.GetBytes(ECDSA_PUBLIC_P256_MAGIC).Concat(BitConverter.GetBytes(32)).Concat(pubkey).ToArray(); * using (CngKey key = CngKey.Import(pubkey, CngKeyBlobFormat.EccPublicBlob)) * using (ECDsaCng ecdsa = new ECDsaCng(key)) * { * var result = ecdsa.VerifyData(message, signature, HashAlgorithmName.SHA256); * } */ /////////////////// return(verifier.VerifySignature(derSignature)); }