Skip to main content

TurbID

Build Status License

Overview

TurbID is a Python library that provides ID obfuscation and encryption for sequential integer primary keys. With TurbID, your database can store clear, sequential integer primary keys, while your public API and the rest of the world sees opaque and seemingly random long-form string IDs. This approach avoids the database performance downsides of long random IDs and sidesteps the privacy and security risks of clear integer IDs.

Unlike other libraries that merely encode integers with a randomized alphabet, TurbID uses format-preserving encryption for additional security.

TurbID currently supports SQLAlchemy with an optional extension that provides a custom column type, but it can be extended to work with other ORMs or frameworks.

Installation

TurbID is compatible with Python 3.8+ and available on PyPI. Install it with pip, or your package manager of choice:

pip install turbid

But you probably want to install with the optional SQLAlchemy extension:

pip install turbid[sqlalchemy]

SQLAlchemy Usage

With SQLAlchemy, just replace your column's Integer column type with TurbIDType:

class User(Base):
    __tablename__ = "user"

    user_id = sa.Column(TurbIDType(key=KEY, tweak="user"), primary_key=True)
    name = sa.Column(sa.String(200))

If you have foreign keys, do the same for the ForeignKey columns, but remember to use the same key and tweak values as the referenced column:

class Post(Base):
    __tablename__ = "post"

    post_id = sa.Column(TurbIDType(key=KEY, tweak="post"), primary_key=True)
    user_id = sa.Column(TurbIDType(key=KEY, tweak="user"), sa.ForeignKey("user.user_id"))
    title = sa.Column(sa.String(200))

You can use your columns as usual, in joins, filters, data retrieval, etc. In queries or when updating data you can use either the original integer ID or the obfuscated string ID, but retrievals will always return the obfuscated string ID.

TurbIDCipher Usage

If you don't use SQLAlchemy or you want to encrypt/decrypt IDs at another layer of your application, like when serializing objects for responses, you can use the TurbIDCipher class directly.

>>> from turbid import TurbIDCipher
>>> import secrets
>>>
>>> key = secrets.token_hex()
>>> tweak = "my_table_name"
>>> obscure_id = TurbIDCipher(key, tweak=tweak)
>>>
>>> # Encrypt an integer ID
>>> encrypted_id = obscure_id.encrypt(12345)
>>> print(f"Encrypted ID: {encrypted_id}")
Encrypted ID: VTxLWjgdCWGjLSIiZtCQCMvu
>>>
>>> # Decrypt the ID back to the original integer
>>> original_id = obscure_id.decrypt(encrypted_id)
>>> print(f"Original ID: {original_id}")
Original ID: 12345

Parameters

The required parameters are:

  • key:
    • A string that will be hashed to generate the encryption key for the AES cipher.
    • Never expose the key in version control or share it publicly.
    • You can generate a random key suitable for this purpose using the secrets.token_hex function.
  • tweak:
    • A string that will be hashed to generate the 7-byte tweak value for FF3-1 encryption.
    • This parameter is not a secret and is used to differentiate the encrypted values of different instances using the same secret key.
    • The value must be unique per table to avoid ID collisions.

SQLAlchemy extension parameters:

  • prefix:
    • An optional string that will be prepended to the encrypted ID. This is also used as the tweak value if an explicit one isn't provided.
    • If you don't want a prefix on your encrypted IDs, you must provide a tweak for each table.
    • You can provide both a tweak and a prefix. In this case, the prefix will be merely cosmetic and the tweak will be used to differentiate the encrypted values.

Optional parameters with tested defaults:

  • length=24:
    • The length of the encrypted ID. The default is 24 characters, but the minimum and maximum lengths are determined by the alphabet length and the maximum value you want to encrypt.
    • A ValueError will be raised if the alphabet length is incompatible with the specified length.
  • alphabet=string.digits + string.ascii_letters:
    • The alphabet used to encode the encrypted ID. The default is all 10 digits and all 52 lowercase and uppercase letters.
    • You can use a different alphabet, as long as it contains all 10 digits and no repeated characters.
    • The alphabet length must be compatible with the specified length.
  • key_length=128:
    • The length of the AES key in bits. The default is 128 bits, which is the recommended key length for AES encryption.
    • Note this refers to the length of the hashed key generated internally, not the length of the string you provide as the key material.

Compatibility and Testing

TurbID is tested with the following values:

  • input ids: sampled from 0 to 2^63-1
  • length: 20 to 32, inclusive
  • alphabet: string.digits + string.ascii_letters and "0123456789abcdef"
  • key_length: 128, 194, and 256

It probably works with other values, but you should review the limitations of the FF3-1 algorithm and the ff3 library and implement tests to ensure it works as expected.

License

TurbID is licensed under the MIT License. See the LICENSE file for details.

Metadata

Release files for turbid 0.2.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 turbid 0.2.2
File Size Uploaded
turbid-0.2.2.tar.gz 48.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for turbid 0.2.2
File Interpreter ABI Platform
turbid-0.2.2-py3-none-any.whl Python 3 none any Details

Total release size: 56.4 kB

Release files / turbid-0.2.2.tar.gz

Download URL turbid-0.2.2.tar.gz
Size 48.9 kB
Tags Source
SHA-256 checksum
How to use checksums
734dfafd19e3ac5818a10ce4afa8aba238e09a8f8b37415422a1f1bd928e625a
BLAKE2b-256 checksum
How to use checksums
edfba332a458b3e9c3cc8b3c18ec9673f33994af6ba301963a4101992f8093df
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.7

Release files / turbid-0.2.2-py3-none-any.whl

Download URL turbid-0.2.2-py3-none-any.whl
Size 7.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
74eb08216e97d72c5e1b032963b443331b4dc37c312c26d3e5a96e6312074c1b
BLAKE2b-256 checksum
How to use checksums
5706d3bb1743830597d1676f6e430bec377cf8d3b964bc33376b56c639a51174
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.7

Release history Release notifications | RSS feed

This release

0.2.2 This release

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.1

2 release files

0.1.0

2 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