Não é possível trocar dados criptografados com o AES-256 entre Java e PHP

Meu problema é: o que criptografa em Java, posso decodificar perfeitamente em Java, mas o PHP mcrypt não pode decifrar. O que eu criptografa com o mcrypt Eu posso descriptografar com o mcrypt , mas não posso em Java.

Quero enviar e receber dados criptografados de um aplicativo Java para uma página PHP, por isso preciso que seja compatível.

Aqui está o que eu tenho …

JAVA…

 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); } 

Corrida:

 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)); } 

Saída:

 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 ); } 

Corrida:

 $crypt = getDecrypt(getEncrypt($str, $key), $key); echo "

Crypt: $crypt

";

Saída:

 Crypt: example                          

Usando PHP para criptografar “exemplo” com a chave “Zvzpv8 / PXbezPCZpxzQKzL / FeoPw68jIb + NONX / LIi8 =” Eu recebo “YTYhgp4zC + w5IsViTR5PUkHMX4i7JzvA6NJT1FqhoGY =”. Usando o Java para criptografar o mesmo com a mesma chave, eu recebo “+ tdAZqTE7WAVPXhB3Tp5 + g ==”.

Estou codificando e decodificando para base64 na ordem correta e testei codificação e decodificação base64 entre Java e PHP e está funcionando.

ERRO # 1

MCRYPT_RIJNDAEL_256 não é AES. O 256 nessa constante refere-se ao tamanho do bloco, não ao tamanho do teclado. Use MCRYPT_RIJNDAEL_128 para obter o mesmo algoritmo que AES. O tamanho do teclado é definido apenas pelo número de bytes no argumento chave que você fornece. Então, forneça 32 bytes e você recebe AES com uma chave de 256 bits.

ERRO # 2

Essas duas linhas nunca são corretas em Java e indicam um mal-entendido fundamental da natureza dos dados binários arbitrários produzidos por transformações criptográficas:

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

Não há nada de errado em transmitir e armazenar byte[] diretamente, mas se você deve usar apenas cadeias de impressão, então você deve codificar / decodificar base64 para fazê-lo. Como você já está usando o base64 extensivamente, isso parece ser o caminho a seguir. Eu acho que as duas linhas corretas seriam:

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

EDITAR:

Apenas brincando com o bug # 2. Na verdade, eu estava errado, não percebi que era a direção do descifrado. Claro, se você sabe que o byte[] descodificado byte[] é uma string válida, então é perfeitamente correto fazer o que seu código faz.

Eu sei que este é um tópico antigo, mas vou adicionar minha solução de trabalho.

Você precisa rewrite o lado PHP do script:

 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 ); } 

Você deve base64_decode ($ sKey) porque sua chave está codificada em base64.

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

Então, você precisa criar esta function (o crédito vai para beltrachi de 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); } 

Use este código para codificar / decodificar:

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

Espero que isso seja útil para alguém! 🙂

Por favor, veja aqui:

  • Diferença na criptografia PHP do iOS e .NET

  • AES Encripta em C #, desencripta em PHP

  • DES Encryption em PHP e C #

O problema que você está encontrando é um problema de preenchimento. Eu não conheço o Java, mas AES/ECB/PKCS5Padding parece que você está usando um preenchimento PKCS # 5 (que é essencialmente o mesmo que o PKCS # 7), enquanto o PHP nativamente apenas suporta NULL -padding. Isso é o que faz PKCS # 5/7:

Coloque a input com uma string de preenchimento entre 1 e 8 bytes para tornar o comprimento total um múltiplo exato de 8 bytes. O valor de cada byte da seqüência de preenchimento é definido como o número de bytes adicionados – ou seja, 8 bytes de valor 0x08, 7 bytes de valor 0x07, …, 2 bytes de 0x02 ou um byte de valor 0x01.

Então, o código PHP para fazer o direito de preenchimento é trivial:

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

Tenha em mente que tenha a mesma codificação para as cordas. Tente converter as seqüências de caracteres em ambos os idiomas para UTF-8, por exemplo, e para converter em dados binários codificados:

PHP (function s. utf8_encode () ):

 $strAndBlob = utf8_encode("My string"); 

Java:

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

O PHP, por exemplo, não deve usar UTF-8 por padrão.