Need to encrypt some text with a password or private key in Python? You certainly came to the right place. AES-256 is a solid symmetric cipher that is commonly used to encrypt data for oneself. In other words, the same person who is encrypting the data is typically decrypting it as well (think password manager).
For this tutorial, we will be using Python 3, so make sure you install pycryptodome, which will give us access to an implementation of AES-256:
pip3 install pycryptodomex
AES-256 typically requires that the data to be encrypted is supplied in 16-byte blocks, and you may have seen that on other sites or tutorials. AES-256 in GCM mode, however, doesn't require any special padding to be done by us manually.
Now we create a simple encrypt(plain_text, password) function. This function uses the password to encrypt the plain text. Therefore, anyone with access to the encrypted text and the password will be able to decrypt it.
def encrypt(plain_text, password):
# generate a random salt
salt = get_random_bytes(AES.block_size)
# use the Scrypt KDF to get a private key from the password
private_key = hashlib.scrypt(
password.encode(), salt=salt, n=2**14, r=8, p=1, dklen=32)
# create cipher config
cipher_config = AES.new(private_key, AES.MODE_GCM)
# return a dictionary with the encrypted text
cipher_text, tag = cipher_config.encrypt_and_digest(bytes(plain_text, 'utf-8'))
return {
'cipher_text': b64encode(cipher_text).decode('utf-8'),
'salt': b64encode(salt).decode('utf-8'),
'nonce': b64encode(cipher_config.nonce).decode('utf-8'),
'tag': b64encode(tag).decode('utf-8')
}
Notes on encrypt() function
def decrypt(enc_dict, password):
# decode the dictionary entries from base64
salt = b64decode(enc_dict['salt'])
cipher_text = b64decode(enc_dict['cipher_text'])
nonce = b64decode(enc_dict['nonce'])
tag = b64decode(enc_dict['tag'])
# generate the private key from the password and salt
private_key = hashlib.scrypt(
password.encode(), salt=salt, n=2**14, r=8, p=1, dklen=32)
# create the cipher config
cipher = AES.new(private_key, AES.MODE_GCM, nonce=nonce)
# decrypt the cipher text
decrypted = cipher.decrypt_and_verify(cipher_text, tag)
return decrypted
Notes on decrypt() function
The decrypt() function needs the same salt, nonce, and tag that we used for encryption. We used a dictionary for convenience in parsing, but if we instead wanted one string of ciphertext we could have used a scheme like salt.nonce.tag.cipher_textThe configuration parameters on the Scrypt and AES functions need to be the same as the encrypt function.
You probably want to see it all work in an example script. Look no further!
# AES 256 encryption/decryption using pycryptodome library
from base64 import b64encode, b64decode
import hashlib
from Cryptodome.Cipher import AES
import os
from Cryptodome.Random import get_random_bytes
def encrypt(plain_text, password):
# generate a random salt
salt = get_random_bytes(AES.block_size)
# use the Scrypt KDF to get a private key from the password
private_key = hashlib.scrypt(
password.encode(), salt=salt, n=2**14, r=8, p=1, dklen=32)
# create cipher config
cipher_config = AES.new(private_key, AES.MODE_GCM)
# return a dictionary with the encrypted text
cipher_text, tag = cipher_config.encrypt_and_digest(bytes(plain_text, 'utf-8'))
return {
'cipher_text': b64encode(cipher_text).decode('utf-8'),
'salt': b64encode(salt).decode('utf-8'),
'nonce': b64encode(cipher_config.nonce).decode('utf-8'),
'tag': b64encode(tag).decode('utf-8')
}
def decrypt(enc_dict, password):
# decode the dictionary entries from base64
salt = b64decode(enc_dict['salt'])
cipher_text = b64decode(enc_dict['cipher_text'])
nonce = b64decode(enc_dict['nonce'])
tag = b64decode(enc_dict['tag'])
# generate the private key from the password and salt
private_key = hashlib.scrypt(
password.encode(), salt=salt, n=2**14, r=8, p=1, dklen=32)
# create the cipher config
cipher = AES.new(private_key, AES.MODE_GCM, nonce=nonce)
# decrypt the cipher text
decrypted = cipher.decrypt_and_verify(cipher_text, tag)
return decrypted
def main():
password = input("Password: ")
# First let us encrypt secret message
encrypted = encrypt("The secretest message here", password)
print(encrypted)
# Let us decrypt using our original password
decrypted = decrypt(encrypted, password)
print(bytes.decode(decrypted))
main()
By Lane Wagner