Невозможно обменять данные, зашифрованные с помощью AES-256 между Java и PHP

Моя проблема: что я шифрую в Java, я могу отлично расшифровать Java, но PHP mcrypt не может расшифровать. Что я mcrypt с помощью mcrypt я могу расшифровать с помощью mcrypt , но не могу на Java.

Я хочу отправить и получить зашифрованные данные из приложения Java на страницу PHP, поэтому мне нужно, чтобы она была совместимой.

Вот что у меня есть …

ЯВА…

 public static String crypt(String input, String key){ byte[] crypted = null; try{ SecretKeySpec skey = new SecretKeySpec(Base64.decodeBase64(key), "AES"); Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); cipher.init(Cipher.ENCRYPT_MODE, skey); crypted = cipher.doFinal(input.getBytes()); }catch(Exception e){ } return Base64.encodeBase64String(crypted); } public static String decrypt(String input, String key){ byte[] output = null; try{ SecretKeySpec skey = new SecretKeySpec(Base64.decodeBase64(key), "AES"); Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); cipher.init(Cipher.DECRYPT_MODE, skey); output = cipher.doFinal(Base64.decodeBase64(input)); }catch(Exception e){ } return new String(output); } 

Бег:

 public static void main(String[] args) { String key = "Zvzpv8/PXbezPCZpxzQKzL/FeoPw68jIb+NONX/LIi8="; String data = "example"; System.out.println(Cpt.decrypt(Cpt.crypt(data, key), key)); } 

Вывод:

 example 

PHP …

 function getEncrypt($sStr, $sKey) { return base64_encode( mcrypt_encrypt( MCRYPT_RIJNDAEL_256, $sKey, $sStr, MCRYPT_MODE_ECB ) ); } function getDecrypt($sStr, $sKey) { return mcrypt_decrypt( MCRYPT_RIJNDAEL_256, $sKey, base64_decode($sStr), MCRYPT_MODE_ECB ); } 

Бег:

 $crypt = getDecrypt(getEncrypt($str, $key), $key); echo "<p>Crypt: $crypt</p>"; 

Вывод:

 Crypt: example                          

Использование PHP для склеивания «пример» с ключом «Zvzpv8 / PXbezPCZpxzQKzL / FeoPw68jIb + NONX / LIi8 =« Я получаю »YTYhgp4zC + w5IsViTR5PUkHMX4i7JzvA6NJT1FqhoGY =". Используя Java для шифрования одной и той же вещи с одним и тем же ключом, я получаю «+ tdAZqTE7WAVPXhB3Tp5 + g ==».

Я кодирую и декодирую base64 в правильном порядке, и я протестировал base64, кодируя и декодируя совместимость между Java и PHP и работаю.

BUG # 1

MCRYPT_RIJNDAEL_256 не AES. 256 в этой константе ссылаются на блокировку, а не на ключи. Используйте MCRYPT_RIJNDAEL_128 чтобы получить тот же алгоритм, что и AES. Ключ определяется только количеством байтов в указанном ключевом аргументе. Итак, поставьте 32 байта, и вы получите AES с 256-битным ключом.

BUG # 2

Эти две строки никогда не верны в Java и указывают на фундаментальное непонимание природы произвольных двоичных данных, создаваемых криптографическими преобразованиями:

 output = cipher.doFinal(Base64.decodeBase64(input)); return new String(output); 

Нет ничего плохого в передаче и хранении byte[] напрямую, но если вы должны использовать только печатные строки, тогда вы должны кодировать / декодировать base64, чтобы сделать это. Поскольку вы уже используете base64 экстенсивно, что будет похоже на путь. Я бы предположил, что правильные две строки будут:

 output = cipher.doFinal(Base64.decodeBase64(input)); return new String(Base64.encodeBase64(output), "UTF-8"); 

РЕДАКТИРОВАТЬ:

Просто шучу о ошибке №2. На самом деле, я был неправ, я не заметил, что это было дешифрование. Конечно, если вы знаете, что дешифрованный byte[] является допустимой строкой, то совершенно правильно делать то, что делает ваш код.

Я знаю, что это старая тема, но я добавлю свое рабочее решение.

Вы должны переписать PHP-часть скрипта:

 function getEncrypt($sStr, $sKey) { return base64_encode( mcrypt_encrypt( MCRYPT_RIJNDAEL_128, base64_decode($sKey), $sStr, MCRYPT_MODE_ECB ) ); } function getDecrypt($sStr, $sKey) { return mcrypt_decrypt( MCRYPT_RIJNDAEL_128, base64_decode($sKey), base64_decode($sStr), MCRYPT_MODE_ECB ); } 

Вы должны base64_decode ($ sKey), потому что ваш ключ закодирован base64.

 $key = "Zvzpv8/PXbezPCZpxzQKzL/FeoPw68jIb+NONX/LIi8="; 

Затем вам нужно создать эту функцию (кредит отправляется в поясраки из http://www.php.net/manual/en/function.mcrypt-decrypt.php ):

 function pkcs5_pad ($text, $blocksize) { $pad = $blocksize - (strlen($text) % $blocksize); return $text . str_repeat(chr($pad), $pad); } 

Используйте этот код для кодирования / декодирования:

 $decrypt = getDecrypt("6XremNEs1jv/Nnf/fRlQob6oG1jkge+5Ut3PL489oIo=", $key); echo $decrypt; echo "\n\n"; echo getEncrypt(pkcs5_pad("My very secret text:)", 16), $key); 

Надеюсь, это будет полезно для кого-то! 🙂

См. Здесь:

  • Разница в PHP-шифровании от iOS и .NET

  • AES Шифрование в C #, расшифровка в PHP

  • DES Шифрование в PHP и C #

Проблема, с которой вы сталкиваетесь, – это проблема с дополнением. Я не знаю Java, но AES/ECB/PKCS5Padding выглядит так, как будто вы используете PKCS # 5 (это по сути то же самое, что и PKCS # 7), в то время как PHP изначально поддерживает NULL padding. Вот что делает PKCS # 5/7:

Вставьте входную строку с отступом от 1 до 8 байтов, чтобы общая длина была кратной 8 байтам. Значение каждого байта строки заполнения устанавливается на количество добавленных байтов – т.е. 8 байтов значения 0x08, 7 байтов значения 0x07, …, 2 байта 0x02 или один байт значения 0x01.

Таким образом, PHP-код для выполнения права заполнения тривиален:

 $blockSize = mcrypt_get_block_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB); $padding = $blockSize - (strlen($data) % $blockSize); $data .= str_repeat(chr($padding), $padding); 

Имейте в виду, чтобы иметь такую ​​же кодировку для строк. Попробуйте преобразовать строки на обоих языках в UTF-8, например, и преобразовать в двоичные данные, которые закодированы:

Функция PHP (s. Utf8_encode () ):

 $strAndBlob = utf8_encode("My string"); 

Ява:

 String str = "My string"; byte[] blob = str.getBytes("utf-8"); 

Например, PHP не должен использовать UTF-8 по умолчанию.