2

I'm testing BouncyCastle for verifying signature with ECDSA, nist P251. (Xamarin's crypto API not implemented yet, I started to use Bouncy Castle lib.)

Anyway, What I'm facing with below code, is... method B is working correctly with C# API, method A isn't. The ECPoint of A method looks problem but I can't check the details.

(I've checked, but couldn't fix.)

How should I change the A method? Any idea is welcome.Thanks in advance.

using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.Nist;
using Org.BouncyCastle.Asn1.X9;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Math.EC;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities.Encoders;
using System;
using System.Linq;
using System.Security.Cryptography;
using System.Text;

namespace TestMe
{
    class Program
    {

        public static byte[] HexStringToByteArray(string Hex)
        {
            byte[] Bytes = new byte[Hex.Length / 2];
            int[] HexValue = new int[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
                                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x0B, 0x0C, 0x0D,
                                 0x0E, 0x0F };

            for (int x = 0, i = 0; i < Hex.Length; i += 2, x += 1)
            {
                Bytes[x] = (byte)(HexValue[Char.ToUpper(Hex[i + 0]) - '0'] << 4 |
                                  HexValue[Char.ToUpper(Hex[i + 1]) - '0']);
            }

            return Bytes;
        }

        static void Main(string[] args)
        {
            String sig
                = "e1f5cecccedfe5228d9331098e84b69a0675cdd9ac066ecfada7fea761f52a4cde902a0abd362883127230326fb556af14e894d39a3e14437aaa4134a3476c84";

            String msg = "00000000dcb320137ddd6f825660750ab655219fad66951c64f0420be8ac902975197ed2b0da54cd3d502d34dd04c8d74b2958a0b8792ae4730df6d25a6969bcad9f93a7d6229e5a0100000017cf5242732bba21a0b0e7dad7102cf7bdb2c8d7a665045816a886d7";
            String pub = "b679e27513e2fff8fdeb54409c242776f3517f370440d26885de574a0b0e5309a9de4ea055b0bf302d9f00875f80e28cd29bb95a48aa53746d7de9465123dbb7";


            A(HexStringToByteArray(msg), HexStringToByteArray(sig), HexStringToByteArray(pub));
            B(HexStringToByteArray(msg), HexStringToByteArray(sig), HexStringToByteArray(pub));

        }

        //incorrect
        static void A(byte[] message, byte[] signature, byte[] pubkey)
        {            
            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);
            bool result = verifier.VerifySignature(signature);

            Console.WriteLine("result: "  + result);
        }


        // correct
        static void B(byte[] message, byte[] signature, byte[] pubkey)
        {
            var Q = new System.Security.Cryptography.ECPoint();
            var param = new ECParameters();
            Q.X = pubkey.Take(32).ToArray();
            Q.Y = pubkey.Skip(32).ToArray();
            param.Curve = System.Security.Cryptography.ECCurve.NamedCurves.nistP256;
            param.Q = Q;            

            var ecdsa = ECDsa.Create(param);
            bool result = ecdsa.VerifyData(message, signature, HashAlgorithmName.SHA256);
            Console.WriteLine("result: " + result);
        }


    }
}
slavoo
  • 5,798
  • 64
  • 37
  • 39
madenmud
  • 51
  • 1
  • 7
  • *"Method B is working correctly with C# API, method A isn't..."* - That is not a good problem statement. You should clearly state the problem and where it is occurring. What does *"method A not working"* mean? – jww Mar 24 '18 at 07:03
  • I have the same implementation for method B and it always returns false. Did method B ever return true and if so, can you shed some light on how you got it to return true? – josagyemang Nov 25 '19 at 20:38

2 Answers2

7

Your code to verify signature with bouncy castle is correct. Problem is in signature format.

ECDSA signature is basically two numbers, usually called r and s. In signature from your example, those 2 numbers are just concatenated together. Each of them is 32 bytes, so your signature is 64 bytes.

That format (concatenated numbers) is what .NET api expects, but NOT what Bouncy Castle expects. Bouncy Castle expects signature to be DER-encoded (like specification states it should be).

So you need to "convert" signature from current format to format BC expects, like this:

// 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();

Then verify this signature (it's 70 bytes by the way now):

bool result = verifier.VerifySignature(derSignature);

And it will work fine.

Evk
  • 98,527
  • 8
  • 141
  • 191
4

With recent versions of Bouncy Castle, it is possible to create a verifier with "SHA-256withPLAIN-ECDSA". This allows you to pass in the original 64 byte signature array without needing to create a DerSequence.

var verifier = SignerUtilities.GetSigner("SHA-256withPLAIN-ECDSA");
fractor
  • 1,534
  • 2
  • 15
  • 30
  • 1
    Solved a nightmare for us, thanks! (we've been struggling with the `SHA256WITHECDSA` that creates incorrect signatures, incompatible with java default reader) – Wiktor Zychla Sep 11 '20 at 12:57