Assuming you're using the Fernet class provided by the cryptography python package, you need to encode your key as base64 not decode it before passing it in. Encoding converts to the form specified, decoding converts from the form specified. What you're currently doing is converting exit_care
to ascii (not necessary), computing the md5 hash, getting a hexidecimal representation, and converting that to ascii again. Then your program is trying to interpret that hexidecimal->ascii md5 hash as a base64-encoded string when you use base64.urlsafe_b64decode(key)
. This is the failure point at the moment. Likely you mean to use base64.urlsafe_b64encode(key)
instead to convert it into the base64 required to use Fernet.
It's possible you may need to pad it to 32 bytes as the Fernet documentation suggests https://cryptography.io/en/latest/fernet/#cryptography.fernet.Fernet
Parameters: key (bytes) – A URL-safe base64-encoded 32-byte key. This must be kept secret. Anyone with this key is able to create and read messages.
This is because MD5 will produce a 128-bit value which is encoded as a 22 character base64 string (actually 24 because python automatically pads to a multiple of 4). See https://stackoverflow.com/a/13296298/6269138 as to why this is the case. Looking at the Fernet implementation, they check the length of the 64-bit-encoded string to see if its length is 32 and will error if it is not. You can right-pad with =
if you want, or you can use a key-generating/key-stretching algorithm described below.
I recommend using a similar setup to the one on the Fernet documentation of the cryptograpy python package found here https://cryptography.io/en/latest/fernet/#using-passwords-with-fernet for key-stretching. The code from the page is pasted below, swapping out PBKDF2HMAC with HKDF because the former requires a salt and is likely overkill for this situation as long as you aren't storing the passwords on a production database.
>>> import base64
>>> import os
>>> from cryptography.fernet import Fernet
>>> from cryptography.hazmat.backends import default_backend
>>> from cryptography.hazmat.primitives import hashes
>>> from cryptography.hazmat.primitives.kdf.hkdf import HKDF
>>> password = b"password"
>>> hkdf = HKDF(
... algorithm=hashes.SHA256(), # You can swap this out for hashes.MD5()
... length=32,
... salt=None, # You may be able to remove this line but I'm unable to test
... info=None, # You may also be able to remove this line
... backend=default_backend()
... )
>>> key = base64.urlsafe_b64encode(hkdf.derive(password))
>>> f = Fernet(key)
>>> token = f.encrypt(b"Secret message!")
>>> token
b'...'
>>> f.decrypt(token) # Process the key in the exact same manner to decode an encoded message
b'Secret message!'