【发布时间】:2017-11-30 15:16:11
【问题描述】:
我的情况是 JSON 在 PHP 的 openssl_encrypt 中加密,需要在 JAVA 中解密。
$encrypted = "...ENCRYPTED DATA...";
$secretFile = "/path/to/secret/saved/in/text_file";
$secret = base64_decode(file_get_contents($secretFile));
var_dump(strlen($secret)); // prints : int(370)
$iv = substr($encrypted, 0, 16);
$data = substr($encrypted, 16);
$decrypted = openssl_decrypt($data, "aes-256-cbc", $secret, null, $iv);
这个$decrypted 有正确的数据,现在已解密。
现在,问题是当我尝试在 Java 中做同样的事情时它不起作用:(
String path = "/path/to/secret/saved/in/text";
String payload = "...ENCRYPTED DATA...";
StringBuilder output = new StringBuilder();
String iv = payload.substring(0, 16);
byte[] secret = Base64.getDecoder().decode(Files.readAllBytes(Paths.get(path)));
String data = payload.substring(16);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKeySpec secretKeySpec = new SecretKeySpec(secret, "AES");
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv.getBytes(), 0, cipher.getBlockSize());
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec); // This line throws exception :
cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
这里是:
Exception in thread "main" java.security.InvalidKeyException: Invalid AES key length: 370 bytes
at com.sun.crypto.provider.AESCrypt.init(AESCrypt.java:87)
at com.sun.crypto.provider.CipherBlockChaining.init(CipherBlockChaining.java:91)
at com.sun.crypto.provider.CipherCore.init(CipherCore.java:591)
at com.sun.crypto.provider.AESCipher.engineInit(AESCipher.java:346)
at javax.crypto.Cipher.init(Cipher.java:1394)
at javax.crypto.Cipher.init(Cipher.java:1327)
at com.sample.App.main(App.java:70)
我已经访问过类似的问题,例如
AES-256 CBC encrypt in php and decrypt in Java or vice-versa
openssl_encrypt 256 CBC raw_data in java
Unable to exchange data encrypted with AES-256 between Java and PHP
列表还在继续......但没有运气
顺便说一句,这就是 PHP 中的加密方式
$secretFile = "/path/to/secret/saved/in/text_file";
$secret = base64_decode(file_get_contents($secretFile));
$iv = bin2hex(openssl_random_pseudo_bytes(8));
$enc = openssl_encrypt($plainText, "aes-256-cbc", $secret, false, $iv);
return $iv.$enc;
是的,我忘了提到我的 JRE 已经在 UnlimitedJCEPolicy 并且我无法更改 PHP 代码。
我完全被困在这一点上,无法前进。请帮忙。
编辑#1
byte[] payload = ....;
byte[] iv = ....;
byte[] secret = ....; // Now 370 bits
byte[] data = Base64.getDecoder().decode(payload);
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
SecretKeySpec secretKeySpec = new SecretKeySpec(Arrays.copyOfRange(secret, 0, 32), "AES");
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv, 0, cipher.getBlockSize());
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
byte[] output = cipher.doFinal(data);
System.out.println(new String(output).trim());
上面的 sn-p 似乎正在使用 openssl_encrypt
编辑#2
我不确定这是否正确,但以下是我所做的,双方的加密-解密工作正常。
PHP 加密,JAVA 解密使用AES/CBC/NoPadding
JAVA加密,PHP解密使用AES/CBC/PKCS5Padding
【问题讨论】:
-
使用长度正确的密钥,“aes-256”是一个 32 字节的密钥。
-
为什么要使用 370 字节的 AES 密钥?
-
^ 因为密钥生成不在我手中。它在 PHP 端完成并在那里完美运行。
标签: java php security encryption cryptography