$ fernet-decrypt.py

A minimal helper that takes a Fernet key and an encrypted value, decrypts it and prints the plaintext.

#!/usr/bin/env python
from cryptography.fernet import Fernet
import argparse


parser = argparse.ArgumentParser()
parser.add_argument("-f", "--fernet", required=True, help="Fernet Key")
parser.add_argument("-v", "--val", required=True, help="Value to decode")
args = parser.parse_args()

KEY = args.fernet
VAL = bytes(args.val, 'utf-8')

def decrypt_message(encrypted_message, KEY):
    """
    Decrypts an encrypted message
    """
    f = Fernet(KEY)
    decrypted_message = f.decrypt(encrypted_message)

    print(decrypted_message.decode())

if __name__ == "__main__":
    decrypt_message(VAL, KEY)

$ usage

# Install the library if it is missing
pip3 install cryptography

# Decrypt a token with the recovered key
python3 fernet-decrypt.py -f "<FERNET_KEY>" -v "<gAAAAA...>"

$ identifying a Fernet token

Fernet ciphertext is URL-safe base64 of a versioned structure, so real tokens always start with gAAAAA (version byte 0x80 followed by a timestamp). A token is typically 120–288 bytes: version, 8-byte timestamp, 16-byte IV, AES-128-CBC ciphertext (padded to 16-byte blocks) and a 32-byte HMAC-SHA256 signature, all base64-encoded.

# Spot tokens in source, logs and dumps
grep -rE "gAAAAA[0-9A-Za-z_-]{80,}" . --exclude-dir=.git

# Confirm the structure manually (version byte 0x80 then a unix timestamp)
echo "<token>" | base64 -d | xxd | head -3

$ generating a key

python3 -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"

$ decrypt without the script

python3 -c 'from cryptography.fernet import Fernet; print(Fernet(b"<FERNET_KEY>").decrypt(b"<gAAAAA...>").decode())'

$ where keys leak

Fernet keys are usually baked into the application rather than generated at runtime, so hunt for them in:

# Environment variables and process environments
cat /proc/<pid>/environ | tr '\0' '\n' | grep -i -E "fernet|secret|key"
env | grep -i -E "fernet|crypt"

# Config files
grep -rE "SECRET_KEY|FERNET|ENCRYPTION" /etc /opt /srv /home 2>/dev/null
grep -rE "SECRET_KEY|FERNET" . --exclude-dir=.git

# Committed secrets in git history
git log -p | grep -iE "fernet|secret_key"
git log --all --full-history -- "*settings*" "*config*"

$ key vs password

A Fernet key is a full 128-bit AES key plus signing key encoded as 44 base64 characters — there is no password derivation and no KDF. Brute-forcing is pointless: the keyspace is 2126-ish, so you cannot guess it. The attack is reconnaissance: find the key in the source, config, environment or git history, then decrypt. If a Fernet key is generated with Fernet.generate_key() at startup and never stored, decryption of old data may be impossible — but a hard-coded or committed key is effectively a plaintext secret.