[ Log On ]
  • Home
  • Tst
  • Cha
  • Enc
  • Code
  • IP
  • Fun
  • Sub
  • DigF
  • Cis
  • Com
  • Db
  • About
  • Netsim

Fernet (Auto key)

[Back] Fernet is a symmetric encryption method which makes sure that the message encrypted cannot be manipulated/read without the key. It uses URL safe encoding for the keys. Fernet uses 128-bit AES in CBC mode and PKCS7 padding, with HMAC using SHA256 for authentication. The IV is created from os.random(). Generate an example and use the decrypt page: [Fernet Decrypt]

Message

Result

The key generated is a URL-safe base64-encoded key with 32 bytes. When the message is encrypted it contains the time it was generated in plaintext. If we use:

decrypt(token,TTL)

then an exception is raised is the token was created more that TTL seconds ago.

Outline

The token has a version number, a time stamp, the IV, the cipher text and an HMAC signature:

  • Version: 8 bits
  • Timestamp: 64 bits
  • IV: 128 bits
  • Ciphertext - variable length: Multiple of 128 bits
  • HMAC: 256 bits

The token is then created in a Base-64 format:

Key:  Ed_KChj5Qv2WQYRNBAXn5qwflq48b248LVDCKHMeO9M=
Token gAAAAABWC882Iuv67vS758XNJGIrU24Qlw58_6RVgpyX3x4xg9QWG_DJPaSuj3404ULhhZJwGS
HFaeqHU7jB3JyrQra2O__Q3Q==
Current time:   Wed Sep 30 13:01:58 2015

Token Details
=============
Decoded data:  8000000000560bcf3622ebfaeef4bbe7c5cd24622b536e10970e7cffa455829c9
7df1e3183d4161bf0c93da4ae8f7e34e142e18592701921c569ea8753b8c1dc9cab42b6b63bffd0d
d
======Analysis====
Version:        80
Date created:   00000000560bcf36
IV:             22ebfaeef4bbe7c5cd24622b536e1097
Cipher:         0e7cffa455829c97df1e3183d4161bf0
HMAC:           c93da4ae8f7e34e142e18592701921c569ea8753b8c1dc9cab42b6b63bffd0dd

======Converted====
Time stamp:     1443614518
Date created:   Wed Sep 30 13:01:58 2015
IV:             22ebfaeef4bbe7c5cd24622b536e1097
Decoded:        password

Code

The following is some sample code:

# Based on code at https://cryptography.io/en/stable/_modules/cryptography/fernet/
import base64
import binascii
import os
import struct
import time
import six
_MAX_CLOCK_SKEW = 60

from cryptography.exceptions import InvalidSignature
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes, padding
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.primitives.hmac import HMAC

import sys

test="password"


def decrypt(self, token, ttl=None):
        current_time = int(time.time())
	print "Current time:\t",time.ctime(current_time)

        print "\nToken Details"
        print "============="
        if not isinstance(token, bytes):
            raise TypeError("token must be bytes.")


        try:
            data = base64.urlsafe_b64decode(token)
        except (TypeError, binascii.Error):
            raise InvalidToken

	print "Decoded data: ",binascii.hexlify(bytearray(data))
	print "======Analysis===="
	print "Version:\t",binascii.hexlify(bytearray(data[0:1]))

	print "Date created:\t",binascii.hexlify(bytearray(data[1:9]))
	print "IV:\t\t",binascii.hexlify(bytearray(data[9:25]))
	print "Cipher:\t\t",binascii.hexlify(bytearray(data[25:-32]))

	print "HMAC:\t\t",binascii.hexlify(bytearray(data[-32:]))

	print "======Converted===="

        if not data or six.indexbytes(data, 0) != 0x80:
            raise InvalidToken

        try:
            timestamp, = struct.unpack(">Q", data[1:9])
            print "Time stamp:\t",timestamp
            print "Date created:\t",time.ctime(timestamp)
 
        except struct.error:
            raise InvalidToken
        if ttl is not None:
            if timestamp + ttl < current_time:
                raise InvalidToken
        if current_time + _MAX_CLOCK_SKEW < timestamp:
            raise InvalidToken


        h = HMAC(self._signing_key, hashes.SHA256(), backend=self._backend)
        h.update(data[:-32])

        try:
            h.verify(data[-32:])
        except InvalidSignature:
            raise InvalidToken

        iv = data[9:25]
        print "IV:\t\t",binascii.hexlify(iv)

        ciphertext = data[25:-32]
        decryptor = Cipher(
            algorithms.AES(self._encryption_key), modes.CBC(iv), self._backend
        ).decryptor()
        plaintext_padded = decryptor.update(ciphertext)
        try:
            plaintext_padded += decryptor.finalize()
        except ValueError:
            raise InvalidToken
        unpadder = padding.PKCS7(algorithms.AES.block_size).unpadder()

        unpadded = unpadder.update(plaintext_padded)
        try:
            unpadded += unpadder.finalize()
        except ValueError:
            raise InvalidToken
        print "Decoded:\t",unpadded
        return unpadded

from cryptography.fernet import Fernet
key = Fernet.generate_key()
print "Key: ",key
f = Fernet(key)
token = f.encrypt(test)
print "Token", token
decrypt(f,token)