Skip to main content

Tink-based encrypted model fields for Django

Project description

Django Tink Fields

PyPI version Python Support Django Support License Code style: black Tests

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

  1. Key Management: Use encrypted keysets in production with proper key management systems
  2. Key Rotation: Implement regular key rotation strategies
  3. Access Control: Restrict access to keyset files and master keys
  4. AAD Usage: Use AAD to bind encryption to specific contexts
  5. 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

  1. Use appropriate field types - CharField for short text, TextField for long content
  2. Cache keysets - Keysets are automatically cached for performance
  3. Minimize AAD complexity - Keep AAD callbacks simple and fast
  4. Batch operations - Process multiple records together when possible

🤝 Contributing

We welcome contributions! Please see our Contributing Guide for details.

Development Workflow

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Add tests for new functionality
  5. Ensure all tests pass
  6. 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

📞 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

django_tink_fields-0.3.2.tar.gz (17.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

django_tink_fields-0.3.2-py3-none-any.whl (19.6 kB view details)

Uploaded Python 3

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

Hashes for django_tink_fields-0.3.2.tar.gz
Algorithm Hash digest
SHA256 7915dff5960e5469ea546f68b3f57de13eccc3f36c4c03f3d583443da0ca9faf
MD5 7245a834e1fbff0d268421b69dea6434
BLAKE2b-256 8eadcfaecb3fd6608e56117e258337d0c4f64074efc215d07b4cea9478352d81

See more details on using hashes here.

File details

Details for the file django_tink_fields-0.3.2-py3-none-any.whl.

File metadata

File hashes

Hashes for django_tink_fields-0.3.2-py3-none-any.whl
Algorithm Hash digest
SHA256 6cce31cfca2439e9835201eb065a19bd5a3a31b207ee3ef42784bbbab2f0e07f
MD5 c8dae299662726fe833b1260e60e984e
BLAKE2b-256 89c7c57231b3b9575c0b8a38961d1811326b32221808d30b52294b36a6a8b766

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page