如何在Pycrypto中实现与OpenSSL raw RSA签名验证相同的功能?
在PyCrypto中实现OpenSSL
rsautl -raw -verify的功能 要实现和OpenSSL rsautl -raw -verify完全一致的解析验证功能,核心要理解raw RSA签名的本质:它其实就是用RSA私钥对payload直接做模幂加密(m^d mod n),而验证解析则是用公钥(或包含公钥信息的私钥)做反向模幂运算(s^e mod n)还原原始payload。
PyCrypto的verify()方法是为标准RSA签名(哈希+标准填充)设计的,只返回布尔值,无法直接还原payload,所以我们需要手动实现模幂运算来完成解析。
实现步骤
1. 核心原理
OpenSSL的rsautl -raw -sign生成的签名数据,本质是payload的RSA私钥加密结果。要还原payload,只需对签名数据执行公钥模幂运算(签名^e mod n)——不管你用私钥还是公钥文件,最终都是用公钥的e(公钥指数)和n(模数)来计算,因为RSA私钥已经包含了公钥的所有参数。
2. 代码实现
用公钥解析签名
from Crypto.PublicKey import RSA # 1. 读取签名数据(rsautl -raw -sign的输出结果) with open("signature.bin", "rb") as f: signature = f.read() # 2. 导入PEM格式的公钥 with open("public_key.pem", "r") as f: pub_key = RSA.importKey(f.read()) # 3. 将签名字节转换为整数(RSA运算基于大整数) sig_int = int.from_bytes(signature, byteorder="big") # 4. 执行模幂运算还原payload整数 payload_int = pow(sig_int, pub_key.e, pub_key.n) # 5. 将整数转换回字节串(长度匹配密钥的字节长度,比如2048位密钥对应256字节) payload = payload_int.to_bytes(pub_key.size_in_bytes(), byteorder="big") # 如果你的自定义填充包含前导零或长度标识,这里可以根据逻辑处理payload,比如截断前导零 # payload = payload.lstrip(b'\x00')
用私钥解析签名
因为RSA私钥包含公钥的e和n,所以代码逻辑和公钥几乎一致,只是导入私钥即可:
from Crypto.PublicKey import RSA # 1. 读取签名数据 with open("signature.bin", "rb") as f: signature = f.read() # 2. 导入PEM格式的私钥 with open("private_key.pem", "r") as f: priv_key = RSA.importKey(f.read()) # 3. 签名转整数 sig_int = int.from_bytes(signature, byteorder="big") # 4. 模幂运算还原payload(用私钥里的e和n,和公钥逻辑完全一样) payload_int = pow(sig_int, priv_key.e, priv_key.n) # 5. 整数转字节串 payload = payload_int.to_bytes(priv_key.size_in_bytes(), byteorder="big")
关键注意事项
- 自定义填充处理:你提到已经用自定义填充缓解raw RSA的风险,还原后的payload可能包含填充内容(比如前导随机数、长度标记),需要根据你的填充规则进一步处理,比如截断前导零或提取有效数据段。
- PyCrypto的局限性:PyCrypto已经停止维护,建议迁移到PyCryptodome(它是PyCrypto的分支,API完全兼容),代码无需修改即可直接运行。
- 安全性提醒:即使有自定义填充,raw RSA仍然存在诸多安全风险(比如选择明文攻击),如果后续有机会,建议迁移到标准的RSA签名方案(如PKCS#1 v1.5或PSS填充)。
内容的提问来源于stack exchange,提问作者Alastair McCormack
相关产品推荐
相关产品推荐

