Использование Node.js библиотека ‘jsrsasign’ для проверки подписи, сгенерированной библиотекой .NET Bouncy Castle

#javascript #c# #node.js #bouncycastle

#javascript #c# #node.js #bouncycastle

Вопрос:

Я создаю подписи на C #, используя библиотеку Bouncy Castle следующим образом:

 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=
 

На node.js приложение, я использую jsrsasign для проверки сгенерированной подписи для той же полезной нагрузки следующим образом:

 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! 
 

Я был бы признателен, если бы вы могли помочь мне определить, в чем может быть проблема.

Я бы также принял предложения по другим Node.js библиотеки, которые могут проверять подписи, сгенерированные с помощью ECDSA с помощью SHA512.

Комментарии:

1. В Node.js код, когда вы создаете строку pem из publicKey, я считаю, что publicKey не должен быть в формате base64. В любом случае, не могли бы вы добавить publicKey в формате PEM в вопросе?

2. @Boney ключ действителен: -----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAErFY9cGQi XgkGn83VuMAY8xoyRB2pDPCuYzSZR4od/oUx VnJX3OBpqfYre1CSN8nWemzqeq NBiOQsLmWo4Xw== -----END PUBLIC KEY----- вот что он расшифровывает lapo.it/asn1js /…

Ответ №1:

Скорее всего, это ошибка в jsrsasign библиотеке, из-за которой она генерирует неправильные сигнатуры ECDSA с помощью хэш-функций, выходные данные которых превышают битовую длину n в битах. Ожидая ответа автора, смотрите более подробную информацию здесь https://github.com/kjur/jsrsasign/issues/394 .

Используя другой пакет elliptic curves package и генерируя обрезая хэш полезной нагрузки вручную, я смог убедиться, что подписи, сгенерированные Bouncy Castle в C #, действительны:

 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