OpenSSL - 正确的 RSA 签名生成和验证



我正在学习一些OpenSSL RSA用法。我注意到有两种不同的方法来生成和验证文件签名。一个使用 openssl-dgst(1(,另一个使用openssl-pkeyutl(1(,它们似乎都可以验证、接受私有和公共证书、输出签名文件、接受算法,但它们不可互换。由openssl-pkeyutl生成的签名在验证中不能作为openssl-dgst的签名工作,相反的情况似乎也是如此。即使两个签名文件具有相似的数据结构格式。

注意:这是专门针对 RSA 证书的。我不完全确定 X.509 证书是否存在同样的可能性。

问题:哪个用法更合适?OpenSSL-Pkeyutl还是OpenSSL-DGST

方法1:openssl dgst

# directory/
#     test.txt      - File to create a signature for
#     cert.pem      - Private/Public RSA Key, encrypted with hmacWithSHA256 via PKCS#8
#     cert.pub.pem  - Public Key of cert.pem extracted with `openssl rsa -pubout...`
#     test.sig      - File signature created by OpenSSL
# Create test.sig
$ openssl dgst -sha256 -sign cert.pem -out test.sig test.txt
Enter pass phrase for cert.pem: test
# Verify with the private key
$ openssl dgst -sha256 -verify cert.pub.pem -signature test.sig test.txt
Verified OK
# Verify with the public key
$ openssl dgst -sha256 -prverify cert.pem -signature test.sig test.txt
Enter pass phrase for cert.pem: test
Verified OK

方法2:openssl pkeyutl

# directory/
#     test.txt      - File to create a signature for
#     cert.pem      - Private/Public RSA Key, encrypted with hmacWithSHA256 via PKCS#8
#     cert.pub.pem  - Public Key of cert.pem extracted with `openssl rsa -pubout...`
#     test.sig      - File signature created by OpenSSL
# Create test.sig
$ openssl pkeyutl -sign -in test.txt -out test.sig -inkey cert.pem
Enter pass phrase for cert.pem: test
# Verify with the private key
$ openssl pkeyutl -verify -sigfile test.sig -in test.txt -inkey cert.pub.pem -pubin
Signature Verified Successfully
# Verify with the public key
$ openssl pkeyutl -verify -sigfile test.sig -in test.txt -inkey cert.pem
Enter pass phrase for cert.pem: test
Signature Verified Successfully

好的,我第一次错过了您在第二种方法中省略了任何哈希。大多数人偶然发现了带有dgst -sign的正确哈希和符号与带有dgstrsautlpkeyutl的稍微不正确的哈希和符号之间的区别,而不是您所做的完全不正确的符号。

所以答案是:pkeyutl单独是完全错误的。 (rsautl一个人也是如此。

RSA 签名原语本身仅限于少量数据,主要取决于密钥大小,现在大约 240 字节。大多数应用程序,如文档、电子邮件、代码和通信(SSH、SSL/TLS(需要处理比这更多的数据,所以我们总是先对数据进行哈希处理,然后对哈希进行 RSA 签名——加上填充,这是问题通常出现的地方,见下文。DSA和ECDSA以及EdDSA的一种变体也是如此,尽管EdDSA的首选变体使用不同的解决方案。

请参阅当前版本的 PKCS1 标准(或其任何前身(,注释 8.2.1 与 9.2 相结合给出了一个四步过程:对数据进行哈希处理,在 ASN.1 中"编码"哈希,有效地添加前缀(填充(,如"注释"所示,用另一个填充(块类型 1(显式填充编码的哈希,最后计算 RSA 原语 rdmod n。 (8.2.2 中的验证执行相同的操作,但颠倒了 RSA 原语。

openssl dgst -$hash -sign pubkey正确地执行组合过程。

openssl dgst -$hash -binary | openssl pkeyutl -sign -pkeyopt digest:$hash也是正确的(尽管更复杂(。

openssl dgst -$hash -binary | openssl pkeyutl -sign没有-pkeyoptopenssl dgst -$hash -binary | openssl rsautl -sign错了,但很微妙;他们做哈希垫符号,这似乎是正确的,但他们不做填充的 ASN.1 部分。 这就是我认为是重复的先前许多Q中解释的差异。

使用临时文件或其他介质而不是管道有效地执行相同操作的变体同样正确或不正确;这允许将操作的哈希部分与其他部分分开,如果数据位于与键不同的系统或设备上(反之亦然(,这可能很有用。

没有前面的哈希步骤openssl pkeyutl -sign是公然错误的。


我不确定您对"RSA 证书"和"X.509 证书"提出的问题。您使用的两种文件格式 - PKCS8用于私钥,OpenSSL称为公钥的PUBKEY - 都是密钥而不是任何类型的证书,即使您误导性地为它们命名以cert开头。这两种文件格式都是"通用的"——它们支持多种算法,包括 RSA 和许多其他算法。X.509 证书包含公钥和许多其他数据,并且是支持 RSA 和许多其他算法的不同通用格式。因此,您可以有一个包含 RSA 私钥的私钥 (PKCS8

( 文件,通常简称为 RSA 私钥文件,包含 RSA 公钥的公钥文件,通常简称为 RSA 公钥文件,和/或包含 RSA 公钥的 (X.509( 证书文件,通常简称为 RSA 证书。dgst -sign/verify分别只使用私钥或公钥文件,从不使用证书。它支持多种算法,而不仅仅是 RSA。

pkeyutl -sign仅使用私钥文件,但-verify可以使用私钥文件、公钥文件证书文件,后两者具有-pubin-certin。它支持多种算法。rsautl接受相同的文件格式,但仅支持 RSA。

最新更新