Java javax.crypto 和 PHP openssl_decrypt 不相同

标签 java php encryption cryptography

我正在将 java 解密器代码移植到 PHP。 我有 3 个文件:

  • encrypted.data - 它是使用 AES/CBC/NoPadding(128) 加密的数据 算法。
  • aes.key - 这是 secret key 。
  • initialization.vector - 它是初始化 vector

参见此处link

我在Java javax.crypto 包中使用AES/CBC/NoPadding (128) 算法来解密数据。在 PHP 中我使用 openssl 扩展

PHP 版本 7.1.0 PHP 信息(openssl):

  • OpenSSL 库版本 LibreSSL 2.4.4
  • OpenSSL header 版本 LibreSSL 2.4.4

我的代码示例:

我的Java代码:

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.nio.file.Files;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

public class Main {
    public static void main(String[] args) throws IOException, InvalidAlgorithmParameterException, InvalidKeyException, NoSuchPaddingException, NoSuchAlgorithmException, BadPaddingException, IllegalBlockSizeException {
        File AesKeyFile = new File("./Cipher2PHP/aes.key");
        File InitializationVectorFile = new File("./Cipher2PHP/initialization.vector");
        File EncryptedDataFile = new File("./Cipher2PHP/encrypted.data");
        byte[] AesKeyData = Files.readAllBytes(AesKeyFile.toPath());
        byte[] InitializationVectorData = Files.readAllBytes(InitializationVectorFile.toPath());
        byte[] EncryptedData = Files.readAllBytes(EncryptedDataFile.toPath());

        Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
        SecretKeySpec keySpec = new SecretKeySpec(AesKeyData, "AES");
        cipher.init(Cipher.DECRYPT_MODE, keySpec, new IvParameterSpec(InitializationVectorData));

        byte[] result = cipher.doFinal(EncryptedData);
        String decrypted = new String(result);

        System.out.printf("Your data: %s\n", decrypted);
    }
}

我的可移植 PHP 代码

<?php
$AesKeyData = file_get_contents('./Cipher2PHP/aes.key');
$InitializationVectorData = file_get_contents('./Cipher2PHP/initialization.vector');
$EncryptedData = file_get_contents('./Cipher2PHP/encrypted.data');
$decrypted = openssl_decrypt(
    $EncryptedData,
    'AES-128-CBC',
    $AesKeyData,
    OPENSSL_NO_PADDING,
    $InitializationVectorData
);
printf("Your data: %s\n", $decrypted);

Java 代码根据需要工作。 PHP 代码在不匹配的情况下工作。

Java代码输出:

Your data: My very secure data. Very secure
Process finished with exit code 0

PHP 代码输出:

