Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/352.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
AES-256-CBC用PHP加密并用Java解密_Java_Php_Security_Encryption_Cryptography - Fatal编程技术网

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

AES-256-CBC用PHP加密并用Java解密,java,php,security,encryption,cryptography,Java,Php,Security,Encryption,Cryptography,我遇到的情况是,JSON在PHP的openssl\u 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 =

我遇到的情况是,JSON在PHP的
openssl\u 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做同样的事情时,它不起作用:(

这是:

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)
我已经访问过类似的问题,比如

名单还在继续……但运气不好

顺便说一句,这就是如何在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\u encrypt

编辑#2

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

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


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

我不会提供完整的解决方案,但有一些差异需要注意

编码:

String iv = payload.substring(0, 16);
String data = payload.substring(16);
你确定IV和数据在Java和PHP中是相同的吗(IV是字符串?)?如果数据被加密,它们应该被视为字节数组,而不是字符串。只需确保它们是相同的(在PHP和Java中打印十六进制/base64)

对于IV,您可以在结束时调用
IV.getBytes()
,但区域设置编码可能/将损坏您的值。该字符串应仅在实际为字符串(文本)时使用。不要将字符串用于二进制文件

只需将数据和iv视为字节[]

根据openssl生成密钥

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

下面是EVP_BytesToKey的实现:

您应该使用EVP_BytesToKey函数(openssl使用的密钥派生函数)生成256位密钥

编辑:


Maarten(在评论中)是正确的。键参数就是键。PHP函数似乎接受了任何长度的参数,这是误导性的。根据一些文章(例如),键被构造或填充到必要的长度(因此370位的键似乎被截断为256位的长度).

根据您的示例,我为PHP和Java编写了完全可用的代码:
aesciper类:

备注:
-默认情况下,algo为AES-128-CBC。
-默认情况下,初始向量为16字节。
-编码结果=base64(initVector+aes-crypt)。
-编码/解码的结果以自身对象的形式呈现,在编码/解码操作之后,它可以更有效地检查错误、获取错误消息和获取初始向量值

PHP:

JAVA:


使用长度正确的密钥,对于“aes-256”,这是一个32字节的密钥。为什么要尝试使用370字节的aes密钥?^因为密钥生成不在我手上。它在PHP端完成,并且在那里工作得非常好。别忘了!我同意第一部分。简单地说,现代密码是对字节(或八位字节字符串)进行操作的不是字符串。对问题中的文本字符串所做的任何操作都是错误的,尤其是在Java中。在Java中,您需要对
byte[]进行操作
。请注意,PHP可以使用转义对字符串中的任何内容进行编码,因此密文可能在那里是正确的……如果我查看
openssl\u encrypt
API描述,第二部分似乎不正确-我只看到key和IV,没有密码和salt。我已将实现更改为
byte[]
。但你们是对的,不知何故PHP将这个超出的长度截断为256位。我做了一些更改,现在正在工作。请检查更新。我认为,如果在
openssl\u en/decrypt
中默认截断密钥,这会产生某种误导。这可能是一个愚蠢的问题,但如果两个密钥具有相同的初始256位呢应该添加简短的解释,然后链接到完整的解决方案
String iv = payload.substring(0, 16);
String data = payload.substring(16);
$secretKey = '26kozQaKwRuNJ24t';
$text = 'Some text'
$encrypted = AesCipher::encrypt($secretKey, $text);
$decrypted = AesCipher::decrypt($secretKey, $encrypted);

$encrypted->hasError(); // TRUE if operation failed, FALSE otherwise
$encrypted->getData(); // Encoded/Decoded result
$encrypted->getInitVector(); // Get used (random if encode) init vector
// $decrypted->* has identical methods
String secretKey = "26kozQaKwRuNJ24t";
String text = "Some text";

AesCipher encrypted = AesCipher.encrypt(secretKey, text);
AesCipher decrypted = AesCipher.decrypt(secretKey, encrypted);

encrypted.hasError(); // TRUE if operation failed, FALSE otherwise
encrypted.getData(); // Encoded/Decoded result
encrypted.getInitVector(); // Get used (random if encode) init vector
// decrypted.* has identical methods