Alex
Alex

Reputation: 135

jsrsasign with ECDSA verifying issue

I could verify an ECDSA / SHA256 signature using the standard library of Javascript (window.crypto.subtle.verify) but cannot using the jsrsasign library (KJUR.crypto). I have also tried 'KJUR.crypto.ECDSA' class directly but no luck neither.

See below both script methods which dont provide same result. Could someone advise the issue(s) ?

    //function to convert HEX to Decimal - return Arraybuffer
    function hexStringToUint8Array(hexString) {
        if (hexString.length % 2 != 0)
            throw "Invalid hexString";
        var arrayBuffer = new Uint8Array(hexString.length / 2);

        for (var i = 0; i < hexString.length; i += 2) {
            var byteValue = parseInt(hexString.substr(i, 2), 16);
            if (byteValue == NaN)
                throw "Invalid hexString";
            arrayBuffer[i / 2] = byteValue;
        }

        return arrayBuffer;
    }

    //function to convert Base64 to hex (8 bits formats)
    function base64ToHex(str) {
      const raw = atob(str);
      let result = '';
      for (let i = 0; i < raw.length; i++) {
        const hex = raw.charCodeAt(i).toString(16);
        result += (hex.length === 2 ? hex : '0' + hex);
      }
      return result;
    }

    //convert Base64 URL to Base64
    function base64urlToBase64(base64url) {
        base64url = base64url.toString();
        return base64url
            .replace(/\-/g, "+")
            .replace(/_/g, "/");
    }


    //Define values
    Base64URL_coordX = '2uYQAsY-bvzz7r7SL-tK2C0eySfYEf1blv91cnd_1G4';
    Base64URL_coordY = 'S3j1vy2sbkExAYXumb3w1HMVH-4ztoHclVTwQd45Reg';
    signature = 'ed0c2b2e56731511ce2cea1d7320cdbc39dbabca7f525ec5d646b7c11cb35d5846a1cb70c2a1d8480f5ef88b46d401ca78b18ccae9ae4e3934a6b8fe412f7b11';
    dataHex = '48656c6c6f20386777696669';  // ='Hello 8gwifi'


    ////////////Verifying Method using standard javascript
    var dataToVerify = hexStringToUint8Array(dataHex);
    var SignatureToVerify = hexStringToUint8Array(signature);

    window.crypto.subtle.importKey(
        "jwk", //can be "jwk" (public or private), "spki" (public only), or "pkcs8" (private only)
        {   //this is an example jwk key, other key types are Uint8Array objects
            kty: "EC",
            crv: "P-256",
            x: Base64URL_coordX, // expects  x and y to be «base64url» encoded
            y: Base64URL_coordY,
            ext: true,
        },
        {   //these are the algorithm options
            name: "ECDSA",
            namedCurve: "P-256", //can be "P-256", "P-384", or "P-521"
        },
        false, //whether the key is extractable (i.e. can be used in exportKey)
        ["verify"] //"verify" for public key import, "sign" for private key imports
    )
    .then(function(publicKey){
            window.crypto.subtle.verify(
                {
                    name: "ECDSA",
                    hash: {name: "SHA-256"}, //can be "SHA-1", "SHA-256", "SHA-384", or "SHA-512"
                },
                publicKey, //from generateKey or importKey above
                SignatureToVerify,  //ArrayBuffer of the signature
                dataToVerify //ArrayBuffer of the data
            )
            .then(function(isvalid){
                console.log('Signature valid1: ', isvalid);
            })
            .catch(function(err){
                console.error(err);
            });
    });


    ////////////Verifying Method using KJUR
    Hex_coordX = base64ToHex(base64urlToBase64(Base64URL_coordX));
    Hex_coordY = base64ToHex(base64urlToBase64(Base64URL_coordY));
    var XY = Hex_coordX.toString(16) + Hex_coordY.toString(16);

    var sig = new KJUR.crypto.Signature({"alg": "SHA256withECDSA", "prov": "cryptojs/jsrsa"});
    sig.init({xy: XY, curve: "secp256r1"});
    sig.updateHex(dataHex);
    var result = sig.verify(signature);

    //Printing Verification
    console.log('Signature valid2: ', result);

Upvotes: 0

Views: 678

Answers (1)

Maarten Bodewes
Maarten Bodewes

Reputation: 93948

It says in the description of the library that it is JCA style. This probably means that the signature generation / verification functions have a ASN.1 / DER encoded input / output.

This consist of an ASN.1 SEQUENCE (tag 0x30), the length of the two integers inside. These two INTEGER's have tag 0x02 and a length of the size of the integer value of the r and s components of the signature. These are big endian, signed integers (which means stripping bytes if they are 0x00 or adding a 0x00 if the top byte is 0x80 or higher).

In your case that would be:

r = ed0c2b2e56731511ce2cea1d7320cdbc39dbabca7f525ec5d646b7c11cb35d58
s = 46a1cb70c2a1d8480f5ef88b46d401ca78b18ccae9ae4e3934a6b8fe412f7b11

Now converting these to DER ASN.1:

ri = 02 21  00 ed0c2b2e56731511ce2cea1d7320cdbc39dbabca7f525ec5d646b7c11cb35d58
si = 02 20 46a1cb70c2a1d8480f5ef88b46d401ca78b18ccae9ae4e3934a6b8fe412f7b11

and finally adding the sequence and adding the concatenation of above:

sig = 30 45 02 21  00 ed0c2b2e56731511ce2cea1d7320cdbc39dbabca7f525ec5d646b7c11cb35d58
02 20 46a1cb70c2a1d8480f5ef88b46d401ca78b18ccae9ae4e3934a6b8fe412f7b11

and checking the result e.g. here.

But I guess in your case just calling the function concatSigToASN1Sig would be faster :P

Upvotes: 1

Related Questions