Symmetric data encryption with Python


Welcome to the next pikoTutorial!

One of the simplest ways to perform symmetric encryption in Python is to use Fernet algorithm from cryptography module. Let’s install it with command:

pip install cryptography

Having cryptography module available, let’s write our first encryption script:

# import Fernet
from cryptography.fernet import Fernet
# Generate a key
key = Fernet.generate_key()
# Create a Fernet instance providing the generated key
fernet = Fernet(key)
# Encrypt the data
data = b'Some secret data'
encrypted_data = fernet.encrypt(data)
# Decrypt the data
decrypted_data = fernet.decrypt(encrypted_data)
print(f"Decrypted text: {decrypted_data.decode()}")

Note for beginners: the key is necessary both when encrypting and decrypting the data, so you can’t generate every time a new key. After encrypting the data, you need to store the key, but because it is something what alows you to decrypt the data, remember to store it in some secure way!

The key generated in the example above consists of random bytes. Such keys are very secure, however often you need your encryption to be password based – by password I mean some phrase which is easily understadable by humans and provided dynamicaly by the user as an input. Below you can find Python code showing how to get a password from the user as an input and how to turn it into the encryption key:

# import utility for Base64 encoding
import base64
# import Fernet
from cryptography.fernet import Fernet
# import getpass for secure input reading
from getpass import getpass
# read plain text password
plain_text_password: str = getpass(prompt='Password: ')
# Fernet requires 32 byte key, so the password also must have 32 characters
if len(plain_text_password) != 32:
    raise RuntimeError(f'Password length must be equal 32!')
# Encode plain text password to ASCII bytes
password_ascii: bytes = plain_text_password.encode('ascii')
# Fernet requires key to be url-safe base64-encoded
key: bytes = base64.urlsafe_b64encode(password_ascii)
# Create a Fernet instance providing the generated key
fernet = Fernet(key)
# Encrypt the data
data = b'Some secret data'
encrypted_data = fernet.encrypt(data)
# Decrypt the data
decrypted_data = fernet.decrypt(encrypted_data)
print(f"Decrypted text: {decrypted_data.decode()}")

Note for advanced: this pikoTutorial focuses on how to use Fernet for symmetric encryption, so it simplifies the encryption key creation. In practice, when you need to create an encryption key out of a user-provided password, you should use Key Derivation Function like PBKDF2HMAC.