Расшифровать данные в Java из пользовательского шифрования AES-256-CBC в PHP - PullRequest
0 голосов
/ 29 января 2019

У меня есть задача перенести 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;
}

1 Ответ

0 голосов
/ 30 января 2019

Следующий 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...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...