Следующий Java-код фокусируется на части шифрования / дешифрования без сложной обработки исключений и т. Д. Вы должны адаптировать ее к вашим требованиям.Поскольку PHP-код является справочным, необходимо учитывать двойное заполнение.По аналогии с PHP-методами в Java-методах используются значения по умолчанию и пользовательские отступы PKCS7 (другой подход заключается в том, чтобы использовать не заполнение по умолчанию (т. Е. AES/CBC/NoPadding
), а полностью пользовательское заполнение).
Пользовательский PKCS7-Padding:
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;
}
Unpadding:
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...
, который равен выводу методов PHP, когдаиспользуется один и тот же простой текст, ключ и IV.
РЕДАКТИРОВАТЬ:
Поскольку AES-256-CBC
используется в PHP-методах, длина ключа составляет 32 байта.Число обозначает длину ключа в битах (16-байтовый ключ необходим, например, для AES-128-CBC
).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...