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

Java/BouncyCastle加密后用OpenSSL解密出空文件,求排查方案

BouncyCastle加密后用OpenSSL解密失败问题排查

问题场景

尝试用BouncyCastle加密字符串,再通过OpenSSL命令行解密,加密代码如下:

String text = "Asdf";

String encryptedText;
Security.addProvider(new BouncyCastleProvider());
String algorithm = "AES/CBC/PKCS7Padding";

byte[] keyBytes = "0123456789abcdef".getBytes(StandardCharsets.UTF_8);
SecretKey secretKey = new SecretKeySpec(keyBytes, "AES");

byte[] ivBytes = new byte[16];
IvParameterSpec ivParameterSpec = new IvParameterSpec(ivBytes);
SecureRandom secureRandom = new SecureRandom();
secureRandom.nextBytes(ivBytes);

Cipher cipher = Cipher.getInstance(algorithm, "BC");
cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivParameterSpec);

byte[] ciphertext = cipher.doFinal(text.getBytes(StandardCharsets.UTF_8));
encryptedText = Base64.getEncoder().encodeToString(ciphertext);

加密后得到Base64字符串:

fH/ybmlsrqaj1jVsjJEyBg==

将该字符串保存到in.txt后执行OpenSSL命令:

openssl enc -d -aes-128-cbc -K 30313233343536373839616263646566 -iv 00000000000000000000000000000000 -nopad  -base64 -in in.txt -out decrypted.tx

命令无报错,但解密文件为空。

错误原因分析

  • IV生成逻辑错误:代码中先基于全0的ivBytes创建IvParameterSpec,之后才用SecureRandom生成随机IV写入ivBytes。但IvParameterSpec的构造函数会复制传入数组的当前内容,因此实际加密使用的是全0 IV(而非后续生成的随机IV)。不过你在OpenSSL命令中指定了全0 IV,这部分倒是匹配,但这属于代码逻辑漏洞,若后续要使用随机IV会直接导致解密失败。
  • OpenSSL命令参数错误:
    • 加密时使用了PKCS7Padding,但命令中添加了-nopad参数,这会让OpenSSL跳过填充校验与去除,导致解密后的内容包含填充字节,甚至因数据长度不匹配出现异常(此处无报错但输出为空,大概率是填充处理错误导致)。
    • OpenSSL的enc命令默认会给密文添加Salted__头并加盐处理,但你的密文是纯Base64编码的原始密文,未包含盐信息,因此需要添加-nosalt参数,否则OpenSSL会尝试解析盐信息,导致解密逻辑异常。
  • 文件名笔误:命令中输出文件名是decrypted.tx(少了最后一个t),虽然不影响解密逻辑,但可能导致你找错文件。

修正方案

1. 修复Java加密代码的IV逻辑

调整IV生成顺序,确保IvParameterSpec使用随机生成的IV;若要使用随机IV解密,需将IV与密文一起输出:

String text = "Asdf";

String encryptedText;
Security.addProvider(new BouncyCastleProvider());
String algorithm = "AES/CBC/PKCS7Padding";

byte[] keyBytes = "0123456789abcdef".getBytes(StandardCharsets.UTF_8);
SecretKey secretKey = new SecretKeySpec(keyBytes, "AES");

// 先生成随机IV
byte[] ivBytes = new byte[16];
SecureRandom secureRandom = new SecureRandom();
secureRandom.nextBytes(ivBytes);
// 再基于随机IV创建IvParameterSpec
IvParameterSpec ivParameterSpec = new IvParameterSpec(ivBytes);

Cipher cipher = Cipher.getInstance(algorithm, "BC");
cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivParameterSpec);

byte[] ciphertext = cipher.doFinal(text.getBytes(StandardCharsets.UTF_8));
// 将IV与密文拼接后再Base64编码,方便后续解密拆分
byte[] combined = new byte[ivBytes.length + ciphertext.length];
System.arraycopy(ivBytes, 0, combined, 0, ivBytes.length);
System.arraycopy(ciphertext, 0, combined, ivBytes.length, ciphertext.length);
encryptedText = Base64.getEncoder().encodeToString(combined);

2. 修正OpenSSL解密命令

场景1:使用全0 IV(对应原加密逻辑)

修正后的命令:

openssl enc -d -aes-128-cbc -K 30313233343536373839616263646566 -iv 00000000000000000000000000000000 -nosalt -base64 -in in.txt -out decrypted.txt
  • 去掉-nopad,让OpenSSL自动处理PKCS7填充
  • 添加-nosalt,告知OpenSSL密文无盐头
  • 修正输出文件名为decrypted.txt

场景2:使用随机IV(对应修正后的Java代码)

需先从Base64字符串中拆分IV和密文,再执行解密:

# 解码Base64得到拼接的IV+密文
base64 -d in.txt > combined.bin
# 提取前16字节作为IV(转为十六进制格式)
IV=$(xxd -p -l 16 combined.bin)
# 提取剩余部分作为纯密文
tail -c +17 combined.bin > ciphertext.bin
# 执行解密
openssl enc -d -aes-128-cbc -K 30313233343536373839616263646566 -iv $IV -nosalt -in ciphertext.bin -out decrypted.txt

结论

这种跨工具加密解密的场景完全可行,只要保证两端的算法、密钥、IV、填充方式、密文格式完全一致即可。你之前的问题主要是代码逻辑错误(IV生成顺序)和OpenSSL命令参数错误导致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 16:34:58