Linux下RSA密钥生成异常致API调用500错误,Windows运行正常求助
问题分析与解决方案
看起来你遇到了一个典型的跨平台编码/二进制处理问题,核心线索是Windows生成的密钥能在Linux正常工作——这说明问题出在Linux环境下的密钥生成或加密环节,而非API调用本身。
可能的根源
二进制密钥的字符串转换损坏数据
你生成的AES密钥是byte[]类型的二进制数据,但在调用加密方法时,你把它转成了String再传入:new String(appKey)。二进制数据直接转字符串会依赖平台默认字符编码,Windows下通常是GBK,Linux下是UTF-8,这会导致同一个字节数组在不同系统转成字符串后,再转回字节数组时内容不一致,最终加密结果不符合API要求,触发500错误。字符串转字节时的编码不统一
处理UserId这类字符串时,你用了password.getBytes(),同样依赖平台默认编码,跨平台后字节数组内容不同,加密结果也会不一致。加密方法的明显bug
注意你接收byte[]类型appKey的encryptAsymmetricKey重载方法,最后返回的是null——这绝对是个bug,等于直接丢弃了加密结果,这会导致Linux下生成的appKey完全无效!
修复步骤
1. 修复二进制密钥加密的bug
修改接收byte[]参数的加密方法,返回正确的Base64编码结果:
public static String encryptAsymmetricKey(String pubkey, byte[] appKey) throws Exception { PublicKey publicKeys = convertPubStringToKey(pubkey); Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1PADDING"); cipher.init(Cipher.ENCRYPT_MODE, publicKeys); byte[] encryptedText = cipher.doFinal(appKey); // 替换return null,返回Base64编码后的加密字符串 return Base64.getEncoder().encodeToString(encryptedText); }
2. 移除二进制密钥的字符串转换
直接用createAESKey()生成的字节数组调用加密方法,不要转成字符串:
// 生成AES密钥字节数组 byte[] appKeyBytes = createAESKey(); // 直接传入字节数组加密,跳过字符串转换 String appkeye = encryptAsymmetricKey(publicKey, appKeyBytes);
3. 统一字符串转字节的编码
处理UserId这类字符串时,指定统一的UTF-8编码,避免依赖平台默认编码:
// 显式指定UTF-8编码转字节数组 String password = encryptAsymmetricKey(publicKey, "UserId".getBytes(StandardCharsets.UTF_8)); // 也可以优化字符串参数的加密方法,内部统一编码: public static String encryptAsymmetricKey(String pubkey, String password) throws Exception { // 内部统一用UTF-8转字节,避免外部调用者遗漏 return encryptAsymmetricKey(pubkey, password.getBytes(StandardCharsets.UTF_8)); }
额外验证建议
修改后,在Windows和Linux分别打印appkeye和password的Base64字符串,如果两者完全一致,说明跨平台一致性问题已解决。
另外可以检查Linux下的JDK是否支持256位AES:Java 8默认可能限制密钥长度,可通过添加JVM启动参数-Dcrypto.policy=unlimited(OpenJDK 8u161+支持)或安装JCE无限制权限策略文件解决,但根据你的现象,这大概率不是当前问题的根源。
内容的提问来源于stack exchange,提问作者Gaurav Singh

