L'attaque sur les blocs en mode ECB (Electronic Code Book)
Les chiffrements symétriques par bloc découpent les données en blocs de taille fixe. Ces blocs sont de 128-bit pour les algorithmes récents (recommandés) ou 64-bit pour des algorithmes plus anciens comme le DES.Pour des raisons de sécurité, des modes liant les blocs entre eux sont recommandés (CBC, OFB, etc). Dans ces cas, les blocs subissent habituellement un chaînage entre eux selon un mode opératoire défini de façon a rendre le chiffré le plus indépendant possible des données en clair pour une même clef de chiffrement.
Le mode ECB est l'absence de mode spécifique. L'algorithme symétrique par bloc (DES, AES, Twofish, ...) est dans ce cas appliqué directement au données sans autre traitement des blocs.
Le mode ECB est à proscrire absolument car il laisse fuir de l'information. Malheureusement, de nombreux développeurs l'utilisent par méconnaissance des risques associés à ce mode opératoire.
La problématique est que tout bloc de données en clair donne le même bloc chiffré pour une même clef. Ce principe laisse fuir de l'information ou permet des altérations valides du chiffré. L'exemple suivant de l'image BMP chiffrée en mode ECB en AES illustre cette faiblesse.
Version plaintext
Version ciphertext
Un outil de chiffrement d'images BMP en AES-ECB est disponible là: http://www.willhackforsushi.com/code/ecb_encrypt_image.zip
La bijectivité du mode ECB expose les données chiffrées à des attaques par substitution, suppression ou ajout de blocs dans un message chiffré.
L'exemple utilisé s'appuie sur le cryptogramme de la chaîne de caractères "id=123456&value=52&acct=000000178356" en DES avec la clef 0x0011223344556677:
$ echo -ne "id=123456&value=52&acct=000000178356" | openssl enc -des-ecb -K 0011223344556677 | xxd -p
34738ccb598fcaff3bf8fb2c6b1d9db312405ac7072f1c45396e156b2749f8ad6f2fcdb9d36dda57
id=123456&value=52&acct=000000178356
L'attaque ECB bloc shuffling
Tout d'abord, un éclatement des chaînes clair/chiffré en bloc de 8 octets permet de mieux visualiser le principe.$ echo -ne "id=123456&value=52&acct=000000178356" | sed 's/.\{8\}/& /g'
id=12345 6&value= 52&acct= 00000017 8356
$ echo -ne 34738ccb598fcaff3bf8fb2c6b1d9db312405ac7072f1c45396e156b2749f8ad6f2fcdb9d36dda57 | sed 's/.\{16\}/& /g'; echo
34738ccb598fcaff 3bf8fb2c6b1d9db3 12405ac7072f1c45 396e156b2749f8ad 6f2fcdb9d36dda57
Mapping des blocs
id=12345 6&value= 52&acct= 00000017 835634738ccb598fcaff 3bf8fb2c6b1d9db3 12405ac7072f1c45 396e156b2749f8ad 6f2fcdb9d36dda57
1 2 3 4 5
L'attaque consiste à ajouter/supprimer/réordonner des blocs. L'exemple illustré infra est d'insérer le bloc 4 après le bloc 2. Le dernier bloc doit être conservé en fin de cryptogramme car il contient le padding qui validera ou non le déchiffrement.
$ echo -ne "34738ccb598fcaff3bf8fb2c6b1d9db3396e156b2749f8ad12405ac7072f1c45396e156b2749f8ad6f2fcdb9d36dda57" | xxd -r -p | openssl enc -des-ecb -d -K 0011223344556677; echo
id=123456&value=0000001752&acct=000000178356
Le déchiffrement est correct car le dernier bloc possède toujours un padding valide.
Le résultat donne une valeur différente pour le paramètre value.
value=52 devient value=0000001752
De réelles attaques existent avec ce concept, y compris dans le monde Web ou certains paramètres (token, cookie, panier, ...) peuvent être gérés de manière stateless côté serveur en chiffrant des données dont la gestion est déléguée au navigateur du client.
Padding PKCS#7
Dans un chiffrement par bloc, le padding sert à combler le dernier bloc pour l'aligner sur la taille du bloc. Si les données sont un multiple du bloc, alors un bloc complet de padding est ajouté. La procédure de déchiffrement contrôle la validité du padding, avant de l'extraire pour retourner les données en clair. Le padding permet de déterminer que le déchiffrement c'est passé correctement.
Plusieurs types de padding existent, mais le plus utilisé consiste à écrire le nombre d'octets de padding dans chaque octet de padding (standard PKCS#7, PKCS#5, RFC1423) :
Plusieurs types de padding existent, mais le plus utilisé consiste à écrire le nombre d'octets de padding dans chaque octet de padding (standard PKCS#7, PKCS#5, RFC1423) :
01
02 02
03 03 03
...
Le padding du dernier bloc est visible dans la commande de déchiffrement infra qui demande de ne pas tenir compte du padding avec l'argument "-nopad".
$ echo -ne "34738ccb598fcaff3bf8fb2c6b1d9db3396e156b2749f8ad12405ac7072f1c45396e156b2749f8ad6f2fcdb9d36dda57" | xxd -r -p | openssl enc -des-ecb -nopad -d -K 0011223344556677 | hd
00000000 69 64 3d 31 32 33 34 35 36 26 76 61 6c 75 65 3d |id=123456&value=|
00000010 30 30 30 30 30 30 31 37 35 32 26 61 63 63 74 3d |0000001752&acct=|
00000020 30 30 30 30 30 30 31 37 38 33 35 36 04 04 04 04 |000000178356....|
00000030
Les autres paddings
Dans le monde des cartes à puce, c'est le padding NIST 800-38a qui est couramment implémenté. Il s'agit d'un bit à 1 suivi de bit à 0. Soit 0x80 (b1000 0000).
H e l l o ? ? ?
48 65 6C 6C 6f 80 00 00
Parfois, le padding consiste à valoriser l'octet par son rang, ex: 04 03 02 01
H e l l o ? ? ?
48 65 6C 6C 6f 03 02 01
On rencontre également des paddings composés exclusivement du caractère nul (0x00) ou espace (0x20) lorsqu'il s'agit de texte.
H e l l o ? ? ?
48 65 6C 6C 6f 00 00 00
48 65 6C 6C 6f 20 20 20