OpenSSL: 使用私钥加密,公钥解密RSA

9
我想使用OpenSSL和RSA算法,使用私钥加密一个文件:
openssl rsautl -in txt.txt -out txt2.txt -inkey private.pem -encrypt

现在,如果我执行解密操作:
openssl rsautl -in txt2.txt -pubin -inkey public.pem -decrypt

这个操作需要私钥

我知道在加密时应该使用公钥,而如果我使用私钥,则会得到一个签名。

但是,出于学习目的,我想这样做。


2
我的猜测是,在第一条命令中,即使您传递了一个私钥,它仅读取文件的前两个组件作为公钥,并执行公钥操作。您必须使用签名和验证子命令来完成您试图做的事情。 - President James K. Polk
2个回答

5

您正在错误使用密钥。在公钥加密中,加密使用公钥:

openssl rsautl -in txt.txt -out txt2.txt -inkey public.pem -pubin -encrypt

解密时,使用与公钥相关的私钥:

openssl rsautl -in txt2.txt -inkey private.pem -decrypt

私钥(不包括 -pubin)可用于加密,因为它实际上包含了公共指数。需要注意的是,RSA 通常不应直接用于加密数据,而只应用于“封装”(RSA-KEM)或“包装”用于对称加密的密钥。
但您提到您实际上想学习签名。虽然历史上 RSA 签名有时被描述为“使用私钥加密”,但该描述是误导性的,并且实际上实现该描述被发现是不安全的。签名和验证实际上是与加密和解密分开的不同操作,而 rsautl 只执行其中的部分。例如,您可以进行以下操作:
# hash the data and encode the result in ASN.1 
openssl rsautl -sign -in hashenc.dat -out sig.dat -inkey private.pem
...
# on the recipient (with signature and purportedly correct data)
openssl rsautl -verify -in sig.dat -out hashenc.dat -inkey public.pem -pubin 
# or often more appropriate use a certificate for the public key
openssl rsautl -verify -in sig.dat -out hashenc.dat -inkey cert.pem -certin
# now either decode hashenc.dat and compare the hash
# to a new hash of the data (which should be the same)
# or compare all of hashenc.dat to an encoding of a new hash

相反,最好使用openssl dgst,它按照PKCS1 例如rfc8017规定的整个签名和验证序列执行。例如,对于使用SHA256的RSASSA-PKCS1v1_5签名:

openssl dgst -sha256 -sign private.pem -in data.txt -out sig.dat
# or can be abbreviated
openssl sha256 -sign private.pem -in data.txt -out sig.dat
# hashes the data, encodes the hash, does type 1 padding and modexp d
...
openssl dgst -sha256 -verify public.pem -in data.txt -signature     sig.dat
# or abbreviated 
openssl sha256 -verify public.pem -in data.txt -signature sig.dat 
# does modexp e and type 1 unpadding, and compares the result to a hash of the data

# notice you don't specify which key is public or private
# because this command knows what to expect

# however it does not accept the public key from a certificate, 
# you must extract the public key from the cert first

此表单(但不包括 rsautl)还支持更新且技术更好的,但不太常用的 PSS 填充。这仅在 dgst 手册页面上引用,并在 pkeyutl 手册页面上进行了大部分记录,这并不明显。

在其他更相关的堆栈上,请参见例如: https://security.stackexchange.com/questions/93603/understanding-digitial-certifications
https://security.stackexchange.com/questions/87325/if-the-public-key-cant-be-used-for-decrypting
https://security.stackexchange.com/questions/11879/is-encrypting-data-with-a-private-key-dangerous
https://security.stackexchange.com/questions/68822/trying-to-understand-rsa-and-its-terminology
https://crypto.stackexchange.com/questions/2123/rsa-encryption-with-private-key-and-decryption-with-a-public-key
https://crypto.stackexchange.com/questions/15997/is-rsa-encryption-the-same-as-signature-generation
https://crypto.stackexchange.com/questions/15295/why-the-need-to-hash-before-signing-small-data


@dave_thompson_085,感谢您的编辑。您想将此答案设为社区共享吗? - kelalaka
我认为没有必要再进行更改,因为在我的看法中,它已经完整且正确无误。当然,在 Stack 上,任何人都可以提出或请求进一步的更改。 - dave_thompson_085
但是为什么您不能使用私钥解密使用私钥加密的内容呢?私钥不是公钥的倒数吗? - ezio
@ezio,你读错了。OP试图使用公钥解密。私钥包含所有信息,使得所有者可以加密和解密使用该公钥加密的消息。 - kelalaka

-1

我看到你说“想为了学习目的而这样做”。那么,对于其他人来说,这也应该只用于“学习目的”,而不是任何生产或声称安全的系统。

正如@kelalaka所指出的,在公钥密码学中,公钥用于加密,私钥用于解密。然而,如果你正在学习RSA,你也知道“加密/解密”和“签名/验证”使用相同的基本数学公式:
enter image description here

此外,加密将m提高到e的幂次方,mod(n),而解密将c提高到d的幂次方,mod(n),其中(e, n)是公钥,(d, n)是私钥。鉴于这个数学基础,我认为一个自然的问题是,我们如何将m提高到d的幂次方,反之亦然?
原来消息签名将hash(m)提高到d的幂,mod(n),而消息验证将tag提高到e的幂,mod(n)。如果您宽松地定义“加密”为“将m提高到一个数字的幂,mod (n)”,那么Openssl CLI可以使用私钥“加密文件”(实际上是签名以创建tag)。rsautl子命令可以这样使用(请注意,输入数据必须与用于加密/签名的密钥具有相同的位长度,因此需要501字节的“A”填充):

# Create the file to have a `tag` created for:
python3 -c "print('Hello World'+501*'A', end='')" > txt.txt
# Create a `tag` called `txt2.txt` for the `txt.txt` file:
openssl pkeyutl -sign -inkey private_key.pem -in tx.txt -out txt2.txt -pkeyopt rsa_padding_mode:none

现在,txt2.txt 包含将 txt.txt 提高到幂次方 d,mod(n) 的结果。

如果您宽泛地定义“解密”为“将 m 提高到一个数的幂次方,mod (n)”,那么 Openssl CLI 可以“使用公钥解密文件”(实际上是验证,但可以查看中间步骤的原始结果)。可以像这样使用 rsautl 子命令:

openssl rsautl -verify -inkey public_key.pem -pubin -in txt2.txt -raw -hexdump

现在stdout包含将txt2.txt提高到e次幂,模(n)的结果。


你的建议是错误的。私钥绝不能用于加密! - kelalaka
使用公钥基础设施中的私钥加密 - kelalaka

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接