Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Node.js 'jsrsasign' library to verify signature generated by .NET Bouncy Castle library

I'm generating signatures in C# using the Bouncy Castle library as follows:

var privateKeyBase64 = "MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgg8/MbvGGTDMDpfje8lQBZ8st+l3SK7jRl7OWlyUl/VagCgYIKoZIzj0DAQehRANCAARkQIUpkKbxmJJicvG450JH900JjmJOGdlMCZl3BIXvPBBKkaTMsQc6l3O4vJA6Yc23nr3Ox/KwFUl6gdo5iTqV";
var publicKeyBase64 = "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEZECFKZCm8ZiSYnLxuOdCR/dNCY5iThnZTAmZdwSF7zwQSpGkzLEHOpdzuLyQOmHNt569zsfysBVJeoHaOYk6lQ==";

var plainText = "aaa";
var plainTextBytes = Encoding.UTF8.GetBytes(plainText);

// Sign
var privateKey = PrivateKeyFactory.CreateKey(Convert.FromBase64String(privateKeyBase64));
var signer = SignerUtilities.GetSigner(X9ObjectIdentifiers.ECDsaWithSha512.Id);
signer.Init(true, privateKey);
signer.BlockUpdate(plainTextBytes, 0, plainTextBytes.Length);

var signature = signer.GenerateSignature();
var signatureBase64 = Convert.ToBase64String(signature);

Console.WriteLine("Signature base64: {0}", signatureBase64);

// Verify
Console.WriteLine("-------------------- Verifying signature ");
Console.WriteLine("Public key base64: {0}", publicKeyBase64);

var publicKey = PublicKeyFactory.CreateKey(Convert.FromBase64String(publicKeyBase64));
var verifier = SignerUtilities.GetSigner(X9ObjectIdentifiers.ECDsaWithSha512.Id);
verifier.Init(false, publicKey);
verifier.BlockUpdate(plainTextBytes, 0, plainTextBytes.Length);
Console.WriteLine("Signature valid?: {0}", verifier.VerifySignature(Convert.FromBase64String(signatureBase64)));

// Prints: MEUCIBEcfv2o3UwqwV72CVuYi7HbjcoiuSQOULY5d+DuGt3UAiEAtoNrdNWvjfdz/vR6nPiD+RveKN5znBtYaIrRDp2K7Ks=

On the node.js app, I'm using jsrsasign to verify the generated signature on same payload as follows:

let rs = require('jsrsasign');
let pem = `-----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEZECFKZCm8ZiSYnLxuOdCR/dNCY5iThnZTAmZdwSF7zwQSpGkzLEHOpdzuLyQOmHNt569zsfysBVJeoHaOYk6lQ== -----END PUBLIC KEY-----`;

let plainText = 'aaa';

let signature = 'MEUCIBEcfv2o3UwqwV72CVuYi7HbjcoiuSQOULY5d+DuGt3UAiEAtoNrdNWvjfdz/vR6nPiD+RveKN5znBtYaIrRDp2K7Ks=';
let signatureHex = Buffer.from(signature, 'base64').toString('hex');

var sig = new rs.Signature({alg: 'SHA512withECDSA'});
sig.init(pem);
sig.updateString(plainText);
var isValid = sig.verify(signatureHex);
console.log('Is signature valid: ', isValid); // <--- returns false always! 

I'd be grateful if you could assist me in identifying what the issue could be.

I'd also accept suggestions for other Node.js libraries that can validate signatures generated using ECDSA with SHA512.

like image 545
0xFF Avatar asked Apr 17 '19 05:04

0xFF


1 Answers

This is very likely a bug in the jsrsasign library where it generates wrong ECDSA signatures with hash functions that have an output larger than the bit length of n in bits. Awaiting the answer of the author, see more details here https://github.com/kjur/jsrsasign/issues/394.

Using another package elliptic curves package and generating + truncating the hash of the payload manually, I was able to verify that the signatures generated by Bouncy Castle in C# are valid:

let elliptic = <any>window.require('elliptic');
let hash = <any>window.require('hash.js')
let ec = new elliptic.ec('p256');

// Same key from my original post, just hex encoded
let keyPair = ec.keyFromPrivate("83CFCC6EF1864C3303A5F8DEF2540167CB2DFA5DD22BB8D197B396972525FD56");
let pubKey = keyPair.getPublic();

// The first 32 bytes (256 bits) of the SHA521 hash of the payload "aaa"
// sha512('aaa') => d6f644b19812e97b5d871658d6d3400ecd4787faeb9b8990c1e7608288664be77257104a58d033bcf1a0e0945ff06468ebe53e2dff36e248424c7273117dac09
let msgHash = 'd6f644b19812e97b5d871658d6d3400ecd4787faeb9b8990c1e7608288664be7'

// Same signature from original post above
let signatureBase64 = 'MEUCIBEcfv2o3UwqwV72CVuYi7HbjcoiuSQOULY5d+DuGt3UAiEAtoNrdNWvjfdz/vR6nPiD+RveKN5znBtYaIrRDp2K7Ks='
let signatureHex = Buffer.from(signatureBase64, 'base64').toString('hex');
let validSig = ec.verify(msgHash, signatureHex, pubKey);
console.log("Signature valid?", validSig);   // <------- prints TRUE
like image 61
0xFF Avatar answered Oct 11 '22 03:10

0xFF