我正在使用Bouncy Castle库在C#中生成签名,如下所示:
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生成的签名。
答案 0 :(得分:5)
这很可能是jsrsasign
库中的错误,在该错误中它会生成错误的ECDSA签名,这些签名的散列函数输出的位数大于n
的位长度。等待作者的答案,请在https://github.com/kjur/jsrsasign/issues/394处查看更多详细信息。
使用另一个包椭圆曲线包并手动生成+截断有效载荷的哈希,我能够验证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