django-pgcrypto-fields
django-pgcrypto-fields
is a Django
extension which relies upon pgcrypto to
encrypt and decrypt data for fields.
django-pgcrypto-fields
has 4 fields grouped in two categories:
- hash based fields (
DigestField
andHMACField
); - pgp fields (
PGPPublicKeyField
andPGPSymmetricKeyField
).
Requirements
- postgres with pgcrypto
Installation
pip
pip install django-pgcrypto-fields
Fields
DigestField
DigestField
is a hash based field. The value is hashed in the database when
saved with the digest
pgcrypto function using the sha512
algorithm.
HMACField
HMACField
is a hash based field. The value is hashed in the database when
saved with the hmac
pgcrypto function using a key and the sha512
algorithm.
key
is set in settings.PGCRYPTO_KEY
.
PGPPublicKeyField
Public key encryption. It generates a token generated with a public key to encrypt the data and a private key to decrypt it.
Public and private keys can be set in settings with PUBLIC_PGP_KEY
and
PRIVATE_PGP_KEY
.
Generate GPG keys.
The public key is going to encrypt the message and the private key will be needed to decrypt the content. The following commands have been taken from the pgcrypto documentation (see Generating PGP Keys with GnuPG).
Generating a public and a private key:
$ gpg --gen-key
$ gpg --list-secret-keys
/home/bob/.gnupg/secring.gpg
---------------------------
sec 2048R/21 2014-10-23
uid Test Key <[email protected]>
ssb 2048R/42 2014-10-23
$ gpg -a --export 42 > public.key
$ gpg -a --export-secret-keys 21 > private.key
PGPSymmetricKeyField
Symmetric key encryption. Encrypt and decrypt the data with settings.PGCRYPTO_KEY
.
settings.py
BASEDIR = os.path.dirname(os.path.dirname(__file__))
PUBLIC_PGP_KEY_PATH = os.path.abspath(os.path.join(BASEDIR, 'public.key'))
PRIVATE_PGP_KEY_PATH = os.path.abspath(os.path.join(BASEDIR, 'private.key'))
# Used by PGPPublicKeyField
PUBLIC_PGP_KEY = open(PUBLIC_PGP_KEY_PATH).read()
PRIVATE_PGP_KEY = open(PRIVATE_PGP_KEY_PATH).read()
# Used by HMACField and PGPSymmetricKeyField
PGCRYPTO_KEY='ultrasecret'
# And add 'pgcrypto_fields' to `INSTALLED_APPS` to create the extension for
# pgcrypto (in a migration).
INSTALLED_APPS = (
...
'pgcrypto_fields',
...
)
Usage
Model definition
from django.db import models
from pgcrypto_fields import fields
class MyModel(models.Model):
digest_field = fields.DigestField()
hmac_field = fields.HMACField()
pgp_pub_field = fields.PGPPublicKeyField()
pgp_sym_field = fields.PGPSymmetricKeyField()
Encrypting
Data is encrypted when inserted into the database.
Example:
>>> MyModel.objects.create(value='Value to be encrypted...')
Decrypting
PGP fields
When accessing the field name attribute on a model instance we are getting the decrypted value.
Example:
>>> # When using a PGP public key based encryption
>>> my_model = MyModel.objects.get()
>>> my_model.value_decrypted # field's proxy
'Value decrypted'
To be able to filter PGP values we first need to use an aggregate method to decrypt the values.
Example when using a PGPPublicKeyField
:
>>> from pgcrypto_fields.aggregates import PGPPublicKeyAggregate
>>> my_models = MyModel.objects.annotate(PGPPublicKeyAggregate('pgp_pub_field'))
[<MyModel: MyModel object>, <MyModel: MyModel object>]
>>> my_models.filter(pgp_pub_field__decrypted='Value decrypted')
[<MyModel: MyModel object>]
>>> my_models.first().pgp_pub_field__decrypted
'Value decrypted'
Example when using a PGPSymmetricKeyField
:
>>> from pgcrypto_fields.aggregates import PGPSymmetricKeyAggregate
>>> my_models = MyModel.objects.annotate(PGPSymmetricKeyAggregate('pgp_sym_field'))
[<MyModel: MyModel object>, <MyModel: MyModel object>]
>>> my_models.filter(pgp_pub_field__decrypted='Value decrypted')
[<MyModel: MyModel object>]
>>> my_models.first().pgp_sym_field__decrypted
'Value decrypted'
Hash fields
To filter hash based values we need to compare hashes. This is achieved by using
a __hash_of
lookup.
Example:
>>> my_model = MyModel.objects.filter(digest_field__hash_of='value')
[<MyModel: MyModel object>]
>>> my_model = MyModel.objects.filter(hmac_field__hash_of='value')
[<MyModel: MyModel object>]