{"id":37064596,"url":"https://github.com/pjwerneck/turbid","last_synced_at":"2026-01-14T07:33:01.801Z","repository":{"id":251422473,"uuid":"835510201","full_name":"pjwerneck/turbid","owner":"pjwerneck","description":"Transparent ID obfuscation and encryption for database keys, with SQLAlchemy support","archived":false,"fork":false,"pushed_at":"2025-11-07T19:42:43.000Z","size":1486,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-12-14T16:57:17.926Z","etag":null,"topics":["database-ids","encryption","format-preserving-encryption","obfuscation","sqlalchemy"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pjwerneck.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-07-30T01:51:21.000Z","updated_at":"2025-11-07T19:42:47.000Z","dependencies_parsed_at":"2024-08-02T22:59:02.209Z","dependency_job_id":"89c48457-3d2f-4462-ad54-8c939877e05e","html_url":"https://github.com/pjwerneck/turbid","commit_stats":null,"previous_names":["pjwerneck/turbid"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/pjwerneck/turbid","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pjwerneck%2Fturbid","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pjwerneck%2Fturbid/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pjwerneck%2Fturbid/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pjwerneck%2Fturbid/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pjwerneck","download_url":"https://codeload.github.com/pjwerneck/turbid/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pjwerneck%2Fturbid/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28413402,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T05:26:33.345Z","status":"ssl_error","status_checked_at":"2026-01-14T05:21:57.251Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["database-ids","encryption","format-preserving-encryption","obfuscation","sqlalchemy"],"created_at":"2026-01-14T07:33:01.126Z","updated_at":"2026-01-14T07:33:01.787Z","avatar_url":"https://github.com/pjwerneck.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# TurbID\n\n[![Build Status](https://github.com/pjwerneck/turbid/actions/workflows/pytest.yml/badge.svg?branch=main)](https://github.com/pjwerneck/turbid/actions/workflows/pytest.yml)\n[![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)\n\n\n- [TurbID](#turbid)\n  - [Overview](#overview)\n  - [Installation](#installation)\n  - [SQLAlchemy Usage](#sqlalchemy-usage)\n  - [TurbIDCipher Usage](#turbidcipher-usage)\n  - [Parameters](#parameters)\n  - [Compatibility and Testing](#compatibility-and-testing)\n  - [License](#license)\n\n\n\n\n## Overview\n\nTurbID is a Python library that provides ID obfuscation and encryption for\nsequential integer primary keys. With TurbID, your database can store clear,\nsequential integer primary keys, while your public API and the rest of the world\nsees opaque and seemingly random long-form string IDs. This approach avoids the\ndatabase performance downsides of long random IDs and sidesteps the privacy and\nsecurity risks of clear integer IDs.\n\nUnlike other libraries that merely encode integers with a randomized alphabet,\nTurbID uses format-preserving encryption for additional security.\n\nTurbID currently supports SQLAlchemy with an optional extension that provides a\ncustom column type, but it can be extended to work with other ORMs or\nframeworks.\n\n\u003e [!WARNING]\n\u003e\n\u003e TurbID is not intended for protecting sensitive numeric data, such as credit card numbers or PINs. For these use cases, please use standard, secure encryption methods.\n\n## Installation\n\nTurbID is compatible with Python 3.8+ and available on PyPI. Install it with\npip, or your package manager of choice:\n\n```bash\npip install turbid\n```\n\nBut you probably want to install with the optional SQLAlchemy extension:\n\n```bash\npip install turbid[sqlalchemy]\n```\n\n## SQLAlchemy Usage\n\nWith SQLAlchemy, just replace your column's `Integer` column type with `TurbIDType`:\n\n```python\n\nclass User(Base):\n    __tablename__ = \"user\"\n\n    user_id = sa.Column(TurbIDType(key=KEY, tweak=\"user\"), primary_key=True)\n    name = sa.Column(sa.String(200))\n\n```\n\nIf you have foreign keys, do the same for the `ForeignKey` columns, but remember\nto use the same `key` and `tweak` values as the referenced column:\n\n```python\nclass Post(Base):\n    __tablename__ = \"post\"\n\n    post_id = sa.Column(TurbIDType(key=KEY, tweak=\"post\"), primary_key=True)\n    user_id = sa.Column(TurbIDType(key=KEY, tweak=\"user\"), sa.ForeignKey(\"user.user_id\"))\n    title = sa.Column(sa.String(200))\n\n```\n\nYou can use your columns as usual, in joins, filters, data retrieval, etc. In\nqueries or when updating data you can use either the original integer ID or the\nobfuscated string ID, but retrievals will always return the obfuscated string\nID.\n\n## TurbIDCipher Usage\n\nIf you don't use SQLAlchemy or you want to encrypt/decrypt IDs at another layer\nof your application, like when serializing objects for responses, you can use\nthe `TurbIDCipher` class directly.\n\n```python\n\u003e\u003e\u003e from turbid import TurbIDCipher\n\u003e\u003e\u003e import secrets\n\u003e\u003e\u003e\n\u003e\u003e\u003e key = secrets.token_hex()\n\u003e\u003e\u003e tweak = \"my_table_name\"\n\u003e\u003e\u003e obscure_id = TurbIDCipher(key, tweak=tweak)\n\u003e\u003e\u003e\n\u003e\u003e\u003e # Encrypt an integer ID\n\u003e\u003e\u003e encrypted_id = obscure_id.encrypt(12345)\n\u003e\u003e\u003e print(f\"Encrypted ID: {encrypted_id}\")\nEncrypted ID: VTxLWjgdCWGjLSIiZtCQCMvu\n\u003e\u003e\u003e\n\u003e\u003e\u003e # Decrypt the ID back to the original integer\n\u003e\u003e\u003e original_id = obscure_id.decrypt(encrypted_id)\n\u003e\u003e\u003e print(f\"Original ID: {original_id}\")\nOriginal ID: 12345\n```\n\n## Parameters\n\nThe required parameters are:\n\n- **key**:\n  - A string that will be hashed to generate the encryption key for the AES cipher.\n  - Never expose the key in version control or share it publicly.\n  - You can generate a random key suitable for this purpose using the\n    `secrets.token_hex` function.\n- **tweak**:\n  - A string that will be hashed to generate the 7-byte tweak value for FF3-1\n    encryption.\n  - This parameter is not a secret and is used to differentiate the encrypted\n    values of different instances using the same secret `key`.\n  - The value **must** be unique per table to avoid ID collisions.\n\nSQLAlchemy extension parameters:\n\n- **prefix**:\n  - An optional string that will be prepended to the encrypted ID. This is also\n    used as the `tweak` value if an explicit one isn't provided.\n  - If you don't want a prefix on your encrypted IDs, you must provide a `tweak` for each table.\n  - You can provide both a `tweak` and a `prefix`. In this case, the `prefix`\n    will be merely cosmetic and the `tweak` will be used to differentiate the\n    encrypted values.\n\nOptional parameters with tested defaults:\n\n- **length=`24`**:\n  - The length of the encrypted ID. The default is 24 characters, but the\n    minimum and maximum lengths are determined by the alphabet length and the\n    maximum value you want to encrypt.\n  - A `ValueError` will be raised if the alphabet length is incompatible with\n    the specified length.\n- **alphabet=`string.digits + string.ascii_letters`**:\n  - The alphabet used to encode the encrypted ID. The default is all 10 digits\n    and all 52 lowercase and uppercase letters.\n  - You can use a different alphabet, as long as it contains all 10 digits and\n    no repeated characters.\n  - The alphabet length must be compatible with the specified `length`.\n- **key_length=`128`**:\n  - The length of the AES key in bits. The default is 128 bits, which is the\n    recommended key length for AES encryption.\n  - Note this refers to the length of the hashed key generated internally, not\n    the length of the string you provide as the key material.\n\n## Compatibility and Testing\n\nTurbID is tested with the following values:\n\n- input ids: sampled from `0` to `2^63-1`\n- `length`: `20` to `32`, inclusive\n- `alphabet`: `string.digits + string.ascii_letters` and `\"0123456789abcdef\"`\n- `key_length`: `128`, `194`, and `256`\n\nIt probably works with other values, but you should review the limitations of\nthe FF3-1 algorithm and the [ff3](https://github.com/mysto/python-fpe) library\nand implement tests to ensure it works as expected.\n\n## License\n\nTurbID is licensed under the MIT License. See the [LICENSE](LICENSE) file for\ndetails.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpjwerneck%2Fturbid","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpjwerneck%2Fturbid","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpjwerneck%2Fturbid/lists"}