Your data: �j��2��䈤�n�h�/sEH�,/-��-�^[
Process finished with exit code 0

Base64编码数据:

PHP:

Base64 AES Key:                 "Kl/LF5HSL7YCRbPYNp7QssJzcVY/vx88nt9rEYJaXQo="
Base64 InitializationVector:    "QXF/8HO4te38LhhuFP9+hA=="
Base64 EncryptedData:           "eA1w+ysqsHIdaXsQRSgt9nLPDj7ILcqyZdCW3wDBcy0="
Decrypted Result:               "xmqJ0TKgx+SIpP1u/hNoyS9zRUjEAAEsLy251S2hXls="

Java:

Base64 AES Key:                 "Kl/LF5HSL7YCRbPYNp7QssJzcVY/vx88nt9rEYJaXQo="
Base64 InitializationVector:    "QXF/8HO4te38LhhuFP9+hA=="
Base64 EncryptedData:           "eA1w+ysqsHIdaXsQRSgt9nLPDj7ILcqyZdCW3wDBcy0="
Decrypted Result:               "TXkgdmVyeSBzZWN1cmUgZGF0YS4gVmVyeSBzZWN1cmU="

控制台中的文件:

./Cipher2PHP mac$ file -I *
aes.key:               application/octet-stream; charset=binary
initialization.vector: application/octet-stream; charset=binary
encrypted.data:        application/octet-stream; charset=binary
./Cipher2PHP mac$ xxd  aes.key 
0000000: 2a5f cb17 91d2 2fb6 0245 b3d8 369e d0b2  *_..../..E..6...
0000010: c273 7156 3fbf 1f3c 9edf 6b11 825a 5d0a  .sqV?..<..k..Z].
./Cipher2PHP mac$ xxd  initialization.vector 
0000000: 4171 7ff0 73b8 b5ed fc2e 186e 14ff 7e84  Aq..s......n..~.
./Cipher2PHP mac$ xxd  encrypted.data 
0000000: 780d 70fb 2b2a b072 1d69 7b10 4528 2df6  x.p.+*.r.i{.E(-.
0000010: 72cf 0e3e c82d cab2 65d0 96df 00c1 732d  r..>.-..e.....s-
./Cipher2PHP mac$ xxd -b aes.key 
0000000: 00101010 01011111 11001011 00010111 10010001 11010010  *_....
0000006: 00101111 10110110 00000010 01000101 10110011 11011000  /..E..
000000c: 00110110 10011110 11010000 10110010 11000010 01110011  6....s
0000012: 01110001 01010110 00111111 10111111 00011111 00111100  qV?..<
0000018: 10011110 11011111 01101011 00010001 10000010 01011010  ..k..Z
000001e: 01011101 00001010                                      ].
./Cipher2PHP mac$ xxd -b initialization.vector 
0000000: 01000001 01110001 01111111 11110000 01110011 10111000  Aq..s.
0000006: 10110101 11101101 11111100 00101110 00011000 01101110  .....n
000000c: 00010100 11111111 01111110 10000100                    ..~.
./Cipher2PHP mac$ xxd -b encrypted.data 
0000000: 01111000 00001101 01110000 11111011 00101011 00101010  x.p.+*
0000006: 10110000 01110010 00011101 01101001 01111011 00010000  .r.i{.
000000c: 01000101 00101000 00101101 11110110 01110010 11001111  E(-.r.
0000012: 00001110 00111110 11001000 00101101 11001010 10110010  .>.-..
0000018: 01100101 11010000 10010110 11011111 00000000 11000001  e.....
000001e: 01110011 00101101   

最佳答案

在 Java 中,要使用的 AES 版本(128、192 或 256 位)由您提供的 key 长度决定,该长度必须恰好是这些长度之一。

在 PHP 中,您可以在方法参数中显式指定要使用的 AES 版本为 openssl_decryptopenssl_encrypt ,例如“aes-128-cbc”。然后,PHP 将截断或用零字节扩展您提供的 key ,使其达到所需的长度。

您使用的是 32 字节(256 位) key ,因此您的 Java 代码使用 AES-256。但是您的 PHP 代码指定“AES-128-CBC”,因此您使用的是不同的版本。

要使 PHP 版本的行为与 Java 版本类似,请将调用中的方法字符串从 openssl_decrypt 更改为 'aes-256-cbc'

要使 Java 版本的行为与 PHP 版本类似(我认为您不想这样做,但为了完整性我将其包含在内),请复制 key 的前 16 个字节,并仅在创建 SecretKeySpec 时使用它们对象。

关于Java javax.crypto 和 PHP openssl_decrypt 不相同,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42878885/

相关文章:

php - 将带有非数字键的 PHP 数组编码为 JSON 数组

写入文件时的 PHP,如何将文本添加到现有文本的文件中?

encryption - 无需付费即可加密静态数据库?

iphone - 在 iOS 应用程序中使用 SSL 进行登录

java - 扩展 JSP 标签库

java - 将值从一个 Activity 返回到另一个 Activity

java - 使用 Java 泛型、接口(interface)和继承的不兼容性

java - 如何在Java游戏中实现音频?

php - HMAC - 在 Objective-C 中实现 PHP 算法

JavaScript 代码加密