node.js 加密签名和 openssl 签名不匹配

node.js crypto signature and openssl signature does not match

我想对 node.js 中的文件执行 RSA-SHA512。我可以计算与 openssl 匹配的给定数据文件的 sha512 哈希。 但是,当尝试在同一哈希上获取数字签名时,node.js 签名与 openssl 签名不同。 下面是一个示例代码片段:

var data = new Buffer(512);
data = fs.readFileSync('/tmp/data');
var pem = fs.readFileSync('/tmp/boot2-prvKey.pem');
var privateKey = pem.toString('ascii');

var signer = crypto.createSign("RSA-SHA256");
signer.update(data);
var sign = signer.sign(privateKey, 'hex');
console.log("SIGN " + sign + '\n');

用于签署数据的 Openssl 命令:

openssl rsautl -sign -in /tmp/data -inkey /tmp/boot2-prvKey.pem -out sig

以上两者生成不同的签名。

我有几个问题 1)我想计算一个文件的RSA-SHA256,所以我先计算整个文件的sha256散列,并将这个散列作为输入传递给签名函数。 这是正确的做法吗? 2)如果是,上面的代码可能出了什么问题?如果不是,正确的方法是什么?

node.js我用的版本是0.10.36,openssl版本是1.0,1.

问题是您的 Openssl 命令只是在没有散列函数的情况下签署您的数据。 您必须首先使用 openssl 散列您的数据,并使用与您的 nodejs 代码 (SHA-256) 中相同的函数,然后使用您的命令对散列进行签名以获得最终签名: openssl rsautl -sign -in /tmp/data -inkey /tmp/boot2-prvKey.pem -out sig

你可以看到在这个命令中你没有指定任何哈希函数。

获取签名:data -> SHA-256 = hash -> RSA = signature

我没有足够的时间来测试它并给你正确的代码,我希望它会有所帮助。

当您向签名程序提供输入时,它可能会假设输入尚未经过哈希处理,并会在签名前对其进行哈希处理。这里的问题是 Node 正在(重新)散列输入,而 rsautl 正在按原样使用输入。 (请注意,即使您在将输入提供给 rsautl 之前单独重新散列输入,它仍然不会匹配,因为 rsautl 不使用 ASN1 编码;见下文。)

要使 OpenSSL 在生成 RSA 签名之前生成 SHA256 哈希(就像 Node 那样),您需要使用带有 -sha256-sign 参数的 dgst 命令:

openssl dgst -sha256 -sign /tmp/boot2-prvKey.pem -hex < /tmp/data

这将散列 /tmp/data 并使用 RSA 对散列进行签名,这正是 Node 的 RSA-SHA256 签名者所做的。

有关详细信息,请参阅 Difference between openSSL rsautl and dgst

The simple answer is that dgst -sign creates a hash, ASN1 encodes it, and then signs the ASN1 encoded hash, whereas rsautl -sign just signs the input without hashing or ASN1 encoding.

Node 的 sign 方法的行为类似于 dgst -sign 而不是 rsautl -sign

Node 似乎没有提供类似 rsautl 的内置机制来进行无散列和 ASN1 编码的签名。因此,您可能需要直接对文档进行签名,而不是对文档的散列进行操作。如果由于某种原因你真的不能这样做,你可以下载 Node rsautl module from NPM,它为 rsautl.

提供节点绑定