Skip to main content

Django Keyring

Django Integration with Keyring: A simple encryption-at-rest with key rotation support for Python.

keyring: Simple encryption-at-rest with key rotation support for Python.

N.B.: keyring is not for encrypting passwords--for that, you should use something like bcrypt. It's meant for encrypting sensitive data you will need to access in plain text (e.g. storing OAuth token from users). Passwords do not fall in that category.

The goal of this project is providing a easily integration with Django ORM.

Installation

Add package django-keyring to your requirements.txt or:

pip install django-keyring

Usage

Encryption

By default, AES-128-CBC is the algorithm used for encryption. This algorithm uses 16 bytes keys, but you're required to use a key that's double the size because half of that keys will be used to generate the HMAC. The first 16 bytes will be used as the encryption key, and the last 16 bytes will be used to generate the HMAC.

Using random data base64-encoded is the recommended way. You can easily generate keys by using the following command:

$ dd if=/dev/urandom bs=32 count=1 2>/dev/null | openssl base64 -A
qUjOJFgZsZbTICsN0TMkKqUvSgObYxnkHDsazTqE5tM=

Include the result of this command in the value section of the key description in the keyring. Half this key is used for encryption, and half for the HMAC.

Key size

The key size depends on the algorithm being used. The key size should be double the size as half of it is used for HMAC computation.

  • aes-128-cbc: 16 bytes (encryption) + 16 bytes (HMAC).

About the encrypted message

Initialization vectors (IV) should be unpredictable and unique; ideally, they will be cryptographically random. They do not have to be secret: IVs are typically just added to ciphertext messages unencrypted. It may sound contradictory that something has to be unpredictable and unique, but does not have to be secret; it is important to remember that an attacker must not be able to predict ahead of time what a given IV will be.

With that in mind, keyring uses base64(hmac(unencrypted iv + encrypted message) + unencrypted iv + encrypted message) as the final message. If you're planning to migrate from other encryption mechanisms or read encrypted values from the database without using keyring, make sure you account for this. The HMAC is 32-bytes long and the IV is 16-bytes long.

Keyring

Keys are managed through a keyring--a short python Dictionary describing your encryption keys. The keyring must be a Dictionary object mapping numeric ids of the keys to the key values. A keyring must have at least one key. For example:

# settings.py
...
KEYRINGPY_KEYS = {
    "1": "uDiMcWVNTuz//naQ88sOcN+E40CyBRGzGTT7OkoBS6M=",
    "2": "VN8UXRVMNbIh9FWEFVde0q7GUA1SGOie1+FgAKlNYHc="
}


KEYRINGPY_SALT = "salt_and_peepers"
...

The id is used to track which key encrypted which piece of data; a key with a larger id is assumed to be newer. The value is the actual bytes of the encryption key.

Key Rotation

With keyring you can have multiple encryption keys at once and key rotation is fairly straightforward: if you add a key to the keyring with a higher id than any other key, that key will automatically be used for encryption when objects are either created or updated. Any keys that are no longer in use can be safely removed from the keyring.

It's extremely important that you save the keyring id returned by encrypt(); otherwise, you may not be able to decrypt values (you can always decrypt values if you still possess all encryption keys).

If you're using keyring to encrypt database columns, it's recommended to use a separated keyring for each table you're planning to encrypt: this allows an easier key rotation in case you need (e.g. key leaking).

N.B.: Keys are hardcoded on these examples, but you shouldn't do it on your code base. You can retrieve keyring from environment variables if you're deploying to Heroku and alike, or deploy a JSON file with your configuration management software (e.g. Ansible, Puppet, Chef, etc).

Basic usage of django-keyring

# models.py
from django.db import models
from keyring.fields import KeyringField


class Message(models.Model):
    user = KeyringField(
        disgest_field=True
    )
    
    text = KeyringField()

    room = KeyringField(
        disgest_field='room_sha_digest'
    )

Use your model normaly. In database your users data are cryptographed.

# sqlite3 db.sqlite
sqlite> .mode column
sqlite> SELECT * FROM sample_app_message;
id  user    text    room    encrypted_with_key user_digest room_sha_digest
1   SEmy... 8nDD... nFRB... 2                2b248a5d... cef4523d1ec9...
...
sqlite>

Exchange data with Ruby

If you use Ruby, you may be interested in https://github.com/fnando/attr_keyring, which is able to read and write messages using the same format.

Exchange data with Node.js

If you use Node.js, you may be interested in https://github.com/fnando/keyring-node, which is able to read and write messages using the same format.

Development

After checking out the repo, run pip install -r requirements.dev.txt to install dependencies. Then, run pytest to run the tests.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/dannluciano/django-keyring. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.

License

The gem is available as open source under the terms of the MIT License.

Icon

Icon made by Icongeek26 from Flaticon is licensed by Creative Commons BY 3.0.

Acknowledgments

Inspired:

Thanks to IFPI for pay my salary!

IFPI

Metadata

Release files for django-keyring 2.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for django-keyring 2.0.0
File Size Uploaded Provenance Actions
django_keyring-2.0.0.tar.gz 7.5 kB Without provenance Details for django_keyring-2.0.0.tar.gz

Release files / django_keyring-2.0.0.tar.gz

Download URL django_keyring-2.0.0.tar.gz
Size 7.5 kB
Tags Source
SHA-256 checksum
How to use checksums
75051c2836854dfc7044c9c17c3ddf9e9bbbb804ac70f24c0e2dd7416872f758
BLAKE2b-256 checksum
How to use checksums
354c93677ff4ee7e8b3abd26b71e98981ba52589df50de5996d8d9f53174765b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.7

Security for django-keyring 2.0.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

2.0.0 This release

1 release file No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page