Преобразование кода шифрования PHP в Java показать ошибку? - PullRequest
0 голосов
/ 04 января 2019

Я создаю приложение, которое вызывает сторонний API, они предоставили код PHP, а нам нужен код Java.

Код PHP приведен ниже:

function encryptIt( $string ) {
$key = 'qJB0rGtIn5UB1xG03efyCp';
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length('aes-256-cbc'));
$encrypted = openssl_encrypt($string, 'aes-256-cbc', $key, 0, $iv);
return base64_encode($encrypted . '::' . $iv);
}

Теперь я изменил код abouve на java следующим образом:

private static String openssl_encrypt(String data, String strKey, String strIv) throws Exception {
        SecureRandom randomSecureRandom = new SecureRandom();
        Base64 base64 = new Base64();
        Cipher ciper = Cipher.getInstance("AES/CBC/PKCS5Padding");
        byte[] ivv = new byte[ciper.getBlockSize()];
        randomSecureRandom.nextBytes(ivv);
        SecretKeySpec key = new SecretKeySpec(strKey.getBytes(), "AES");
        IvParameterSpec iv = new IvParameterSpec(ivv, 0, ciper.getBlockSize());

        // Encrypt
        ciper.init(Cipher.ENCRYPT_MODE, key, iv);
        byte[] encryptedCiperBytes = ciper.doFinal(data.getBytes());

        String s = new String(base64.encode(encryptedCiperBytes));
        System.out.println("Ciper : " + s);
        return s;
    }

На самом деле я не очень хорош в методах шифрования, поэтому код PHP создает код IV, но после поиска в Интернете я попытался создать код IV, как указано выше,

Но я получил ошибку как:

java.security.InvalidKeyException: Invalid AES key length: 22 bytes
    at com.sun.crypto.provider.AESCipher.engineGetKeySize(AESCipher.java:509)
    at javax.crypto.Cipher.passCryptoPermCheck(Cipher.java:1067)
    at javax.crypto.Cipher.checkCryptoPerm(Cipher.java:1038)
    at javax.crypto.Cipher.init(Cipher.java:1393)
    at javax.crypto.Cipher.init(Cipher.java:1327)

Пожалуйста, помогите мне решить эту проблему

ОБНОВЛЕНО:

Я обновил код до:

private static String openssl_encrypt(String data) throws Exception {
        SecureRandom random = new SecureRandom();
        byte[] salt = new byte[16];
        random.nextBytes(salt);
        KeySpec spec = new PBEKeySpec("qJB0rGtIn5UB1xG03efyCp".toCharArray(), salt, 65536, 256); // AES-256
        SecretKeyFactory f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
        byte[] key = f.generateSecret(spec).getEncoded();
        SecretKeySpec keySpec = new SecretKeySpec(key, "AES");

        byte[] ivBytes = new byte[16];
        random.nextBytes(ivBytes);
        IvParameterSpec iv = new IvParameterSpec(ivBytes);

        Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
        c.init(Cipher.ENCRYPT_MODE, keySpec, iv);
        byte[] encValue = c.doFinal(data.getBytes());

        byte[] finalCiphertext = new byte[encValue.length+2*16];
        System.arraycopy(ivBytes, 0, finalCiphertext, 0, 16);
        System.arraycopy(salt, 0, finalCiphertext, 16, 16);
        System.arraycopy(encValue, 0, finalCiphertext, 32, encValue.length);
        String s = new String(Base64.getEncoder().encodeToString(finalCiphertext));
        return s;
    }

Тем не менее я получил сообщение об ошибке:

java.security.InvalidKeyException: недопустимый размер ключа

Мои провайдеры API говорят, что это ключ!

1 Ответ

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

Как и злополучная хрень mcrypt, openssl_encrypt позволяет использовать ключи неправильного размера.Вместо того, чтобы отклонять такие ключи, он просто заполняет остальную часть ключа байтами с нулевым значением ("\0" в PHP).Это полностью противоречит любой хорошей криптографической практике, практически любой библиотекой для языков более высокого уровня.

Это очень вероятно по двум причинам:

  • C, что обычно предполагает указатель на ключ , для которого заранее определен размер (отсюда -256 в командах openssl).
  • PHP, имеющий динамическую типизацию переменных, заставляет пользователей ожидать, что функции будут принимать любой видиз crap тип или состояние переменной.

Чтобы скопировать некорректный код PHP, вам необходимо заполнить ключ нулевыми байтами (пока массив не станет длиной 32 байта).В Java это обычно выполняется с использованием ужасных Arrays.copyOf в настоящее время (поскольку он также правит нулевые байты).

Обратите внимание, что IV, конечно, по-прежнему будет следить за тем, чтобы ваши результаты шифрования никогда не совпадали.Вместо этого попробуйте расшифровать на Java и использовать ту же схему для шифрования, убедившись, что IV остается случайным в конечном коде.


Ключи никогда не являются строками.Ключи состоят из битов или - предпочтительно - ссылок на ключи, хранящиеся где-то в защищенной памяти.Однако пароли являются строками, и использование PKBDF2 действительно должно быть предпочтительным.

Конечно, для использования PBKDF2 необходимо:

  1. сделать то же самое в вашем PHP-коде и
  2. убедитесь, что вы используете либо среду Java с данными (настоятельно рекомендуется для защищенных сред), либо устанавливаете файлы политики неограниченной юрисдикции в среду выполнения Java.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...