寻找支持RSA_PKCS1_PADDING模式公钥解密的Python库
解决方案
你常用的pycryptodome库就可以实现需求,只是标准接口没有直接暴露公钥解密的独立方法(该操作在密码学标准中属于签名验签的底层步骤),基于基础运算封装即可完全匹配RSA_PKCS1_PADDING填充模式,功能对齐Node.js的crypto.publicEncrypt和crypto.publicDecrypt。
依赖安装
pip install pycryptodome
完整实现代码
from Crypto.PublicKey import RSA from Crypto.Util.number import bytes_to_long, long_to_bytes import Crypto.Random def rsa_public_encrypt(plaintext: bytes, pub_key: RSA.RsaKey) -> bytes: """ 对应Node.js crypto.publicEncrypt,RSA_PKCS1_PADDING填充 """ mod_byte_len = pub_key.size_in_bytes() max_plain_len = mod_byte_len - 11 if len(plaintext) > max_plain_len: raise ValueError(f"明文长度超出限制,最大支持{max_plain_len}字节") # 生成PKCS#1 v1.5 加密填充(类型0x02) padding = b"" while len(padding) < mod_byte_len - len(plaintext) - 3: rand_byte = Crypto.Random.get_random_bytes(1) if rand_byte != b"\x00": padding += rand_byte padded_data = b"\x00\x02" + padding + b"\x00" + plaintext # 公钥加密运算 m = bytes_to_long(padded_data) c = pow(m, pub_key.e, pub_key.n) return long_to_bytes(c, mod_byte_len) def rsa_public_decrypt(ciphertext: bytes, pub_key: RSA.RsaKey) -> bytes: """ 对应Node.js crypto.publicDecrypt,RSA_PKCS1_PADDING填充 用于解密私钥加密的内容 """ mod_byte_len = pub_key.size_in_bytes() if len(ciphertext) != mod_byte_len: raise ValueError(f"密文长度错误,需为{mod_byte_len}字节") # 公钥解密运算 c = bytes_to_long(ciphertext) m = pow(c, pub_key.e, pub_key.n) padded_data = long_to_bytes(m, mod_byte_len) # 校验并移除PKCS#1 v1.5 签名填充(类型0x01,私钥加密默认使用该填充) if padded_data[:2] != b"\x00\x01": raise ValueError("无效的PKCS#1 v1.5填充") sep_pos = padded_data.find(b"\x00", 2) if sep_pos == -1: raise ValueError("无效的PKCS#1 v1.5填充") return padded_data[sep_pos+1:] # 使用示例 if __name__ == "__main__": # 导入公钥(支持PEM格式、DER格式或者直接传入n/e参数构造) pub_pem = b"""-----BEGIN PUBLIC KEY----- 替换为你的公钥内容 -----END PUBLIC KEY-----""" pub_key = RSA.import_key(pub_pem) # 1. 公钥加密:用于向服务端发送加密消息 test_plain = b"test message to server" encrypted_by_pub = rsa_public_encrypt(test_plain, pub_key) # 2. 公钥解密:用于解密服务端用私钥加密的返回内容 # 注意:实际使用时先把服务端返回的base64/hex编码密文转成字节再传入 # encrypted_by_priv = base64.b64decode(response_data) # decrypted_result = rsa_public_decrypt(encrypted_by_priv, pub_key) # print(decrypted_result)
注意事项
- 若服务端返回的密文是base64、hex等编码格式,需要先解码为原始字节再传入解密函数
- 密钥长度支持1024/2048/4096等所有标准RSA密钥长度
- 严格遵循RSA PKCS#1 v1.5填充规范,和主流语言的对应接口兼容
内容的提问来源于stack exchange,提问作者Dirog
相关产品推荐
相关产品推荐

