AES-256 CBC шифрует в php и расшифровывает на Java или наоборот

ЯВА

import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import org.apache.commons.codec.binary.Base64; class AES256JavaPhp{ public static void main(String[] args) throws Exception { Base64 base64 = new Base64(); Cipher ciper = Cipher.getInstance("AES/CBC/PKCS5Padding"); SecretKeySpec key = new SecretKeySpec("PasswordPassword".getBytes("UTF-8"),"AES"); IvParameterSpec iv = new IvParameterSpec ("dynamic@dynamic@".getBytes("UTF-8"),0,ciper.getBlockSize()); //Encrypt ciper.init(Cipher.ENCRYPT_MODE, key,iv); byte[] encryptedCiperBytes = base64.encode ((ciper.doFinal("Hello".getBytes()))); System.out.println("Ciper : "+new String(encryptedCiperBytes)); //Decrypt ciper.init(Cipher.DECRYPT_MODE, key,iv); byte[] text = ciper.doFinal(base64.decode(encryptedCiperBytes)); System.out.println("Decrypt text : "+new String(text)); } } 

Выход Java:

 Ciper : KpgzpzCRU7mTKZePpPlEvA== Decrypt text : Hello 

PHP

 <?php> $cipherText = encrypt("Hello", 'aes-256-cbc'); exit(); function encrypt($data, $algo) { $key = 'PasswordPassword'; //$iv = random_bytes(openssl_cipher_iv_length($algo)); $iv = 'dynamic@dynamic@'; $cipherText = openssl_encrypt( $data, $algo, $key, OPENSSL_RAW_DATA, $iv ); $cipherText = base64_encode($cipherText); printData("Ciper Text : $cipherText"); $cipherText = base64_decode($cipherText); $plaintext = openssl_decrypt( $cipherText, $algo, $key, OPENSSL_RAW_DATA, $iv ); printData("Plain Text after decryption : $plaintext"); } function printData($obj) { print_r($obj); } ?> 

Выход PHP:

 Ciper Text : ef/ENVlBn9QBFlkvoN7P2Q== Plain Text after decryption : Hello 

Получающиеся шифры различны, хотя они используют один и тот же ключ и IV. Как это возможно?

Очевидно, что вы должны использовать один и тот же ключ AES и IV для безопасного сеанса. И они должны быть надлежащим образом и надежно переданы через клиентов. Неважно, на каком языке написаны клиенты. Ваша проблема заключается не в понимании протокола для заключения соглашения и установления сеанса.

Вектор инициализации не является защищенным значением; т.е. вы не шифруете его при общении между клиентами. Он должен быть упакован в текстовое поле с зашифрованным ключом AES (который вы выписываете из некоторого протокола соглашения о соглашении).

CMS использует KeyTransRecipientInfo для доставки этой информации. TLS также определяет, как IV устанавливает свое рукопожатие . Я бы настоятельно рекомендовал следовать реализации CMS, а не что-то надуманное и почти гарантированно содержать ошибки безопасности.


Обновить

Теперь ясно, что вы путаетесь, почему результирующие зашифрованные тексты не детерминированы. Это связано с тем, что реализация Java по умолчанию выполняет 128-битное шифрование и ему предоставляется 128-битный ключ, но PHP-код запрашивает шифрование с 256-битным напряжением и только один и тот же 128-битный ключ . Поэтому PHP должен заполнять ключ.


Обновление 2

На основе приведенных ниже комментариев приведен пример использования Java для генерации 256-битного ключа:

 KeyGenerator generator = KeyGenerator.getInstance("AES"); generator.init(256); // The AES key size in number of bits SecretKey secKey = generator.generateKey(); 

Ваш ключ имеет длину 128 бит (16 байт), но вы запрашиваете AES-256 в PHP. Это приведет к заполнению ключа AES с 256 бит (32 байта). Вы должны запросить AES-128 для этого. Именно так работает OpenSSL-расширение в PHP.

Ключ должен идеально выглядеть как случайный шум, чтобы предотвратить атаки грубой силы. Ваш текущий ключ – ничего, кроме этого. Это очень предсказуемо. Вы действительно должны генерировать случайный ключ и добавлять его в свой код в кодированной форме, например Base64. Затем вы можете декодировать его перед использованием.