5

我正在尝试编写代码来验证一些 RSA 签名。签名是使用 OpenSSL 命令行工具生成的,使用此命令行的等效项:

openssl dgst -sha1 -sign private_key_file.pem < binary_data_file > sig

我正在尝试使用libtomcrypt来进行验证:

https://www.libtom.net/

这是 RSA 验证函数的调用签名libtomcrypt

int rsa_verify_hash_ex(
    const unsigned char *sig, unsigned long siglen,  // signature to verify
    const unsigned char *hash, unsigned long hashlen,  // hash value to check against sig
    int padding,  // defined constant value, see below
    int hash_idx,  // identifies which hash algorithm, see below
    unsigned long saltlen,  // specify salt length, see below
    int *stat,  // output parameter, returns whether verify succeeded or not
    rsa_key *key);  // RSA public key to use for verify

如果该函数运行没有错误,则返回 0,否则返回错误代码。如果运行无误,则stat输出参数指示签名是否经过验证。

大多数参数看起来很简单:传入要检查的签名、用于比较它的哈希值以及用于检查的 RSA 密钥。 hash_idx从附带的示例代码中可以清楚地看出libtomcrypt;它是支持的哈希算法表的索引,我可以找到与此代码片段一起使用的正确值:hash_idx = find_hash("sha1")

但我想知道paddingandsaltlen值。 padding不用太担心,因为只有两个可能的值,我可以同时尝试它们。但是我应该通过saltlen什么?

用于 RSA 验证的 OpenSSL 函数的 OpenSSL 文档不显示saltlen参数。openssl dgst(即 的结果)的手册页man dgst没有讨论盐。

所以我的问题:

  • 如何确定要使用的正确盐长度?
  • OpenSSL 的dgst命令是否在输入中插入任何额外的内容,例如:(stdin)=

(我(stdin)=通过搜索 StackOverflow 找到了那个东西:Why are the RSA-SHA256 signatures I generate with OpenSSL and Java different?

  • libtomcrypt还有一个名为pkcs_1_pss_decode()“解码 PSS 编码签名块”的函数。有没有可能这是我需要调用的函数?

感谢你给与我的帮助。

编辑:感谢以下来自@Jonathan Ben-Avraham 的帮助,我今天能够完成这项工作。我的问题的答案分别是:

  • 使用长度 0 作为盐,完全没有盐。
  • 不,OpenSSL 没有插入任何额外的东西,例如(stdin)=
  • 我需要调用rsa_verify_hash_ex(),并且需要将padding参数指定为LTC_LTC_PKCS_1_V1_5
4

2 回答 2

8

无盐:

首先,生成数据的二进制 SHA1 哈希:

openssl dgst -sha1 -binary -out hash1 some_data_file

这是一个 SHA1 哈希或摘要。文件中没有添加盐some_data_fileopenssl dgst -sha1本身不加盐。请注意,输出文件只是一个没有加盐的 20 字节 SHA1 哈希。如果有盐,则哈希必须包含它,可能在保存 SHA1 哈希的最后 20 个字节之前添加。

hash1接下来,使用您的私钥签署 SHA1 哈希文件:

openssl pkeyutl -sign -in hash1 -inkey privkey.pem -pkeyopt digest:sha1 -out sig1

现在签名some_data_fileopenssl dgst

openssl dgst -sha1 -sign privkey.pem < some_data_file > sig2

最后,比较两个签名:

diff sig1 sig2

你应该看到它们是一样的。这告诉我们,在不加盐的情况下对文件的原始 SHA1 哈希进行签名与使用openssl dgst -sha1 -sign命令对文件进行签名是相同的,因此该openssl dgst -sha1 -sign命令在为sig2.

另请注意,您无法使用 deprecated 获得相同的结果rsautl

openssl rsautl -sign -in hash1 -inkey privkey.pem -out sig1

而不是openssl pkeyutl, 因为openssl rsautl -sign没有按照 RFC3447 第 9.2 节第 2 步中定义的 RSASSA-PKCS1-v1_5 的要求对 DigestInfo 进行 ASN.1 编码。(这就是为什么你需要-pkeyopt digest:,即使它pkeyutl -sign本身不做任何散列。)看这个SE发帖了解详情。

于 2013-04-27T22:13:03.057 回答
3

需要强调的一件事:一定要传递散列而不是实际数据。这让我迷惑了一段时间。这是一个有效的片段(但使用 sha256):

void
verify_tomcrypt(unsigned char *keyblob, size_t klen,
                unsigned char *payload, size_t dlen,
                unsigned char *signature, size_t slen)
{
    rsa_key key;
    int stat;
    unsigned long len;
    unsigned char digest2[SHA256_DIGEST_LENGTH];

    ltc_mp = ltm_desc;
    register_hash(&sha256_desc);

    /* try reading the key */
    if (rsa_import(keyblob, klen, &key) != CRYPT_OK) {
        printf("Error reading key\n");
        exit(-1);
    }

    int hash_idx = find_hash("sha256");
    if (hash_idx == -1) {
        printf("LTC_SHA256 not found...?\n");
        exit(-1);
    }
    len = sizeof(digest2);
    if (hash_memory(hash_idx, payload, dlen, digest2, &len) != CRYPT_OK) {
        printf("sha256 fails...?\n");
        exit(-1);
    }

    if (rsa_verify_hash_ex(signature, slen, digest2, sizeof(digest2), LTC_LTC_PKCS_1_V1_5, hash_idx, 0, &stat, &key) == CRYPT_OK) {
        if (stat == 1)
            printf("Tomcrypt: Signature OK!\n");
        else
            printf("Tomcrypt: Signature NOK?\n");
    } else {
        printf("Tomcrypt: Signature error\n");
    }
}
于 2015-12-10T13:33:54.717 回答