I have a problem when I try to verify the ECDSA signature in Bouncy Castle in C#. The code is adopted from Java example that I have, so I am 100% sure that the public key and signature are correct. But the C# implementation always returns that the signature is not valid. I checked the curve parameters and they are correct. I tried with DER and "raw" signature and again it did not work.
Can anybody spot what I am doing wrong:
namespace TestECDSA
{
    class Program
    {
    static void Main(string[] args)
    {
        byte[] b = new byte[] { 0x2B, 0xA1, 0x41, 0x00 };
        string pubKey = "044F6D3F294DEA5737F0F46FFEE88A356EED95695DD7E0C27A591E6F6F65962BAF";
        string signature = "AAD03D3D38CE53B673CF8F1C016C8D3B67EA98CBCF72627788368C7C54AA2FC4";
        X9ECParameters curve = SecNamedCurves.GetByName("secp128r1");
        ECDomainParameters curveSpec = new ECDomainParameters(curve.Curve, curve.G, curve.N, curve.H, curve.GetSeed());
        ECPublicKeyParameters key = new ECPublicKeyParameters("ECDSA", curve.Curve.DecodePoint(Hex.Decode(pubKey)), curveSpec);
        ISigner signer = SignerUtilities.GetSigner("NONEwithECDSA");             
        signer.Init(false, key);
        signer.BlockUpdate(b, 0, b.Length);
        if (signer.VerifySignature(derEncodeSignature(Hex.Decode(signature))))
            System.Console.WriteLine("Verified Signature");
        else
            System.Console.WriteLine("Not Verified Signature");
    }
    public static byte[] derEncodeSignature(byte[] signature)
    {
        byte[] encoded = new byte[6 + signature.Length];
        byte[] r = RangeSubset(signature, 0, 16);
        byte[] s = RangeSubset(signature, 16, 16);
        encoded[0] = 0x30;
        encoded[1] = 0x24;
        encoded[2] = 0x02;
        encoded[3] = 0x10;
        encoded[4 + r.Length] = 0x02;
        encoded[5 + r.Length] = 0x10;
        Array.Copy(r, 0, encoded, 4, r.Length);
        Array.Copy(s, 0, encoded, 6 + r.Length, r.Length);
        return encoded;
    }
    public static T[] RangeSubset<T>(T[] array, int startIndex, int length)
    {
        T[] subset = new T[length];
        Array.Copy(array, startIndex, subset, 0, length);
        return subset;
    }
}
}
                Instead of DER-encoding the signature by yourself, you can use signer.GenerateSignature() like so:
        var signerAlgorithm = "SHA256withECDSA";
        ISigner signer = SignerUtilities.GetSigner(signerAlgorithm);
        signer.Init(true, privateSigningKey);
        signer.BlockUpdate(data, 0, data.Length);
        byte[] signature = signer.GenerateSignature();
        return signature;
                        dbugger was right. DER encoding is wrong. The code in question should be replaced by:
    private static byte[] derEncodeSignature(byte[] signature)
    {
        byte[] r = signature.RangeSubset(0, (signature.Length / 2));
        byte[] s = signature.RangeSubset((signature.Length / 2), (signature.Length / 2));
        MemoryStream stream = new MemoryStream();
        DerOutputStream der = new DerOutputStream(stream);
        Asn1EncodableVector v = new Asn1EncodableVector();
        v.Add(new DerInteger(new BigInteger(1, r)));
        v.Add(new DerInteger(new BigInteger(1, s)));
        der.WriteObject(new DerSequence(v));
        return stream.ToArray();
    }
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With