Cosa sono ECB e CBC?

Iniziamo con le basi della crittografia basata su cifratura a blocchi (cipher block encryption). Per crittografare dei dati, abbiamo bisogno di due pezzi d’informazione, da dare in pasto alla funzione crittografica utilizzata: Il messaggio e la chiave (key). Il messaggio in questo caso potrebbe essere qualsiasi cosa: una stringa, dati binari, numeri, un file. Non ha importanza. La chiave è il segreto (o quasi) che rende impossibile decrittare i dati senza di essa. Ma con la chiave, decrittare è molto facile (proprio come la chiave corretta rende facile l’apertura del lucchetto per cui è stata realizzata).

Il metodo crittografico che andremo ad usare non è tanto importante, basta che sia basato sulla cifratura a blocchi. Ora, i cifrari a blocchi sono algoritmi che usano una singola chiave sia per crittografare che per decrittografare (sono conosciuti anche come symmetrical cipher). Un’altra proprietà è che agiscono su un blocco di dati.

Se avete un grosso messaggio (ad esempio un’immagine da 1MB), dev’essere suddivisa in blocchi più piccoli, della lunghezza esatta della vostra chiave. Se usate una chiave a 64 bit, avrete blocchi da 64 bit (ovvero 8 byte). Una chiave da 256 bit vi darà blocchi da 32 byte e così discorrendo…

E’ sempre possibile, che un messaggio non sia esattamente un multiplo del numero di bit della chiave. Però è sempre possibile crittare un messaggio di 9 byte con una chiave da 8 byte (64 bit). Per far si che funzioni, bisogna applicare uno schema di padding per riempire l’ultimo blocco.


+--------+--------+
| BLOCK1 | BLOCK2 |
+--------+--------+
|12345678|9PPPPPPP|
+--------+--------+

Come a, l’ultimo blocco (block2) ha del padding extra (P). Che andrà tolto in fase di decrittazione, da operazioni di routine automatiche.

Modalità Operative

Discuteremo solo due modalità operative, ma ce ne sono molte altre. Spiegazioni di questo tipo son ormai molto diffuse, e su wikipedia troviamo chiare analogie, cercherò dunque di aggiungere qualcosina in più al brodo.

La modalità operativa (Operation Mode) specifica come i blocchi si interconnettono l’uno con l’altro, ogni modalità ha i suoi vantaggi e i suoi svantaggi. Le modalità più diffuse sono ECB e CBC, quelle che adesso andremo a trattare.

ECB

ECB sta per Electronic CodeBook. In questa modalità ogni blocco viene concatenato al blocco successivo, non potrebbe essere più facile. Tuttavia, presenta qualche inconveniente:

Prima di tutto, ogni blocco di dati è crittato con la sola chiave e il messaggio come input. Supponiamo si voglia crittare il testo “HELLOYOU” con un algoritmo con dimensione del blocco di 64bit, come blowfish. Questo messaggio entra perfettamente nel blocco, dal momento che è di lunghezza 8 byte (64bit). Ora, questo testo viene ripetuto 10 volte. Questo vuol dire che il nostro output sarà di 10 volte lo stesso messaggio crittografato. Vediamo un esempio in PHP:

<?php
// La dimensione della chiave non ha importanza
$key = "1234567890";
 
// Il Messaggio è 10 volte la stringa HELLOYOU. Dal momento che ogni stringa è
// 64bit, questo porterà ad avere ogni HELLOYOU crittato separatamente.
$message = str_repeat("HELLOYOU", 10);
 
// Blowfish è un algoritmo che usa blocchi da 64 bit
 
$crypted = mcrypt_encrypt(MCRYPT_BLOWFISH, $key, $message, MCRYPT_MODE_ECB);
 
// Mostra il risultato in hex
for ($i=0; $i!=strlen($crypted); $i++) {
        printf ("%02X ", ord($crypted[$i]));
        if ($i % 8 == 7) print "\n";
}
?>

Il risultato sarà qualcosa del genere:

3F 89 AD 58 3C C8 21 CD
3F 89 AD 58 3C C8 21 CD
3F 89 AD 58 3C C8 21 CD
3F 89 AD 58 3C C8 21 CD
3F 89 AD 58 3C C8 21 CD
3F 89 AD 58 3C C8 21 CD
3F 89 AD 58 3C C8 21 CD
3F 89 AD 58 3C C8 21 CD
3F 89 AD 58 3C C8 21 CD
3F 89 AD 58 3C C8 21 CD

Questa crittografia è deterministica dal momento che lo stesso input darà sempre come risultato lo stesso output. Senza sapere l’attuale messaggio, sappiamo che il messaggio è di 8 byte e ripetuto 10 volte. E’ il modo di funzionare di ECB, e possiede dei vantaggi così come degli svantaggi:

Prima di tutto, molto facilmente si possono vedere i pattern presenti nell’output ottenuto. Secondo, è molto facile per qualcuno muovere e spostare i blocchi, facendo in modo che risultati tutt’altro plaintext (non in questo caso, siccome il plaintext per ogni blocco è uguale), e ugualmente sarà decrittato.
Questa modalità operativa non è molto reattiva agli errori. Se accade qualcosa ai dati nel blocco 1, solo quel blocco sarà corrotto. Tutti i blocchi rimanente saranno intatti, come mostrato in questo esempio:

<?php
// La dimensione della chiave non ha importanza
$key = "1234567890";
 
