M2加密签名“算法”

发布于 2024-11-01 06:43:49 字数 797 浏览 5 评论 0原文

这两个代码提供了相同的签名,这是预期的:

code1:

from M2Crypto import RSA, EVP
import base64, hashlib

text = "some text"

pkey = EVP.load_key("mykey.pem")  #"mykey.pem" was generated as: openssl genrsa -des3 -out mykey.pem 2048
pkey.sign_init()
pkey.sign_update(text)
signature = pkey.sign_final()
print base64.b64encode(signature)

code2:

pkey = RSA.load_key("mykey.pem")
signature = pkey.sign(hashlib.sha1(text).digest())
print base64.b64encode(signature)

但是,如果我想“模仿”签名算法,即用私钥加密摘要,我会得到不同的签名,即:

pkey = RSA.load_key("mykey.pem")
signature = pkey.private_encrypt(hashlib.sha1(text).digest(), RSA.pkcs1_padding)
print base64.b64encode(signature)  #different from the two above

您能否提供一些解释?后一种签名方式有什么问题吗?

These two codes provide the same signature, which is expected:

code1:

from M2Crypto import RSA, EVP
import base64, hashlib

text = "some text"

pkey = EVP.load_key("mykey.pem")  #"mykey.pem" was generated as: openssl genrsa -des3 -out mykey.pem 2048
pkey.sign_init()
pkey.sign_update(text)
signature = pkey.sign_final()
print base64.b64encode(signature)

code2:

pkey = RSA.load_key("mykey.pem")
signature = pkey.sign(hashlib.sha1(text).digest())
print base64.b64encode(signature)

However, if I want to "imitate" the signature algorithm, i.e. encrypting the digest with the private key, I get a different signature, i.e.:

pkey = RSA.load_key("mykey.pem")
signature = pkey.private_encrypt(hashlib.sha1(text).digest(), RSA.pkcs1_padding)
print base64.b64encode(signature)  #different from the two above

Could you please provide some explanation? What is wrong with the latter way of signing?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

左耳近心 2024-11-08 06:43:49

我认为不同之处在于,RSA_sign 将摘要 PKCS1 算法标识符与摘要数据一起签名,其中 RSA_private_encrypt 仅对摘要数据进行签名。

RSA_private_encrypt 手册页:

RSA_PKCS1_PADDING
    PKCS #1 v1.5 padding. This function does not handle the
    algorithmIdentifier specified in PKCS #1. When generating or
    verifying PKCS #1 signatures, RSA_sign(3) and RSA_verify(3) should
    be used.

I believe the difference is that RSA_sign signs the digest PKCS1 algorithmIdentifier along with the digest data, where RSA_private_encrypt signs only the digest data.

From the RSA_private_encrypt man page:

RSA_PKCS1_PADDING
    PKCS #1 v1.5 padding. This function does not handle the
    algorithmIdentifier specified in PKCS #1. When generating or
    verifying PKCS #1 signatures, RSA_sign(3) and RSA_verify(3) should
    be used.
猥琐帝 2024-11-08 06:43:49

EVP.sign() 内部发生的情况如下(与普通的 RSA.sign() 相反):

sha1_hash = hashlib.sha1(MESSAGE).digest()
# Add ASN.1 SHA-1 OID prefix
sha1_asn1_prefix = '3021300906052b0e03021a05000414'.decode('hex')
asn1_hash = sha1_asn1_prefix + sha1_hash
rsa = RSA.load_key(KEY)
# Use PKCS#1 padding
signature = rsa.private_encrypt(asn1_hash, RSA.pkcs1_padding).encode('hex')

请参阅 这个答案以获得更详细的解释和这个要点 获取完整示例。

但底线是应该使用 EVP.sign() 来代替上面的代码 1 - 它在内部做了正确的事情。

What happens internally in EVP.sign() is as follows (as opposed to plain RSA.sign()):

sha1_hash = hashlib.sha1(MESSAGE).digest()
# Add ASN.1 SHA-1 OID prefix
sha1_asn1_prefix = '3021300906052b0e03021a05000414'.decode('hex')
asn1_hash = sha1_asn1_prefix + sha1_hash
rsa = RSA.load_key(KEY)
# Use PKCS#1 padding
signature = rsa.private_encrypt(asn1_hash, RSA.pkcs1_padding).encode('hex')

See this answer for longer explanation and this gist for a full example.

But the bottom line is that EVP.sign() should be used instead as in code 1 above - it does the right thing internally.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文