Skip to content

Instantly share code, notes, and snippets.

@dmwyatt
Last active June 8, 2024 16:43
Show Gist options
  • Save dmwyatt/4c0ef48a516bf5067b1ff78fb94d1249 to your computer and use it in GitHub Desktop.
Save dmwyatt/4c0ef48a516bf5067b1ff78fb94d1249 to your computer and use it in GitHub Desktop.
An experimental Django EncryptedField for encryption-at-rest
"""
Encrypted field for Django for encrypting data at rest.
Inspired by: https://scottarc.blog/2024/06/02/encryption-at-rest-whose-threat-model-is-it-anyway/
"""
import base64
import os
from django.db import models
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
# Replace this with your actual key management system
SECRET_KEY = os.urandom(32) # This should be securely managed
class EncryptedField(models.BinaryField):
def __init__(self, *args, **kwargs):
self.aad_field = kwargs.pop('aad_field', None)
super().__init__(*args, **kwargs)
def get_aad(self, instance):
if self.aad_field:
return str(getattr(instance, self.aad_field)).encode()
return b''
def encrypt(self, value, aad):
aesgcm = AESGCM(SECRET_KEY)
nonce = os.urandom(12)
ciphertext = aesgcm.encrypt(nonce, value.encode(), aad)
return nonce + ciphertext
def decrypt(self, value, aad):
aesgcm = AESGCM(SECRET_KEY)
nonce, ciphertext = value[:12], value[12:]
plaintext = aesgcm.decrypt(nonce, ciphertext, aad)
return plaintext.decode()
def from_db_value(self, value, expression, connection):
if value is None:
return value
return value
def to_python(self, value):
if isinstance(value, bytes) or value is None:
return value
return value
def get_prep_value(self, value):
if value is None:
return value
return value
def pre_save(self, model_instance, add):
raw_value = getattr(model_instance, self.attname)
if raw_value is None:
return None
aad = self.get_aad(model_instance)
encrypted_value = self.encrypt(raw_value, aad)
setattr(model_instance, self.attname, encrypted_value)
return encrypted_value
def get_db_prep_value(self, value, connection, prepared=False):
if value is None:
return value
return value
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment