gpt4 book ai didi

java - AES-256-CBC 用 PHP 加密并用 Java 解密

转载 作者:行者123 更新时间:2023-12-02 11:56:23 25 4
gpt4 key购买 nike

我遇到的情况是,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());

上面的代码片段似乎适用于openssl_encrypt

编辑#2

我不确定这是否正确,但以下是我所做的,并且双方的加密解密工作正常。

在 PHP 中加密,在 JAVA 中解密使用 AES/CBC/NoPadding

在JAVA中加密,在PHP中解密使用AES/CBC/PKCS5Padding

最佳答案

我不会提供完整的解决方案,但您应该注意一些差异

编码:

String iv = payload.substring(0, 16);
String data = payload.substring(16);

您确定 Java 和 PHP 中的 IV 和数据相同(IV 是字符串吗?)?如果数据已加密,则应将它们视为字节数组,而不是字符串。只要真正确保它们是相同的(在 php 和 java 中打印 hex/base64)

对于 IV,您最后调用 iv.getBytes(),但区域设置编码可能会损坏您的值。仅当字符串确实是字符串(文本)时才应使用该字符串。不要对二进制文件使用字符串。

简单地将 data 和 iv 视为 byte[]

根据 openssl 生成 key

AES key 的长度必须为 256 位才能使用 aes-256-cbc。问题是 - openssl 默认情况下不使用提供的 secret 作为 key (我相信它可以,但我不知道如何在 PHP 中指定它)。

参见OpenSSL EVP_BytesToKey issue in Java

这是 EVP_BytesToKey 实现:https://olabini.com/blog/tag/evp_bytestokey/

您应该使用 EVP_BytesToKey 函数(它是 openssl 使用的 key 派生函数)生成 256 位 key 。

编辑:

Maarten(在评论中)是对的。 key 参数是键。似乎 PHP 函数接受任何长度的参数,这是误导性的。根据一些文章(例如 http://thefsb.tumblr.com/post/110749271235/using-opensslendecrypt-in-php-instead-of ), key 被截断或填充到必要的长度(因此似乎 370 位 key 被截断为 256 位长度)。

关于java - AES-256-CBC 用 PHP 加密并用 Java 解密,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47576722/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com