In this tutorial we will check how to encrypt and decrypt data with AES-128 in ECB mode, using Python and the pycrypto library.
Introduction
In this tutorial we will check how to encrypt and decrypt data with AES-128 in ECB mode, using Python and the pycrypto library.
AES stands for Advanced Encryption Standard and it is a cryptographic symmetric cipher algorithm that can be used to both encrypt and decrypt information [1].
The algorithm can use keys of 128, 192 and 256 bits and operates on data blocks of 128 bits (16 bytes) [1]. We are going to use a key of 128 bits.
Since we may want to encrypt data larger than 128 bits, we need to choose a block mode. In our case, we are going to use ECB (Electronic Code Book), which uses the same unaltered key to encrypt each block of plain text [2].
In terms of security, ECB is generally a bad choice since identical plain text blocks are encrypted to identical cipher text blocks [2], which allows a possible attacker to disclose patterns in our ciphered messages. You can check here a very illustrative example of the security problems that may arise from using ECB mode.
Even for single block messages, if we repeat the same message over time, then an attacker can understand which messages are identical.
Nonetheless, ECB is very interesting for an illustrative point of view due to its simplicity, which is why we are analyzing it in this tutorial.
Installing pycrypto
As mentioned, we will use the pycrypto library to encrypt and decrypt the data with AES. The easiest way to install it is using pip, a Python package manager.
To install it via pip, simply send the following command on the command line (depending on how you have installed Python and pip, you may need to be in a specific folder such as the Scripts folder before running pip commands):
pip install pycrypto
This tutorial was tested on Python 2.7.
The code
The first thing we are going to do is importing the AES module from the pycrypto library. This module will provide the functions and classes we need to both encrypt and decrypt the data.
from Crypto.Cipher import AES
Next we need to set our secret encryption key. Since AES is a symmetric encrypton algorithm, the key is private and needs to be known only by the two communicating parties.
The length of the key needs to be 16, 24 or 32 bytes long, depending if we want to use AES-128, AES-192 or AES-256 respectively [3], as we have mentioned in the introduction.
We are going to choose an arbitrary 16Â bytes key just for illustrations purposes. Note that the key chosen is not secure at all and for real scenario use cases you should use strong keys.
key = 'abcdefghijklmnop'
Next we need to call the new function of the AES module. This function will return an object of class AESCipher [4], which provides the functions to both encrypt and decrypt the data.
This function has many optional parameters that you can check here, but we are only going to use the key and mode parameters.
The key parameter corresponds to the encryption key to be used by the algorithm and we will pass it the key we previously defined [4].
The mode parameter corresponds to the chaining mode that is used for decryption / encryption [4]. We are going to pass the value MODE_ECB, to use the electronic code book mode.
cipher = AES.new(key, AES.MODE_ECB)
Now that we have our AESCipher object, we can encrypt the data with a call to the encrypt method. As input, this method receives the plain text string and encrypts it with the provided key and configurations used in the new function call.
Remember that the length of the message to encrypt needs to be a multiple of the block size, which is 16 bytes. In this case, the plain text message I’m passing has 32 bytes and the first block is equal to the second, to later illustrate the pattern repetition on the ciphered text, from using the ECB mode.
This encrypt method call will return as output a string with the cipher text. We will also print the type of the returned value to confirm it is indeed a string.
msg =cipher.encrypt('TechTutorialsX!!TechTutorialsX!!') print (type(msg))
To make the result more user friendly, we will convert the cipher text to its hexadecimal representation. To do it, we call the encode method on our cipher text string, passing the value “hex” as input.
print(msg.encode("hex"))
Now that we have our cipher text, we will decrypt it back to plain text. Note that since the cipher object we have created before is stateful [5], we should create a new one for decryption calling the new function again, with the same input parameters.
decipher = AES.new(key, AES.MODE_ECB)
Finally, we call the decrypt method on our new object, passing as input the ciphered text. It returns as output the original decrypted plain text, which we will print.
print(decipher.decrypt(msg))
The final source code can be seen below.
from Crypto.Cipher import AES key = 'abcdefghijklmnop' cipher = AES.new(key, AES.MODE_ECB) msg =cipher.encrypt('TechTutorialsX!!TechTutorialsX!!') print (type(msg)) print(msg.encode("hex")) decipher = AES.new(key, AES.MODE_ECB) print(decipher.decrypt(msg))
Testing the code
To test the code, simply run it on your Python environment of choice. I’m using IDLE, the IDE that comes by default with the Python installation.
You should get an output similar to figure 1, which shows the results of running the program. The first thing we can see is that the output of the encrypt method is indeed a string.
Then, we can check the cipher text resulting from encrypting the input plain text. I’ve highlighted the two blocks of the cipher text and, as can be seen, they are equal because the originating blocks of plain text were also equal. This illustrates the problem of using ECB and why we should use stronger modes.
Finally, we can check the the decryption result, obtained from using the same key.
Figure 1 – Output of the program.
References
[1]Â https://nvlpubs.nist.gov/nistpubs/fips/nist.fips.197.pdf
[2]Â https://proandroiddev.com/security-best-practices-symmetric-encryption-with-aes-in-java-7616beaaade9
[3]Â https://www.dlitz.net/software/pycrypto/api/current/Crypto.Cipher.AES-module.html
[4]Â https://www.dlitz.net/software/pycrypto/api/current/Crypto.Cipher.AES-module.html#new
Pingback: ESP32 Arduino: Encryption using AES-128 in ECB mode | techtutorialsx
Pingback: ESP32 Arduino: Encryption using AES-128 in ECB mode | techtutorialsx
Pingback: ESP32 Arduino: Decrypt AES-128 in ECB mode | techtutorialsx
Pingback: ESP32 Arduino: Decrypt AES-128 in ECB mode | techtutorialsx
Pingback: ESP32 Arduino mbed TLS: using the SHA-256 algorithm | techtutorialsx
Pingback: ESP32 Arduino mbed TLS: using the SHA-256 algorithm | techtutorialsx
A slight modification to that code for Python 3.7 with Pycrytodome 3.6.6 would be
from Crypto.Cipher import AES
key = ‘abcdefghijklmnop’
cipher = AES.new(key.encode(“utf8”), AES.MODE_ECB)
msg = cipher.encrypt(b’TechTutorialsX!!TechTutorialsX!!’)
print(type(msg))
print(msg.hex())
decipher = AES.new(key.encode(“utf8”), AES.MODE_ECB)
msg_dec = decipher.decrypt(msg)
print(msg_dec)
print(type(msg_dec))
Hi!
Thank you very much for sharing 🙂
Best regards,
Nuno Santos
A slight modification to that code for Python 3.7 with Pycrytodome 3.6.6 would be
from Crypto.Cipher import AES
key = ‘abcdefghijklmnop’
cipher = AES.new(key.encode(“utf8”), AES.MODE_ECB)
msg = cipher.encrypt(b’TechTutorialsX!!TechTutorialsX!!’)
print(type(msg))
print(msg.hex())
decipher = AES.new(key.encode(“utf8”), AES.MODE_ECB)
msg_dec = decipher.decrypt(msg)
print(msg_dec)
print(type(msg_dec))
Hi!
Thank you very much for sharing 🙂
Best regards,
Nuno Santos
We are facing issue whenever there is a byte in key is greater than 127.
We see following error message, Our Key is of length 16bytes only
File “/usr/local/lib/python3.4/dist-packages/Crypto/Cipher/blockalgo.py”, line 141, in __init__
self._cipher = factory.new(key, *args, **kwargs)
ValueError: AES key must be either 16, 24, or 32 bytes long
Hi!
That’s a weird issue, I haven’t run into such problem yet so I cannot help much :/
My suggestion is to look in the GitHub page of the module to see if there’s some mention of a similar issue and if not to open an issue describing the situation:
https://github.com/dlitz/pycrypto
Hope it helps getting you in the right direction.
Best regards,
Nuno Santos
We are facing issue whenever there is a byte in key is greater than 127.
We see following error message, Our Key is of length 16bytes only
File “/usr/local/lib/python3.4/dist-packages/Crypto/Cipher/blockalgo.py”, line 141, in __init__
self._cipher = factory.new(key, *args, **kwargs)
ValueError: AES key must be either 16, 24, or 32 bytes long
Hi!
That’s a weird issue, I haven’t run into such problem yet so I cannot help much :/
My suggestion is to look in the GitHub page of the module to see if there’s some mention of a similar issue and if not to open an issue describing the situation:
https://github.com/dlitz/pycrypto
Hope it helps getting you in the right direction.
Best regards,
Nuno Santos