AES-128 CBC (Cipher Block Chaining) Encryption using Python and XML file

Hemant Nikam
4 min readSep 3, 2024

--

Rotor Cipher Machine

Introduction

Originally developed in 1998 by two Belgian cryptographers, Vincent Rijmen and Joan Daemen, AES has been around for more than 20 years. At first, it was referred to as Rijndael — a combination of the names of its developers.

It was established by the U.S. National Institute of Standards and Technology (NIST) in 2001 after it was submitted to NIST during the AES selection process.

The AES Encryption algorithm is a symmetric block cipher algorithm with a block/chunk size of 128 bits. It converts these individual blocks using keys of 128, 192, and 256 bits. Once it encrypts these blocks, it joins them together to form the ciphertext.

It is based on a substitution-permutation network. It consists of a series of linked operations, including replacing inputs with specific outputs (substitutions) and others involving bit shuffling (permutations).

Following is the python code to encrypt/decrypt raw text using AES-128 CBC (Cipher Block Chaining) Encryption. More information on different modes of AES can be found here.

We are using PyCryptodome library for AES encryption which can be installed using following command. Refer this link for more information.

C:\smime> pip install pycryptodome

Encrypt/Decrypt

Following is the python code, create new file aes128cbc.py:

# install PyCryptodome library using following command
# pip install pycryptodome

import base64
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
from Crypto import Random

# AES CBC mode is used for encryption
def encrypt(plain_text, key):
cipher = AES.new(key, AES.MODE_CBC)
b = pad(plain_text.encode("UTF-8", "ignore"), AES.block_size)
return base64.b64encode(cipher.iv + cipher.encrypt(b))

def decrypt(enc_text, key):
enc_text = base64.b64decode(enc_text)
iv = enc_text[:AES.block_size]
enc_text = enc_text[AES.block_size:]
cipher = AES.new(key, AES.MODE_CBC, iv=iv)
b = unpad(cipher.decrypt(enc_text), AES.block_size)
return b.decode("UTF-8", "ignore")

#Secret key for encryption - must be 16 characters for AES128 (128 bits = 16 bytes)
key = Random.get_random_bytes(16)
# key = b"0361231230000000" # manually set the key in form of bytes
plain_text = "This is the secret text to encrypt"

print("Key: ", base64.b64encode(key))
print("plain_text: ", plain_text)

try:
# Encrypt the data using key, iv is added at the beginning of the encryted data
# iv can also be user defined but here we are using auto generated
encrypted_data = encrypt(plain_text, key)
print("encrypted_data: ", encrypted_data)

# Decrypt the data using key, assuming that the key is shared secretly
decrypted_data = decrypt(encrypted_data, key)
print("decrypted_data: ", decrypted_data)
except (ValueError, KeyError):
print("Error occured")

After executing the code, following output will be displayed:

Encrypt/Decrypt and save/read using an XML file

Now, let us try to save and read the encrypted data to/from a file. We will use an XML file here (more information here), but any other file type (e.g. .txt or .json) can be used.

Create an XML file, msg.xml in the same folder as python file. Add following contents in the XML file. This will become the input file and the python code will convert plain text message to encrypted text and then decrypt the encrypted text back to original plain text.

<?xml version="1.0"?>
<data>
<user name="user1">
<msg>user1: This is the secret text to encrypt by user1</msg>
</user>
<user name="user2">
<msg>user2: This is the secret text to encrypt by user2</msg>
</user>
<user name="user3">
<msg>user3: This is the secret text to encrypt by user3</msg>
</user>
</data>

Following is the python code, create new file aes128cbc_xml.py:


import base64
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
from Crypto import Random

# library used for xml file manipulation
import xml.etree.ElementTree as ET

# AES CBC mode is used for encryption
def encrypt(plain_text, key):
cipher = AES.new(key, AES.MODE_CBC)
b = pad(plain_text.encode("UTF-8", "ignore"), AES.block_size)
return base64.b64encode(cipher.iv + cipher.encrypt(b))

