我将尝试使用命令验证来自 opensll 生成的签名:
openssl pkeyutl -in mess.txt -out sign.txt -inkey priv.pem -sign
和我的脚本:
const fs = require('fs');
const forge = require('node-forge');
function verifySignature(publicKeyPem, message, signatureFile) {
try {
const publicKey = forge.pki.publicKeyFromPem(publicKeyPem);
const signatureBytes = fs.readFileSync(signatureFile,'binary');
const md = forge.md.sha256.create();
md.update(message);
const verified = publicKey.verify(md.digest().getBytes(), signatureBytes);
if (verified) {
console.log('Signature is valid. Message is authenticated.');
} else {
console.error('Signature is invalid. Message could not be authenticated.');
}
} catch (error) {
console.error('Error during signature verification:', error);
}
}
const publicKeyPem = fs.readFileSync('pub.pem', 'utf-8');
const messageToSign = fs.readFileSync('mess.txt', 'utf-8');
const signatureFile = 'sign.txt';
verifySignature(publicKeyPem, messageToSign, signatureFile);
错误:字节数太少,无法读取 ASN.1 值。
我该如何解决这个问题
为了验证成功,必须在
verify()
的第一个参数中传递消息本身(而不是消息哈希),并且必须在第三个参数中指定'NONE'
作为方案(以便使用默认值RSASSA-PKCS1-V1_5
未使用),如以下示例代码所示(签名是使用您的 OpenSSL 语句生成的):
function verifySignature(publicKeyPem, message, signatureFile) {
try {
const publicKey = forge.pki.publicKeyFromPem(publicKeyPem);
const verified = publicKey.verify(message, signatureBytes, 'NONE');
if (verified) {
console.log('Signature is valid. Message is authenticated.');
} else {
console.error('Signature is invalid. Message could not be authenticated.');
}
} catch (error) {
console.error('Error during signature verification:', error);
}
}
const publicKeyPem = `-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAunF5aDa6HCfLMMI/MZLT
5hDk304CU+ypFMFiBjowQdUMQKYHZ+fklB7GpLxCatxYJ/hZ7rjfHH3Klq20/Y1E
bYDRopyTSfkrTzPzwsX4Ur/l25CtdQldhHCTMgwf/Ev/buBNobfzdZE+Dhdv5lQw
KtjI43lDKvAi5kEet2TFwfJcJrBiRJeEcLfVgWTXGRQn7gngWKykUu5rS83eAU1x
H9FLojQfyia89/EykiOO7/3UWwd+MATZ9HLjSx2/Lf3g2jr81eifEmYDlri/OZp4
OhZu+0Bo1LXloCTe+vmIQ2YCX7EatUOuyQMt2Vwx4uV+d/A3DP6PtMGBKpF8St4i
GwIDAQAB
-----END PUBLIC KEY-----`;
const messageToSign = 'some test data signed without hashing';
const signatureBytes = forge.util.decode64('jmcuQ0vROjdre1S8HkiH/jUYgxQX3n6IR+VsDq99Mq3yewbNxxbrevQ01widgB/iUws1ifavSxNl+Bhyo063ehQVkDfejE1JbdGIzMCqMl8CRK7TpCRSSXzGzL10EpYMK/kaYm0xNc2DH6obG5r7pho+qWmlKFAEolbYNHx70G+GZs0Fr5xnDNEfTKZjDI1X6RT0CPCq7IDVRsjdQJarAj1ngJhYgR3RHY0qdo+7nu5gzGCgpFBCNETafjtMmRs/B5wrS1Hn2ns4m3vjZE0lzbpVVpLEeHIXKokkW7xd9nqo/qmTbtuLcYXpItNEMxMqLLwuUSO+CGcjGiL9Fa9/Ow==');
verifySignature(publicKeyPem, messageToSign, signatureBytes);
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/forge.min.js"></script>
完成这些更改后,验证成功。
说明:
OpenSSL 语句直接填充并签署消息,而不是DigestInfo值的 DER 编码(由摘要的 OID 和消息的哈希值组成)。
因此,要验证的消息不得在 JavaScript 代码中进行哈希处理。并且
'NONE'
指定从签名确定的数据代表消息本身,而不是 DigestInfo 值的 DER 编码,并在验证期间进行相应处理。
请注意,在填充和签名之前,通常会对消息进行哈希处理,并将生成的哈希值完成为 DigestInfo 值的 DER 编码,如 RFC8017 中所述。您的 OpenSSL 声明与此不同。如果您想遵守该标准,则必须调整 OpenSSL 声明。
以下是一些可能性(以 SHA256 为例):
-pkeyopt digest:sha256
添加到 OpenSSL 语句中:
openssl pkeyutl -in messHash.txt -out sign.bin -inkey private.pem -sign -pkeyopt digest:sha256
-rawin -digest sha256
添加到 OpenSSL 声明中(从 v3.0 开始):
openssl pkeyutl -in mess.txt -out sign.bin -inkey private.pem -rawin -digest sha256
openssl dgst -sha256 -sign private.pem -out sign.bin mess.txt
通过这些更改,不需要调整 JavaScript 代码。