------------------------------------------------------------------------------- Fernet Encryption Format It is meant to be used for small amounts of encrypted data (tokens) It is not designed for LARGE files requiring data streams. A Encryption using AES128-CBC with HMAC authentication The IV is normally randomised on encrypt Specification, and Generation https://github.com/fernet/spec/blob/master/Spec.md Format... 1 byte, version (currenly only 0x80) 8 byte, UNIX timestamp (seconds since epoch) 8 byte, IV randomised on encryption Cythertext AES128-CBC with IV and encryption key, padded pkcs#7 32 byte, HMAC SHA267 of all 4 previous fields Which is then base64 encoded. Timestamp is to ensure message is not too old. The data will always be a multiple of 16, +1 before base64 encoding. It is assumed the transport will provide the total length of the above. Encrypted base16 string length is 100 bytes for data 15 bytes or less 120 bytes for 16 to 31 bytes of data, 140 bytes for 32 to 47 bytes of data 164 bytes for 48 to 63 bytes of data JavaScript (node & browser)... https://github.com/csquared/fernet.js ------------------------------------------------------------------------------- Python implementation https://cryptography.io/en/latest/fernet.html Install module python -m pip install cryptography Also installs "cffi" and "pycparser" (which is not actually needed to use it!) Python Sample Code... https://nitratine.net/blog/post/encryption-and-decryption-in-python/ =======8<--------CUT HERE---------- # -- Generate the key -- #from cryptography.fernet import Fernet #key = Fernet.generate_key() #print(key) # a base 64 string # -- OR the base64 key from a password -- import os import base64 from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC password = b"password" # from user input salt = os.urandom(16) # should change, so needs to be stored with encryption iterations = 100000 # must be fixed or be stored as well kdf = PBKDF2HMAC( algorithm=hashes.SHA256(), length=32, salt=salt, iterations=iterations ) key = base64.urlsafe_b64encode(kdf.derive(password)) print(key) # a base 64 string # --- # Set up cypher using a base64 key # key = ... # whereever was generated import json from cryptography.fernet import Fernet, InvalidToken cipher = Fernet(key) # Encrypt # Data to Encrypt (can be any string, array or hash) info = "secret_data" # this can be a data-structure encrypted = cipher.encrypt(json.dumps(info)) print(encrypted) # base 64 encrypted string # HERE you would save/recover data, # with any required 'salt' or 'iterations' values needed, to recreate 'key' # And use key to re-create the same crypher for decryption # Decrypt try: decrypted = json.loads(cipher.decrypt(encrypted)) except InvalidToken: print( f'Decrypt Error') print(decrypted) =======8<--------CUT HERE---------- -------------------------------------------------------------------------------