def decrypt(enc_text, key):
enc_text = base64.b64decode(enc_text)
iv = enc_text[:AES.block_size]
enc_text = enc_text[AES.block_size:]
cipher = AES.new(key, AES.MODE_CBC, iv=iv)
b = unpad(cipher.decrypt(enc_text), AES.block_size)
return b.decode("UTF-8", "ignore")


# key = b"0123456701234567" # can set a manual key
# Secret key for encryption - must be 16 characters for AES128 (128 bits = 16 bytes)
key = Random.get_random_bytes(16)
plain_text = "This is the secret text to encrypt"

print("Key: ", base64.b64encode(key))
print("plain_text: ", plain_text)


try:
# Encrypt the msg tag using key
tree = ET.parse('msg.xml')
root = tree.getroot()
for msg in root.iter('msg'):
enc_msg = encrypt(msg.text, key)
# decoding is required to save the encrypted data as string
msg.text = str(enc_msg.decode("utf-8"))
msg.set('encryption', 'AES-128 CBC')

tree.write('encrypted_msg.xml')
print("Encrypted messages stored in encrypted_msg.xml file")

# Decrypt the msg tag using key, assuming that the key is shared secretly
tree = ET.parse('encrypted_msg.xml')
root = tree.getroot()
for msg in root.iter('msg'):
dec_msg = decrypt(msg.text, key)
msg.text = str(dec_msg)
# msg.set('encryption', 'AES-128 CBC')

tree.write('decrypted_msg.xml')
print("Decrypted messages stored in decrypted_msg.xml file")
except (ValueError, KeyError):
print("Error occured")

After execution, it will create two files

  1. encrypted_msg.xml: msg tag in msg.xml file is encrypted and saved as encrypted text in this file. It will also add an attribute called encryption to the msg tag.
  2. decrypted_msg.xml: encrypted msg tag from encrypted_msg.xml file is read, decrypted and saved in this file

The contents of the file will be as follows (the encrypted text will be different):

encrypted_msg.xml

<data>
<user name="user1">
<msg encryption="AES-128 CBC">RaFc2EpLDBMV1TkhZStC6ebtTDto6JjKAR9XFm2iJMmZtlMKflnBsLR9Z2hJYCVgVjU1vFq7802mH8fsDDqIdKf7mA0EgVK/KtNNfzW09Pc=</msg>
</user>
<user name="user2">
<msg encryption="AES-128 CBC">8r4xwFqeVgbIB6tMOzqGwiO4Ovhk0eU7m/NdcrOqDqkQbgPTdvZSdViUPmTjRer6pAGLa1ZrSMin1aNvkEk5B5z/Szt2AF705yfbyMSV1Gk=</msg>
</user>
<user name="user3">
<msg encryption="AES-128 CBC">ABsqzy5DYgSpsprMRvU4HIZys2035pdcBsxQQd8RAfxeSstA/NcHldgKYQW8FN34yfu5dclMrF1Qev2mJ20j56C24l26980DUFPqMKkAVp4=</msg>
</user>
</data>

decrypted_msg.xml

<data>
<user name="user1">
<msg encryption="AES-128 CBC">user1: This is the secret text to encrypt by user1</msg>
</user>
<user name="user2">
<msg encryption="AES-128 CBC">user2: This is the secret text to encrypt by user2</msg>
</user>
<user name="user3">
<msg encryption="AES-128 CBC">user3: This is the secret text to encrypt by user3</msg>
</user>
</data>

Here are few resource links to further explore AES:

  1. https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.197-upd1.pdf
  2. https://nvlpubs.nist.gov/nistpubs/legacy/sp/nistspecialpublication800-38a.pdf
  3. https://ciit.finki.ukim.mk/data/papers/10CiiT/10CiiT-46.pdf

P.S. Please post your questions in comments section and I will reply.

--

--

No responses yet