我正在学习一些OpenSSL RSA的用法。我注意到有两种不同的生成和验证文件签名的方法。一种是通过使用 openssl-dgst(1) 另一个使用 openssl-pkeyutl(1) 而它们似乎都能验证、接受私证书和公证书、输出签名文件、接受算法,但它们不能互换。由 openssl-pkeyutl 在验证中不能作为带有 openssl-dgst而相反的情况似乎也是如此。尽管两个签名文件的数据结构格式相似。
请注意,这是专门针对RSA证书的。 这是专门针对RSA证书的 我不完全确定X.509证书是否存在同样的可能性。
问题:哪种用法更正确? 哪种用法更正确?openssl-pkeyutl 或 openssl-dgst?
方法一: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
方法二: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
与稍有不妥的哈希符号的对比 dgst
和 rsautl
或 pkeyutl
而不是你所做的完全不正确的只签。
所以答案是: pkeyutl
ALONE是完全错误的。 (所以是 rsautl
单独的。)
RSA签名基元本身对少量数据的限制,主要取决于密钥大小,现在大约是240字节。大多数应用如文档、电子邮件、代码和通信(SSH、SSLTLS)都需要处理比这更多的数据,所以我们 始终 先对数据进行散列,然后对散列进行RSA签名--再加上填充,这也是通常出现问题的地方,见下文。对于DSA和ECDSA来说也是如此,而且。一个 的变体,尽管EdDSA的首选变体使用了不同的解决方案。
参见 现行PKCS1标准版本 (或它的任何前辈)和注释8.2.1结合9.2给出了一个四步过程:散列数据,在ASN.1中对散列进行 "编码",这实际上是增加了一个前缀(填充),如 "注释 "所示,用另一个填充(块类型1)显式地对编码后的散列进行填充,最后计算RSA基元r。d mod 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
WITHOUT -pkeyopt
或openssl dgst -$hash -binary | openssl rsautl -sign
是错误的,但很微妙;他们做了哈希-垫号,这似乎是正确的,但他们没有做ASN.1部分的填充。这是在我认为是重复的之前的许多问题中解释的区别。
使用临时文件或其他介质代替管道做有效相同的事情的变体同样正确或不正确;这允许将操作的散列部分与其他部分分开,如果数据在与密钥不同的系统或设备上(反之亦然),这可能是有用的。
openssl pkeyutl -sign
没有前面的散列步骤是公然错误的。
我不太清楚你问的 "RSA证书 "和 "X.509证书 "是什么。你使用的两种文件格式--PKCS8代表私钥,OpenSSL称为PUBKEY代表公钥--都是。钥匙 而不是任何类型的证书,尽管你误导性地给他们起了一个名字,以 cert
. 这两种文件格式都是 "通用的"--它们支持多种算法,包括RSA和许多其他算法。X.509证书 包含 a publickey和MUCH其他数据,并且是一个 不同 的通用格式,支持RSA和许多其他算法。因此,你可以有一个包含 RSA 私钥的私钥文件(PKCS8),通常被简单地称为 RSA 私钥文件,一个包含 RSA 公钥的公钥文件,通常被简单地称为 RSA 公钥文件,或者一个包含 RSA 公钥的(X.509)证书文件,通常被简单地称为 RSA 证书。
dgst -sign/verify
分别只使用一个私钥或公钥文件,从不使用证书。它支持多种算法,而不仅仅是RSA。
pkeyutl -sign
只使用一个私钥文件,但 -verify
可以使用私钥文件、公钥文件。或 证书文件,并附有 -pubin
或 -certin
为后两者。它支持多种算法。rsautl
接受相同的文件格式,但只支持RSA。