Skip to content

Instantly share code, notes, and snippets.

@jsatt
Created June 30, 2021 20:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jsatt/6c2016eae467348427b588e4d8d074ec to your computer and use it in GitHub Desktop.
Save jsatt/6c2016eae467348427b588e4d8d074ec to your computer and use it in GitHub Desktop.
Django Encrypted Data field
import base64
import json
from typing import Any, Optional, Union
from cryptography.fernet import Fernet
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from django.conf import settings
from django.db import models
class EncryptedDataField(models.BinaryField):
description = 'Data encrypted at rest'
def __init__(self, *args, key: Optional[Union[str, bytes]] = None, **kwargs):
super().__init__(*args, **kwargs)
self.suite = Fernet(self._get_key(key or settings.SECRET_KEY))
def from_db_value(self, value, expression, connection):
if value:
return self._decrypt(value.tobytes())
return value
def to_python(self, value):
value = super().to_python(value)
if value:
return self._decrypt(value)
return value
def get_db_prep_value(self, value, connection, prepared=False):
if value:
value = self._encrypt(value)
return super().get_db_prep_value(value, connection, prepared)
def _get_key(self, base: Union[str, bytes]) -> bytes:
if isinstance(base, str):
base = base.encode()
digest = hashes.Hash(hashes.SHA256(), backend=default_backend())
digest.update(base)
return base64.urlsafe_b64encode(digest.finalize())
def _encrypt(self, value: Any) -> bytes:
string = json.dumps(value)
return self.suite.encrypt(string.encode())
def _decrypt(self, value: bytes) -> Any:
string = self.suite.decrypt(value)
return json.loads(string.decode())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment