Crittografia a chiave privata con AES (Advanced Encryption Standard)


Oggi parliamo di crittografia a chiave privata e di come utilizzarla in Php.

Prima di tutto è importante capire cosa sia la crittografia a chiave privata, chiamata anche crittografia simmetrica, e le sue differenze con quella a chiave pubblica o asimmetrica.

Nella crittogravia a chiave privata viene utilizzata un’unica chiave sia per codificare, sia per decodificare i messaggi, quindi la segretezza di questa chiave risulta fondamentale. Questo presuppone che ci sia un canale sicuro con il quale i due interlocutori si scambiano questa chiave segreta.

Questo problema viene invece risolto dalla crittografica a chiave pubblica, nel quale ogni personaggio in gioco ha due chiavi, una pubblica e una privata. Chiunque voglia mandare a me un messaggio crittato deve crittare il messaggio con la mia chiave pubblica, e solo io lo posso decrittare grazie la mia chiave privata, che rimane sempre in mano mia.

Per maggiori informazioni vi rimando a Wikipedia.

Come anticipato prima in quest’articolo ci occuperemo solo della crittografia a chiave privata, e in particolare dell’algoritmo AES (Advanced Encryption Standard) con chiave a 256 bit, algoritmo utilizzato dal governo degli stati uniti d’america per la classificazione di documenti come TOP SECRET.

Nel seguente esempio in Php andremo prima a crittare, poi a decrittare, un brano della divina commedia. E’ importante notare che nella decrittazione, oltre ovviamente alla chiave segreta, c’è bisogno dell’ Initialization vector, non è importante hai fini della sicurezza che questo rimanga segreto, però è fondamentale per la decrittazione, quindi quano salvate nel database del testo crittato, salvate anche l’Initialization vector utilizzato per la crittazione, altrimenti non riuscirete più a decrittare il testo.

<?php
 
//AES (Advanced Encryption Standard) 
//richiede mcrypt ( con debian apt-get install php5-mcrypt)
 
$plainText = "PER ME SI VA NE LA CITTA' DOLENTE, PER ME SI VA NE L'ETERNO DOLORE, PER ME SI VA TRA LA PERDUTA GENTE. GIUSTIZIA MOSSE IL MIO ALTO FATTORE: FECEMI LA DIVINA POTESTATE, LA SOMMA SAPIENZA E'L PRIMO AMORE. DINANZI A ME NON FUR COSE CREATE SE NON ETERNE, E IO ETERNA DURO. LASCIATE OGNI SPERANZA, VOI CH'ENTRATE.";
 
$pKey=md5("lamiachiavesegreta");
 
echo "PlainText: --$plainText--&lt;br/&gt;&lt;br/&gt;\n";
 
echo "pKey: --$pKey--&lt;br/&gt;&lt;br/&gt;\n";
 
/* Open the cipher */
$td = mcrypt_module_open('rijndael-256', '', 'ofb', '');
 
/* Create the IV and determine the keysize length, use MCRYPT_RAND on Windows instead */
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_DEV_RANDOM);
 
echo "Iv: --$iv--&lt;br/&gt;&lt;br/&gt;\n";
 
$ks = mcrypt_enc_get_key_size($td);
 
if(strlen($pKey)!=$ks) 
	die("Private key length wrong");
 
/* Intialize encryption */
mcrypt_generic_init($td, $pKey, $iv);
 
/* Encrypt data */
$encryptedText = mcrypt_generic($td, $plainText);
 
/* Terminate encryption handler */
mcrypt_generic_deinit($td);
 
echo "EncryptedText: --$encryptedText--&lt;br/&gt;&lt;br/&gt;\n";
 
/* Initialize encryption module for decryption */
mcrypt_generic_init($td, $pKey, $iv);
 
/* Decrypt encrypted string */
$decryptedText = mdecrypt_generic($td, $encryptedText);
 
/* Terminate decryption handle and close module */
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
 
echo "DecryptedText: --$decryptedText--&lt;br/&gt;&lt;br/&gt;\n";
 
