Cifratura simmetrica, un discorso campato in aria

E quando poi si parla di algoritmi di cifratura simmetrici, si dice che c'è bisogno dello scambio sicurodella chiave di decodifica, e, i più, a questo punto si tacciono.

E tra i più c'ero anch'io.

Di fatto lo scambio sicuro della chiave può essere fatto su di un canale differe, ad esempio tramite un database, ad esempio si può scambiare un messaggio tra 2 attori che non si fidano l'un dell'altro dividendolo in 2 parti: identificazione (da verificare), messaggio oscurato (cifrato).

Infatti in molti casi può non essere così importante la segretezza del messaggio, ma esserlo l'autenticità del mittente.

In un semplice schema, se da una parte c'è un canale sicuro asincrono, come ad esempio è un database, e da un altra si invia un messaggio verso un servizio che ha accesso a questo database, il detto servizio è in grado di controllare l'autenticità del messaggio semplicemente decifrandolo utilizzando la chiave segreta presente (o deducibile da qualche dato) nel db.

Ecco, trovo sia abbastanza buona come idea, il fatto è che gli algoritmi di cifratura a chiave simmetrica, se usati tramite le funzioni mcrypt_* di PHP sono piuttosto delicati, e ce poco che sia trasparente.

Le cose che bisogna sapere sono:

  1. la cifratura AES è anche detta RIJNDAEL, ovvero Java dice AES, php dice RIJNDAEL, ma è lo stesso.
  2. AES è un algoritmo di cifratura a blocchi, con ciò che ne consegue: un blocco ha una lunghezza fissa.
  3. ECB è un modo sbagliato di fare le cose, infatti non prevede di sporcare i blocco da cifrare con i dati del blocco precedente.
  4. CBC (o altri metodi che prevedono l'uso del blocco precedente) pretende un initialization vector, che è un blocco creato a caso (random) di dati affinche si possa usare come blocco sporcatore. Esso verra messo all'inizio del messaggio cifrato (verrà messo in chiaro), cosicché il ricevente possa raccapezzarcisi.
  5. È un algoritmo a blocchi, quindi il messaggio deve stare precisamente in una lunghezza multipla della lunghezza del blocco, ovvero PKCS padding è appunto il metodo col quale si aggiungono i dati mancanti.
  6. Non è strano che venga aggiunto un blocco intero quando la lunghezza dell'input è esattamente un multiplo del blocco, infatti il blocco di padding tipicamente contiene, codificato per ogni sottoblocco (byte), la lunghezza dei dati di padding: [messaggio][padding] ... dove [padding] = 0x04,0x04,0x04,0x04 , vale a dire leggendo l'ultimo byte so quanti byte scartare. Quindi una parte di padding DEVE esistere sempre. I blocchi sono di lunghezza 16 bytes (o 32 bytes per RIJNDAEL 256), 8 bits sono sufficienti a rapresentarli
  7. Per effetto della vettore iniziale, scelto spesso in modo casuale, lo stesso testo, codificato con la stessa chiave produce una stringa differente, OGNI VOLTA. Ossia encrypt('stringa') != encrypt('stringa')

È anche possibile quindi passare dei dati nel primo blocco, quello fittizio, sempre facendo attenzione di non passaredati sensibili, e comunque di non superare i 128 bit, ossia i 16 bytes a disposizione.

Ora Steven Holder ha rilasciato questo pacchetto: https://github.com/stevenholder/PHP-Java-AES-Encrypt

Purtroppo sul padding c'era un bug (di cui il punto 6), inoltre a me sembrava migliore instanziare un oggetto (con la chiave passata nel cotruttore) e poi chiare encrypt o decrypt, la chiave è l'hash md5 di una stringa, perché md5 ha esattamente lunghezza 16 bytes, ossia 128 bit. Qui https://github.com/danielecr/aes128encrypter c'è anche l'implementazione node relativa, e strutturalmente equivalente (classe instanziata e encrypt, decrypt).

 Tool online per la codifica https://www.tools4noobs.com/online_tools/encrypt/