You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP RSA加密后安卓端解密异常问题求助

解决安卓RSA公钥与PHP跨平台加解密不匹配问题

我之前也踩过不少RSA跨平台加解密的坑,结合你给出的代码和报错情况,核心问题大概率是填充方式不一致或者公钥解析错误导致的,咱们一步步来排查和解决:

先明确你的现有代码(方便对照)

安卓端密钥生成代码

// 安卓端密钥生成代码(你提供的原代码)
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();

// 你提供的公钥格式示例
String publicKeyStr = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxQ...(完整公钥内容)";

PHP端加密逻辑(提取模数指数)

// PHP端加密代码(你原逻辑)
require_once('Crypt/RSA.php');
$rsa = new Crypt_RSA();
$rsa->loadKey(array(
    'n' => new Math_BigInteger(base64_decode($modulus), 256),
    'e' => new Math_BigInteger(base64_decode($exponent), 256)
));
$rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1);
$ciphertext = $rsa->encrypt($plaintext);
$encryptedStr = base64_encode($ciphertext);

安卓端解密代码

// 安卓端解密代码(你提供的原代码)
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] decryptedBytes = cipher.doFinal(Base64.decode(encryptedStr, Base64.DEFAULT));
String decryptedStr = new String(decryptedBytes);

核心问题分析与解决方案

1. 填充方式不匹配(最常见原因)

安卓中Cipher.getInstance("RSA")是不明确指定填充方式的写法,不同Android厂商的默认实现可能不一样:有的是RSA/ECB/PKCS1Padding,有的可能是RSA/ECB/NoPadding。而你PHP里用的是CRYPT_RSA_ENCRYPTION_PKCS1(对应PKCS1填充),两者不一致就会导致解密失败或乱码。

修正方案:安卓解密时明确指定填充方式,和PHP对齐:

try {
    // 强制指定PKCS1填充,和PHP的加密模式匹配
    Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
    cipher.init(Cipher.DECRYPT_MODE, privateKey);
    // 用NO_WRAP避免Base64换行导致的解析问题
    byte[] encryptedBytes = Base64.decode(encryptedStr, Base64.NO_WRAP);
    byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
    // 明确指定UTF-8编码,避免字符集不一致导致乱码
    String decryptedStr = new String(decryptedBytes, StandardCharsets.UTF_8);
    Log.d("DecryptSuccess", "解密结果:" + decryptedStr);
} catch (Exception e) {
    e.printStackTrace();
}

2. 公钥手动提取模数/指数出错

你手动从安卓公钥提取n和e的过程很容易出错——安卓的公钥是X.509格式的ASN.1结构,手动截取字符串或解析二进制很容易搞混编码、长度。一旦公钥解析错误,PHP加密出来的密文就是无效的,安卓解密时自然会出现数组越界(密文长度不符合2048位RSA的256字节要求)。

更稳妥的方案:直接把安卓的完整公钥传给PHP,用phpseclib直接加载,不用手动提取n和e:

require_once('Crypt/RSA.php');
$rsa = new Crypt_RSA();
// 给安卓的Base64公钥补上头尾(如果你的公钥没有的话)
$androidPublicKey = "-----BEGIN PUBLIC KEY-----\n" . $yourAndroidPublicKeyStr . "\n-----END PUBLIC KEY-----";
$rsa->loadKey($androidPublicKey);
$rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1);
// 可选:指定哈希算法,确保跨平台一致性
$rsa->setHash('sha256');

$plaintext = "测试加密内容";
$ciphertext = $rsa->encrypt($plaintext);
// 直接输出Base64编码的密文,供安卓解密
echo base64_encode($ciphertext);

3. 其他注意事项

  • RSA加密长度限制:2048位RSA用PKCS1填充时,最多只能加密245字节左右的明文(因为填充占了11字节),如果要加密大内容,建议用AES对称加密,再用RSA加密AES密钥。
  • 字符编码一致性:安卓和PHP都要统一用UTF-8编码处理字符串转字节数组,避免乱码。
  • Base64编码差异:安卓的Base64.DEFAULT会自动换行,PHP的base64_encode不会,所以安卓解密时用Base64.NO_WRAP更稳妥。

内容的提问来源于stack exchange,提问作者Introser

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 08:16:04