2009-12-08 12 views
10

Questa domanda è la continuazione della mia ultima, riguardante How to make Ruby AES-256-CBC and PHP MCRYPT_RIJNDAEL_128 play well together. Ora funziona, ma sto ancora lottando per andare nella direzione opposta. Il crittogramma generato da PHP sembra avere tutte le informazioni fornite, ma non posso ottenere il codice Ruby per decodificarlo senza errori.Parte II: Come far giocare bene Ruby AES-256-CBC e PHP MCRYPT_RIJNDAEL_128

Ecco il codice PHP che sto usando per generare il crittogramma:

$cleartext = "Who's the clever boy?"; 
$key = base64_decode("6sEwMG/aKdBk5Fa2rR6vVw==\n"); 
$iv = base64_decode("vCkaypm5tPmtP3TF7aWrug=="); 
$cryptogram = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $cleartext, MCRYPT_MODE_CBC, $iv); 
$result = base64_encode($cryptogram); 
print "\n'$result'\n"; 

RESULT 
'JM0OxMINPTnF1vwXdI3XdKI0KlVx210CvpJllFja+GM=' 

Poi ecco il tentativo di decifrare in Ruby:

>> cipher = OpenSSL::Cipher::Cipher.new('aes-128-cbc') 
>> cipher.key = Base64.decode64("6sEwMG/aKdBk5Fa2rR6vVw==\n") 
>> cipher.iv = Base64.decode64("vCkaypm5tPmtP3TF7aWrug==") 
>> cryptogram = Base64.decode64('JM0OxMINPTnF1vwXdI3XdKI0KlVx210CvpJllFja+GM=') 
>> cleartext = cipher.update(cryptogram) 
=> "Who's the clever" 
>> cleartext << cipher.final 
OpenSSL::Cipher::CipherError: bad decrypt 
from (irb):100:in `final' 
from (irb):100 

La cosa veramente frustrante di questo è che è possibile ottenere l'intero testo chiaro da quella stringa crittografata. Ripetendo quanto sopra, ma l'aggiunta di un pad senza senso per il crittogramma:

>> cleartext = cipher.update(cryptogram + 'pad') 
    => "Who's the clever boy?\000\000\000\000\000\000\000\000\000\000\000" 
    >> cleartext << cipher.final 
    OpenSSL::Cipher::CipherError: bad decrypt 
    from (irb):119:in `final' 
    from (irb):119 

Nel mio caso uso effettivo del testo in chiaro è strutturato (una stringa JSON, dal momento che si chiede), così ho stare tranquillo un questo punto che ho potuto dire utilizzare questo schema e rilevare input scarsamente codificati senza eseguire lo cipher.final. Tuttavia, non posso tollerare questo tipo di kludge nel mio codice, quindi mi piacerebbe capire come rendere il codice ruby ​​gestire il blocco finale con grazia.

risposta

15

Il problema è che mcrypt non riempie l'ultimo blocco, mentre il collegamento OpenSSL di Ruby utilizza il metodo di riempimento OpenSSL predefinito, che è il riempimento PKCS. Non posso migliorare realmente sulla descrizione dalla documentazione OpenSSL:

PKCS imbottitura funziona con l'aggiunta di n imbottitura byte di valore n di rendere il totale lunghezza dei dati un multiplo della dimensione del blocco. Il riempimento è sempre aggiunto quindi se i dati sono già un multiplo della dimensione del blocco n sarà uguale alla dimensione del blocco. Ad esempio se la dimensione del blocco è 8 e 11 byte sono da crittografare, quindi verranno aggiunti 5 byte di riempimento del valore 5.

È necessario aggiungere manualmente il riempimento appropriato alla fine del testo in chiaro prima di crittografare. Per farlo, passa il tuo $cleartext attraverso questa funzione pkcs5_pad sul lato PHP prima di cifrarlo (passando 16 come blocco).

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

Se anche va nella direzione opposta (cifrare in Ruby e decifrare con mcrypt), dovrete togliere i byte di riempimento dopo la decrittografia.

nota laterale: Il motivo è necessario aggiungere imbottitura, anche se il testo in chiaro è già un multiplo della dimensione del blocco (un intero blocco di imbottitura), è così che quando si decodifica di sapere che l'ultimo byte del l'ultimo blocco è sempre la quantità di riempimento aggiunto. Altrimenti, non si può dire la differenza tra testo in chiaro con un singolo byte di riempimento e un testo in chiaro senza byte di riempimento che è appena terminato con il valore 0x01.

+1

Grazie per i vostri pensieri, caf. Aggiungere testo al testo in chiaro è solo creare una stringa diversa da crittografare; non cambia il risultato. Concordo sul fatto che il problema abbia a che fare con il modo in cui le due implementazioni riguardano l'ultimo blocco del flusso crittografato. L'output dei due algoritmi è identico fino all'ultimo blocco a 32 byte, in cui gli ultimi 16 byte sono completamente diversi. Ho esaurito la pazienza con il problema, quindi a meno che qualche samaritano non arrivi e lo risolva per me, vado con il kludge qui sopra. – dondo

+0

Il testo aggiunto alla fine del cleartext (padding) deve essere di una forma molto specifica, che il lato Ruby si aspetta. Analizzerò il metodo di riempimento utilizzato e aggiornerò la risposta. – caf

+0

... il padding PKCS funziona aggiungendo n byte padding di valore n per rendere la lunghezza totale dei ** dati cifrati ** un multiplo della dimensione del blocco ... – dondo

0

Sembra PHP \0 che rimuove il testo in chiaro prima di crittografarlo. Puoi impostare Ruby per disabilitare il padding.

http://www.ruby-doc.org/stdlib-1.9.3/libdoc/openssl/rdoc/OpenSSL/Cipher.html#method-i-padding-3D

Questo funzionerà, ma poi si deve spogliare l'imbottitura spegnere manualmente.

1.9.3p125 :008 > cipher = OpenSSL::Cipher::Cipher.new('aes-128-cbc') 
=> #<OpenSSL::Cipher::Cipher:0x0000000561ee78> 
1.9.3p125 :009 > cipher.decrypt 
=> #<OpenSSL::Cipher::Cipher:0x0000000561ee78> 
1.9.3p125 :010 > cipher.padding = 0 
=> 0 
1.9.3p125 :011 > cipher.key = Base64.decode64("6sEwMG/aKdBk5Fa2rR6vVw==\n") 
=> "\xEA\xC100o\xDA)\xD0d\xE4V\xB6\xAD\x1E\xAFW" 
1.9.3p125 :012 > cipher.iv = Base64.decode64("vCkaypm5tPmtP3TF7aWrug==") 
=> "\xBC)\x1A\xCA\x99\xB9\xB4\xF9\xAD?t\xC5\xED\xA5\xAB\xBA" 
1.9.3p125 :013 > cryptogram = Base64.decode64('JM0OxMINPTnF1vwXdI3XdI2j8NJ8kr+Du0fnkxorNl0=') 
=> "$\xCD\x0E\xC4\xC2\r=9\xC5\xD6\xFC\x17t\x8D\xD7t\x8D\xA3\xF0\xD2|\x92\xBF\x83\xBBG\xE7\x93\x1A+6]" 
1.9.3p125 :014 > cleartext = cipher.update(cryptogram) 
=> "Who's the clever girl?\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" 
1.9.3p125 :015 > cleartext << cipher.final 
=> "Who's the clever girl?\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" 



1.9.3p125 :042 > cleartext.strip 
=> "Who's the clever girl?" 
Problemi correlati