When I decrypt my string with the correct password following this simple guide on the library's website I get a correct string response. When I change the final w to an e to get an invalid key, I get a padding bytes error like this stemming from:
lib/python3.8/site-packages/cryptography/hazmat/primitives/padding.py", line 101, in _byte_unpadding_check
Which is then followed by the cryptography.fernet.InvalidToken error I was expecting.
ValueError: Invalid padding bytes.
During handling of the above exception, another exception occurred:
cryptography.fernet.InvalidToken
I've read Stackoverflow and can only find one example of this but it didn't seem to apply when this is just the actual example from their site.
What am I missing?
from cryptography.fernet import Fernet
# print(Fernet.generate_key()) # used this to get the below
bytes_key = b'tsuG7oqhwyCsfUof35btDJA2eM7AdGf4tAM0o1zXOew='
# changed just one digit of key to test incorrect key
# bytes_key = b'tsuG7oqhwyCsfUof35btDJA2eM7AdGf4tAM0o1zXOee='
f = Fernet(bytes_key)
# encrypt a message
# token = f.encrypt(b"A really secret message. Not for prying eyes.")
# print(token)
# b'gAAAAABiIOCx9Pp8HB9Asq0HUXb-t0SwX-W5ue7O3GJfuF9Rm4ue8I0Drk36NIyuZ0Mufknad5xkoL3091ZGOOS-QTqMbM-MeNrEC9jvmYx_Y0ojoSTaZWO9AXMJFZgdnvgPTB-wQIQd'
print(f.decrypt(b'gAAAAABiIOCx9Pp8HB9Asq0HUXb-t0SwX-W5ue7O3GJfuF9Rm4ue8I0Drk36NIyuZ0Mufknad5xkoL3091ZGOOS-QTqMbM-MeNrEC9jvmYx_Y0ojoSTaZWO9AXMJFZgdnvgPTB-wQIQd'))
print(f.decrypt(b'gAAAAABiIOCx9Pp8HB9Asq0HUXb-t0SwX-W5ue7O3GJfuF9Rm4ue8I0Drk36NIyuZ0Mufknad5xkoL3091ZGOOS-QTqMbM-MeNrEC9jvmYx_Y0ojoSTaZWO9AXMJFZgdnvgPTB-wQIQd').decode('utf-8'))
Details about the structure of the Fernet key, the Fernet token and the algorithms involved can be found here.
The Fernet key consists of the concatenation of a 16 bytes signing key and a 16 bytes encryption key, Base64url encoded.
For the posted valid Fernet key is:
Fernet key (Base64url): tsuG7oqhwyCsfUof35btDJA2eM7AdGf4tAM0o1zXOew=
Signing key (hex): b6cb86ee8aa1c320ac7d4a1fdf96ed0c
Encryption key (hex): 903678cec07467f8b40334a35cd739ec
and for the posted invalid key:
Fernet key (Base64url): tsuG7oqhwyCsfUof35btDJA2eM7AdGf4tAM0o1zXOee=
Signing key (hex): b6cb86ee8aa1c320ac7d4a1fdf96ed0c
Encryption key (hex): 903678cec07467f8b40334a35cd739e7
Note that both encryption keys differ in the last byte (0xec
vs 0xe7
), i.e. your change has modified the encryption key!
The wrong key causes that the decryption generates a wrong plaintext with a wrong padding. It is not the length of the padding that is wrong, but the values of the padding bytes themselves.
Details: The plaintext used in the example:
A really secret message. Not for prying eyes.
consists of 45 bytes, i.e. the padding consists of 3 bytes, namely the byte sequence 0x030303
, since PKCS#7 padding is applied. For PKCS7# padding all padding bytes have the same value and this value corresponds to the number of padding bytes, for details see PKCS#7. If the ciphertext is decrypted with the wrong key, the last three bytes are 0x07e3f2
, which does not correspond to a valid PKCS#7 padding and generates the ValueError: Invalid padding bytes error message.
Note: If the padding is correct, it is automatically removed.
Similarly, an invalid signing key generates a corresponding error message InvalidSignature: Signature did not match digest.
The padding 0x07e3f2
can be determined as follows:
The structure of the token is: version (1 byte) || timestamp (8 bytes) || IV (16 bytes) || ciphertext || HMAC (32 bytes
). Thus, from the token, the IV and ciphertext below can be derived:
IV: f4fa7c1c1f40b2ad075176feb744b05f
ciphertext: e5b9b9eecedc625fb85f519b8b9ef08d03ae4dfa348cae67432e7e49da779c64a0bdf4f7564638e4be413a8c6ccf8c78
This allows decryption with AES/CBC without padding using the appropriate tools (e.g. here) and results in the following byte sequence for decryption with the wrong key:
6afb18a9791e407ce0eafd1d2c2ae1cef403e94903cf80e90193fafd0681e58f0e8fff0d3f3542901bced6fc8e07e3f2
with 0x07e3f2
as invalid padding bytes.
In contrast, if the correct key is supplied for decryption, the result is:
41207265616c6c7920736563726574206d6573736167652e204e6f7420666f7220707279696e6720657965732e030303
with the correct padding 0x030303
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With