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