3

我有一个 256 位私钥,我想用它来签署 SHA-1 摘要(20 字节)。直接使用openssl似乎可以工作

回声无关紧要 | openssl dgst -sha1 -binary | openssl rsautl -sign -inkey 256bit_private_key.pem | openssl enc -base64

给了我预期的 Base64 输出。

但是使用 OpenSSL 失败并显示“错误:04075070:rsaroutines:RSA_sign:digest too big for rsa key”。正如您在下面看到的,我将 20 字节 (SHA_DIGEST_LENGTH=20) SHA-1 摘要作为输入传递给 RSA_sign。即使有填充,它也不应该超过我可以用 256 位模数密钥加密的最大 32 字节?!

unsigned char digest[SHA_DIGEST_LENGTH];
SHA1(message, messageSize, digest);

unsigned int privateKeySize = RSA_size(privateKey); // 256 bits = 32 bytes
unsigned char* signature = new unsigned char[privateKeySize];
unsigned int signatureSize;

int res = RSA_sign(NID_sha1, digest, SHA_DIGEST_LENGTH, signature, &signatureSize, privateKey);

if(res == 0)
{
    int err = ERR_get_error(); // 67588208
    char *s = ERR_error_string(err, 0); // error:04075070:lib(4):func(117):reason(112)

    delete [] signature;

    [...]
}

我在代码中做错了什么?

4

3 回答 3

3

看看这个答案rsautl折旧有利于pkeyutl

本质上,RSA 签名应该使用 RSA-PSS 签名填充方案以确保安全,并且 RSA-PSS 将严格大于摘要,因为需要通信盐。此外,RSA_sign将摘要作为签名方案的一部分,因此您的代码将对摘要进行摘要。您想改为直接传递消息,或者RSA_private_encrypt与合适的RSA_padding_add_x调用结合使用。

正如我在评论中所说,256 位密钥对于对称算法来说足够安全,但破解 RSA 私钥将是微不足道的(在几年前的机器上大约需要 4 分钟)。使用最少的 1024 位密钥(可能是 2048 或 4096 位密钥)将为您提供大致相当于 128 位对称算法的安全级别。

于 2013-02-26T18:58:01.557 回答
3

Re Peter Elliott:不完全是。

RFC8017 第 8.2.1 节(和 9.2,在 rfc4347 和 rfc3447 中类似)中的 PKCS1v1_5 标准序列是散列,在 ASN.1 中编码,填充('type 1')和 modexp d。(PSS 省略了 ASN.1 步骤并使用不同的填充。)

OpenSSL(低级)RSA_sign执行最后三个(使用 v1.5 填充)但不是第一个 - 即它编码散列但它不执行散列;甚至更低RSA_private_encrypt的是最后两个。更高级别的信封模块(原始EVP_Sign{Init,Update,Final}*,增强EVP_DigestSign*)完成所有四个。正是 ASN.1 编码使该值对于 256 位密钥来说太大了——正如所说的那样,无论如何都是可以破解的。

rsautl只执行最后两个步骤而不是编码,因此它运行但给出非标准结果。 pkeyutl对于 RSA,默认情况下也是如此,但可以被告知进行编码。

此外,PSS 具有更好的安全证明,但据我所知,v1.5 没有受到实际攻击,它仍然被广泛使用。如果你有PSS的选择(双方/各方都支持)选择它,但不用担心使用v1.5。

于 2013-10-10T20:55:18.357 回答
1

猜猜我找到了解决方案。openssl rsautl -sign使用RSA_private_encrypt而不是RSA_sign(我所期望的)。RSA_sign创建比我提供的 20 字节消息更长的结构,因此它会因给定错误而失败。

于 2013-02-26T15:18:02.013 回答