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

JNI调用OpenSSL RSA解密异常:加密正常但解密输出错误

问题排查与解决方案

针对JNI环境下OpenSSL RSA解密长度正确但内容异常的问题,以下是核心排查点和解决方法:

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

加密与解密必须使用完全一致的填充模式,否则会出现长度正确但内容乱码的情况:

  • 检查RSA_public_encrypt和RSA_private_decrypt的最后一个参数,确保两者填充模式相同(如均为RSA_PKCS1_PADDING或RSA_PKCS1_OAEP_PADDING)。
  • 示例正确配对代码:
    // 加密
    int encrypt_len = RSA_public_encrypt(plain_len, (unsigned char*)plain_data, 
                                        cipher_data, rsa_pub, RSA_PKCS1_PADDING);
    // 解密
    int decrypt_len = RSA_private_decrypt(cipher_len, (unsigned char*)cipher_data, 
                                        plain_data, rsa_pri, RSA_PKCS1_PADDING);
    

2. JNI层字节处理错误

(1)密文被当作字符串处理

二进制密文包含大量不可打印字符,若在Java/JNI层将密文转为String传递,会导致字节损坏:

  • 修正方案:全程用byte[]传递密文,避免转成String。
    Java层调用示例:
    byte[] plainBytes = "test".getBytes(StandardCharsets.UTF_8);
    byte[] cipherBytes = nativeEncrypt(plainBytes);
    byte[] decryptedBytes = nativeDecrypt(cipherBytes);
    String result = new String(decryptedBytes, StandardCharsets.UTF_8);
    

(2)编码不一致

Java字符串转字节数组时必须指定编码(如UTF-8),加密和解密阶段的编码要统一,否则会出现内容乱码:

  • 禁止依赖系统默认编码,明确使用StandardCharsets.UTF_8或固定编码。

3. 密钥加载与配对问题

(1)私钥加载失败未检测

加载私钥时必须检查返回值,若PEM_read_RSAPrivateKey返回NULL,会使用无效私钥解密,导致内容异常:

RSA* load_private_key(const char* pem_path) {
    FILE* fp = fopen(pem_path, "r");
    if (!fp) return NULL;
    RSA* rsa = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL);
    fclose(fp);
    // 打印OpenSSL错误信息,排查加载失败原因
    if (!rsa) ERR_print_errors_fp(stderr);
    return rsa;
}

(2)密钥对不匹配

加密用的公钥和解密用的私钥必须是配对的密钥对:

  • 用OpenSSL命令行验证密钥有效性:
    # 用公钥加密测试文本
    echo "test_content" | openssl rsautl -encrypt -inkey public.pem -pubin -out cipher.bin
    # 用私钥解密验证
    openssl rsautl -decrypt -inkey private.pem -in cipher.bin
    
    若命令行解密结果正确,说明代码逻辑存在问题;若命令行也异常,说明密钥本身无效或不配对。

4. 缓冲区与内存处理错误

  • 解密时输出缓冲区需足够大(至少为RSA_size(rsa)),且要根据RSA_private_decrypt返回的实际明文长度截取内容,避免缓冲区残留的垃圾数据混入结果:
    unsigned char* decrypted_buf = (unsigned char*)malloc(RSA_size(rsa_pri));
    int actual_len = RSA_private_decrypt(...);
    // 仅取前actual_len字节作为有效明文
    jbyteArray result = env->NewByteArray(actual_len);
    env->SetByteArrayRegion(result, 0, actual_len, (jbyte*)decrypted_buf);
    free(decrypted_buf);
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 17:55:20