RSA-SHA1 签名在 JavaScript 和 PHP 中不同

RSA-SHA1 signature differs in JavaScript and PHP

我需要在 nodeJS 中创建一个 RSA-SHA1 签名,我正在使用以下代码

const crypto = require("crypto");
const sign = crypto.createSign('RSA-SHA1');
sign.update(data);
const result = sign.sign(privateKey, 'base64')
console.log(result);

我仔细检查了我的代码结果是否正确,如果我使用 select sha1WithRSA 算法,我与在线工具的结果相同,我在 PHP 中也得到相同的结果我使用 openssl_sign 函数

我需要为一家银行签署数据API,很遗憾他们不接受我的签名并且他们没有 NodeJS 实现

他们的文档也一团糟,这是C#他们文档

的实现
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.FromXmlString(“<RSAKeyValue><Modulus>oQRshGhLf2Fh...”);
string data = "DATA";
byte[] signMain = rsa.SignData(Encoding.UTF8.GetBytes(data), new
SHA1CryptoServiceProvider());
sign = Convert.ToBase64String(signMain); 

谁能帮我理解为什么我的签名不等于 C# 实现(我不检查 C# 的结果,但他们的服务器是用 C# 编写的,他们不验证我的签名)

PHP 中其他官方代码片段的以下链接与他们的服务器一起工作,但结果不同于 PHP 中的标准 openssl_sign 函数:index L211-L216, RSAProcessor L45, rsa.class L17-L22, rsa.class L63-L82 .

  1. 他们的实现是非标准的 RSA-SHA1 吗?
  2. 他们不接受我的 NodeJS 代码有什么问题?

NodeJS代码和发布的C#代码为相同的待签名数据和相同的私钥提供相同的签名。

来自已发布的 link it can be seen that the SHA1 hashed data is passed to RSA::rsa_sign,但 SHA1 摘要 ID 无处可寻。与此一致的是,函数参数中也没有指定摘要。

填充本身发生在 RSA::add_PKCS1_padding 中。这里,为了签名,应用 RSASSA-PKCS1-v1_5。如前所述,在不考虑摘要 ID 的情况下处理传递的(已经散列的)数据。

因此,PHP代码创建的签名不符合RSASSA-PKCS1-v1_5,而NodeJS代码和C#代码都符合标准。

据我所知,当使用 NodeJScrypto 模块的 sign 方法签名时,摘要必须始终指定并且摘要 ID 始终设置为 隐式 ,因此 PHP 代码的签名无法用此复制。

如果使用相同的数据和私钥,允许设置摘要ID的替代方法是crypto.privateEncrypt. The following code generates the signature of the PHP code or the signing process described in the posted link

var crypto = require('crypto')

var sha1 = crypto.createHash('sha1')
sha1.update(data)
var hash = sha1.digest()

var signature = crypto.privateEncrypt({key: privateKey, padding: crypto.constants.RSA_PKCS1_PADDING}, hash) 
console.log(signature.toString('base64'))

另一个问题是这个签名是否可以被银行验证API。毕竟API的文档显然包含了两个不一致的实现,所以文档看起来不是很可靠。此外,其他缺陷当然是可能的,请参阅 fgrieu 的评论。