An example implementation of AES
Let's implement the AES cipher technique using a Python cryptographic library called PyCryptodome. We will be using the PyCryptodome library throughout this chapter to implement other ciphers and hashing algorithms.
We will use the AES module from Crypto.Cipher package and we will also import a module from Crypto.Random package to generate a random key for AES, as follows:
from Crypto.Cipher import AES from Crypto.Random import get_random_bytes
The encrypting end will create the ciphertext by using a randomly selected symmetric key. Once we have imported the required modules, a 16-byte key is generated using the Crypto.Random package. This is written to a file, which needs to be kept secret:
with open("aes.key", "wb") as file_out: key = get_random_bytes(16) file_out.write(key)
The AES cipher object is created by passing the key. Cipher mode EAX is used in the code. This object is used to encrypt the data. Nonce, tag, and ciphertext are stored and transmitted to the decryption end:
data = "plaintext for AES" cipher = AES.new(key, AES.MODE_EAX) cipher_text, tag = cipher.encrypt_and_digest(data.encode()) with open("encrypted.bin", "wb") as file_out: [file_out.write(x) for x in (cipher.nonce, tag, cipher_text)] print("Data is encrypted and stored in a file")
The decryption part of AES uses the same 16-byte symmetric key generated during encryption. Ideally, this key has to be transferred over a secure channel to the recipient. The received encrypted binary file is read to get the nonce, tag, and the ciphertext itself. The AES cipher object is created using the same key and nonce value. Finally, decryption is performed using the decrypt_and_verify method by providing cipher_text and tag. The tag is provided to perform verification; it checks for any modifications in the ciphertext:
with open("aes.key", "rb") as file_in: key = file_in.read(16) with open("encrypted.bin", "rb") as file_in: nonce, tag, cipher_text = [file_in.read(x) for x in (16, 16, -1)] cipher = AES.new(key, AES.MODE_EAX, nonce) data = cipher.decrypt_and_verify(cipher_text, tag) print("Decrypted data is : \"{}\"".format(data.decode()))
A successful execution of both the encryption and decryption operations will produce the following output:
Data is encrypted and stored in a file Decrypted data is : "plaintext for AES"
When the encryption and decryption parts of the AES program are run, we get the original data back after decryption. Any modification to the ciphertext would result in a MAC check error, and Python would throw ValueError: MAC check failed.