Search code examples
pythonpython-3.xcryptographypython-cryptography

Python cryptography Fernet.generate_key() key length


I don't know much about cryptography but when I used cryptography library in python and tried generating a key, the key length was above 32

from cryptography.fernet import Fernet
import base64

key = Fernet.generate_key()
>>>x2pXHXqCcUGjcq4HTcvdqH5xSEF_SLATO6p1Xk3tejM=

If I use this key to decrypt a message online or outside python, it would say key's max length is 32 I read that cryptography library uses 128 bit key CBC AES.

I'm not sure if this is something related to padding, my question is it possible to decrypt Fernet-encrypted messages outside python using this key or is there anyway I can get the original 16 bytes key (since it should be using 128 key)


Solution

  • The key generated by Fernet.generate_key() and expected by the constructor actually consists of two 128-bit keys: one for signing, and the other is for encryption, concatenated in that order.

    From the source code:

        key = base64.urlsafe_b64decode(key)
        if len(key) != 32:
            raise ValueError(
                "Fernet key must be 32 url-safe base64-encoded bytes."
            )
    
        self._signing_key = key[:16]
        self._encryption_key = key[16:]
    

    Update thanks to @PaulKehrer

    This is described in the format specification, quoting below:

    A fernet key is the base64url encoding of the following fields:

    Signing-key ‖ Encryption-key
    
    • Signing-key, 128 bits
    • Encryption-key, 128 bits

    Using low-level libraries and services to decrypt Fernet messages requires parsing the token format manually:

    • Fernet produces url-safe base64
    • Besides data, the token contains version, timestamp, IV and HMAC