Tink-based encrypted model fields for Django
Project description
Django Tink Fields
Django Tink Fields is a simple, production-ready way to encrypt Django model fields using the Google Tink cryptographic library. It offers drop-in encrypted field types for Django models, so you can protect sensitive data with minimal code changes.
Keywords: Django field encryption, encrypted model fields, Google Tink, AEAD, deterministic encryption.
✨ Features
- 🔐 Strong Encryption: Uses Google Tink for state-of-the-art cryptographic operations
- 🛡️ AEAD Security: Provides both confidentiality and integrity through Authenticated Encryption with Associated Data
- 🔧 Easy Integration: Drop-in replacement for Django's standard field types
- ⚡ High Performance: Optimized with caching and efficient key management
- 🔑 Flexible Key Management: Support for both cleartext and encrypted keysets
- ☁️ Cloud Integration: Works with AWS KMS, GCP KMS, and other key management systems
- 📊 Comprehensive Testing: 97%+ test coverage with modern Python practices
- 🐍 Modern Python: Supports Python 3.12+ with full type hints
🚀 Quick Start
Installation
pip install django-tink-fields
Basic Configuration
Add to your settings.py:
TINK_FIELDS_CONFIG = {
"default": {
"cleartext": True,
"path": "/path/to/your/keyset.json",
}
}
Create a Keyset
Generate a test keyset using tinkey:
tinkey create-keyset \
--out-format json \
--out keyset.json \
--key-template AES128_GCM
Use in Your Models
from django.db import models
from tink_fields import EncryptedCharField, EncryptedTextField
class UserProfile(models.Model):
name = EncryptedCharField(max_length=100)
bio = EncryptedTextField()
email = EncryptedEmailField()
age = EncryptedIntegerField()
created_at = EncryptedDateTimeField()
📖 Documentation
Supported Field Types
| Field Type | Django Equivalent | Description |
|---|---|---|
EncryptedCharField |
CharField |
Encrypted character field |
EncryptedTextField |
TextField |
Encrypted text field |
EncryptedEmailField |
EmailField |
Encrypted email field |
EncryptedBooleanField |
BooleanField |
Encrypted boolean field |
EncryptedIntegerField |
IntegerField |
Encrypted integer field |
EncryptedPositiveIntegerField |
PositiveIntegerField |
Encrypted positive integer field |
EncryptedFloatField |
FloatField |
Encrypted float field |
EncryptedDecimalField |
DecimalField |
Encrypted decimal field |
EncryptedUUIDField |
UUIDField |
Encrypted UUID field |
EncryptedJSONField |
JSONField |
Encrypted JSON field |
EncryptedURLField |
URLField |
Encrypted URL field |
EncryptedSlugField |
SlugField |
Encrypted slug field |
EncryptedDateField |
DateField |
Encrypted date field |
EncryptedDateTimeField |
DateTimeField |
Encrypted datetime field |
EncryptedBinaryField |
BinaryField |
Encrypted binary field |
Deterministic Field Types
| Field Type | Django Equivalent | Description |
|---|---|---|
DeterministicEncryptedTextField |
TextField |
Deterministic encrypted text field |
DeterministicEncryptedCharField |
CharField |
Deterministic encrypted character field |
DeterministicEncryptedEmailField |
EmailField |
Deterministic encrypted email field |
DeterministicEncryptedIntegerField |
IntegerField |
Deterministic encrypted integer field |
DeterministicEncryptedUUIDField |
UUIDField |
Deterministic encrypted UUID field |
DeterministicEncryptedBooleanField |
BooleanField |
Deterministic encrypted boolean field |
DeterministicEncryptedDateField |
DateField |
Deterministic encrypted date field |
DeterministicEncryptedDateTimeField |
DateTimeField |
Deterministic encrypted datetime field |
Configuration Options
Cleartext Keysets (Development/Testing)
TINK_FIELDS_CONFIG = {
"default": {
"cleartext": True,
"path": "/path/to/cleartext_keyset.json",
}
}
Encrypted Keysets (Production)
from tink.integration import gcpkms
from tink import aead
# Register AEAD primitives
aead.register()
# Configure GCP KMS
TINK_MASTER_KEY_URI = "gcp-kms://projects/your-project/locations/global/keyRings/your-keyring/cryptoKeys/your-key"
gcp_client = gcpkms.GcpKmsClient(TINK_MASTER_KEY_URI, "")
gcp_aead = gcp_client.get_aead(TINK_MASTER_KEY_URI)
TINK_FIELDS_CONFIG = {
"default": {
"cleartext": False,
"path": "/path/to/encrypted_keyset.json",
"master_key_aead": gcp_aead,
}
}
Multiple Keysets
TINK_FIELDS_CONFIG = {
"default": {
"cleartext": True,
"path": "/path/to/default_keyset.json",
},
"sensitive": {
"cleartext": False,
"path": "/path/to/sensitive_keyset.json",
"master_key_aead": sensitive_aead,
}
}
Advanced Usage
Custom Keyset per Field
class SensitiveData(models.Model):
# Uses the "sensitive" keyset
secret = EncryptedCharField(max_length=100, keyset="sensitive")
# Uses the default keyset
public_data = EncryptedCharField(max_length=100)
Associated Authenticated Data (AAD)
Add additional context to your encryption for enhanced security:
def get_aad_for_field(field):
"""Generate AAD based on field and model context."""
return f"model_{field.model._meta.label}_{field.name}".encode()
class UserData(models.Model):
# Each field gets unique AAD
ssn = EncryptedCharField(
max_length=11,
aad_callback=get_aad_for_field
)
Field Validation
Encrypted fields support all standard Django field validators:
class ValidatedModel(models.Model):
email = EncryptedEmailField(unique=True)
age = EncryptedIntegerField(validators=[MinValueValidator(18)])
name = EncryptedCharField(max_length=50, blank=False)
Key Management
Creating Keysets with tinkey
Cleartext keyset (development):
tinkey create-keyset \
--out-format json \
--out dev_keyset.json \
--key-template AES128_GCM
Encrypted keyset with GCP KMS:
tinkey create-keyset \
--out-format json \
--out prod_keyset.json \
--key-template AES256_GCM \
--master-key-uri=gcp-kms://projects/my-project/locations/global/keyRings/my-keyring/cryptoKeys/my-key
Encrypted keyset with AWS KMS:
tinkey create-keyset \
--out-format json \
--out prod_keyset.json \
--key-template AES256_GCM \
--master-key-uri=aws-kms://arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012
🔒 Security Considerations
Best Practices
- Key Management: Use encrypted keysets in production with proper key management systems
- Key Rotation: Implement regular key rotation strategies
- Access Control: Restrict access to keyset files and master keys
- AAD Usage: Use AAD to bind encryption to specific contexts
- Field Selection: Only encrypt truly sensitive data to maintain performance
Limitations
- No Database Queries: Encrypted fields cannot be used in database queries (except
isnull) - No Indexing: Encrypted fields cannot be indexed or used as primary keys
- Performance: Encryption/decryption adds computational overhead
- Key Management: Requires careful key management and rotation
🧪 Testing
The package includes comprehensive tests with 97%+ coverage:
# Run tests
pytest
# Run with coverage
pytest --cov=tink_fields --cov-report=html
# Run specific test categories
pytest tink_fields/test/test_fields.py # Basic functionality
pytest tink_fields/test/test_coverage.py # Edge cases
Integration Test Harness
This repo ships a minimal Django project under example_project/ that exercises
real model usage and verifies ciphertext at rest, tamper detection, deterministic
lookups, and AAD behavior:
pytest -c example_project/pytest.ini example_project/example_app/tests
🛠️ Development
Setup Development Environment
# Clone the repository
git clone https://github.com/script3r/django-tink-fields.git
cd django-tink-fields
# Create virtual environment
python -m venv .venv
source .venv/bin/activate # On Windows: .venv\Scripts\activate
# Install development dependencies
pip install -r requirements-dev.txt
# Install package in development mode
pip install -e .
Code Quality
The project uses modern Python tooling:
# Format code
black tink_fields/
isort tink_fields/
# Lint code
flake8 tink_fields/
# Type checking
mypy tink_fields/
# Run all quality checks
tox
📊 Performance
Benchmarks
| Operation | Time (μs) | Memory (KB) |
|---|---|---|
| Encrypt 1KB | ~50 | ~2 |
| Decrypt 1KB | ~45 | ~2 |
| Field Creation | ~5 | ~1 |
Benchmarks on Python 3.13, Django 5.2, with AES128_GCM
Optimization Tips
- Use appropriate field types -
CharFieldfor short text,TextFieldfor long content - Cache keysets - Keysets are automatically cached for performance
- Minimize AAD complexity - Keep AAD callbacks simple and fast
- Batch operations - Process multiple records together when possible
🤝 Contributing
We welcome contributions! Please see our Contributing Guide for details.
Development Workflow
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests for new functionality
- Ensure all tests pass
- Submit a pull request
📝 Changelog
v0.3.2 (Latest)
- ✨ Modernized codebase with Python 3.10+ support
- 🔧 Updated dependencies to latest versions
- 📊 Improved test coverage to 97%+
- 🎨 Applied modern Python formatting and linting
- 📚 Enhanced documentation and examples
v0.2.0
- 🐛 Fixed compatibility issues
- 📦 Updated package structure
📄 License
This project is licensed under the BSD License - see the LICENSE.txt file for details.
🙏 Acknowledgments
- Google Tink - The cryptographic library powering this package
- Django Fernet Fields - Original inspiration for this project
- Django Community - For the amazing framework
📞 Support
Made with ❤️ for the Django community
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file django_tink_fields-0.3.2.tar.gz.
File metadata
- Download URL: django_tink_fields-0.3.2.tar.gz
- Upload date:
- Size: 17.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7915dff5960e5469ea546f68b3f57de13eccc3f36c4c03f3d583443da0ca9faf
|
|
| MD5 |
7245a834e1fbff0d268421b69dea6434
|
|
| BLAKE2b-256 |
8eadcfaecb3fd6608e56117e258337d0c4f64074efc215d07b4cea9478352d81
|
File details
Details for the file django_tink_fields-0.3.2-py3-none-any.whl.
File metadata
- Download URL: django_tink_fields-0.3.2-py3-none-any.whl
- Upload date:
- Size: 19.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6cce31cfca2439e9835201eb065a19bd5a3a31b207ee3ef42784bbbab2f0e07f
|
|
| MD5 |
c8dae299662726fe833b1260e60e984e
|
|
| BLAKE2b-256 |
89c7c57231b3b9575c0b8a38961d1811326b32221808d30b52294b36a6a8b766
|