2010-12-27 10 views
11

Il mio problema è: cosa crittografo in Java Posso decodificare perfettamente in Java, ma PHP mcrypt non può decrittografare. Cosa crittografo con mcrypt Posso decifrare con mcrypt, ma non posso in Java.Impossibile scambiare dati crittografati con AES-256 tra Java e PHP

Desidero inviare e ricevere dati crittografati da un'applicazione Java a una pagina PHP, quindi ho bisogno che sia compatibile.

Ecco quello che ho ...

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

Esecuzione:

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

uscita:

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

Esecuzione:

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

uscita:

Crypt: example������������������������� 

Utilizzo di PHP per criptare "esempio" con il tasto "Zvzpv8/PXbezPCZpxzQKzL/FeoPw68jIb + NONX/LIi8 =" ottengo "YTYhgp4zC + w5IsViTR5PUkHMX4i7JzvA6NJT1FqhoGY =". Usando Java per criptare la stessa cosa con lo stesso tasto ottengo "+ tdAZqTE7WAVPXhB3Tp5 + g ==".

Sto codificando e decodificando su base64 nell'ordine corretto e ho testato la codifica base64 e decodificato la compatibilità tra Java e PHP e funziona.

risposta

14

BUG # 1

MCRYPT_RIJNDAEL_256non è AES. Il 256 in quella costante si riferisce al blockize, non al keysize. Utilizzare MCRYPT_RIJNDAEL_128 per ottenere lo stesso algoritmo di AES. Il keysize è impostato solo dal numero di byte nell'argomento chiave fornito. Quindi fornisci 32 byte e ottieni AES con una chiave a 256 bit.

BUG # 2

Queste due linee non sono mai corrette in Java e indicano un fraintendimento fondamentale della natura dei dati binari arbitrari prodotti dalle trasformazioni crittografiche:

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

Non c'è nulla di sbagliato con la trasmissione e la memorizzazione diretta di byte[], ma se è necessario utilizzare solo stringhe stampabili, è necessario codificare/decodificare in base64 per farlo. Dato che stai già usando ampiamente base64, sembrerebbe la strada da percorrere. Direi che le giuste due linee sarebbero:

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

EDIT:

Sto scherzando su bug # 2. Davvero, ho sbagliato, non ho notato che era la decifratura. Naturalmente, se si conosce la decodifica byte[] è una stringa valida, allora è perfettamente corretto fare ciò che fa il codice.

+0

Vedo, l'ho scoperto, ma pensavo che stavo usando AES-128. Quindi è davvero 256. Riguardo queste righe, l'ho fatto solo perché sono sicuro che i dati criptati contengono sempre solo stringhe e nessun dato binario. – LZZ

1

Ricordare di avere la stessa codifica per le stringhe. Prova a convertire le stringhe in entrambe le lingue a UTF-8, ad esempio, e poi convertire in dati binari codificato:

PHP (s utf8_encode() funzione.):

$strAndBlob = utf8_encode("My string"); 

Java:

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

PHP, ad esempio, non deve utilizzare UTF-8 per impostazione predefinita.

+1

Sì, è importante, ma non è questo il problema. – LZZ

3

prega di consultare qui:

Il problema incontrato è un padding-problema . Non conosco Java, ma lo AES/ECB/PKCS5Padding sembra che tu stia usando un padding PKCS # 5 (che è essenzialmente lo stesso di PKCS # 7) mentre PHP nativamente supporta solo NULL -padding.Questo è quello PKCS # 5/7 fa:

Pad ingresso con una stringa di imbottitura tra 1 e 8 byte per rendere la lunghezza totale un multiplo esatto di 8 byte. Il valore di ciascun byte della stringa imbottitura è impostato al numero di byte aggiunto - ossia 8 byte di valore 0x08, 7 byte di valore 0x07, ..., 2 byte di 0x02 o un byte di valore 0x01.

Così il codice PHP per fare il giusto imbottitura è banale:

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

Bene, ho fatto esattamente quello che hai detto, ma non ha risolto il problema, tuttavia ho notato che PHP poteva decodificare il testo crittografato di Java se avessi usato 128 bit. Suppongo che la mia applicazione Java stia criptando con AES-128, anche con una chiave da 32 byte. – LZZ

9

So che questo è un vecchio argomento, ma aggiungerò la mia soluzione di lavoro.

si deve riscrivere lato PHP dello 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 
); 
} 

Si dovrebbe base64_decode ($ sKey) perché la chiave è codificato in base64.

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

Quindi, è necessario creare questa funzione (merito va a beltrachi da 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); 
} 

Usa questo codice non codifica/decodifica:

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

Spero che questa volontà essere utile per qualcuno! :)

+0

pkcs5_pad ci ha salvato da un sacco di agonia! – kouton

Problemi correlati