##// END OF EJS Templates
comments: always show comment count
comments: always show comment count

File last commit:

r3522:3910c057 default
r3640:1403c308 new-ui
Show More
encrypt2.py
69 lines | 2.1 KiB | text/x-python | PythonLexer
import os
import base64
from cryptography.fernet import Fernet, InvalidToken
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
class Encryptor(object):
key_format = 'enc2$salt:{}$data:{}'
pref_len = 5 # salt:, data:
def __init__(self, enc_key):
self.enc_key = enc_key
def b64_encode(self, data):
return base64.urlsafe_b64encode(data)
def b64_decode(self, data):
return base64.urlsafe_b64decode(data)
def get_encryptor(self, salt):
"""
Uses Fernet as encryptor with HMAC signature
:param salt: random salt used for encrypting the data
"""
kdf = PBKDF2HMAC(
algorithm=hashes.SHA512(),
length=32,
salt=salt,
iterations=100000,
backend=default_backend()
)
key = self.b64_encode(kdf.derive(self.enc_key))
return Fernet(key)
def _get_parts(self, enc_data):
parts = enc_data.split('$', 3)
if len(parts) != 3:
raise ValueError('Encrypted Data has invalid format, expected {}'.format(self.key_format))
prefix, salt, enc_data = parts
try:
salt = self.b64_decode(salt[self.pref_len:])
except TypeError:
# bad base64
raise ValueError('Encrypted Data salt invalid format, expected base64 format')
enc_data = enc_data[self.pref_len:]
return prefix, salt, enc_data
def encrypt(self, data):
salt = os.urandom(64)
encryptor = self.get_encryptor(salt)
enc_data = encryptor.encrypt(data)
return self.key_format.format(self.b64_encode(salt), enc_data)
def decrypt(self, data, safe=True):
parts = self._get_parts(data)
salt = parts[1]
enc_data = parts[2]
encryptor = self.get_encryptor(salt)
try:
return encryptor.decrypt(enc_data)
except (InvalidToken,):
if safe:
return ''
else:
raise