【问题标题】:OpenSSL - Proper RSA Signature Generation and VerificationOpenSSL - 正确的 RSA 签名生成和验证
【发布时间】:2020-09-08 16:06:50
【问题描述】:

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

注意:这是专门针对 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

【问题讨论】:

标签: encryption openssl rsa digital-signature


【解决方案1】:

好的,我第一次错过了您在第二种方法中省略了 any 散列。大多数人偶然发现了使用dgst -sign 的正确散列和签名与使用dgstrsautlrsautlpkeyutl 的稍微不正确的散列和签名之间的区别,而不是您所做的完全不正确的仅签名。

所以答案是:pkeyutl 单独是完全错误的。rsautl 单独也是如此。)

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

参见current version of the PKCS1 standard(或其任何前身),注释 8.2.1 结合 9.2 给出了一个四步过程:散列数据,在 ASN.1 中“编码”散列,这实际上是添加前缀 ( padding),如“注释”所示,用另一个填充(块类型 1)显式填充编码的哈希,最后计算 RSA 原语 rd 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 没有-pkeyoptopenssl dgst -$hash -binary | openssl rsautl -sign 错了,但很微妙;他们做 hash-pad-sign,这似乎是正确的,但他们不做填充的 ASN.1 部分。 这是我认为是重复的许多先前 Q 中解释的差异。

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

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


我不太确定您对“RSA 证书”和“X.509 证书”的要求是什么。您使用的两种文件格式 - PKCS8 用于私钥,OpenSSL 称为 PUBKEY 用于公钥 - 是 keys 而不是任何类型的证书,即使您误导性地给它们提供了以 cert 开头的名称.这两种文件格式都是“通用的”——它们支持多种算法,包括 RSA 和许多其他算法。 X.509 证书包含一个公钥和许多其他数据,并且是一种支持 RSA 和许多其他算法的不同通用格式。因此,您可以拥有一个包含 RSA 私钥且通常简称为 RSA 私钥文件的私钥 (PKCS8) 文件、一个包含 RSA 公钥且通常简称为 RSA 公钥文件的公钥文件,和/或 (X. 509) 证书文件,其中包含 RSA 公钥,通常简称为 RSA 证书。

dgst -sign/verify 分别只使用私钥或公钥文件,从不使用证书。它支持多种算法,不仅是 RSA。

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

【讨论】:

  • 非常感谢您的详细解释。尤其是PKCS8私钥、RSA公钥、X.509证书的应用。以及有关填充使用的说明。对于不正确的术语和参考资料,我深表歉意。
猜你喜欢
  • 1970-01-01
  • 2017-06-22
  • 1970-01-01
  • 2013-04-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多