// ancora: aggiungiamo padding fino a raggiungere la dimensione del blocco
$message = "1111111122222222333333334444444455555555666666667777777788888888";
 
// Blowfish usa blocchi a 64 bit
$crypted = mcrypt_encrypt(MCRYPT_BLOWFISH, $key, $message, MCRYPT_MODE_ECB);
 
// "Corrompiamo" adesso i dati nel 2 blocco
$crypted[10] = "A";
 
// Decrittiamo, e guardiamo i risultati:
$plaintext = mcrypt_decrypt(MCRYPT_BLOWFISH, $key, $crypted, MCRYPT_MODE_ECB);
print $plaintext."\n";
?>

l’output apparirà in questo modo:

11111111T#####zO333333334444444455555555666666667777777788888888

Vedete, solo il secondo blocco è corrotto. Gli altri possono essere decrittati perfettamente. In situazioni particolari può capitare che un blocco si corrompa (non nelle odierne connessioni TCP, ma in generale…).

Un altro (grosso) vantaggio, è che si possono crittare e decrittare più blocchi in parallelo. Per esempio, è possibile crittare il blocco 10 inizialmente e dopo il blocco 1. Basta assicurarsi che alla fine vengano posizionati nell’ordine corretto.
Questo rende più facile per sistemi multicore, crittare pezzi dello stesso file simultaneamente.

Tuttavia, quando usiamo la modalità ECB, i vantaggi non superano gli svantaggi. La modalità operativa CBC che andremo a vedere, è più sicura sotto diversi aspetti.

CBC

CBC o Cipher Block Chaining è tutto un altro modo di connettere i blocchi assieme. Quel che viene fatto è, piuttosto che processare ogni blocco separatamente, verrà fatto lo “XOR” con il blocco precedentemente crittografato. Questo significa che ogni blocco dipende dall’output del blocco precedente.

Crittografica con operation mode cbc

Guardiamo un esempio in PHP:

<?php
// La grandezza della chiave non ha importanza
$key = "1234567890";
 
// L'IV, inizialization vector, dev'essere uguale alla grandezza del blocco del metodo crittografico scelto
$iv = "IAMWEASEL";
 
// Il Messaggio è 10 volte la stringa HELLOYOU. Dal momento che ogni stringa è
// 64bit, questo porterà ad avere ogni HELLOYOU crittato separatamente.
$message = str_repeat("HELLOYOU", 10);
 
// Blowfish è un algoritmo crittografico che utilizzata blocchi a 64bit
 
$crypted = mcrypt_encrypt(MCRYPT_BLOWFISH, $key, $message, MCRYPT_MODE_CBC, $iv);
 
// Mostra i risultati in esadecimale:
for ($i=0; $i!=strlen($crypted); $i++) {
        printf ("%02X ", ord($crypted[$i]));
        if ($i % 8 == 7) print "\n";
}
?>

Come avrete notato, abbiamo introdotto un altro pezzo, chiamato IV o Inizialization Vector, cioè vettore d’inizializzazione. E ne parleremo fra poco. Nel frattempo questo l’output generato:

B1 2C 46 D5 E1 73 E3 52
22 1F BA 57 F1 83 F3 4A
63 2F 21 37 4D 9E 93 55
40 BE AA C9 58 2F 5A 5D
FA 84 60 45 9C 99 AB 6F
C5 71 70 52 61 4A DA E8
21 00 0F 93 35 6C AC 45
EA C4 6E 3C EA 50 83 A7
FF 1A 28 9F 7C 69 49 ED
EF 88 CA 25 F6 F2 98 1C

Come potete vedere, non c’è più ripetizione, anche se state crittografando 10 volte lo stesso messaggio. Il vantaggio è chiaro: non è possibile dedurre il messaggio in chiaro semplicemente osservando i singoli blocchi crittati separatamente. Tuttavia, ecco alcune conseguenze:

Prima: non è possibila la crittografica parallela: dobbiamo prima calcolare l’hash del blocco 1 prima di poter calcolare quello del blocco 2, poichè il blocco n dipende dal blocco n-1 (o dall’inizialization vector nel caso i blocchi in totale siano 1). Un altro svantaggio, è che un error in un blocco, porterà al fallimento di tutti i blocchi successivi. Quindi se al blocco n-1 si verifica un errore, anche il blocco n porterà con se questo errore.

Il Vettore d’inizializzazione (IV)

La variabile $iv presente nell’esempio visto sopra, è detta vettore d’inizializzazione. Nel CBC si usa l’output della funziona crittografica sul primo blocco come input addizionale per calcolare l’output del 2 blocco. Ma Il primo blocco, essendo il primo, da chi prende un output? ed è proprio qui che entra in gioco il vettore d’inizializzazione.
Questo comporta dunque alcune cose:

Dobbiamo usare un vettore d’inizializzazione, che sia lo stesso sia nelle fasi di cifratura che decrittazione. Usando vettori differenti otteniamo plaintext corrotti.
Inoltre l’IV dev’essere della stessa dimensione del blocco. Dunque per un blocco di 64bit abbiamo bisogno di un vettore di 64bit. PHP in particolare possiede una funzione che serve proprio a determinare la dimensione dell’IV (mcrypt_enc_get_iv_size()).
Il vettore d’inizializzazione dev’essere cambiato ad ogni operazione di crypt! Non dev’essere una costante. Altrimenti significherebbe far diventare nuovamente l’operazione di cifratura, determinisitica!