if($decryptedText!=$plainText) 
	echo "Shit!!!";
 
?>

Il seguente codice richiede il modulo php mcrypt, installabile, su sistemi debian, tramite il comando apt-get install php5-mcrypt se non è gia installato.

Condividi questo articolo:
  • E-mail this story to a friend!
  • Google Bookmarks
  • Digg
  • Sphinn
  • del.icio.us
  • Facebook
  • Mixx
  • LinkedIn
  • MySpace
  • StumbleUpon
  • Technorati

8 Responses to “Crittografia a chiave privata con AES (Advanced Encryption Standard)”

  1. gianluca Says:

    Ciao,
    volevo chiederti una cosa:

    come faccio a verificare, una volta salvato l’IV e la password criptata sul DB, se la password inserita da un form è giusta? poichè il metodo mdecrypt_generic decripta anche se la pkey è sbagliata. quindi mi servirebbe un controllo che mi verificasse la validità della pkey inserita…. ho provato a ri-criptare l’output decriptato ma non funziona…. mi daresti una mano per cortesia? grazie!

  2. admin Says:

    non ti basta crittare ancora la password inserita nel form con la tua chiave privata e l’IV che hai salvato nel database, se il risultato coincide con quello salvato nel database allora ok. Altrimenti decritta la password salvata nel database sempre con l’IV salvato e la tua chiave privata e confronta il dato con quello inserito nel form.

    In generale comunque, per salvare una password crittata nel database, viene molto più comodo usare la funzione php sha1 o md5. Salvi nel db l’sha1 o l’md5 della password, poi al momento del login confronti quel valore con l’sha1 o l’md5 della password inserita nel form di login.

  3. gianluca Says:

    Grazie per la celere risposta, il mio scenario è un portale protetto che mi da la lista di tutti le macchine unix, con una mia scelta attraverso un tag html select mi scelgo l’host della macchina e pooi inserisco la mia passphrease per quel record che ho precedentemente inserito sul DB cryptato con il tuo script.

    ma in effetti quando vaodo a re-cryptare l’output del decrypt iniziale per compararlo con quello sul DB, è come se mcrypt si impallasse e anche nel caso che metto una passphrease sbagliata il dato cryptato risulta sempre uguale a quello salvato nel DB.

    cerco di spiegarmi meglio…

    il mio codice è il seguente:

    ******

    $td = mcrypt_module_open(‘rijndael-256′, ”, ‘ofb’, ”);
    $ks = mcrypt_enc_get_key_size($td);

    if (strlen($pKey) != $ks) {
    die(“Chiave Privata di dimensioni sbagliate”);
    }

    // DECIFRO I DATI ATRAVERSO UN FORM PASSANDO LA $pKEY e poi $iv e $pswd li prelevo dal DB

    //$pKey mi arriva dal form
    //$iv mi arriva dal DB
    mcrypt_generic_init($td, $pKey, $iv);

    // $decrypted mi arriva dal DB
    echo $decryptedTestofinale = mdecrypt_generic($td, $pswd);
    mcrypt_generic_deinit($td);

    //// quindi ora ho $decryptedTestofinale che dovrebbe essere la password decrittata con l’IV del DB la pKey digitata dal form.

    non mi resta che re-cryptare $decryptedTestofinale e compararlo con quello sul DB che è: $pswd

    //a questo punto re inizializzo mcrypt per il re-crypt:

    mcrypt_generic_init($td, $pKey, $iv);
    echo $recrypt = mcrypt_generic($td, $$decryptedTestofinale);
    mcrypt_generic_deinit($td);
    mcrypt_module_close($td);

    non ci crederai ma $pswd e $recrypt risultano sempre uguali indipendentemente se la $pKey è corretta oppure no…

    quindi non riesco a comparare i due dati per verificare la password è esatta.

    cosa sbaglio??? a me sembra più un bug di mcrypt… boh…

    Grazie mille!!
    Gianluca.

  4. gianluca Says:

    forse non mi sono spiegto bene….

    il portale è praticamente un archivio di password root di sistemi linux protetti da una master password (passphrease)….

    Sul form io inserisco la chiave privata, quindi lo script utilizza la $pKey passata dal form con gli altri dati $iv e $pswd recuperati dal DB e li decifra con il metodo mdecrypt_generic.

    qunidi io inserendo la mia master-password (passphrease) sul portale posso recuperare la password di root di tutte le macchine unix che sono molto complesse e impossibili da ricordare a memoria.

    fin qui non ci piove… nel senso che se inserisco la mia passphrease corretta lo script mi decifra il campo $pswd registrato sul DB e mi visualizza a schermo la password decifrata.

    il problema e che se io sbaglio passphrease ($pKey) il metodo mdecrypt_generic decifra comunque la stringa però utilizzando la pkey sbagliata, e di conseguenza lo script mi visualizzerà una password sbagliata.

    il problema appunto e verificare che il dato decifrato corrisponda a quello originale cifrato sul db ($pswd).

    quindi ho pensato di cifrare nuovamente, con lo stesso iv presente sul DB, la password decifrata precedentemente, e poi confrontare il risultato del crypt con quelllo memorizzato sul db.

    ma nello script quando provo a cifrare nuovamente la variabile risultante del decrypt si incazza e mi visualizza lo stesso valore del campo $pswd presente sul DB, come se non gli piacesse che provenga da una variabile, difatti ho provato a scrivere il valore all’interno degli apici e cosi funziona, quindi invece di:

    mcrypt_generic($td,$TestoDecifrato);

    ho messo:

    mcrypt_generic($td, “testodecifrato”);

    cosi in teoria potrei fare il confronto senza problemi.

    ma quello che non capisco è perchè si comporta così??? c’è una soluzione secondo te? è un problema di mcrypt..

    io utilizzo wamp server 2.0 con PHP 5.3 e mysql 5.1.36.

    Grazie di un tuo cortese riscontro.
    Gianluca.

  5. admin Says:

    echo $recrypt = mcrypt_generic($td, $$decryptedTestofinale);

    c’è un $ in più in $$decryptedTestofinale, toglilo

    :)

    questo sito, dove metti la master password, è in https vero???

    No perchè se non lo è se qualcuno è sulla tua stessa rete locale o wireless e sniffa tutto il traffico di rete può allegramente leggersi questa master password.

    Ciao
    Zago

  6. gianluca Says:

    no, scusa nel codice originale la $ in più non c’è… è solo che ho rinominato tutte le variabili per farti capire… e mi è scappato male un copia incolla…

    quindi il problema è quello che ti dievo…. e come se quando reinizializzo mcrypt per la seconda volta va i tilt…. e mi visualizza sempre come valore quello del campo delDB $pswd…. ho provato da due diversi ambienti WAMP ed il risultato è sempre lo stesso…. quindi m confermi che non è un problema del codice??? ma potrebbe essere la libreria mcrypt???

    cmq per l’Https gia ci avevo pensat ma per il momento devo risolvere questo problemuccio….

    che mi consigli di fare??

    grazie mille ancora. :)

  7. gianluca Says:

    giusto cosi per verifica ti posto il codice integrale, e ti confermo che non funziona, o meglio funziona il decrypt ma non il re-crypt per la verifica della password, in quanto alla fine la variabile $recrypt assume sempre il valore di $pswd:

  8. admin Says:

    Allora:

    1: https se hai tempo io lo metterei
    2: quando dici “quando provo a cifrare nuovamente la variabile risultante del decrypt si incazza” intendi che ti da un qualche warnings? o non da nulla?
    3: ora non ho molto tempo, anzi tra 2 ore parto per le vacanze, ma dovrei fare uno script simile al tuo per provare di persona, nel frattempo potrei consigliarti questo per finire il progetto, ovvero: Crei una procedura di login sul sito, con username e password (o masterpassword), se mettono la password sbagliata gli dai l’errore username e/o password sbagliate, altrimenti li fai loggare e usi la masterpassword per decrittare i dati nel db (che a questo punto sono giusti per forza)

    ciao

Lascia un commento

Categorie

Cerca

Meta