M2crypto 签名“算法”

5 投票
2 回答
3242 浏览
提问于 2025-04-16 15:44

这两段代码产生了相同的签名,这是正常的:

代码1:

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)

代码2:

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

你能帮我解释一下吗?后面这种签名方式有什么问题吗?

2 个回答

1

在内部,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 所示 - 它在内部处理得更好。

3

我认为这两者的区别在于,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.

撰写回答