Keeping Secrets Secret in Python

Based on an article by originally published by Jason Goldberger but unfortunately the original is not online anymore so I have rewritten a short version, since this is something I have been looking for a while.

Fernet has one classmethod called generate_key() and two instance methods encrypt(plaintext_binary) and decrypt(cipher_binary).

Step 1 : Generate a key

Generate a key and save it to the OS’s environment variables:

1
2
3
from cryptography.fernet import Fernet
key = Fernet.generate_key()
print(key)

Will output something like 'BP04_l7C3wByNiEaEiseNiP0ZrqZ7s3qL-mkG8eHlJY='

Add the key to your environment variables

1
export SECRET_FERNET_KEY='BP04_l7C3wByNiEaEiseNiP0ZrqZ7s3qL-mkG8eHlJY='

Keeping secrets as environment variables is more secure than putting them into source control.

But it’s not fool proof

Step 2 : Functions

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
from cryptography.fernet import Fernet
import os

crypto = Fernet(os.environ.get('SECRET_FERNET_KEY'))

def encrypt(plain_text):
    if isinstance(plain_text, basestring):
        string_text = str(plain_text)
        return crypto.encrypt(bytes(string_text))
    else:
        raise Exception('Encryption Error. Only strings are allowed.')

def decrypt(cipher_text):
    return crypto.decrypt(cipher_text)

Step 3: Use it

1
2
encrypted_spoiler = encrypt('Snape kills Dumbledore.')
print encrypted_spoiler

output something like : “gAAAAABVLTmsBrJWKMzjn4pDlRwtk1j3TFcF1lrRlXo8_ASbR42vEiAcagNKR3”

1
2
plaintext_spoiler = decrypt(encrypted_spoiler)
print plaintext_spoiler

output the original string.