Utilisation d'AES-ECB en Python

 

PS: Utilisation d'AES-ECB est non sécurisé

Maintenant que nous avons présenté le chiffrement par bloc AES et expliqué un peu ses caractéristiques internes dans l'article pécédent (voir ici), voyons comment l'utiliser dans la pratique. Le problème avec un chiffrement par bloc est qu'il ne peut chiffrer un bloc que par lui-même. Pour chiffrer quelque chose qui n'est pas exactement 128 bits, nous devons utiliser un rembourrage ainsi qu'un mode de fonctionnement. Voyons donc en quoi consistent ces deux concepts

imaginez que vous vouliez chiffrer un long message. Naïvement, vous pourriez diviser le message en blocs de 16 octets (la taille de bloc d'AES). Ensuite, si le dernier bloc de texte brut est inférieur à 16 octets, vous pouvez ajouter quelques octets supplémentaires à la fin jusqu'à ce que le texte brut atteigne 16 octets de long. C'est ça le rembourrage ! Il existe plusieurs façons de spécifier comment choisir ces octets de remplissage, mais l'aspect le plus important du remplissage est qu'il doit être réversible. Une fois que nous avons déchiffré le texte chiffré, nous devrions être en mesure de supprimer le rembourrage pour récupérer le message original non rempli. Le simple fait d'ajouter des octets aléatoires, par exemple, ne fonctionnerait pas car vous ne seriez pas en mesure de discerner si les octets aléatoires faisaient partie du message d'origine ou non.

Le mécanisme de remplissage le plus populaire est souvent appelé rembourrage PKCS#7, qui est apparu pour la première fois dans la norme PKCS#7 publiée par RSA (une société) à la fin des années 1990. Le remplissage PKCS#7 spécifie une règle : la valeur de chaque octet de remplissage doit être définie sur la longueur du remplissage requis. Que se passe-t-il si le texte en clair fait déjà 16 octets ? Ensuite, nous ajoutons un bloc complet de remplissage défini sur la valeur 16. Pour supprimer le rembourrage, vous pouvez facilement vérifier la valeur du dernier octet de texte brut et l'interpréter comme la longueur du rembourrage à supprimer.

Maintenant, il y a un gros problème dont je dois parler. Jusqu'à présent, pour chiffrer un long message, vous venez de le diviser en blocs de 16 octets (et peut-être avez-vous rempli le dernier bloc). Cette manière naïve est appelée le mode de fonctionnement du Electronic Code Book (ECB). Comme vous l'avez appris, le chiffrement est déterministe, et donc chiffrer deux fois le même bloc de texte en clair conduit au même texte chiffré. Cela signifie qu'en chiffrant chaque bloc individuellement, le texte chiffré résultant peut avoir des motifs répétitifs.

voici le code en python:

import os
from cryptography.hazmat.primitives.ciphers import Cipher
from cryptography.hazmat.primitives.ciphers.algorithms import AES
from cryptography.hazmat.primitives.ciphers.modes import ECB
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import padding

if __name__ == "__main__" :

#texte clair à garder confidentiel
plaintext = b'cryptographie fondamentale en python'
print(f"Texte Clair: {plaintext}")

#256-bit AES Key
key = os.urandom(256 // 8)

#Creer le chiffrement AES ECB
aes_ecb_cipher = Cipher(AES(key), ECB(), backend=default_backend())

#Chiffrement
ciphertext = aes_ecb_cipher.encryptor().update(plaintext)
print(f"Texte Chiffré: {ciphertext}")

#Dechiffrement
recovered_plaintext = aes_ecb_cipher.decryptor().update(ciphertext)
print(f"Texte clair récupérer: {recovered_plaintext}")

#tamponner le texte clair
pkcs7_padder = padding.PKCS7(AES.block_size).padder()
padded_plaintext = pkcs7_padder.update(plaintext) + pkcs7_padder.finalize()
print(f"texte clair rembourré: {padded_plaintext}")

#chiffrer le remplissage en texte clair
ciphertext = aes_ecb_cipher.encryptor().update(padded_plaintext)
print(f"Texte Chiffré: {ciphertext}")

#déchiffrer en texte clair de remplissage
recovered_plaintext_with_padding = aes_ecb_cipher.decryptor().update(ciphertext)
print(f"Texte clair récupérer avec rembourrage: {recovered_plaintext_with_padding}")

#Supprimer le rembourrage
pkcs7_unpadder = padding.PKCS7(AES.block_size).unpadder()
recovered_plaintext = pkcs7_unpadder.update(recovered_plaintext_with_padding) + pkcs7_unpadder.finalize()
print(f"recovered_plaintext: {recovered_plaintext}")
assert (recovered_plaintext == plaintext)

le resultat après exécution:

 
Texte Clair: b'cryptographie fondamentale en python'
Texte Chiffré: b'\\\xd72\x99c\x9713\x13k\xdb\x14\xa8Y_\xc1\x96"|\x84\x16\xcfA\x9d\xe8b\x1a\xa2G\x07\xd9\xef'
Texte clair récupérer: b'cryptographie fondamentale en py'
texte clair rembourré: b'cryptographie fondamentale en python\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c'
Texte Chiffré: b'\\\xd72\x99c\x9713\x13k\xdb\x14\xa8Y_\xc1\x96"|\x84\x16\xcfA\x9d\xe8b\x1a\xa2G\x07\xd9\xef$@/\x9f\xf3|\x86xp\xaa\xf5\xe9\x10\xf2n\xda'
Texte clair récupérer avec rembourrage: b'cryptographie fondamentale en python\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c'
recovered_plaintext: b'cryptographie fondamentale en python'


Pour chiffrer plus de 128 bits de texte en clair en toute sécurité, il existe de meilleurs modes de fonctionnement qui "randomisent" le chiffrement. L'un des modes de fonctionnement les plus populaires pour AES est le Cipher Bloc Chaining (CBC). CBC fonctionne pour n'importe quel chiffrement par bloc déterministe (pas seulement AES) en prenant une valeur supplémentaire appelée vecteur d'initialisation (IV) pour randomiser le chiffrement. Pour cette raison, l'IV est la longueur de la taille du bloc (16 octets pour AES) et doit être aléatoire et imprévisible.



Aucun commentaire:

Enregistrer un commentaire

Pages