R调用Python传敏感参数:RSA加密解密失败技术问询
解决R与Python间RSA加密解密的二进制数据传递问题
你碰到的这个问题其实挺典型的——核心就是二进制加密数据在跨进程传递时的格式混乱,再加上原代码里的几个小错误(比如密钥用反了、填充不匹配),导致解密完全不对。我来帮你一步步修正:
先说说原代码的几个关键问题
- 直接把R中
PKI.encrypt返回的原始二进制数据传给Python:命令行参数只能传字符串,二进制数据会被自动转成R的原始字符串表示(比如raw(n) 0xXX 0xXX...),Python拿到的根本不是真实的加密字节。 - RSA密钥用反了:RSA的正确逻辑是公钥加密,私钥解密,你原代码用私钥加密,不仅失去了加密的意义(公钥是公开的,任何人都能解密),还会导致填充逻辑不匹配。
- 填充方式没明确指定:R和Python默认的填充规则可能不一致,直接解密就会触发填充错误。
修正后的完整代码
R端代码(main.R)
# main.R library(PKI) library(base64enc) # 生成2048位RSA密钥对 key_pair <- PKI.genRSAkey(2048L) # 保存私钥给Python解密用 PKI.save.key(key_pair, target = "privkey.pem", private = TRUE) # 提取公钥用于加密(正确流程:公钥加密,私钥解密) pubkey <- PKI.save.key(key_pair, target = NULL, private = FALSE) pubkey <- PKI.load.key(pubkey) # 要加密的敏感数据,转成原始字节 msg <- charToRaw("password") # 用公钥加密,指定PKCS#1 v1.5填充(和Python端统一) msg_encrypted <- PKI.encrypt(msg, pubkey, type = "PKCS1") # 把二进制加密数据转成Base64字符串,避免命令行传递时的二进制转义问题 msg_encrypted_b64 <- base64encode(msg_encrypted) # 调用Python脚本,传递Base64编码的加密字符串 result <- system2("python", args = c("dostuff.py", msg_encrypted_b64), stdout = TRUE) print(result)
Python端代码(dostuff.py)
# dostuff.py from Crypto.PublicKey import RSA from Crypto.Cipher import PKCS1_v1_5 import base64 import sys # 加载R生成的私钥 private_key = RSA.import_key(open("privkey.pem").read()) # 初始化PKCS#1 v1.5解密器(和R端的填充方式一致) cipher = PKCS1_v1_5.new(private_key) # 接收命令行传入的Base64加密字符串,解码回二进制数据 encrypted_b64 = sys.argv[1] encrypted_data = base64.b64decode(encrypted_b64) # 解密数据,转成UTF-8字符串 decrypted_data = cipher.decrypt(encrypted_data, sentinel=None).decode("utf-8") print(f"Decryption returned: {decrypted_data}")
关键说明
- Base64编码的必要性:二进制数据在命令行传递时会被shell解析转义,Base64把二进制转成纯ASCII字符串,完美解决跨进程传递的格式损坏问题。
- 密钥流程修正:公钥加密保证只有持有私钥的一方能解密,这才是RSA加密的正确用法。
- 填充方式统一:两端都明确使用PKCS#1 v1.5填充,避免出现"binascii.Error: Incorrect padding"这类填充错误。
前置依赖安装
- R端:运行前先安装需要的包
install.packages(c("PKI", "base64enc")) - Python端:安装
pycryptodome(替代过时的pycrypto)pip install pycryptodome
现在运行你的脚本,应该就能得到预期的password了!
内容的提问来源于stack exchange,提问作者Wassadamo




