我的任务是将php代码迁移到Java,但是我无法像这些功能那样解密信息。我读过许多类似的消息,但没有解决方案可以解决问题。
static function pkcs7_unpad($data) {
return substr($data, 0, -ord($data[strlen($data) - 1]));
}
static function decrypt($enc_name) {
$encryption_key = 'secret_key';
$iv = 'inizialization_vector';
$name = Encryptation::pkcs7_unpad(openssl_decrypt(
$enc_name,
'AES-256-CBC',
$encryption_key,
0,
$iv
));
return $name;
}
更新
使用加密代码更新:
static function pkcs7_pad($data, $size) {
$length = $size - strlen($data) % $size;
return $data . str_repeat(chr($length), $length);
}
static function encrypt($name) {
$encryption_key = 'secret_key';
$iv = 'inizialization_vector';
$enc_name = openssl_encrypt(
Encryptation::pkcs7_pad($name, 16), // padded data
'AES-256-CBC', // cipher and mode
$encryption_key, // secret key
0, // options (not used)
$iv // initialisation vector
);
return $enc_name;
}
答案 0 :(得分:1)
以下Java代码专注于加密/解密部分,而没有复杂的异常处理等。您应该根据需要对其进行调整。由于PHP代码是参考,因此必须考虑双填充。与PHP方法类似,Java方法中使用了默认方法和自定义PKCS7填充(另一种方法是不使用默认填充(即AES/CBC/NoPadding
),而使用完全自定义的填充)。
自定义PKCS7填充:
private static byte[] addPKCS7Padding(byte[] data, int size) {
byte pad = (byte)(size - (data.length % size));
byte[] output = new byte[data.length + pad];
System.arraycopy(data, 0, output, 0, data.length);
for (int i = data.length; i < output.length; i++)
output[i] = (byte)pad;
return output;
}
展开:
private static byte[] removePKCS7Padding(byte[] data, int size) {
byte pad = data[data.length - 1];
byte[] output = new byte[data.length - pad];
System.arraycopy(data, 0, output, 0, data.length - pad);
return output;
}
PHP加密方法可能的对应方法是:
public static String encrypt(byte[] plainData) throws Exception {
SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
byte[] plainDataPKCS7Padded = addPKCS7Padding(plainData, 16);
byte[] encryptedData = cipher.doFinal(plainDataPKCS7Padded);
return Base64.getEncoder().encodeToString(encryptedData);
}
与PHP解密方法相对应的是:
public static byte[] decrypt(String encodedAndEncryptedData) throws Exception {
SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
byte[] encryptedData = Base64.getDecoder().decode(encodedAndEncryptedData);
byte[] decryptedData = cipher.doFinal(encryptedData);
return removePKCS7Padding(decryptedData, 16);
}
测试:
public class Cryptography {
private static byte[] key = "01234567890123456789012345678901".getBytes(StandardCharsets.UTF_8);
private static byte[] iv = "0123456789012345".getBytes(StandardCharsets.UTF_8);
public static void main(String[] args) throws Exception {
String plainText = "This is a plain text which needs to be encrypted...";
String encrypedData = encrypt(plainText.getBytes(StandardCharsets.UTF_8));
System.out.println(encrypedData);
byte[] decryptedData = decrypt(encrypedData);
String decryptedText = new String(decryptedData, StandardCharsets.UTF_8);
System.out.println(decryptedText);
}
...
}
输出:
cPF/JWAwp8G9xkUhHIMHLaS8WVfJM2UCxf2bphgOuJ6JVBmMFWAc5rwZzS/hNpAUx3+94UEEwXso2v/LkXVeXJmmfSgIaIvc9oDtGDUoQVo=
This is a plain text which needs to be encrypted...
等于使用相同的纯文本,键和IV时PHP方法的输出。
编辑:
由于PHP方法中使用了AES-256-CBC
,因此密钥长度为32字节。数字表示以位为单位的密钥长度(例如,AES-128-CBC
需要16字节的密钥)。 PHP-openssl方法会自动使用0x0值填充太短的键。在Java中,这不是自动发生的,而是必须明确实现,例如与
private static byte[] padKey(byte[] key) {
byte[] paddedKey = new byte[32];
System.arraycopy(key, 0, paddedKey, 0, key.length);
return paddedKey;
}
要进行测试替换
private static byte[] key = "01234567890123456789012345678901".getBytes(StandardCharsets.UTF_8);
与
private static byte[] shortLengthKey = "012345678".getBytes(StandardCharsets.UTF_8);
private static byte[] key = padKey(shortLengthKey);
其中shortLengthKey
代表您的9字节密钥。
输出是针对PHP和Java的:
CLPqFawQclb9PPOzcKowWBCi2gsaBJPXpl+kbGD8xYmTgL3WOtGUKpAskhXxhU4SKFZheEWiz+xkUEzLsKht3YzL9ZkSTuYtYwaZ0BjuWLM=
This is a plain text which needs to be encrypted...