AES 256 Encryption and Decryption in Python
You might have come across “Caesar cipher“, which is one of the oldest and simple encryption techniques that helps to encrypt and decrypt a secret message. In this digital age, Have you ever wondered, what the latest technique is used to encrypt and decrypt messages?
AES 256 encryption & decryption uses a 256-bit key. Rijndael algo encrypts/decrypts data in 128-bit blocks via substitution, permutation & linear operations. The key schedule generates round keys. Ciphertext generated by last round transformation on the plaintext. Decryption is the reverse process.
![AES 256 Encryption and Decryption in Python - Explained](https://codingspell.com/wp-content/uploads/2023/10/Screenshot-2023-10-10-at-1.32.27-PM.png)
Introduction to AES 256 Encryption and Decryption
AES (Advanced Encryption Standard) is a widely used encryption algorithm that is designed to be both secure and efficient. AES is a block cipher that works by dividing plaintext into blocks of fixed size (usually 128 bits), and then encrypting each block separately using a key. AES is available in three key sizes: 128-bit, 192-bit, and 256-bit. We are going to discuss 256-bit in-depth
Setting up the environment
To perform AES-256 encryption and decryption in Python, We need to have pycryptodome library installed, we can always install using pip as below:
pip install pycryptodome
If you are using Pycharm IDE, You can follow the below step to install pycryptodome
Pycharm -> preferences -> python interpreter -> + -> search "pycryptodome" and install
![step to install pycryptodome](https://codingspell.com/wp-content/uploads/2023/10/Screenshot-2023-10-10-at-1.35.03-PM.png)
Once pycryptodome is installed, we can begin writing our encryption and decryption code.
Generating a 256-bit key
As an initial step to encrypt and decrypt using AES-256, we need a 256-bit key. Which, We can generate using the secrets module in Python:
import secrets key = secrets.token_bytes(32)
In the above code, We are using secrets.token_bytes(32) to generate a random 32-byte key, which is equivalent to a 256-bit key.
Encrypting plaintext using AES-256
Padding the plaintext
AES encryption works on fixed-size blocks of data, so we need to ensure that our plaintext is a multiple of the block size (which is 16 bytes for AES). We can do this using the pad function from the Crypto.Util.Padding module:
from Crypto.Util.Padding import pad plaintext = b'This is a secret message.' padded_plaintext = pad(plaintext, AES.block_size)
Initializing the AES cipher
Next, we need to initialize an AES cipher object with our key and a nonce. The nonce is a random value used to ensure the uniqueness of the ciphertext, and should be different for each encryption operation. We can generate a random nonce using secrets.token_bytes shown below
from Crypto.Cipher import AES cipher = AES.new(key, AES.MODE_EAX, nonce=secrets.token_bytes(16))
Encrypting the plaintext
With our cipher object initialized, we can now encrypt the padded plaintext using the encrypt method:
ciphertext = cipher.encrypt(padded_plaintext)
Generating an authentication tag
Finally, we need to generate an authentication tag, which is used to ensure the integrity of the ciphertext. The tag is generated by calling the digest method on our cipher object:
tag = cipher.digest()
Complete code for AES-256 encryption
from Crypto.Cipher import AES from Crypto.Util.Padding import pad import secrets # Generate a random 256-bit (32-byte) key key = secrets.token_bytes(32) # Generate a random 128-bit (16-byte) nonce nonce = secrets.token_bytes(16) # Create an AES cipher object with EAX mode and the random key and nonce cipher = AES.new(key, AES.MODE_EAX, nonce=nonce) # Define the plaintext message to be encrypted plaintext = b'Coding spell is a awesome learning platform..' # Pad the plaintext message padded_plaintext = pad(plaintext, AES.block_size) # Encrypt the padded plaintext message ciphertext = cipher.encrypt(padded_plaintext) # Get the authentication tag tag = cipher.digest() # Print the results print("Key: ", key) print("Nonce: ", nonce) print("Ciphertext: ", ciphertext) print("Tag: ", tag)
Output:
![Complete code execution for AES-256 encryption](https://codingspell.com/wp-content/uploads/2023/10/Screenshot-2023-10-10-at-1.41.14-PM-1024x516.png)
Key: b'\xa7\xc3\xa5\xc7y\xbf\xb4$\xbb\x96\x8c}\xfc\x84\xb7}\xc94\xa9\xb0hF(\xea\xdaj<\xd7\xfb\xefk\xe2' Nonce: b'\xbf\xe3\x84\xe1\x91\x1a\x8d:S\x83\xfe\x02\xb9\xdb\xc5\xc9' Ciphertext: b'\x7fs\xb2\r\xfa\x7f\xeeM\x81\xb3\xc4\xe2\xf6\x7f\xc7\x03k\xd2\xe9\x85\x9e=]c\x96v\xd9\x1f\xc7\x1d\n\x940\x887\xa9z\xed\xf2V\xee\x7f\x99\x08\x0b\x14P\xee' Tag: b'\x101\x8a\xe4\xee\x18\xdcD\xcaX\x03A[]d1' Process finished with exit code 0
Decrypting ciphertext using AES-256
To decrypt ciphertext that has been encrypted using AES-256, Which is a reverse process of Encryption Below are the steps that need to be performed.
Initializing the AES cipher with the same key and nonce
First, we need to initialize an AES cipher object with the same key and nonce that were used to encrypt the plaintext:
from Crypto.Cipher import AES cipher = AES.new(key, AES.MODE_EAX, nonce=nonce)
Verifying the authentication tag
Next, we need to verify the authentication tag to ensure that the ciphertext has not been tampered with:
from Crypto.Util.Padding import unpad try: cipher.verify(tag) except ValueError: print("Incorrect key or corrupt ciphertext")
If the authentication tag is valid, the verify method will not raise a ValueError. If the tag is invalid, the verify method will raise a ValueError with the message “MAC check failed”.
Example:
If we supplied an incorrect tag, we will see the below error message, Which shows that it is used to verify the authenticity of the message
raise ValueError("MAC check failed") ValueError: MAC check failed
Decrypting the ciphertext and unpadded the plaintext
Assuming the authentication tag is valid, we can now decrypt the ciphertext and unpad the plaintext:
decrypted_padded_plaintext = cipher.decrypt(ciphertext) plaintext = unpad(decrypted, AES.block_size) padded_plaintext, AES.block_size)
Complete code for AES-256 decryption
from Crypto.Cipher import AES from Crypto.Util.Padding import unpad # Define the key, nonce, and ciphertext generated in the encryption example key = b'\xa7\xc3\xa5\xc7y\xbf\xb4$\xbb\x96\x8c}\xfc\x84\xb7}\xc94\xa9\xb0hF(\xea\xdaj<\xd7\xfb\xefk\xe2' nonce = b'\xbf\xe3\x84\xe1\x91\x1a\x8d:S\x83\xfe\x02\xb9\xdb\xc5\xc9' ciphertext = b'\x7fs\xb2\r\xfa\x7f\xeeM\x81\xb3\xc4\xe2\xf6\x7f\xc7\x03k\xd2\xe9\x85\x9e=]c\x96v\xd9\x1f\xc7\x1d\n\x940\x887\xa9z\xed\xf2V\xee\x7f\x99\x08\x0b\x14P\xee' tag = b'\x101\x8a\xe4\xee\x18\xdcD\xcaX\x03A[]d1' # Create an AES cipher object with EAX mode and the key and nonce cipher = AES.new(key, AES.MODE_EAX, nonce=nonce) # Decrypt the ciphertext and verify the tag try: plaintext = cipher.decrypt_and_verify(ciphertext, tag) print("Message is authentic.") print("Plaintext: ", plaintext.decode()) except ValueError: print("Message is not authentic!")
Output:
![Complete code execution for AES-256 decryption](https://codingspell.com/wp-content/uploads/2023/10/Screenshot-2023-10-10-at-1.43.31-PM-1024x437.png)
Message is authentic. Plaintext: Coding spell is a awesome learning platform. Process finished with exit code 0
Conclusion
In this tutorial, we’ve seen how to perform AES-256 encryption and decryption in Python using the pycryptodome library. We generated a random 256-bit key, padded the plaintext, initialized an AES cipher object with a nonce, encrypted the plaintext, generated an authentication tag, and then decrypted the ciphertext and unpadded the plaintext.
If you want to learn more about AES encryption in Python, here are some useful resources:
Good Luck with your Learning !!
Related Topics:
Mastering Python List of Dictionaries: Your Step-By-Step Guide
Python was not found; run without arguments
- How to Fix – TypeError: only size-1 arrays can be converted to Python scalars - 16 October 2023
- How to Implement d’wave qbsolv in Python - 16 October 2023
- Resolve Javascript error: ipython is not defined - 15 October 2023