AES stands for Advanced Encryption Standard and is a popularly used symmetric encryption algorithm, that was established by the U.S. National Institute of Standards and Technology (NIST) in 2001. A symmetric key encryption algorithm uses only one key for both encryption and decryption tasks. AES is introduced as a successor to the then popular but aging Data Encryption Standard(DES) algorithm.

AES is a block cipher which means that it breaks the message into blocks and encrypts or decrypts them individually. The size of these blocks is fixed which is 128 bits.

Encryption is the process of hiding or changing the state of your message so that it is only understandable by the person it is intended to go to.

Refer to this article on how to write an encryption program in Python.

In this post, we are going to learn more about AES and its implementation with padding.

**What Is AES?**

The Advanced Encryption Standard algorithm is a symmetric key encryption algorithm so it used only one key for both encryption and decryption. It is also a block cipher meaning it divides the message into blocks each of fixed size 128 bits. The key size of the AES algorithm can be 128,192 and 256 bits. For each key size, there are a number of rounds that take place in this algorithm. AES-128 uses 10 rounds, AES-192 uses 12 rounds, and AES-256 uses 14 rounds. Here is a block diagram to understand AES better.

* Related: *Visit this post to learn about RSA.

In the implementation coming soon, we use something called ECB abbreviation for Electronic Codebook, which is used in encryption algorithms for its simplicity. In ECB, the plaintext is divided into blocks of fixed size, usually 64 or 128 bits. Though simple, it is not recommended to use when you are trying to implement large data.

Since AES is a fixed-size block algorithm, sometimes to fulfill the requirements, we need to add extra bits to fill the empty blocks. This process is called padding. We are going to use PKCS#7 padding in the implementation. This padding is a successor to another padding called PKCS#5. The main difference between these two padding schemes is the block size.

While PKCS5 padding only works for blocks of size 8 bytes, we can use the PKCS7 padding for any algorithm with block sizes between 0 to 255 bytes.

We are going to use two libraries `cryptography`

and `pycryptodome`

for implementing AES.

**AES Implementation Using Cryptography**

Before we start with the code, we need to make sure to install the `cryptography`

library.

```
pip install cryptography
```

Let us see the code now.

```
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.primitives.padding import PKCS7
from cryptography.hazmat.backends import default_backend
import base64
def encrypt(plaintext, key):
cipher = Cipher(algorithms.AES(key), modes.ECB(), backend=default_backend())
encryptor = cipher.encryptor()
padder = PKCS7(algorithms.AES.block_size).padder()
padded_data = padder.update(plaintext) + padder.finalize()
ciphertext = encryptor.update(padded_data) + encryptor.finalize()
encodedciphertext = base64.b64encode(ciphertext)
return encodedciphertext
def decrypt(ciphertext, key):
cipher = Cipher(algorithms.AES(key), modes.ECB(), backend=default_backend())
decryptor = cipher.decryptor()
decodedciphertext = base64.b64decode(ciphertext)
padded_data = decryptor.update(decodedciphertext) + decryptor.finalize()
unpadder = PKCS7(algorithms.AES.block_size).unpadder()
plaintext = unpadder.update(padded_data) + unpadder.finalize()
return plaintext
key = b'\x01\x23\x45\x67\x89\xAB\xCD\xEF\xFE\xDC\xBA\x98\x76\x54\x32\x10' \
b'\x01\x23\x45\x67\x89\xAB\xCD\xEF\xFE\xDC\xBA\x98\x76\x54\x32\x10'
plaintext = input("Enter the plaintext: ").encode()
enc = encrypt(plaintext, key)
print("The encrypted message is :", enc)
dec = decrypt(enc, key)
print("The decrypted message is:", dec.decode('utf-8'))
```

In the first four lines, we are importing the necessary packages. The hazmat is a package of the cryptography library that has all the necessary primitives for encryption. The cipher module contains the symmetric cipher we are going to use for encryption and decryption. The `algorithms`

is a module that contains all the necessary algorithms like DES, AES, and so on. The `modes`

module stores the encryption modes like ECB, CBC, CTR, etc.

We are importing the PKCS#7 padding scheme from the `padding`

module.

The `default_backend`

is the module responsible to perform the cryptography.

We are importing the `base64`

module used for encoding.

We are creating two functions: encrypt and decrypt. The encrypt function takes the plaintext we get in line 23 and the key we created in line 21 as arguments and returns an encoded cipher text as output by performing encryption using the AES algorithm, the ECB mode, and the default_backend using the `PKCS#7`

padding.

The cipher text we got in the previous function is passed as an argument to the decrypt function along with the key. The reverse process of what happened in the previous function takes place here. The cipher text is decoded into plain text by unpadding the ciphertext.

The AES works with the keys of sizes 128,192 and 256 bits. So the key we provide here should be of the determined size.

The two functions are called and the results are stored in variables called `enc and dec`

. These encrypted and decrypted messages are printed on the screen.

**AES Implementation Using Pycryptodome**

We need to install the pycryptodome library before we start coding.

```
pip install pycryptodome
```

```
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
from Crypto.Random import get_random_bytes
import base64
def encrypt(plaintext, key):
cipher = AES.new(key, AES.MODE_ECB)
padtext = pad(plaintext, AES.block_size)
ctext = cipher.encrypt(padtext)
encodedctext= base64.b64encode(ctext)
return encodedctext
def decrypt(ciphertext, key):
cipher = AES.new(key, AES.MODE_ECB)
decodedctext = base64.b64decode(ciphertext)
padded_plaintext = cipher.decrypt(decodedctext)
plaintext = unpad(padded_plaintext, AES.block_size)
return plaintext
key = get_random_bytes(16)
plaintext = input("Enter the plaintext: ").encode()
enc= encrypt(plaintext, key)
print("The encrypted data is:", enc)
decrypted = decrypt(enc, key)
print("The decrypted data is:", decrypted.decode('utf-8'))
```

From the Crypto package, we are importing the AES algorithm. From the `Padding`

module, we’re importing the pad and unpad. We are also importing the random_bytes to generate a key. The base64 is imported for encoding. Just like in the previous example, we are creating the encrypt and decrypt functions.

The encrypt function takes the plain text we input and the key we generated randomly as arguments and returns an encoded text after padding, and encoding using the AES algorithm.

The decrypt function takes the cipher text and the key to return the decrypted or plain text. It performs the opposite of the encrypt function. The cipher text is decoded and unpadded then returned as `plaintext`

.

The `get_random_bytes`

is used to generate a 16 byte(128 bits) key. We are taking the input from the user for plaintext.

The two functions encrypt and decrypt are called and the results are stored in variables called enc and dec respectively.

The results are printed.

**Conclusion**

AES stands for Advanced Encryption Standard Algorithm and is introduced as a successor of DES. It is a symmetric key encryption so used only one key for both encryption and decryption. It is also a block cipher that breaks the plain text into blocks of fixed size.

We have seen the implementation of AES with the two libraries of python – `cryptography`

and `pycryptodome`

.

In the implementation, we take plaintext, apply the AES algorithm on it, pad the message with some bits, and then encode the message to return a cipher text.

The cipher text is passed as an argument to a decryption function which unpads the message and decodes it. Then a plaintext is returned.