[英]OpenSSL RSA signature verification: hash and padding?
I am trying to write code to verify some RSA signatures.我正在尝试编写代码来验证一些 RSA 签名。 The signatures were made using the OpenSSL command-line tool, using the equivalent of this command line:
签名是使用 OpenSSL 命令行工具生成的,使用等效于以下命令行:
openssl dgst -sha1 -sign private_key_file.pem < binary_data_file > sig
I am trying to use libtomcrypt
to do the verify:我正在尝试使用
libtomcrypt
进行验证:
https://www.libtom.net/ https://www.libtom.net/
Here is the calling signature of the RSA verification function in libtomcrypt
:这是
libtomcrypt
RSA 验证函数的调用签名:
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
This function returns a 0 if it operates without error, otherwise returns an error code.如果该函数运行没有错误,则返回 0,否则返回错误代码。 If it operates without error, the
stat
output parameter indicates whether the signature verified.如果运行无误,则
stat
输出参数指示签名是否经过验证。
Most of the arguments seem straightforward: pass in the signature to check, the hash value to use to compare it, and the RSA key to use for the check.大多数参数看起来很简单:传入要检查的签名、用于比较的哈希值以及用于检查的 RSA 密钥。
hash_idx
is clear from the example code included with libtomcrypt
; hash_idx
是从包含在示例代码明确libtomcrypt
; it is an index into a table of supported hash algorithms, and I can find the correct value to use with this code snippet: hash_idx = find_hash("sha1")
它是支持的哈希算法表的索引,我可以找到与此代码片段一起使用的正确值:
hash_idx = find_hash("sha1")
But I'm wondering about the padding
and saltlen
values.但我想知道
padding
和saltlen
值。 padding
doesn't worry me too much, as there are only two possible values, and I can just try them both. padding
不会让我太担心,因为只有两个可能的值,我可以同时尝试它们。 But what should I pass for saltlen
?但是我应该为
saltlen
传递什么?
The OpenSSL documentation for the OpenSSL functions for RSA verify don't show a saltlen
parameter.用于 RSA 验证的 OpenSSL 函数的 OpenSSL 文档未显示
saltlen
参数。 The man page for openssl dgst
(ie the result of man dgst
) does not discuss salt. openssl dgst
的手册页(即man dgst
的结果)没有讨论盐。
So my questions:所以我的问题:
dgst
command insert any extra stuff in the input, such as: (stdin)=
dgst
命令是否在输入中插入任何额外的东西,例如: (stdin)=
(I found that (stdin)=
thing by searching StackOverflow: Why are the RSA-SHA256 signatures I generate with OpenSSL and Java different? ) (我通过搜索 StackOverflow 发现
(stdin)=
东西: 为什么我用 OpenSSL 和 Java 生成的 RSA-SHA256 签名不同? )
libtomcrypt
also has a function called pkcs_1_pss_decode()
which is documented to "decode a PSS encoded signature block". libtomcrypt
还有一个名为pkcs_1_pss_decode()
的函数,它被记录为“解码 PSS 编码的签名块”。 Is there any chance that this is the function I need to call? Thanks for any help you can give me.感谢你给与我的帮助。
EDIT: thanks to the help below, from @Jonathan Ben-Avraham, I was able to get this working today.编辑:感谢以下来自@Jonathan Ben-Avraham 的帮助,我今天能够完成这项工作。 The answers to my questions are, respectively:
我的问题的答案分别是:
(stdin)=
(stdin)=
rsa_verify_hash_ex()
, and I needed to specify the padding
argument as LTC_LTC_PKCS_1_V1_5
.rsa_verify_hash_ex()
,并且需要将padding
参数指定为LTC_LTC_PKCS_1_V1_5
。No salt:无盐:
First, generate a binary SHA1 hash of your data:首先,生成数据的二进制 SHA1 哈希:
openssl dgst -sha1 -binary -out hash1 some_data_file
This is an SHA1 hash or digest.这是一个 SHA1 哈希或摘要。 There is no salt prependended to the file
some_data_file
.文件
some_data_file
没有预先添加盐。 The openssl dgst -sha1
itself does not add salt. openssl dgst -sha1
本身不加盐。 Note that the output file is just a 20 byte SHA1 hash with no salt.请注意,输出文件只是一个没有加盐的 20 字节 SHA1 哈希。 If there were salt, the hash would have to include it, probably prepended before the last 20 bytes that hold the SHA1 hash.
如果有盐,散列必须包含它,可能在保存 SHA1 散列的最后 20 个字节之前。
Next, sign the SHA1 hash file hash1
with your private key:接下来,使用您的私钥对 SHA1 哈希文件
hash1
进行签名:
openssl pkeyutl -sign -in hash1 -inkey privkey.pem -pkeyopt digest:sha1 -out sig1
Now sign the some_data_file
with openssl dgst
:现在签署
some_data_file
与openssl dgst
:
openssl dgst -sha1 -sign privkey.pem < some_data_file > sig2
Finally, compare the two signatures:最后,比较两个签名:
diff sig1 sig2
and you should see that they are the same.你应该看到它们是一样的。 This tells us that signing the raw SHA1 hash of a file with no salt is the same as using the
openssl dgst -sha1 -sign
command to sign the file, so it must be that the openssl dgst -sha1 -sign
command also did not use any salt when generating its SHA1 hash for sig2
.这告诉我们,对文件的原始 SHA1 哈希进行签名而没有使用 salt 与使用
openssl dgst -sha1 -sign
命令对文件进行签名是一样的,所以一定是openssl dgst -sha1 -sign
命令也没有使用为sig2
生成其 SHA1 哈希时的任何盐。
Note also that you cannot achieve the same result using the deprecated rsautl
:另请注意,使用已弃用的
rsautl
无法获得相同的结果:
openssl rsautl -sign -in hash1 -inkey privkey.pem -out sig1
instead of openssl pkeyutl
, because openssl rsautl -sign
does not do the ASN.1 encoding of DigestInfo as required by RSASSA-PKCS1-v1_5 defined in eg RFC3447 section 9.2 step 2. (This is why you need -pkeyopt digest:
even though pkeyutl -sign
itself doesn't do any hashing.) See this SE post for details.而不是
openssl pkeyutl
,因为openssl rsautl -sign
不会按照 RFC3447 第 9.2 步第 2 节中定义的 RSASSA-PKCS1-v1_5 要求对 DigestInfo 进行 ASN.1 编码。(这就是为什么您需要-pkeyopt digest:
即使pkeyutl -sign
本身不做任何散列。)有关详细信息,请参阅此 SE 帖子。
One thing to emphasize: Be sure to pass the hash instead of the actual data.需要强调的一件事:确保传递散列而不是实际数据。 That threw me off for some time.
这让我失望了一段时间。 Here's a snippet that works (but use sha256):
这是一个有效的片段(但使用 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");
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.