How to encrypt and decrypt data in Python 3 using pycrypto
When you wish to encrypt and decrypt data in your Python 3 application, you can take a look at pycrypto.
Given that, let us look at how we can encrypt and decrypt data in Python 3 using pycrpto.
Installing pycrypto into your Python 3 environment
In order to use pycrypto, we need to install it.
Therefore, run the following command to install pycrypto into your Python 3 environment:
pip pycrypto
Getting an instance of the AES to encrypt and decrypt data with the AES encryption algorithm
After you had installed pycrypto in your Python 3 environment, you can then choose an encryption algorithm to encrypt and decrypt your data.
For example, you can write the following Python 3 codes to get an object to encrypt / decrypt data with the AES encryption algorithm:
from Crypto.Cipher import AES # AES key must be either 16, 24, or 32 bytes long COMMON_ENCRYPTION_KEY='asdjk@15r32r1234asdsaeqwe314SEFT' # Make sure the initialization vector is 16 bytes COMMON_16_BYTE_IV_FOR_AES='IVIVIVIVIVIVIVIV' def get_common_cipher(): return AES.new(COMMON_ENCRYPTION_KEY, AES.MODE_CBC, COMMON_16_BYTE_IV_FOR_AES)
As shown above, we first import the AES module. After we had done so, we define an encryption key that is 32 bytes long. In case you are wondering, this key must be either 16, 24 or 32 bytes long.
After that, we define an initialization vector that must be 16 bytes long.
Once we have defined the key and initialization vector, we then define a function to get an AES cipher instance.
Whenever we need to perform encryption or decryption, we can use the get_common_cipher
function.
Since the cipher object is stateful, we should create a new AES cipher instance whenever we wish to encrypt or decrypt data.
How to encrypt string in Python 3 using pycrypto
When we represent our data as string or text, we can transfer our data easily with HTTP.
Given that, let's look at how we can define a function to encrypt string:
import base64 import math def encrypt_with_common_cipher(cleartext): common_cipher = get_common_cipher() cleartext_length = len(cleartext) next_multiple_of_16 = 16 * math.ceil(cleartext_length/16) padded_cleartext = cleartext.rjust(next_multiple_of_16) raw_ciphertext = common_cipher.encrypt(padded_cleartext) return base64.b64encode(raw_ciphertext).decode('utf-8')
As shown above, we first import the base64
and math
modules.
Once we have done so, we define a function encrypt_with_common_cipher
that takes a string as an input.
When the function is called, we first get an instance of the AES cipher to perform the encryption.
Since the cipher does not pad our data, we need to do that on our own. Therefore, we first get the length of the text data to compute the next multiple of 16. Once we get the next multiple of 16, we use the rjust
method to pad the cleartext
with spaces.
Once we had padded our string data to make its size a multiple of 16, we then encrypt it with the AES cipher. When we do so, raw_ciphertext will contain the corresponding cipher text in bytes.
In order to convert the raw_ciphertext
to a string, we call base64.b64encode
on raw_ciphertext
, followed by decode
before returning the result to the caller.
How to decrypt string in Python 3 using pycrypto
Whenever we encrypt our string data, there will be a point in time when we want to decrypt it.
Given that, we can define a function to decrypt the cipher text that was created by encrypt_with_common_cipher
:
def decrypt_with_common_cipher(ciphertext): common_cipher = get_common_cipher() raw_ciphertext = base64.b64decode(ciphertext) decrypted_message_with_padding = common_cipher.decrypt(raw_ciphertext) return decrypted_message_with_padding.decode('utf-8').strip()
Similar to encrypt_with_common_cipher
, we first get an instance of the AES cipher with the same key and initialization vector.
Next, we take the ciphertext
, convert it back to bytes and kept it as raw_ciphertext
.
Once we get back the cipher text in bytes, we use our AES cipher to decrypt it.
When we do so, we will get the decrypted message with padding.
Finally, we decode decrypted_message_with_padding
as a string, call strip
to remove the spaces and return the result to the caller.
How to encrypt JSON data in Python 3 using pycrypto
At this point in time, encrypting JSON data will be straightforward:
import json def encrypt_json_with_common_cipher(json_obj): json_string = json.dumps(json_obj) return encrypt_with_common_cipher(json_string)
As shown above, we can define a encrypt_json_with_common_cipher
function that takes a JSON object as input.
When the function is called, we use json.dumps
to convert the JSON object into a JSON string.
Once we have the JSON string, we pass it to the encrypt_with_common_cipher
function and return the result back to the caller.
How to decrypt JSON data in Python 3 using pycrypto
When we want to get back the JSON data that we had encrypted, we can define the following function:
import json def decrypt_json_with_common_cipher(json_ciphertext): json_string = decrypt_with_common_cipher(json_ciphertext) return json.loads(json_string)
As shown above, the decrypt_json_with_common_cipher
function takes in a JSON cipher text as an input.
When the function is called, we call the decrypt_with_common_cipher function to get back the JSON string.
Once we have the JSON string, we use json.loads
to get back the JSON object and return it back to the caller.
Putting everything together
In case you want a running example of what was discussed, you can run the following script:
from Crypto.Cipher import AES import base64, json, math # AES key must be either 16, 24, or 32 bytes long COMMON_ENCRYPTION_KEY='asdjk@15r32r1234asdsaeqwe314SEFT' # Make sure the initialization vector is 16 bytes COMMON_16_BYTE_IV_FOR_AES='IVIVIVIVIVIVIVIV' def get_common_cipher(): return AES.new(COMMON_ENCRYPTION_KEY, AES.MODE_CBC, COMMON_16_BYTE_IV_FOR_AES) def encrypt_with_common_cipher(cleartext): common_cipher = get_common_cipher() cleartext_length = len(cleartext) nearest_multiple_of_16 = 16 * math.ceil(cleartext_length/16) padded_cleartext = cleartext.rjust(nearest_multiple_of_16) raw_ciphertext = common_cipher.encrypt(padded_cleartext) return base64.b64encode(raw_ciphertext).decode('utf-8') def decrypt_with_common_cipher(ciphertext): common_cipher = get_common_cipher() raw_ciphertext = base64.b64decode(ciphertext) decrypted_message_with_padding = common_cipher.decrypt(raw_ciphertext) return decrypted_message_with_padding.decode('utf-8').strip() def encrypt_json_with_common_cipher(json_obj): json_string = json.dumps(json_obj) return encrypt_with_common_cipher(json_string) def decrypt_json_with_common_cipher(json_ciphertext): json_string = decrypt_with_common_cipher(json_ciphertext) return json.loads(json_string) message = 'This is obviously a secret message.' ciphertext = encrypt_with_common_cipher(message) print('Cipher text: %s' % ciphertext) decrypted_message = decrypt_with_common_cipher(ciphertext) print('Decrypted message: %s' % decrypted_message) json_obj = { 'fruits': ['apple', 'pear', 'orange'] } json_ciphertext = encrypt_json_with_common_cipher(json_obj) print('JSON cipher text: ') print(json_ciphertext) decryped_json_obj = decrypt_json_with_common_cipher(json_ciphertext) print('Decrypted JSON object: ') print(decryped_json_obj)
After the function definition for decrypt_json_with_common_cipher
, we proceeded to encrypt and decrypt a string and a JSON object.
When you run the script, you should get the following output:
Cipher text: Qq3sD/JX0M2Uo5anotgnBhZvyM/KHGWc/Eaoin1ocnoTrPNSZpKUUKtTuzW+ocJs Decrypted message: This is obviously a secret message. JSON cipher text: Tj/KLrTiFQfUJtQOe9FuUkHoMI4BKxjQAtrPyAYxGpDrlOvtcLIUKhVmRhloqNdm Decrypted JSON object: {'fruits': ['apple', 'pear', 'orange']}