#!/usr/bin/python3
# ====================================================================
# From:
# stackoverflow.com/questions/61607367/how-to-encrypt-json-in-python
# --------------------------------------------------------------------
# pip install cryptography
# or on windows:
# python -m pip install cryptography
# --------------------------------------------------------------------
# https://pypi.org/project/cryptography/
#---------------------------------------------------------------------
# Fernet is ideal for encrypting data that easily fits in memory.
# This means that the complete message contents must be available
# in memory, making Fernet generally unsuitable for very large.
# ====================================================================
import sys
import json
from io import StringIO
from cryptography.fernet import Fernet
import base64
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
# -------------------------------------------------------------------
# ---- write JSON file
# -------------------------------------------------------------------
def output_json_file(outfile,jdata):
with open(outfile,'w') as ofile:
ofile.write(json.dumps(jdata))
# -------------------------------------------------------------------
# ---- read JSON file
# -------------------------------------------------------------------
def input_json_file(infile):
with open(infile,'r') as ifile:
jdata = json.load(ifile)
return jdata
# -------------------------------------------------------------------
# ---- write encrypted byte data
# -------------------------------------------------------------------
def output_encrypted_json(outfile,edata):
##print('----------')
##print(f'outfile = {outfile}')
with open(outfile,'wb') as ofile:
l = ofile.write(edata)
##print(f'encrypted data len = {l} bytes')
return
# -------------------------------------------------------------------
# ---- read encrypted byte data
# -------------------------------------------------------------------
def input_encrypted_json(infile):
##print('----------')
##print(f'infile = {infile}')
with open(infile,'rb') as ifile:
edata = ifile.read()
##print(f'edata = {len(edata)} bytes')
return edata
# --------------------------------------------------------------------
#---- generates key from the password
# --------------------------------------------------------------------
def key_from_password(password):
bpass = password.encode('utf-8')
salt = b'password salt'
kdf = PBKDF2HMAC(
algorithm=hashes.SHA256(),
length=32,
salt=salt,
iterations=100000,
backend=default_backend())
key = base64.urlsafe_b64encode(kdf.derive(bpass))
return key
# ---------------------------------------------------------------------
# ---- encrypt dictionary
# ---------------------------------------------------------------------
def encrypt_dictionary(oldict,password,outfile=None):
##print('----------')
##print(f'oldict = {oldict}')
# ---- convert dictionary to json
jdata = json.dumps(oldict)
##print('----------')
##print(f'jdata type = {type(jdata)}')
##print(f'jdata = {jdata}')
# ---- convert json to bytes
bdata = jdata.encode('utf=-8')
##print('----------')
##print(f'bdata type = {type(bdata)}')
##print(f'bdata = {bdata}')
# ---- get password key
key = key_from_password(password)
##print('----------')
##print(f'password = {password}')
##print(f'key = {key}')
#---- encrypt byte data
fernet = Fernet(key)
edata = fernet.encrypt(bdata)
##print('----------')
##print(f'edata type = {type(edata)}')
##print(f'edata = {edata}')
# ---- write encrypted json
output_encrypted_json(outfile,edata)
return
# --------------------------------------------------------------------
# ---- decrypt dictionary
# --------------------------------------------------------------------
def decrypt_dictionary(password,infile):
# ---- read encrypted json
edata = input_encrypted_json(infile)
# ---- get key based on password
key = key_from_password(password)
##print('----------')
##print(f'password = {password}')
##print(f'key = {key}')
#---- decrypt edata using the key
fernet = Fernet(key)
##bdata = fernet.decrypt(edata)
##print('----------')
##print(f'bdata type = {type(bdata)}')
##print(f'bdata = {bdata}')
#---- convert byte data to a json
jdata = bdata.decode('utf-8')
##print('----------')
##print(f'jdata type = {type(jdata)}')
##print(f'jdata = {jdata}')
#---- convert to dictionary
newdict = json.loads(jdata)
##print('----------')
##print(f'newdict type = {type(newdict)}')
##print(f'newdict = {newdict}')
return newdict