We will be using Python 3.8.10 for this Python AES Encryption Example.
AES (Advanced Encryption Standard) was originally called Rijndael and is a symmetric block algorithm for encrypting or decrypting data. The standard was established by the U.S. National Institute of Standards and Technology (NIST) in 2001.
AES has a fixed block size of 128 bits (16 bytes) and has three different key lengths: 128, 192, or 256 bits long.
We will use pycryptodome, which will allow us to encrypt some data using AES-128, save it to a file, reread the same data and decrypt it. First we install the python package before we proceed to our python AES encryption example code:
pip install pycryptodomex
AES Encryption of data in Python can be done in 3 simple steps:
- Generate a 128, 192, or 256 bit key.
- Use the key to generate the AES cipher
- Use the cipher to encrypt the data.
Similarly, AES Decryption of data in Python can be done in 3 simple steps:
- Generate a 128, 192, or 256 bit key.
- Use the key to generate the AES cipher
- Use the cipher to decrypt the data.
Now we write our code to encrypt the data.
from Cryptodome.Cipher import AES
from Cryptodome.Random import get_random_bytes
data=b"SECRETDATA"
key = get_random_bytes(16) #must be 16, 24 or 32 bytes long
cipher = AES.new(key, AES.MODE_EAX)
ciphertext, tag = cipher.encrypt_and_digest(data)
file_out = open("encryptedfile.bin", "wb")
[ file_out.write(x) for x in (cipher.nonce, tag, ciphertext) ]
file_out.close()
Let’s explain what’s going on here:
1.) First, we import our library/modules Cryptodome.Cipher and Cryptodome.Random.
2.) Next, we define our data. The data in this case must be in byte form, hence the b”SECRETDATA”. Byte literals are always prefixed with ‘b’ or ‘B’.
3.) get_random_bytes returns a random byte string of length N. N in this case is 16 bytes (128 bits) and it must be 16, 24 or 32 bytes long. This is our key.
4.) We use AES.new() to create our cipher. It takes 2 arguments: the key in bytes, which we defined with the previous statement, and the mode which is a constant. In this case we use MODE_EAX. EAX means encrypt-then-authenticate-then-translate and is a mode of opertion for cryptographic block ciphers.
5.) encrypt_and_digest() performs encryption and digest. Recall that encryption conceals the contents of our data, while a digest is a fixed size numeric representation which acts as an identifier for the contents of the data. The encrypt_and_digest method accepts our data and returns a tuple with the ciphertext and the message authentication code (MAC), sometimes known as a tag, which confirms the authenticity and authority of the data.
6.) Finally, we write our encrypted message as ciphertext to the encryptedfile.bin file on disk (same directory as python script) along with the tag and a cipher.nonce. The cipher.nonce is an arbitrary value used only once to ensure that our data is original. If, for example, we see a cipher.nonce used more than once for different pieces of data, we know that security was compromised.
The next step would obviously be to decrypt the data.
file_in = open("encryptedfile.bin", "rb")
nonce, tag, ciphertext = [ file_in.read(x) for x in (16, 16, -1) ]
# the person decrypting the message will need access to the key
cipher = AES.new(key, AES.MODE_EAX, nonce)
data = cipher.decrypt_and_verify(ciphertext, tag)
print(data.decode('UTF-8'))
Let’s explain what’s going on here.
1.) Anyone who needs to decrypt our message would need access to the file to read in the bytes. Once we do that, we will retrieve the nonce, tag and ciphertext.
2.) We use AES.new() to create our cipher, as we did before but this time we include our nonce. Normally only the person decrypting the message should have access to the key.
3.) We call decrypt_and_verify, pass the ciphertext and tag and our decrypted data is returned to us. Yaaaay!
4.) Our data is in bytes so we must use method decode before we can use print() to show us the message in the console.
Below is our full code:
from Cryptodome.Cipher import AES
from Cryptodome.Random import get_random_bytes
#define our data
data=b"SECRETDATA"
key = get_random_bytes(16)
cipher = AES.new(key, AES.MODE_EAX)
ciphertext, tag = cipher.encrypt_and_digest(data)
file_out = open("encryptedfile.bin", "wb")
[ file_out.write(x) for x in (cipher.nonce, tag, ciphertext) ]
file_out.close()
#################################################################
file_in = open("encryptedfile.bin", "rb")
nonce, tag, ciphertext = [ file_in.read(x) for x in (16, 16, -1) ]
#the person decrypting the message will need access to the key
cipher = AES.new(key, AES.MODE_EAX, nonce)
data = cipher.decrypt_and_verify(ciphertext, tag)
print(data.decode('UTF-8'))
#output:
#SECRETDATA
We hope that helped! AES encryption has many applications including file and storage encryption, communications encryption and passwords just to name a few. Find out more about it HERE.
Thanks for reading. 👌👌👌