Python与Kotlin的RSA加密无法互解问题求助
RSA跨语言加密解密不互通问题排查与修正
你遇到的问题核心是Python和Kotlin两端的RSA加密参数不匹配,导致互相解密时填充校验失败。以下是具体的问题点和解决方案:
1. 填充方式不匹配(最常见原因)
RSA加密的填充方案必须两端完全一致,否则必然出现填充错误:
- 如果Python用
PKCS1v15填充,Kotlin必须对应RSA/ECB/PKCS1Padding; - 如果用更安全的
OAEP填充,两端必须同步哈希算法(如SHA-256)和MGF1参数。
示例修正(PKCS1v15方案)
Python端(cryptography库)
from cryptography.hazmat.primitives.asymmetric import padding from cryptography.hazmat.primitives import serialization, hashes import base64 # 加密(明确指定PKCS1v15填充) def rsa_encrypt(plaintext: str, pub_key_pem: str) -> str: pub_key = serialization.load_pem_public_key(pub_key_pem.encode('utf-8')) encrypted_bytes = pub_key.encrypt( plaintext.encode('utf-8'), padding.PKCS1v15() # 与Kotlin端填充一致 ) return base64.b64encode(encrypted_bytes).decode('utf-8') # 解密 def rsa_decrypt(ciphertext: str, priv_key) -> str: encrypted_data = base64.b64decode(ciphertext) decrypted_bytes = priv_key.decrypt( encrypted_data, padding.PKCS1v15() ) return decrypted_bytes.decode('utf-8')
Kotlin端(原生加密模块)
import android.util.Base64 import java.security.KeyFactory import java.security.spec.X509EncodedKeySpec import javax.crypto.Cipher object RSAHelper { // 与Python端PKCS1v15完全对应的转换字符串 private const val RSA_TRANSFORMATION = "RSA/ECB/PKCS1Padding" // 解析Python传来的PEM格式公钥 fun loadPemPublicKey(pemStr: String): java.security.PublicKey { val cleanPem = pemStr.replace("-----BEGIN PUBLIC KEY-----", "") .replace("-----END PUBLIC KEY-----", "") .replace("\\s+".toRegex(), "") val keyBytes = Base64.decode(cleanPem, Base64.DEFAULT) val spec = X509EncodedKeySpec(keyBytes) return KeyFactory.getInstance("RSA").generatePublic(spec) } // 加密 fun encrypt(plaintext: String, publicKey: java.security.PublicKey): String { val cipher = Cipher.getInstance(RSA_TRANSFORMATION) cipher.init(Cipher.ENCRYPT_MODE, publicKey) val encryptedBytes = cipher.doFinal(plaintext.toByteArray(Charsets.UTF_8)) return Base64.encodeToString(encryptedBytes, Base64.DEFAULT) } // 解密(需传入对应私钥) fun decrypt(ciphertext: String, privateKey: java.security.PrivateKey): String { val cipher = Cipher.getInstance(RSA_TRANSFORMATION) cipher.init(Cipher.DECRYPT_MODE, privateKey) val encryptedBytes = Base64.decode(ciphertext, Base64.DEFAULT) val decryptedBytes = cipher.doFinal(encryptedBytes) return String(decryptedBytes, Charsets.UTF_8) } }
若使用OAEP更安全方案
Python端调整
# 加密/解密时替换填充为OAEP padding.OAEP( mgf=padding.MGF1(algorithm=hashes.SHA256()), algorithm=hashes.SHA256(), label=None )
Kotlin端调整
// 转换字符串同步为OAEP+SHA256 private const val RSA_TRANSFORMATION = "RSA/ECB/OAEPWithSHA-256AndMGF1Padding" // 部分Android版本需添加BC提供者:"RSA/ECB/OAEPWithSHA-256AndMGF1Padding,BC"
2. 密钥格式不兼容
- Python默认使用PEM格式密钥(带
-----BEGIN PUBLIC KEY-----头),Kotlin需先清理PEM头再解析为X509格式; - 确保两端密钥长度一致(如均为2048位或4096位),长度不匹配会直接导致解密失败。
3. 加密内容长度超限
RSA加密有明文长度限制:
- 2048位RSA+PKCS1v15:最大明文长度为245字节(2048/8 - 11);
- 2048位RSA+OAEP:最大明文长度为214字节(2048/8 - 2*SHA256长度 - 2);
若明文超出长度,会导致加密截断,解密时触发填充错误。
4. 编码方式不一致
加密前的字符串转字节时,两端必须统一使用UTF-8编码,避免因编码差异导致字节流不匹配。
内容的提问来源于stack exchange,提问作者kunteinzo
相关产品推荐
相关产品推荐

