Il nuovo standard AES Algoritmo Rijndael
Transcript
Il nuovo standard AES Algoritmo Rijndael
1 Corso di ELETTRONICA INDUSTRIALE Il nuovo standard AES Algoritmo Rijndael Rodolfo Zunino Edizione 2001 Scuola di Elettronica DIBE – Università degli Studi di Genova 1 2 Algoritmo AES : Rijndael Nelle seguenti pagine sarà descritto l’algoritmo RIJNDAEL i cui autori sono Joan Daemen e Vincent Rijmen. Saranno innanzitutto descritte le basi matematiche per capire l’algoritmo, poi la descrizione stessa seguita dagli aspetti implementativi, sia per la cifratura che per l’inversa. Il campo GF(28) Molte operazioni in Rijndael sono definite lavorando sui singoli byte, c’è quindi la necessità di rappresentare un byte nel campo finito GF(28). Un byte b è composto da 8 bit b7 b6 b5 b4 b3 b2 b1 b0 è considerato come come un polinomio b(x) con coefficienti in {0,1}: b7 x7+ b6 x6 + b5 x5 + b4 x4 + b3 x3 + b2 x2 + b1 x + b0 Esempio: il byte con valore in esadecimale ‘57’ (binario 01010111) corrisponde al polinomio x6 + x4 + x2 + x + 1 Somma Nella rappresentazione polinomiale la somma di due elementi è un polinomio i cui coefficienti sono dati dalla somma modulo 2 dei coefficienti dei due addendi. Esempio: '57'+'83'='D4' o con la notazione polinomiale: (x6 + x4 + x2 + x + 1) + (x7 + x + 1) = x7 + x6 + x4 + x2. In notazione binaria abbiamo: ''01010111'' + ''10000011'' = ''11010100'' Chiaramente l'addizione corrisponde ad un semplice XOR (denotato con ⊕) bit a bit. Moltiplicazione Nella rappresentazione polinomiale, la moltiplicazione in GF(28) corrisponde ad una moltiplicazione di polinomi modulo un polinomio binario irriducibile di grado 8. Un polinomio è irriducibile se non ha divisori oltre che 1 e se stesso. Per Rijndael questo polinomio è chiamato m(x) ed è dato da m(x) = x8 + x4 + x3 + x + 1 o '11B' nella rappresentazione esadecimale. 2 3 Esempio: '53' • '83' = 'C1' o, nella rappresentazione polinomiale (x6 + x4 + x2 + x + 1)(x7 + x + 1) = x13 + x11 + x9 + x8 + x7 x7 + x5 + x3+ x2 + x x 6 + x4 + x2 + x + 1 = x13 + x11 + x9 + x8 + x6 + x5 + x4 + x3 + 1 e facendone modulo m(x) ottengo x7 + x6 + 1 che è il risultato cercato. Chiaramente il risultato deve essere un polinomio binario di grado minore di 8. La moltiplicazione definita prima è associativa ed ha l’elemento neutro che è ‘01’ in notazione esadecimale. Per ogni polinomio binario b(x) di grado minore di 8, l’algoritmo esteso di Euclide puo` essere usato per calcolare i polinomi a(x) e c(x) tali che b(x) a(x) + m(x) c(x) = 1 NOTA: L’algoritmo esteso di Euclide intende trovare il M.C.D. tra i polinomi b(x) e m(x) attraverso la tecnica delle divisioni successive. oppure b-1(x) = a(x) mod m(x). Percio` a(x)• b(x) mod m(x) =1 Abbiamo quindi 256 possibbli valori di byte con l’EXOR come addizione e la moltiplicazione definita come sopra che hanno la struttura del campo finito GF(28). Moltiplicazione per x. Se moltiplichiamo b(x) per il polinomio x (‘02’ in esadecimale) otteniamo b7 x8 + b6 x7 + b5 x6 + b4 x5 + b3 x4 + b2 x3 + b1 x2 + b0 x x • b(x) è ottenuto attraverso la riduzione del suddetto risultato modulo m(x). Se b7 = 0 la riduzione è l’operazione identità, perchè ho già un polinomio di grado minore di 8, mentre se b7 = 1 la riduzione consiste semplicemente nel sottarre (EXOR) m(x) a b(x). La moltiplicazione per x puo` essere implementata come uno shift a sinistra e il successivo EXOR bit a bit con ’1B’. Questa operazione è denotata con b = xtime(a). La moltiplicazione per elevate potenze di x puo` essere implementata ripetendo piu` volte l’operazione xtime. Esempio: ‘57’•’13’ = ‘FE’ ‘57’ • ‘02’ = ‘57’ • ‘04’ = ‘57’ • ‘08’ = ‘57’ • ‘10’ = xtime(57) = ’AE’ xtime(AE) = ‘47’ xtime(47) = ‘8E’ xtime(8E) = ‘07’ ‘57’ • ‘13’ = ‘57’ • (‘01’ ⊕ ‘02’ ⊕ ‘10’) = ‘57’ ⊕ ‘AE’ ⊕ ‘07’ = ‘FE’. 3 4 Polinomi con coefficienti in GF(28). I polinomi possono essere definiti con coefficienti in GF(28). In questo modo un vettore di 4 byte corrisponde ad un polinimio di grado minore di 4. I polinomi possono essere sommati attraverso la somma dei corrispondenti coefficienti. Come l’addizione in GF(28), l’addizione di due vettori è un semplice EXOR bit a bit. La moltiplicazione è piu` complicata: supponiamo di avere due polinomi a(x) = a3 x3 + a2 x2 + a1 x + a0 b(x) = b3 x3 + b2 x2 + b1 x + b0 e Il loro prodotto c(x) = a(x)•b(x) è dato da c(x) = c6 x6 + c5 x5 + c4 x4 + c3 x3 + c2 x2 + c1 x + c0 dove c0 = a0•b0 c1 = a1•b0 ⊕ a0•b1 c2 = a2•b0 ⊕ a1•b1 ⊕ a0•b2 c3 = a3•b0 ⊕ a2•b1 ⊕ a1•b2 ⊕ a0•b3 c4 = a3•b1 ⊕ a2•b2 ⊕ a1•b3 c5 = a3•b2 ⊕ a2•b3 c6 = a3•b3 Chiaramente c(x) non può essere rappresentato come un vettore di 4 byte. Per poterlo fare si deve ridurre c(x) modulo un polinomio di grado 4,che nell'algoritmo in questione è dato da M(x) = x4 + 1 Come xj mod x4 +1 = xj mod 4 il "prodotto modulare", denotato con d(x) = a(x) ⊗ b(x) (e quindi d(x) = c(x) mod M(x) ), è dato da d(x) = d3x3 + d2x2 + d1x + d0 dove d0 = a0•b0 ⊕ a3•b1 ⊕ a2•b2 ⊕ a1•b3 d1 = a1•b0 ⊕ a0•b1 ⊕ a3•b2 ⊕ a2•b3 d2 = a2•b0 ⊕ a1•b1 ⊕ a0•b2 ⊕ a3•b3 d3 = a3•b0 ⊕ a2•b1 ⊕ a1•b2 ⊕ a0•b3 L'operazione consiste nella moltiplicazione per un polinomio fissato a(x) e può essere scritta come una moltiplicazione di matrici, dove la matrice è una matrice circolare. Avremo quindi 4 5 Moltiplicazione per x. Se moltiplichiamo b(x) per il polinomio x avremo b3x4 + b2x3 + b1x2 + b0x x ⊗ b(x) è ottenuto dalla riduzione del precedente risultato modulo x4 +1. Il risultato sarà b2x3 + b1x2 + b0x + b3 La moltiplicazione per x è equivalente alla moltiplicazione con una matrice come sopra , ma con tutti gli ai = '00' ad eccezione di a1 = '01'. Quindi c(x) = x ⊗ b(x) sarà La moltiplicazione per x, o potnze di x, corrisponde quindi ad uno shift ciclco dei byte all'interno del vettore. 5 6 Criteri di Progetto I tre criteri presi in considerazione nel progetto di Rijndael sono i seguenti: • Resistenza contro tutti i tipi di attacchi; • Velocità e compattezza del codice su un ampio range di piattaforme; • Semplicità di progetto. In molti algoritmi di cifratura, la "trasformazione ciclica" o "round transformation" ha una strutura detta "Feistel Structure". In tale struttura parte dei bit dello STATE intermedio sono semplicemente trasposti, senza essere modificati, in un'altra posizione. La trasformazione ciclica di Rijndael non ha la struttura Feistel, ma è composta da tre distinte trasformazioni uniformi e invertibili chiamate layers; con "uniformi" intendiamo che ogni bit dello STATEè trattato nello stesso modo. Le specifiche scelte per i differenti layer sono per la maggior parte basate sulle applicazioni della "Wide Trail Strategy", un metodo di progetto che fornisce resistenza contro criptanalisi lineari e differenziali, dove per criptanalisi si intendono tutte le operazioni e metodi usati per cercare di risalire alla chiave di cifratura. Nel Wide Trail Strategy ogni layer ha delle funzioni proprie: Linear mixing layer: garantisce un'elevata diffusione Non-linear layer: parallel application of S_boxes that have optimum worst-case nonlinearity properties. Key addition layer: un semplice EXOR tra la Round Key e lo STATE intermedio. L'operazione iniziale, prima di applicare il primo ciclo, è proprio l'ultima descritta. La motivazione per questa iniziale key addition è che ogni layer dopo la prima key addition può essere semplicemente tolto senza la conoscenza della chiave e perciò non contribuisce alla sicurezza della cifratura (analogo alla permutazione iniziale e finale del DES ). L'iniziale o finale key addition è applicata anche in altri progetti come IDEA, SAFER, BLOWFISH, che sono stati gli algoritmi competitori con Rijndael per diventare lo standard AES. Allo scopo di fare la cifratura e la sua inversa con una struttura più simile possibile, la linear mixing layer dell'ultimo ciclo è differente dal mixing layer degli altri cicli e si può dimostrare che questo non compromette la sicurezza della cifratura in nessun modo. Questo fatto è simile all'assenza dell'operazione di swap (scambio tra i due semiblocchi) nell'ultimo ciclo del DES. 6 7 Specifiche Rijndael è un algoritmo iterato a blocchi, quindi EBC, con un blocco e con una chiave di dimensione variabile di 128, 192 o 256 bit. Lo STATE, la Cipher Key e il numero di cicli Le varie trasformazioni operano su un blocco intermedio chiamato STATE: Definizione: il risultato intermedio della cifratura è chiamato STATE. Lo State può essere rappresentato come un array di byte. Questo array ha quattro righe e un numero di colonne denotato con Nb ed è uguale alla lunghezza del blocco diviso per 32. La Cipher Key è similmente rappresentata come un array di byte con quattro righe e un numero di colonne denotato con Nk ed è uguale alla lunghezza della chiave diviso 32. I valori di Nb ed Nk sarano 4, 6 o 8 e corrispondono rispettivamente a blocchi di lunghezza 128, 192 o 256. Cipher Key e State sono rappresentate in figura 6. In alcuni casi, questi blocchi sono anche considerati come array unidimensionali di vettori di 4 byte, dove ogni vettore, o parola, consiste nella corrispondente colonna dell'array. Dove è necessario specificare i quattro individuali byte all'interno di uno dei vettori possiamo usare la notazione (a b c d), dove a b c e d sono i byte nelle posizioni 0, 1, 2 e3 all'interno della colonna, parola o vettore considerato. FIGURA 6 : Esempio di State con Nb= 6 e di Cipher Key con Nk= 4. L'input e l'output usati da Rijndael nell'interfaccia con l'esterno sono considerati come un array unidimensionale di byte di 8 bit numerati in modo crescente da 0a 4∗(Nb−1). Questi blocchi hanno perciò lunghezza di 16, 24 0 32 byte e gli indici dell'array hanno un range 0..15, 0..23,o 0..31. 7 8 La Cipher Key è considerata come un array unidimensionale di byte numerati in modo crescente da 0 a 4∗(Nk−1). Questi blocchi hanno quindi lunghezza di 16, 24 o 32 byte e gli indici dell'array hanno un range 0..15, 0..23 o 0..31. I byte di ingresso (quindi il "testo in chiaro" essendo una cifratura di tipo ECB) sono mappati nello State nell'ordine a0,0 a1,0 a2,0 a3,0 a0,1 a1,1 a2,1 a3,1 a4,1 …, e i byte della Cipher Key sono mappati nell'array nell'ordine k0,0 k1,0 k2,0 k3,0 k0,1 k1,1 k2,1 k3,1 k4,1 ….Alla fine dell'operazione di cifratura, l'uscita sarà estratta dallo State, prendendo i byte dello State nello stesso ordine. Perciò se l'indice unidimensionale di un byte all'interno del blocco è n e l'indice in due dimensioni è (i,j), avremo: i = n mod 4; j=n/4; n=i+4∗j; Inoltre, l'indice i è anche il numero del byte all'interno del vettore o parola e j è l'indice del vettore o parola all'interno del blocco. Il numero di cicli o rounds è denotato con Nr e dipende dal valore di Nb ed Nk. Il valore di Nr è dato dalla seguente tabella: La round trasformation La round trasformation è composta da quattro differenti funzioni o trasformazioni. Con una notazione in pseudo C possiamo descrivere la round trasformation come: Il ciclo finale della cifratura è leggermente diverso, ed è definito come segue 8 9 Come si vede l'ultimo ciclo o final round è uguale agli altri cicli ma senza applicare la trasformazione MixColumn. Specificheremo di seguito la struttura delle suddette funzioni. La trasformazione ByteSub La trasformazione ByteSub è una sostituzione di byte non lineare che opera su ogni byte dello State indipendentemente. La tabella di sostituzione o S-box è invertibile ed è costruita attraverso l'applicazione di due trasformazioni: 1) Prima si calcola l'inversa nel campo GF(28), con le notazioni definite nei preliminari matematici.'00' è mappato su se stesso. 2) Poi si applica la trasformazione affine definita come: yi = xi ⊕ x(i+4) mod 8 ⊕ x(i+5) mod 8 ⊕ x(i+6) mod 8 ⊕ x(i+7) mod 8 ⊕ ci per 0 ≤ i ≤ 8, e dove bi è l' i_esimo bit del byte e il byte ci ha il valore '63' o {01100011}. In forma matriciale la trasformazione affine può essere espressa come: L'applicazione della S-box descritta a tutti i byte dello State è denotata come ByteSub(State) La figura 7 illustra l'effetto della trasformazione sullo State 9 10 FIGURA 7: Effetto della S-box sui byte dello State. La S-box in formato esadecimale è mostrata in figura 8: FIGURA 8: Il contenuto della tabella rappresenta il risultato dell’applicazione della S-box ai byte dello State. Per esempio, se a1,1 = '53' il valore della sostituzione può essere determinato intersecando la riga con indice '5' con la colonna con indice '3'. b 1,1 avrà il valore 'ed'. La trasformazione inversa della ByteSub è una sostituzione di byte dove si applica la tabella inversa di figura 9. Qusta è ottenuta la trasformazione affine inversa seguita dal calcolo dell'inversa nel campo GF(28). 10 11 FIGURA 9: Il contenuto della tabella rappresenta il risultato dell’applicazione della S-box inversa ai byte dello State. La trasformazione ShiftRow Nella trasformazione ShiftRow le righe dello State sono ciclicamente shiftate di un'offset che dipende dalla riga presa in considerazione. La riga 0 non viene shiftata, la riga 1 è shiftata di C1 posizioni, , la riga 2 è shiftata di C2 posizioni e la riga 3 è shiftata di C3 posizioni. Gli offset C1 C2 C3 dipendono dalla lunghezza del blocco Nb e i differenti valori sono specificati nella seguente tabella: L'operazione di shift delle righe dello State oltre gli offset sopra specificati è denotata come: ShiftRow( State ) La figura 10 illustra l'effetto della trasformazione ShiftRow sui byte dello State. 11 12 FIGURA 10: Operazione di ShiftRow sui byte dello State. La trasformazione inversa di ShiftRow, è uno shift ciclico delle tre righe di Nb−C1, Nb−C2, Nb−C3 byte rispettivamente, così che i byte nella posizione j della riga i sono spostati nella posizione ( j + Nb−Ci ) mod Nb. La trasformazione MixColumn Nella trasformazione MixColumn le colonne dello State sono considerati come polinomi con coefficienti nel campo GF(28) e sono moltiplicati modulo M(x) = x4 + 1 con un polinomio fissato c(x) dato da: c(x) = '03' x3 + '01' x2 + '01' x + '02'. Questo polinomio è primo con M(x) = x4 + 1 e invertibile.Come descritto nei preliminari matematici la moltiplicazione con c(x) può essere scritta come prodotto di matrici; sia b(x)=c(x)⊗a(x), con ⊗ indicante il prodotto modulare, avremo L'applicazione di questa operazione a tutte le colonne dello State è denotata come MixColumn( State ) La figura 11 illustra l'effetto della trasformazione MixColumn sui byte dello STATE. 12 13 FIGURA 11: Operazione di MixColumn sui byte dello State. La MixColumn inversa è simile alla Mix Column: ogni colonna è trasformata attraverso la moltiplicazione con uno specifico polinomio d(x) definito in modo che: ( '03' x3 + '01' x2 + '01' x + '02' ) ⊗ d(x) = 1. Avremo quindi: d(x) = '0B' x3 + '0D' x2 + '09' x + '0E'. La trasformazione Round Key addition In questa operazione una Round Key è applicata allo State attraverso un semplice EXOR bit a bit. La Round Key è derivata dalla Cipher Key attraverso la Key Schedule. La lunghezza della Round Key deve essere un blocco lungo Nb. La trasformazione che consiste nell'EXOR tra State e Round Key è denotata come: AddRoundKey( State, RoundKey ). La trasformazione è illustrata in figura 12: FIGURA 12: Operazione di Key Addition tra I byte dello State e i byte della Round Key. L'inversa di questa trasformazione è la trasformazione stessa. 13 14 Key Schedule Le Round Key sono derivate dalla Cipher Key per mezzo della Key Schedue ed è composta da due componenti: la Key Expansion e la Round Key Selection. I principi base del loro funzionamento sono: • Il numero totale di bit che compongono le varie Round Key è dato dalla lunghezza del blocco moltiplicato il numero di round o cicli più 1 (ad esempio, per un blocco di lunghezza 128 bit e 10 round, la Cipher Key verrà espansa in 11 Round Key il cui numero complessivo di bit è 1408). • La Cipher Key sarà espansa nella Expanded Key che contiene quindi tutte le Round Key. • Le Round Key sono prese dalla suddetta Expanded Key nel seguente modo: la prima Round Key consiste nelle prime Nb parole (una parola è una stringa di 32 bit corrispondente ad una colonna dell'Expanded Key), la seconda consiste nelle successive Nb parole e così via. La Key Expansion L'Expanded Key è un array lineare di parole di 4 byte ed è denotata con W[Nb∗( Nr+1)]. Le prime Nk parole contengono la Cipher Key. Tutte le altre parole sono definite ricorsivamente. Il funzionamento della Key Expansion dipende dal valore di Nk: c'è una versione per Nk uguale a 4 e 6 ed una versione per Nk uguale a 8. Per Nk ≤ 6 abbiamo: Key Expansion( byte Key[4∗Nk] word W[Nb∗( Nr+1)] ). { for ( i = 0; i < Nk; i++ ) W[i] = ( Key[4∗i] , Key[4∗i+1] , Key[4∗i+2] , Key[4∗i+3] ); } for ( i = Nk; i < Nb∗( Nr+1); i++ ) { temp = W[i-1]; if ( i % Nk == 0 ) temp = SubByte ( RotByte ( temp )) ∧ Rcon [ i / Nk ]; W[i] = W[ i - Nk ] ∧ temp; } In questa descrizione, SubByte( W ) è una funzione che restituisce una parola di 4 byte ottenuta applicando la S_box a tutti i 4 byte della parola W e mantenendone la posizione. La funzione 14 15 RotByte( W ) restituisce una parola in modo tale che i byte all'interno della parola W sono ciclicamente permutati ovvero, se W = (a,b,c,d), ottengo RotByte( W ) = (b,c,d,a). Come possiamo vedere, le prime Nk parole dell'Expanded Key corrispondono proprio alla Cipher Key, mentre ogni parola seguente W[i] , è uguale all' EXOR della precedente parola W[ i-1 ] e la parola che si trova in Nk posizioni prima ovvero W[ i-Nk ]. Per parole che sono in posizione multipla di Nk viene applicata una trasformazione a W[ i-1] prima che venga eseguito l' EXOR con W[ i-Nk]; questa trasformazione consiste nel fare l' EXOR tra una particolare parola Rcon[ i / Nk] che definiremo fra qualche riga e il risultato delle suddette trasformazioni. Per Nk = 8 abbiamo: Key Expansion( byte Key[4∗Nk] word W[Nb∗( Nr+1)] ). { for ( i = 0; i < Nk; i++ ) W[i] = ( Key[4∗i] , Key[4∗i+1] , Key[4∗i+2] , Key[4∗i+3] ); for ( i = Nk; i < Nb∗( Nr+1); i++ ) { temp = W[i-1]; if ( i % Nk == 0 ) temp = SubByte ( RotByte ( temp )) ∧ Rcon [ i / Nk ]; else if ( i % Nk == 4 ) temp = SubByte ( temp ); } } W[i] = W[ i - Nk ] ∧ temp; La differenza con il precedente metodo è che per i-4 multiplo di Nk viene applicata la trasformazione SubByte alla parola W[ i-1 ] prima di eseguire l' EXOR con W[ i-Nk]. La funzione Rcon[ i ] è indipendente dal valore di Nk ed è definita come Rcon[ i ] = ( RC[i] , '00' , '00' , '00' ) Dove RC[i] rappresenta un elemento in GF(28) con un valore di x(i-1) tale che RC[1] = 1 RC[ i ] = x • RC[i-1] = x(i-1) Nota: x è la rappresentazione polinomiale di '02' in esadecimale. 15 16 La Round Key Selection La i_ma Round Key è data dalle parole che vanno da W[Nb∗ i] a W[Nb∗ (i+1)], come illustrato dalla figura 13: FIGURA 13: Key expansion e Round Key selection per Nb= 6 e Nk= 4. La Cifratura L’algoritmo di Rijndael consiste di: • una iniziale Rouns Key addition; • Nr−1 Round o cicli; • un round finale. Descriviamo il tutto in codice pseudo C: Rijndael( State, CipherKey) { KeyExpansion( CipherKey, ExpandedKey); AddRoundKey( State, ExpandedKey); for ( i =1; i< Nr; i++) Round( State,ExpandedKey + Nb∗ i ); FinalRound( State, ExpandedKey + Nb∗Nr ); } La key expansion puo’ essere fatta in anticipo e l’algoritmo puo’ essere specificato in termini di Expanded Key: Rijndael( State, ExpandedKey) { AddRoundKey( State, ExpandedKey); for ( i =1; i< Nr; i++) Round( State,ExpandedKey + Nb∗ i ); FinalRound( State, ExpandedKey + Nb∗Nr ); } 16 17 Una schematizzazione di tutto il processo puo’ essere rappresentata nella figura14 in cui si evidenziano le varie operazioni eseguite sui byte dello State per Nb = 4. FIGURA 14: Rappresentazione delle operazioni che caratterizzano l’algoritmo. NOTA: I rettangolini in alto e in basso della figura rappresentano rispettivamente i byte dello State prima e dopo l’applicazione delle quattro operazioni; i rettangolini corrispondenti alla MixColumn rappresentano la funzione xtime (vedi 3.1.3), mentre i pallini corrispondono all’operazione EXOR. Algoritmo inverso (Decifratura) Con una implementazione dell’algoritmo diretto fatta con LUT ( vedere aspetti implementativi ), è essenziale che lo step non-lineare ( ovvero ByteSub ) sia la prima trasformazione applicata in un round; è altresi’ importante che le righe dello State siano shiftate prima che venga applicata la trasformazione MixColumn. Nel round dell’algoritmo inverso, l’ordine con cui vengono applicate le trasformazioni deve essere invertito e conseguentemente lo step non-lineare diventa l’ultima trasformazione applicata, mentre le righe dello State sono shiftate dopo l’applicazione della MixColumn inversa. Il round inverso non puo’ quindi essere implementato tramite LUT. 17 18 La struttura di Rijndael è tale che la sequenza delle trasformazioni della sua inversa risulterà, come vedremo, uguale a quella diretta, con le trasformazioni sostituite dalla loro inverse e con modifiche nella Key Schedule. Rijndael inverso: variante con due round L’inverso di un round (o ciclo) è dato da: InvRound( State, RoundKey) { AddRoundKey( State,RoundKey); InvMixColumn( State); InvShiftRow( State); InvByteSub( State); } L’inverso di un round finale è dato da: InvFinalRound( State, RoundKey) { AddRoundKey( State,RoundKey); InvShiftRow( State); InvByteSub( State); } L’inversa della variante con due cicli, consiste nell’inverso del round finale seguito dall’inverso di un round, seguito da un Round Key Addition. Avremo: AddRoundKey( State,ExpandedKey + 2∗Nb ); InvShiftRow( State); InvByteSub( State); AddRoundKey( State, ExpandedKey + Nb ); InvMixColumn( State); InvShiftRow( State); InvByteSub( State); AddRoundKey( State, ExpandedKey); Proprietà algebriche Vedremo le proprietà algebriche delle trasformazioni che ci permetteranno di avere lo stesso ordine di esecuzione nel round e nell’inverso. In primo luogo si puo’ notare che l’ordine con cui si applicano ShiftRow e ByteSub è indifferente, infatti la trasformazione Shiftrow è una semplice trasposizione di byte e non ha effetto sul valore degli stessi, mentre la trasformazione ByteSub lavora sul valore del byte indipendente dalla sua posizione. In secondo luogo si nota che la sequenza: 18 19 AddRoundKey( State,RoundKey); InvMixColumn( State); Puo’ essere sostituita dalla sequenza: InvMixColumn( State); AddRoundKey( State,InvRoundKey); Con InvRoundKey ottenuta applicando InvMixColumn alla corrispondente RoundKey. Questo si basa sul fatto che per una trasformazione lineare A si ha: A( h+k ) = A( h ) + A( k ). NOTA: In particolare il passaggio precedente puo’ essere cosi’ sviluppato: Eseguire la trasformazione AddRoundKey significa prendere i byte dallo State, farne l’EXOR co la RoundKey e rimettere il risultato nello State. Successivamente si applica InvMixColumn ai byte dello State, quindi: AddRoundKey( State,RoundKey) = State ⊕ RoundKey = State’ InvMixColumn( State’) = InvMixColumn( State ⊕ RoundKey ) = = InvMixColumn( State ) ⊕ InvMixColumn( RoundKey) = Definendo: InvMixColumn( RoundKey) = InvRoundKey Si ha: = InvMixColumn( State ) ⊕ InvRoundKey Questo equivale a scrivere: InvMixColumn( State); AddRoundKey( State,InvRoundKey); Struttura dell’inversa Usando le proprietà descritte sopra, l’inversa della variante cun due cicli di Rijndael puo’ essere trasformata in: AddRoundKey( State,ExpandedKey + 2∗Nb ); InvByteSub( State); InvShiftRow( State); InvMixColumn( State); AddRoundKey( State, I_ExpandedKey + Nb ); InvByteSub( State); InvShiftRow( State); AddRoundKey( State, ExpandedKey ); 19 20 dove I_ExpandedKey è l’ ExpandedKey a cui ho applicato InvMixColumn. In questo modo abbiamo nuovamente una iniziale AddRoundKey, un round e un round finale, aventi la stessa struttura sia nella cifratura che nella decifratura. Ovviamente questo è generalizzabile ad ogni numero di cicli. Possiamo definire un round e il round finale dell’algoritmo inverso nel seguente modo: I_Round( State, I_RoundKey ) { InvByteSub( State); InvShiftRow( State); InvMixColumn( State); AddRoundKey( State, I_RoundKey ); } I_FinalRound( State, I_RoundKey ) { InvByteSub( State); InvShiftRow( State); AddRoundKey( State, RoundKey0 ); } L’algoritmo inverso Rijndael puo’ ora essere espresso come: I_Rijndael( State, CipherKey) { I_KeyExpansion( CipherKey, I_ExpandedKey); AddRoundKey( State, I_ExpandedKey + Nb ∗ Nr ); for ( i = Nr − 1; i > 0 ; i -- ) Round( State, I_ExpandedKey + Nb ∗ i ); FinalRound( State, I_ExpandedKey ); } La Key Expansion per la cifratura inversa è definita come segue: 1) Si applica la Key Expansion come per la diretta. 2) Si applica la trasformazione InvMixColumn a tutte le Round Key ottenute dalla precedente operazione ad eccezione della prima e dell’ultima. In codice pseudo C avremo: I_KeyExpansion( CipherKey, I_ExpandedKey ) { KeyExpansion( CipherKey, I_ExpandedKey ); for ( i = 1 ; i < Nr ; i ++ ) InvMixColumn( I_ExpandedKey + Nb ∗ i ) } 20 21 Aspetti implementativi L’algoritmo di cifratura Rijndael è adatto per essere implementato efficientemente su un ampio range di processori e hardware dedicato. Vedremo alcuni suggerimenti relativi a processori ad 8 bit, tipici delle ormai diffuse Smart Card, e a processori a 32 bit, tipici dei PC. La nostra implementazione su FPGA verrà esplicitata in seguito. Implementazione dell’algoritmo diretto Processori ad 8 bit Su un processore ad 8 bit, Rijndael puo’ essere pianificato implementando semplicemente le diffetenti trasformazioni che lo compongono. L’implementazione di ShiftRow e di AddRoundKey è immediatamente intuibile, mentre quella di ByteSub richiede una tabella di 256 byte ( vedi pag ? ). La trasformazione MixColumn richiede una moltiplicazione di matrici nel campo GF(28): questo puo’ essere implementato in modo efficiente. Vediamo l’esempio per una colonna: Tmp = a[0] ^ a[1] ^ a[2] ^ a[3] ; Tm = a[0] ^ Tm = a[1] ^ Tm = a[2] ^ Tm = a[3] ^ dove a[1] ; a[2] ; a[3] ; a[0] ; Tm = xtime(Tm) ; Tm = xtime(Tm) ; Tm = xtime(Tm) ; Tm = xtime(Tm) ; a[i] ^= Tm ^ Tmp /* a[i] è un byte della colonna dello State */ a[0] a[1] a[2] a[3] significa fare ; ^= Tm ^ Tmp ; ^= Tm ^ Tmp ; ^= Tm ^ Tmp ; ^= Tm ^ Tmp ; a[i] = a[i] ^ Tm ^ Tmp. Processori a 32 bit Le differenti trasformazioni che compongogno un round possono essere combinate in un set di tabelle di look-up e questo permette di effettuare una veloce implementazione su processori con parole di lunghezza 32 bit o superiore. Vediamo come fare. Esprimiamo con e una colonna dello State a, a cui è stato applicato un round ovvero le quattro trasformazioni fino ad ora trattate. Quindi aij denota un byte di a nella riga i e nella colonna j, ai denota la colonna dello State a. Per le trasformazioni Key Addition e MixColumn avremo: 21 22 Per le trasformazioni Shiftrow e ByteSub avremo: In questa espressione l’indice della colonna deve essere preso modulo Nb. È possibile combinare le varie trasformazioni nel seguente modo: La moltiplicazione di matrici puo’ essere espressa come una combinazione lineare di vettori: La moltiplicazione del fattore S[aij] con i quattro vettori è ottenibile sfruttando una LUT. Definiamo le tabelle Ti : 22 23 Queste sono 4 tabelle con 256 parole di 4 byte ( infatti, una parola è formata da 4 byte presi nel seguente modo: il primo byte preso in S[a]•02 , il secondo preso in S[a] , il terzo preso in S[a] e il quarto preso in S[a]•03 ) per uno spazio complessivo di 4 Kbyte. Usando queste tabelle, la trasformazione round puo’ essere espressa come: nell’implementazione con tabelle di look-up, si hanno quindi 4 tabelle e 4 EXOR per colonna. Si puo’ notare che Ti[a] = RotByte( Ti−1[a] ), allora al costo di tre rotazioni in piu’ per ciclo e per colonna, l’implementazione con LUT puo’essere realizzata con una sola tabella da 1 Kbyte: La dimensione del codice, importante per piccole applicazioni, puo’ essere snellito includendo un codice che genera le tabelle al posto delle tabelle stesse. Parallelismi Possiamo vedere che esistono considerevoli parallelismi nella trasformazione round. Tutte le quattro componenti agiscono in parallelo sui byte, righe o colonne dello State. Nell’implementazione a LUT , tutte le tabelle possono, in linea di principio, essere fatte in parallelo, Come anche l’EXOR, in molti casi, puo’ essere fatto in parallelo. La Key Expansion ha una natura chiaramente piu` sequenziale, infatti è necessario il valore di W[i−1] per il calcolo di W[i]. Essendo inoltre critica la velocità di esecuzione in molte applicazioni, la Key Expansion è eseguita una volta sola per un elevato numero di cifrature. In applicazioni dove la Cipher Key cambia spesso (in estremo una volta per ogni blocco) la Key Expansion e la cifratura possono essere fatte in parallelo. Hardware adatto L’algoritmo è adatto per essere implementato con hardware dedicato e ci sono parecchi compromessi tra occupazione di area sul dispositivo e velocità di esecuzione. Poichè l’implementazione in software è già molto veloce, l’implementazione hardware vuole molto probabilmente essere limita a due specifici casi: • Velocità del chip estremamente alta, senza restrizioni di area: tutte le tabelle T, possono essere inglobate nel codice e gli EXOR fatti in parallelo. • Compattezza del processore per essere inserito su Smart Card. 23 24 Implementazione dell’algoritmo inverso Nonostante la struttura dell’algoritmo inverso sia molto simile alla struttura del diretto, esistono delle asimmetrie dovute al fatto che nelle trasformazioni MixColumn e InvMixColumn si utilizzano due polinomi differenti e, in alcuni casi, anche alla diversa key schedule. Conseguenza di cio` è una diminuzione di performance della cifratura inversa ed è il motivo per cui questa è ritenuta meno importante della diretta. In alcune applicazioni addirittura la decifratura non è usata: questo è il caso per il calcolo del MAC, ma anche quando la cifratura è usata nel modo CFB e OFB. Nota: MAC (Message Authentication Codes) è una ‘hash function’ con l’aggiunta di una chiave segreta. Hash: piccola quantità di dati binari derivati da un messaggio per mezzo di un’algoritmo di hashing; l’esecuzione dell’hashing è unidirezionale, infatti non c’è modo di risalire al messaggio originale, o persino alle sue proprietà, a partire dal valore hash anche se si conosce l’algoritmo di hashing. Un messaggio sottoposto allo stesso algoritmo di hashing produrrà sempre lo stesso hash, mentre anche una piccolissima differenza tra due massaggi (anche solo un carattere) puo` produrre valori di hash molto diversi. L’input di questo algoritmo è una stringa, chiamata pre-image, di lunghezza variabile e viene ridotta ad una stringa di piccola dimensione (fissata), chiamata hash value. Processori ad 8 bit Come descritto nel capitolo 6.1.1 l’operazione MixColumn è efficientemente implementata su processori ad 8 bit. Questo è dovuto al fatto che i coefficienti del polinomio scelto sono limitati a ‘01’, ‘02’ e ‘03’ e per la particolare posizione all’interno del polinomio stesso. La moltiplicazione di polinomi con questi coefficienti puo` essere fatta efficientemente attraverso la procedura xtime(.). I coefficienti di InvMixColumn sono ‘09’, ‘0E’, ‘0B’ e ‘0D’. Nell’implementazione a 8 bit, questa moltiplicazione richiede piu` tempo; una considerevole accelerazione puo` essere ottenuta usando LUT pagando pero` il fatto di avere tabelle in piu`. Processori a 32 bit Un ciclo dell’algoritmo inverso puo` essere implementato con LUT nello stesso modo con cui viene implementato un ciclo dell’algoritmo diretto, non avendo neppure diminuzioni di prestazioni. La Key Expansion dell’inversa risulta piu` lenta, infatti dopo la Key Expansion, a tutte le RoundKey, ad eccezione della prima e dell’ultima, viene applicata la trasformazione InvMixColumn (vedi 5.5.3). 24 25 Glossario e acronimi AES Advanced Encryption Standard. Array Serie ordinata di oggetti uguali. Bit Cifra che puo` avere valore 0 o1. Block Sequenza di bit che comprendono l’ingresso , l’uscita, lo State e la Round Key. La lunghezza di tale sequenza è il numero di bit che contiene. I blocchi sono anche interpretati come array di byte. Byte È un gruppo di 8 bit che è trattato come una singola entità, o come un array di 8 bit. Cifratura Serie di trasformazioni che convertono il testo in chiaro nel testo cifrato. Cifratura inversa Serie di trasformazioni che convertono il testo cifrato nel testo in chiaro. Cipher Key Chiave crittografica segreta che è usata nella Key Expansion per generare il set di Round Key; è un array di byte con quattro righe e Nk colonne. Key Expansion Procedura usata per generare il set di Round Key derivanti dalla Cipher Key. Parola Gruppo di 32 bit che è trattato come una singola entità o come un array di4 byte. Rijndael Algoritmo crittografico specificato nello standard AES. Round Key Sono valori derivanti dalla CipherKey attraverso la procedura Key Expansion; Le Round Key sono applicate allo State della cifratura e dell’inversa. State Risultato intermadio della cifratura che puo` essere rappresentato come un array rettangolare di byte, che ha quattro righe e Nb colonne. S_box Sostituzione non lineare usata nella cifratura e nella Key Expansion. Testo cifrato È l’uscita della cifratura o l’ingresso della cifratura inversa. Testo in chiaro È l’ingresso della cifratura o l’uscita della cifratura inversa. 25 26 Trasformazione Affine È una trasformazione che consiste di una moltiplicazione tra un vettore e una matrice, seguita da una somma con un altro vettore. 26 27 Parametri e funzioni AddRoundKey( ) Trasformazione della cifratura e dell’inversa in cui una Round Key è sommata allo State usando l’operazione EXOR. La lunghezza della Round Key è uguale alla lunghezza dello State. InvSubByte( ) Trasformazione della cifratura inversa che calcola l’inversa di SubByte. InvMixColumn( ) Trasformazione della cifratura inversa che calcola l’inversa di MixColumn. InvShiftRow( ) Trasformazione della cifratura inversa che calcola l’inversa di ShiftRow. K Cipher Key. MixColumn( ) Trasformazione della cifratura che prende tutte le colonne dello State e mescola suoi dati ( indipendentamente l’una dall’altra ) pe produrre una nuova colonna. Nb Numero di colonne (parole di 32 bit) contenute dallo State. Per questo standard Nb = 4. Nk Numero di colonne (parole di 32 bit) contenute dalla Cipher Key. Per questo standard Nk = 4,6, o 8. Nr Numero di cicli o round che dipendono dal valore di Nb e Nk. Per questo standard Nb = 10,12, o 14. RotByte( ) Funzione usata nella Key Expansion che prende una parola di 4 byte e ne sposta i byte che la compongono di una posizione in modo ciclico. . ShiftRow( ) Funzione usata nella cifratura che agisce sulle righe dello State shiftandole ciclicamente di differenti offset. SubByte( ) Funzione usata nella cifratura che agisce sui byte dello State in modo indipendente, effettuando una sostituzione non lineare dei byte stessi. 27