Skip to main content

Note: Encrypted IDs generated by version 0.3.0 onwards will be different from those generated by version 0.2.0. But versions 0.3.x will decrypt the IDs generated by the version 0.2.0.

Note: Version 0.2.0 is a breaking change from versions 0.1.x. If you’ve been using ekey in permalinks, then it is recommended for you to not upgrade to 0.2.x.


Consider this example model:

from django.db import models

from encrypted_id.models import EncryptedIDModel


class Foo(EncryptedIDModel):
    text = models.TextField()

By inheriting from EncryptedIDModel, you get .ekey as a property on your model instances. This is how they will look like:

In [1]: from tapp.models import Foo

In [2]: f = Foo.objects.create(text="asd")

In [3]: f.id
Out[3]: 1

In [4]: f.ekey
Out[4]: 'bxuZXwM4NdgGauVWR-ueUA'
You can do reverse lookup:

In [5]: from encrypted_id import decode

In [6]: decode(f.ekey)
Out[6]: 1

If you can not inherit from the helper base class, no problem, you can just use the ekey() function from encrypted_id package:

In [7]: from encrypted_id import ekey

In [8]: from django.contrib.auth.models import User

In [9]: ekey(User.objects.get(pk=1))
Out[9]: 'bxuZXwM4NdgGauVWR-ueUA'

To do the reverse lookup, you have two helpers available. First is provided by EncryptedIDManager, which is used by default if you inherit from EncryptedIDModel, and have not overwritten the .objects:

In [10]: Foo.objects.get_by_ekey(f.ekey)
Out[10]: <Foo: Foo object>

But sometimes you will prefer the form:

In [11]: Foo.objects.get_by_ekey_or_404(f.ekey)
Out[11]: <Foo: Foo object>

Which works the same, but instead of raising DoesNotExist, it raises Http404, so it can be used in views.

You your manager is not inheriting from EncryptedIDManager, you can use:

In [12]: e = ekey(User.objects.first())

In [13]: e
Out[13]: 'bxuZXwM4NdgGauVWR-ueUA'

In [14]: get_object_or_404(User, e)
Out[14]: <User: amitu>

encrypted_id.get_object_or_404, as well as EncryptedIDManager.get_by_ekey and EncryptedIDManager.get_by_ekey_or_404 take extra keyword argument, that can be used to filter if you want.

If you are curious, the regex used to match the generated ids is:

"[0-9a-zA-Z-_]+"

If you are using smarturls, you can use URL pattern like:

"/<ekey:foo>/"

I recommend this usage of encrypted-id over UUID, as UUIDs have significant issues that should be considered (tldr: they take more space on disk and RAM, and have inferior indexing than integer ids), and if your goal is simply to make URLs non guessable, encrypted id is a superior approach.

If you are curious about the encryption used: I am using AES, from pycrypto library, and am using SECRET_KEY for password (SECRET_KEY[:32]) and IV (first 16 characters of hash of SECRET_KEY and a sub_key), in the AES.CBC mode. The sub_key is taken from the model’s Meta attribute ek_key, or simply db_table if ek_key is not set.

In general it is recommended not to have static IV, but CBC offsets some of the problems with having static IV. What is the the issue with static IV you ask: if plain text “abc” and “abe” are encrypted, the first two bytes would be same. Now this does not present a serious problem for us, as the plain text that I am encrypting uses CRC32 in the beginning of payload, so even if you have ids, 1, 11, an attacker can not say they both start with same first character.

The library also supports the scenario that you have to cycle SECRET_KEY due to some reason, so URLs encrypted with older SECRET_KEY can still be decoded after you have changed it (as long as you store old versions in SECRET_KEYS setting). In order to decrypt the library tries each secret key, and compares the CRC32 of data to know for sure (as sure as things get in such things), that we have decrypted properly.

Do feel free to raise an issue here, if you face any issues, I would be happy to help. The library supports both python 2.7 and 3.5, as well as it all versions of django that django team supports.

Release files for django-encrypted-id 0.3.2

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-encrypted-id 0.3.2
File Size Uploaded
django-encrypted-id-0.3.2.tar.bz2 6.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for django-encrypted-id 0.3.2
File Interpreter ABI Platform
django_encrypted_id-0.3.2-py2.py3-none-any.whl Python 3, Python 2 none any Details

Total release size:11.8 kB

Release files / django-encrypted-id-0.3.2.tar.bz2

Download URL django-encrypted-id-0.3.2.tar.bz2
Size 6.1 kB
Tags Source
SHA-256 checksum
How to use checksums
11aebdf3867f79100fba739d161a72d78b30da204c1b1ccc2288eb4a0f854437
BLAKE2b-256 checksum
How to use checksums
d553e50ad82b8db8d5836ca387cd0c4646f943b4e8a1b5b37205573fe0594a57
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via Python-urllib/3.6

Release files / django_encrypted_id-0.3.2-py2.py3-none-any.whl

Download URL django_encrypted_id-0.3.2-py2.py3-none-any.whl
Size 5.7 kB
Tags Python 2 Python 3
SHA-256 checksum
How to use checksums
9ec99c9f123e63a939f68d4b30dd6a33e07eceb81f442b20c940b60c62f3e976
BLAKE2b-256 checksum
How to use checksums
6f1b367adb7ad3796f7b04be87d8b9aa1b54e8f03c943d248e3f17d967361466
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via Python-urllib/3.6

Release history Release notifications | RSS feed

This release

0.3.2 This release

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.2.0

3 release files

0.1.3

3 release files

0.1.2

3 release files

0.1.1

3 release files

0.1.0

3 release files

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