如何用公钥解密经1024位RSA PKCS#1v1.5私钥编码的128字节串
用公钥解密RSA PKCS#1v1.5私钥加密的128字节十六进制串
问题背景
- 目标串是128字节二进制(对应256字符十六进制),由私钥按RSA PKCS#1v1.5标准加密生成,原始明文为116字节
- 已从X509 PEM公证书中提取模数(modulus)和公钥指数(exponent)
- 尝试用pyCryptodome处理时,使用PKCS1_OAEP出现长度错误,用encrypt方法无法得到正确明文
错误原因
- 加密模式误用:PKCS1_OAEP是RSA加密的安全填充模式,而目标串用的是PKCS#1v1.5的签名/私钥加密填充格式,两者不兼容
- 输入格式错误:直接将十六进制字符串作为字节传入,未转换为对应二进制字节,导致长度不匹配(128字节二进制的十六进制表示是256字符,直接传入会被当作256字节的ASCII串,长度远超128字节)
解决方案代码
from Crypto.PublicKey import RSA import binascii # 公钥参数(从证书提取) exponent = '10001' # 对应十进制65537 modulus = 'DE8CA25087EC1FF6103DA3BDB7A8F960AF93ABFD1B1F5EBEBE88E77885AD5BFC8D4759B79EFE0173B50FD96AC2B05124AE5CC2DBBA1BC804FA80D9EEB1CC547F39E5524D704CACACFFE235E87744E2F0A7660BDB8694B3D84CAB18D71A2593BBF5BC39F7FF67547477803B8B8EBDD390AEB63F742A081AF947C0E85A69DBE3EB' # 目标十六进制密文(完整128字节二进制对应256字符) hex_ciphertext = b'9254A06EBF59BDD4DF6565CDBE94CFA8DD8E540ADC0812C2CFE75A06006304AF30158CD6F00AC52AB32CB464EFD690EE096BE2722613D6E2212161950716D209746081DF5186682480B0E6AD2F1E5F2798DDB082AAA344C1DF8FEC70697FEE3D6E77D16AFECB0566A4590B926B8461DF47CC65CA102C83025469246D7B164EAE' # 1. 构造公钥 n = int(modulus, 16) e = int(exponent, 16) pub_key = RSA.construct((n, e)) # 2. 将十六进制密文转为二进制字节,再转为整数 ciphertext_bytes = binascii.unhexlify(hex_ciphertext) c = int.from_bytes(ciphertext_bytes, byteorder='big') # 3. 执行原始RSA解密运算(私钥加密是m^d mod n,公钥解密是c^e mod n) m = pow(c, e, n) # 4. 将解密后的整数转为128字节大端字节串(匹配1024位RSA长度) m_bytes = m.to_bytes(128, byteorder='big') # 5. 解析PKCS#1v1.5填充格式:0x00 0x01 + 0xff填充 + 0x00 + 明文 # 找到0x00分隔符的位置(跳过开头的0x00 0x01) separator_pos = m_bytes.index(b'\x00', 2) plaintext = m_bytes[separator_pos+1:] # 输出结果 print("解密后的明文(十六进制):", binascii.hexlify(plaintext).decode()) print("解密后的明文(ASCII):", plaintext.decode('utf-8', errors='ignore'))
代码说明
- 直接使用原始RSA运算
pow(c, e, n),因为私钥加密的本质是签名的原始运算,公钥解密就是逆向的指数运算 - 手动解析PKCS#1v1.5的填充格式:私钥加密的内容会以
0x00 0x01开头,随后是若干0xff填充,最后以0x00分隔明文,找到这个分隔符后即可提取原始明文 - 确保输入的十六进制串先转为二进制字节,避免长度错误
内容的提问来源于stack exchange,提问作者Mr_P
相关产品推荐
相关产品推荐

