如何用RSA公钥验证文件?我的Node.js验证代码返回false
RSA签名验证失败的问题分析与修复
嘿,我一眼就看到你代码里的两个关键问题,这就是为什么验证一直返回false的原因:
1. 对verify()方法的返回值理解错误
你在验证代码里写了:
const testSignature = verifier.verify(publicKey, fileSignature, 'base64'); // ... if (testSignature === fileHash) console.log("ok");
这里完全搞反了逻辑!verifier.verify()的返回值是一个布尔值,它直接告诉你签名是否有效(公钥能否验证签名和内容的匹配性),而不是返回文件的哈希值。你拿这个布尔值和fileHash字符串比较,肯定永远不相等,而且这也不是验证签名的正确方式。
2. 签名生成与验证的内容不匹配
看你的签名生成代码:
signer.update(fileHash); // 你是对文件的hex哈希字符串进行签名 fileSignature = signer.sign(privateKey, 'base64');
但在验证代码里,你创建了verifier对象后,根本没有调用verifier.update()来传入要验证的内容!这就相当于你让验证器去验证一个空内容的签名,自然会返回false。
而且更规范的做法是:签名时直接对原始文件内容进行签名(而不是先算哈希再签名),因为crypto.createSign('RSA-SHA256')本身就会先计算SHA256哈希再用RSA签名,你额外再算一次哈希属于画蛇添足,还容易出错。
修正后的完整代码
首先是签名生成代码(优化版,直接处理文件流)
const fs = require('fs'); const crypto = require('crypto'); const signer = crypto.createSign('RSA-SHA256'); const fd = fs.createReadStream("path/to/file"); fd.on('end', () => { signer.end(); const privateKey = fs.readFileSync('keys/private_key.pem'); const fileSignature = signer.sign(privateKey, 'base64'); console.log('生成的签名:', fileSignature); // 这里可以把签名保存到文件或者其他地方 }); fd.pipe(signer); // 直接把文件流导入signer,自动处理内容
然后是验证代码(对应优化后的签名流程)
const fs = require('fs'); const crypto = require('crypto'); const verifier = crypto.createVerify('RSA-SHA256'); const fd = fs.createReadStream("path/to/my/file"); fd.on('end', () => { verifier.end(); const publicKey = fs.readFileSync('keys/public_key.pem'); // 假设fileSignature是你拿到的正确签名字符串 const isSignatureValid = verifier.verify(publicKey, fileSignature, 'base64'); console.log("签名是否有效:", isSignatureValid); if (isSignatureValid) { console.log("验证通过:文件未被篡改,签名合法"); } else { console.log("验证失败:文件被篡改或签名无效"); } }); fd.pipe(verifier); // 同样直接把文件流导入verifier
如果你坚持要保留原有的“先算哈希再签名”的方式(不推荐)
那验证代码也必须对应地先计算出相同的hex哈希,然后对这个哈希字符串做update:
const fs = require('fs'); const crypto = require('crypto'); var hash = crypto.createHash("sha256"); hash.setEncoding("hex"); var fd = fs.createReadStream("path/to/my/file"); fd.on("end", function() { hash.end(); var fileHash = hash.read(); const publicKey = fs.readFileSync('keys/public_key.pem'); const verifier = crypto.createVerify('RSA-SHA256'); // 关键:必须update和签名时相同的内容——也就是fileHash这个hex字符串 verifier.update(fileHash); const isSignatureValid = verifier.verify(publicKey, fileSignature, 'base64'); console.log("签名是否有效:", isSignatureValid); if (isSignatureValid) { console.log("验证通过"); } else { console.log("验证失败"); } }); fd.pipe(hash);
但还是推荐直接用文件流处理的方式,更简洁也不容易出错,因为createSign和createVerify已经内置了哈希计算的逻辑。
内容的提问来源于stack exchange,提问作者iAmoric
相关产品推荐
相关产品推荐

