Python Cryptography Fernet Encrypt Decrypt
python cryptography fernet encrypt decrypt: Learn how to use Fernet in Python's cryptography library to encrypt and decrypt data securely, including key generation, er...
The python cryptography fernet encrypt decrypt workflow is straightforward with the Fernet class. Fernet provides symmetric encryption with built-in authentication, so you don't have to assemble cipher and MAC components yourself. This guide walks through key generation, encryption, decryption, error handling, and key rotation using the cryptography.fernet module.
What Fernet Provides
Fernet is a symmetric encryption scheme specified by the cryptography library. It uses AES-128-CBC for confidentiality and HMAC-SHA256 for integrity. Every token includes a timestamp, which allows optional expiration checks. The API is intentionally small: you generate a key, create a Fernet instance, and call encrypt or decrypt. Because authentication is built in, tampered tokens are rejected automatically.
Generating a Fernet Key
A Fernet key is a URL-safe base64-encoded 32-byte value. The generate_key class method creates a new random key:
from cryptography.fernet import Fernet key = Fernet.generate_key() print(key) # b'...'
The key is the single secret that controls both encryption and decryption. Anyone who obtains the key can decrypt all data encrypted with it. Store it in a secure location such as a secrets manager, environment variable, or key management service. Do not hardcode it in source code or commit it to version control.
Encrypting Data
Encrypt a bytes-like object with the encrypt method. The result is a token that contains the ciphertext, the authentication tag, and the timestamp. The token is URL-safe and can be stored or transmitted as a string.
f = Fernet(key) plaintext = b"confidential message" token = f.encrypt(plaintext) print(token) # b'gAAAAAB...'
The input must be bytes; encode strings before encrypting.
Decrypting Data
Use the decrypt method to recover the original plaintext. If the token is valid and the key matches, you get the original bytes back.
f = Fernet(key) original = f.decrypt(token) print(original) # b'confidential message'
If the token has been altered, the key is wrong, or the token is malformed, decrypt raises InvalidToken. You should catch this exception and handle it according to your application's requirements.
Handling Invalid Tokens
InvalidToken is raised when authentication fails. This is the normal way Fernet signals that data is not trustworthy. Common causes include a wrong key, a modified token, or a token that was truncated. Here is how to handle it:
from cryptography.fernet import InvalidToken try: plaintext = f.decrypt(token) except InvalidToken: # Log the event, return an error, or take other action pass
Do not ignore the exception. An invalid token means the data cannot be safely used. Decide whether to retry, reject the request, or alert an operator.
Key Management and Rotation
Fernet keys are symmetric, so the same key must be shared by every party that needs to encrypt or decrypt data. When a key is compromised or when you want to rotate keys on a schedule, you need a strategy that keeps old data readable.
The MultiFernet class helps with rotation. It accepts a list of Fernet instances. Encryption always uses the first instance, while decryption tries each instance in order until one succeeds.
from cryptography.fernet import MultiFernet old_f = Fernet(old_key) new_f = Fernet(new_key) multi = MultiFernet([new_f, old_f]) # Encrypt with the new key encrypted = multi.encrypt(b"data") # Decrypt will try new_f first, then old_f decrypted = multi.decrypt(encrypted)
This lets you introduce a new key without immediately re-encrypting all existing data. Once all data has been re-encrypted with the new key, you can remove the old key from the list.
Security Considerations for Fernet
Fernet is a good default for application-level symmetric encryption because it avoids common pitfalls like using an unauthenticated cipher mode. However, it has limitations:
- It is symmetric, so it requires a pre-shared secret. For public-key scenarios, use a different scheme.
- The entire plaintext is held in memory during encryption and decryption. For very large files, consider streaming encryption instead.
- Tokens include a timestamp, but expiration is not enforced unless you pass
ttltodecrypt.
# Reject tokens older than 1 hour plaintext = f.decrypt(token, ttl=3600)
Use ttl when you need to limit the lifetime of a token, such as in short-lived authorization codes. Without ttl, a token remains valid indefinitely.
Fernet is suitable for many use cases, including encrypting database fields, API payloads, and configuration values. For data at rest, it provides a solid balance of security and simplicity.