Chapitre 3

La génération des clefs dans l'AES 256 bits .

Comme on le sait chacun des 15 rounds nécessite une clef différente.
Chaque clef fait 128 bits soit 16 bytes qui sera exploité comme un tableau
de 4 x 4 bytes.
Il faut un tableau KEY[] de 240 = 15*16 bytes pour stocker les 15 clefs.

Organisation du tableau KEY[240].

KEY[] est d'abord vu comme un tableau de 240 bytes.
Mais KEY[] code aussi pour les 15 clefs de 16 bytes chacune.
Le byte d'indice 16*k constitue le byte d'indice 0 pour la k-ième clef KEY[k].
Par ailleurs la clef KEY[k] est organisée en 4 groupes de 4 bytes
chaque .
Posant KEY[k] = [w0,w1,w2,w3] .

wo est le tableau de 4 bytes correspondants aux indice 16*k + 0 , ..., 16*k+3.
w1 est le tableau de 4 bytes correspondants aux indice 16*k + 4 , ...,16*k+7.
w2 est le tableau de 4 bytes correspondants aux indice 16*k + 8 , ...,16*k+11.
w3 est le tableau de 4 bytes correspondants aux indice 16*k + 12 , ..,16*k+15
.


byte CryptKey[32] = {	// La clef d'encryptage de 256 bits (test FIPS)
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F
}    ;

byte KEY[240]       ;   // tableau des 15 clefs

Initialisation de KEY[].
Cette initialisation génère KEY[0] et KEY[1] à partir de la clef d'encryptage
de 256 bits stockée dans le tableau CryptKey[] ..


unsigned i	;

for(i=0 ; i< 32 ; i++)KEY[i] = CryptKey[i]	;

Génération des 13 clefs restantes.

Cette génération fait appel aux fonction XOR() et G() définies ci dessous .
Pour k >= 2 KEY[k] est générée à partir de KEY[k-2].

Si on pose KEY[k] = [`w_0`, `w_1`, `w_2`, `w_3`] et KEY[k-2] = [`w_0`', `w_1`', `w_2`', `w_3`']
ou les `w_i` (resp `w_i`') sont les tableaux de 4 bytes définissant les 2 clefs( cf plus haut.)

`w_0` = XOR(`w_0`' , G(`w_3`',round) ;
`w_1` = XOR(`w_1`' , `w_0`) ;
`w_2` = XOR(`w_2`' , `w_1`) ;
`w_3` = XOR(`w_3`' , `w_2`) ;

La fonction ExpandKey() effectue cette génération des clefs.


void ExpandKey(unsigned round){ // calcule Key[i] fonction de Key[i-2] i >= 2
    unsigned i              ;   // first = adresse  du premier byte de K[i]
    byte *  first           ;
    byte temp[4]            ;
    
    //  temp[] contient les éléments de w'3 ( voir le texte) )
    first = KEY + 16*round              ;
    for(i=0; i<4; i++) temp[i] = *(first -4 + i );
    //
    //  w0 = XOR(w'0, G(w'3))
    G(temp,round)                   ;  
    XOR(first, first - 32 , temp)    ;
    
    // pour i= 1 à 3  wi = XOR wi', wi-1)
    //
    for(i=1; i<4; i++) XOR( first + 4*i,first + 4*i -32,  first + 4*i - 4, );
    
}

On aura remarqué que les rounds pairs procèdent de KEY[0] et les impairs de KEY[1].
La fonction G() accentue la différence dans le traitements des clefs en fonction
de la parité des rounds .

La fonction XOR est implémantée void XOR(byte *result, byte *p, byte *q).

p et q sont des pointeurs sur le premier élément de 2 tableaux de 4 bytes.
Un ou exclusif est effectué sur les éléments de même indice de ces tableaux
et le résultat est placé dans le tableau pointé par result.


void XOR(byte *result, byte *p, byte *q){  //   *result = *p XOR *q 
    unsigned i              ;
    
    for(i=0; i<4; i++)*(result+i) = *(p+i) ^ *(q+i) ;
}

La fonction void G( byte *, unsigned)

Elle fait appel , dans l'ordre , à trois fonction.
void RotWord(byte *) . Effectue une rotation sur les 4 bytes de w'3 dont l'adresse est fournie en paramètre .
void SubWord(byte *) . Applique la fonction sbx() ( associée à la S-Box ) aux 4 bytes de w'3
dont l'adresse est fournie en paramètre .
La macro RCon(i) calcule 2 ** (i/2 -1) .
Un ou exclusif de la valeur de w'3 déterminée par les 2 fonctions précédentes est finalement effectué avec RCon(i)



#define RCon(i) (byte) 1<< ((i>>1) -1)    // RCon(i) = 2 ** (i/2 -1) Si  i est  pair 

void RotWord(byte *w){
    byte    aux  ;
    
    aux = *w        ;
    *(w)   = *(w+1) ;
    *(w+1) = *(w+2) ;
    *(w+2) = *(w+3) ;
    *(w+3) = aux    ;
}

void SubWord(byte *w){
    unsigned i  ;
    
    for(i=0;i<4; i++)*(w+i)= sbx(*(w+i)) ;
}


void G(byte *w, unsigned i){
    if(!(i & 1)){           	//  round pair 
        RotWord(w)          ;
        SubWord(w)          ;
        *w ^= RCon(i)       ;
    }
    else SubWord(w)         ;	// round impair
    
}