【问题标题】:Difference between signing with SHA256 vs. signing with RSA-SHA256使用 SHA256 签名与使用 RSA-SHA256 签名之间的区别
【发布时间】:2023-03-10 22:04:01
【问题描述】:

我使用 node.js 玩数字签名。出于测试目的,我创建了一些 XML 数据的数字签名,首先仅使用 SHA256,然后使用 RSA-SHA256。

让我困惑的是两种签名方法都创建了完全相同的签名。两个签名是相同的。如果它们相同,那么为什么要使用两种不同的方法(SHA256 与 RSA-SHA256)?

我在下面包含代码:

var crypto = require('crypto'),
    path   = require('path'),
    fs     = require('fs'),

    pkey_path = path.normalize('private_key.pem'),
    pkey = '';

function testSignature(pkey) {
    var sign1 = crypto.createSign('RSA-SHA256'),
        sign2 = crypto.createSign('SHA256');

    fs.ReadStream('some_document.xml')
        .on('data', function (d) {
            sign1.update(d);
            sign2.update(d);
        })
        .on('end', function () {
            var s1 = sign1.sign(pkey, "base64"),
                s2 = sign2.sign(pkey, "base64");

            console.log(s1);
            console.log(s2);
        });
}

// You need to read private key into a string and pass it to crypto module.
// If the key is password protected, program execution will stop and
// a prompt will appear in console, awaiting input of password.

testSignature(fs.readFileSync(pkey_path));

上面的代码输出一些字符串,即签名,然后再次输出完全相同的字符串,这也是相同数据的签名,但使用 - 据说 - 不同的算法创建,但它与前一个相同.. .

【问题讨论】:

  • @jweyrich 不幸的是它不相关。

标签: node.js rsa digital-signature sha256


【解决方案1】:

仅靠 SHA256 无法创建签名。

SHA256 是一种散列算法;即创建代表任意大量数据的短指纹编号的算法。为了产生一个签名,这个指纹仍然必须以某种方式处理,以允许识别一些私人签名密钥的持有者。一种这样的处理方法是使用 rsa 密钥对的私钥加密指纹,允许其他人使用关联的公钥解密结果,从而验证私钥的保管者确实是签名者。

在您的加密 API 的上下文中,RSA 加密方案要么是未明确命名处理时的默认处理,要么是从您在 sign 调用中用作参数的私钥推导出来的处理类型 -- - 如果是 RSA 私钥,则使用 RSA;如果是 DSA 密钥,则使用 DSA; ...

【讨论】:

    【解决方案2】:

    您正在查看的是 PKCS#1 v1.5 签名的两倍。这是签名的确定性方案,因此它总是返回相同的结果(将此与 PSS 方案进行比较,后者是随机的,提供更好的安全性)。 RSA PKCS#1 v1.5 签名生成和 PSS 签名生成在RFC 3447(也称为 RSA v2.1 规范)中定义。

    如果您使用 RSA 512 位的代码(仅用于测试,使用 2048 位或以上的密钥),那么您将得到以下结果:

    私钥:

    -----BEGIN RSA PRIVATE KEY-----
    MIIBOgIBAAJBALLA/Zk6+4JFJ+XdU6wmUkuEhGa8hLZ+m6J3puZbc9E+DSt7pW09
    yMYwHF5MMICxE86cA6BrLjQLUUwvquNSK0ECAwEAAQJAcI/w4e3vdRABWNFvoCcd
    iWpwSZWK6LR/YuZ/1e1e2DJw+NXyPXbilSrLvAdxnjlWTsTxUiEy1jFh36pSuvMk
    AQIhAO4WtgysOoWkyvIOLIQwD0thWfdHxTpxqfd6flrBJ91hAiEAwDOQqHhnSeET
    +N/hwUJQtCkHBJqvMF/kAi4Ry5G+OeECIEg1Exlc0pLdm781lUKx4LGX4NUiKyrC
    di3cNJ4JnrGBAiEAi2gbYYbLbDO8F8TTayidfr9PXtCPhyfWKpqdv6i7cCECIH7A
    6bh0tDCl6dOXQwbhgqF4hXiMsqe6DaHqIw8+XLnG
    -----END RSA PRIVATE KEY-----
    

    签名为 base 64(使用您的代码):

    YY6sur9gkHXH23cUbDMYjCJYqDdBK8GKp4XyRNl8H09cW8H/gKQI9Z6dkLMhNh7oPq1yABCRfTP8yRtfLVj7FA==
    

    十六进制

    618eacbabf609075c7db77146c33188c2258a837412bc18aa785f244d97c1f4f5c5bc1ff80a408f59e9d90b321361ee83ead720010917d33fcc91b5f2d58fb14
    

    使用 RAW RSA 解密(即仅使用公共指数进行模幂运算):

    0001ffffffffffffffffffff003031300d0609608648016503040201050004202af565b95e5f4479492c520c430f07ae05d2bcff8923322e6f2ef6404d72ac64
    

    这是一个非常清晰的 PKCS#1 签名示例,通过 FF 填充很容易识别,然后是 ASN.1 结构(以 30 开头,SEQUENCE):

    SEQUENCE (2 elem)
      SEQUENCE (2 elem)
      OBJECT IDENTIFIER 2.16.840.1.101.3.4.2.1 {joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101) csor(3) nistAlgorithm(4) hashAlgs(2) sha256(1)}
        NULL
      OCTET STRING(32 byte) 2AF565B95E5F4479492C520C430F07AE05D2BCFF8923322E6F2EF6404D72AC64
    

    所以最后是哈希,在这种情况下只是 Test 123\n,因为我今天不想输入任何 XML。

    $ sha256sum some_document.xml 
    2af565b95e5f4479492c520c430f07ae05d2bcff8923322e6f2ef6404d72ac64  some_document.xml
    
    $ sha256sum some_document.xml 
    2af565b95e5f4479492c520c430f07ae05d2bcff8923322e6f2ef6404d72ac64  some_document.xml
    

    【讨论】:

    • 非常感谢这些名字!多年来,我一直在寻找这两种不同格式的 SHA256WithRSA(2048) 签名的正确名称!因此,确定性的格式称为“PKCS#1 v1.5”格式,这是 JAVA 中的 DEFAULT。第二种称为“PSS”格式。终于,我明白了!
    猜你喜欢
    • 2012-05-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-14
    • 2019-04-24
    • 1970-01-01
    • 2017-06-22
    • 1970-01-01
    相关资源
    最近更新 更多