# Obfuskey
[![pypi][pypi-v]][pypi] [![license][pypi-l]][pypi] [![coverage][codecov-i]][codecov] [![build][workflow-i]][workflow]
Taking lessons learned from supporting [BaseHash][basehash] over the years, it was
obvious that it could be optimized, thus Obfuskey was born. BaseHash had some
misconceptions, mainly that consumers thought it was a crypto library due to the word
"hash". Since hashes are generally irreversible, this new project was born to clearly
convey what it is used for.
Obfuskey was a way to both modernize and simplify [BaseHash][basehash], while keeping
the same functionality. Obfuskey generates obfuscated keys out of integer values that
have a uniform length using a specified alphabet.
**With the release of v0.2.0, Obfuskey now requires Python 3.9 and up.** This version introduces
the `Obfusbit` class for packing multiple values.
**If you need to use Python 3.6, 3.7, or 3.8, you can still use `Obfuskey`'s original
functionality by pinning to version `0.1.3` in your project dependencies.**
When generating keys, the combination of key length and alphabet used will determine the
maximum value it can obfuscate, `len(alphabet) ** key_length - 1`.
## Usage - Obfuskey
To use Obfuskey, you can use one of the available alphabets, or provide your own. You
can also provide your own multiplier, or leave it blank to use the built-in prime
generator.
```python
from obfuskey import Obfuskey, alphabets
obfuscator = Obfuskey(alphabets.BASE36, key_length=8)
key = obfuscator.get_key(1234567890) # Example: FWQ8H52I
value = obfuscator.get_value('FWQ8H52I') # Example: 1234567890
```
To provide a custom multiplier, or if you want to reuse a prime generated from a
previous instance, you can pass it in with `multiplier=`. This value has to be an odd
integer.
```python
from obfuskey import Obfuskey, alphabets
# Using default multiplier (randomly generated prime)
obfuscator_default = Obfuskey(alphabets.BASE62)
key_default = obfuscator_default.get_key(12345) # Example: d2Aasl
# Using a specific custom multiplier
obfuscator_custom = Obfuskey(alphabets.BASE62, multiplier=46485)
key_custom = obfuscator_custom.get_key(12345) # Example: 0cpqVJ
```
If you wish to generate a prime not within the golden prime set, you can overwrite the
multiplier with `set_prime_multiplier`. This method takes an `int` or `float` seed
to generate a new prime.
```python
from obfuskey import Obfuskey, alphabets
obfuscator = Obfuskey(alphabets.BASE62, key_length=2)
key_before_override = obfuscator.get_key(123) # Example: 3f
# Using a float seed to generate a different prime multiplier
obfuscator.set_prime_multiplier(1.75)
key_after_override = obfuscator.get_key(123) # Example: RP
```
There are predefined [alphabets][alphabets] that you can use, but Obfuskey allows you to
specify a custom one during instantiation.
```python
from obfuskey import Obfuskey
obfuscator = Obfuskey('012345abcdef')
key = obfuscator.get_key(123) # Example: 022d43
```
## Usage - Obfusbit (v0.2.0+)
Obfusbit allows you to pack multiple integer values into a single obfuscated key string.
You define a schema where each field has a name and a specified number of bits. Obfusbit
will combine these values into a single large integer, which can then be obfuscated by
an `Obfuskey` instance. This is ideal for compact identifiers that encode multiple pieces
of information.
### Basic Packing and Unpacking (Integer Output)
Define your schema and pack/unpack integers. This is useful if you want to store the
packed integer in a database without obfuscation, or process it numerically.
```python
from obfuskey import Obfuskey, Obfusbit
# Define your data schema with field names and bit lengths
product_schema = [
{"name": "category_id", "bits": 4}, # Max value 15
{"name": "item_id", "bits": 20}, # Max value ~1 million
{"name": "status", "bits": 3}, # Max value 7 (e.g., in_stock=0, low=1, out=2)
]
# Initialize Obfusbit without an Obfuskey instance if you only need the raw integer
# (e.g., for storage in a database)
obb_int_packer = Obfusbit(product_schema)
# Values to pack (must be within the bit limits defined in the schema)
values_to_pack = {
"category_id": 5,
"item_id": 123456,
"status": 1, # Low stock
}
# Pack into a single integer (obfuscate=False for raw integer output)
packed_id_int = obb_int_packer.pack(values_to_pack, obfuscate=False)
print(f"Packed Integer ID: {packed_id_int}") # Example: 809492485
# Unpack back to original values
unpacked_values = obb_int_packer.unpack(packed_id_int, obfuscated=False)
print(f"Unpacked values: {unpacked_values}") # Example: {'status': 1, 'item_id': 123456, 'category_id': 5}
```
### Determining Alphabet and Key Length for Obfusbit
When using `Obfusbit` with an `Obfuskey` instance for obfuscation, it's crucial that the
`Obfuskey` is configured to handle the maximum possible integer value that your schema
can produce.
1. **Calculate Total Bits Required by Schema:** Sum the `bits` for all fields in your
`Obfusbit` schema. This sum represents the total number of bits needed to represent
the packed integer.
- Example: `[{"bits": 4}, {"bits": 20}, {"bits": 3}]` = `4 + 20 + 3 = 27` total bits.
2. **Calculate Maximum Value Represented by Schema:** The maximum integer value your
schema can pack is `(2 ** total_bits) - 1`.
- Example: For 27 total bits, the maximum value is `(2 ** 27) - 1 = 134,217,727`.
3. **Determine `Obfuskey` Capacity:** The maximum value an `Obfuskey` instance can obfuscate
is determined by its alphabet size and key length: `(len(alphabet) ** key_length) - 1`.
- Example: Using `BASE58` (alphabet size 58) with `key_length=5` gives
`(58 ** 5) - 1 = 656,356,799`.
**The `Obfuskey`'s maximum capacity MUST be greater than or equal to the maximum value your
schema can produce.** If it's smaller, `Obfusbit` will raise a `MaximumValueError` during
initialization.
**Tips for Choosing:**
- **`total_bits`:** This is fixed by your schema requirements.
- **`alphabet`:**
- **Smaller alphabets** (e.g., `BASE16`, `BASE36`) result in longer keys for the same
`total_bits`. They are often easier to type or read.
- **Larger alphabets** (e.g., `BASE58`, `BASE62`, `BASE64_URL_SAFE`, `BASE94`) result in shorter,
more compact keys for the same `total_bits`. They might be less human-friendly but more
efficient.
- **`key_length`:** This is derived from your `total_bits` and chosen `alphabet`. You need
to find the smallest `key_length` such that `(len(alphabet) ** key_length) - 1` covers
your `(2 ** total_bits) - 1`.
**To determine the minimum `key_length` required:**
Use the following Python snippet. Just replace `YOUR_TOTAL_BITS` with the sum of bits from your schema and `YOUR_ALPHABET` with the desired alphabet string (e.g., `alphabets.BASE58`).
```python
import math
from obfuskey import alphabets # Assuming alphabets is directly importable
YOUR_TOTAL_BITS = 144 # Example: Sum of bits from your Obfusbit schema
YOUR_ALPHABET = alphabets.BASE58 # Example: Choose your desired alphabet (e.g., alphabets.BASE62, alphabets.BASE64_URL_SAFE)
# Calculate the number of states your schema needs to represent (2^N possibilities)
required_states = 2 ** YOUR_TOTAL_BITS
# Determine the alphabet's length
alphabet_length = len(YOUR_ALPHABET)
# Calculate the minimum key length using logarithms
# This formula is derived from: alphabet_length ** key_length >= 2 ** total_bits
# Which simplifies to: key_length >= total_bits / log2(alphabet_length)
if alphabet_length <= 1:
raise ValueError("Alphabet length must be greater than 1.")
# math.log2 gives log base 2, suitable for this calculation
minimum_key_length = math.ceil(YOUR_TOTAL_BITS / math.log2(alphabet_length))
print(f"For {YOUR_TOTAL_BITS} total bits and alphabet (length {alphabet_length}):")
print(f"Minimum required key_length: {minimum_key_length}")
# Optional: Verify the capacity with this calculated key_length
max_obfuskey_value = (alphabet_length ** minimum_key_length) - 1
max_schema_value = required_states - 1
print(f"Maximum value Obfuskey can represent with this key_length: {max_obfuskey_value}")
print(f"Maximum value schema can produce: {max_schema_value}")
if max_obfuskey_value >= max_schema_value:
print("Obfuskey capacity is sufficient.")
else:
# This case should ideally not be reached if minimum_key_length is correctly calculated
print("WARNING: Obfuskey capacity is NOT sufficient. This indicates an issue with the calculation.")
```
### Packing and Unpacking with Obfuscation (String Output)
To get a human-readable, fixed-length obfuscated key string, you associate an `Obfuskey`
instance with `Obfusbit`. Ensure the `Obfuskey`'s `maximum_value` is large enough to
cover the total bits in your schema, as checked during `Obfusbit` initialization.
```python
import datetime
import uuid
from obfuskey import Obfuskey, Obfusbit, alphabets
# Define a more complex schema, including a UUID
# UUIDs are 128-bit numbers.
complex_id_schema = [
{"name": "entity_uuid", "bits": 128},
{"name": "version", "bits": 4}, # e.g., schema version (0-15)
{"name": "creation_day", "bits": 9}, # Day of the year (1-366, needs 9 bits for 0-511)
{"name": "environment_id", "bits": 2}, # e.g., 0=Dev, 1=Staging, 2=Prod (0-3)
{"name": "is_active", "bits": 1}, # Boolean flag (0 or 1)
]
# Calculate required bits for this schema: 128 + 4 + 9 + 2 + 1 = 144 bits.
# For BASE58 (alphabet length 58), you need `math.ceil(144 / math.log2(58))` which is 25.
# Using key_length=26 provides a bit of buffer.
obfuscator_large = Obfuskey(alphabets.BASE58, key_length=26)
# Initialize Obfusbit with the schema and the Obfuskey instance
# This will raise a MaximumValueError if obfuscator_large is too small for the schema.
obb_obfuscated_packer = Obfusbit(complex_id_schema, obfuskey=obfuscator_large)
# Prepare values for packing
current_uuid = uuid.uuid4()
current_day_of_year = datetime.datetime.now().timetuple().tm_yday
values_to_pack_complex = {
"entity_uuid": current_uuid.int, # Convert UUID object to its 128-bit integer
"version": 1,
"creation_day": current_day_of_year,
"environment_id": 2, # Production
"is_active": 1, # True
}
# Pack and obfuscate into a string
obfuscated_code = obb_obfuscated_packer.pack(values_to_pack_complex, obfuscate=True)
print(f"Obfuscated Complex ID: {obfuscated_code}") # Example: T6ATbW8QpS3qBVACGganMCi4rU... (length 26)
# Unpack and de-obfuscate
unpacked_complex_values = obb_obfuscated_packer.unpack(obfuscated_code, obfuscated=True)
print(f"Unpacked Complex Values: {unpacked_complex_values}")
# Example: {'entity_uuid': 230751111624891151670977227092809615560, 'version': 1, 'creation_day': 208, 'environment_id': 2, 'is_active': 1}
# Convert the UUID integer back to a UUID object for verification
reconstructed_uuid = uuid.UUID(int=unpacked_complex_values["entity_uuid"])
print(f"Reconstructed UUID: {reconstructed_uuid}")
print(f"Original UUID matches reconstructed: {reconstructed_uuid == current_uuid}")
# This will raise a BitOverflowError if any single value exceeds its allocated bits in the schema.
```
## Large Integer Support (`gmpy2`)
If you need to obfuscate or pack integers that are larger than 512-bit, you will need to
install the optional [gmpy2][gmpy2] dependency. This library provides highly optimized
arbitrary-precision arithmetic.
```code
$ pip install gmpy2
# OR, if using poetry with extras:
$ poetry install --extras gmpy2
```
[basehash]: https://github.com/bnlucas/python-basehash
[alphabets]: https://github.com/bnlucas/obfuskey/blob/main/obfuskey/alphabets.py
[gmpy2]: https://pypi.org/project/gmpy2/
[pypi]: https://pypi.python.org/pypi/Obfuskey
[pypi-v]: https://img.shields.io/pypi/v/Obfuskey.svg
[pypi-l]: https://img.shields.io/pypi/l/Obfuskey.svg
[codecov]: https://codecov.io/gh/bnlucas/Obfuskey
[codecov-i]: https://img.shields.io/codecov/c/github/bnlucas/Obfuskey/master.svg
[workflow]: https://github.com/bnlucas/Obfuskey/actions?query=branch%3Amain+
[workflow-i]: https://img.shields.io/github/workflow/status/bnlucas/Obfuskey/CI/main
Raw data
{
"_id": null,
"home_page": "https://github.com/bnlucas/obfuskey",
"name": "obfuskey",
"maintainer": null,
"docs_url": null,
"requires_python": "<3.13,>=3.9",
"maintainer_email": null,
"keywords": "obfuskey, obfuscate, basehash, key",
"author": "Nathan Lucas",
"author_email": "nathan@bnlucas.com",
"download_url": "https://files.pythonhosted.org/packages/00/a6/0040f2697d22d3f948dbd7d35b7a3a856e0388c2e9a156a389afde56a1d4/obfuskey-0.2.0.tar.gz",
"platform": null,
"description": "# Obfuskey\n\n[![pypi][pypi-v]][pypi] [![license][pypi-l]][pypi] [![coverage][codecov-i]][codecov] [![build][workflow-i]][workflow]\n\nTaking lessons learned from supporting [BaseHash][basehash] over the years, it was\nobvious that it could be optimized, thus Obfuskey was born. BaseHash had some\nmisconceptions, mainly that consumers thought it was a crypto library due to the word\n\"hash\". Since hashes are generally irreversible, this new project was born to clearly\nconvey what it is used for.\n\nObfuskey was a way to both modernize and simplify [BaseHash][basehash], while keeping\nthe same functionality. Obfuskey generates obfuscated keys out of integer values that\nhave a uniform length using a specified alphabet.\n\n**With the release of v0.2.0, Obfuskey now requires Python 3.9 and up.** This version introduces\nthe `Obfusbit` class for packing multiple values.\n**If you need to use Python 3.6, 3.7, or 3.8, you can still use `Obfuskey`'s original\nfunctionality by pinning to version `0.1.3` in your project dependencies.**\n\nWhen generating keys, the combination of key length and alphabet used will determine the\nmaximum value it can obfuscate, `len(alphabet) ** key_length - 1`.\n\n## Usage - Obfuskey\n\nTo use Obfuskey, you can use one of the available alphabets, or provide your own. You\ncan also provide your own multiplier, or leave it blank to use the built-in prime\ngenerator.\n\n```python\nfrom obfuskey import Obfuskey, alphabets\n\nobfuscator = Obfuskey(alphabets.BASE36, key_length=8)\n\nkey = obfuscator.get_key(1234567890) # Example: FWQ8H52I\nvalue = obfuscator.get_value('FWQ8H52I') # Example: 1234567890\n```\n\nTo provide a custom multiplier, or if you want to reuse a prime generated from a\nprevious instance, you can pass it in with `multiplier=`. This value has to be an odd\ninteger.\n\n```python\nfrom obfuskey import Obfuskey, alphabets\n\n# Using default multiplier (randomly generated prime)\nobfuscator_default = Obfuskey(alphabets.BASE62)\nkey_default = obfuscator_default.get_key(12345) # Example: d2Aasl\n\n# Using a specific custom multiplier\nobfuscator_custom = Obfuskey(alphabets.BASE62, multiplier=46485)\nkey_custom = obfuscator_custom.get_key(12345) # Example: 0cpqVJ\n```\n\nIf you wish to generate a prime not within the golden prime set, you can overwrite the\nmultiplier with `set_prime_multiplier`. This method takes an `int` or `float` seed\nto generate a new prime.\n\n```python\nfrom obfuskey import Obfuskey, alphabets\n\nobfuscator = Obfuskey(alphabets.BASE62, key_length=2)\nkey_before_override = obfuscator.get_key(123) # Example: 3f\n\n# Using a float seed to generate a different prime multiplier\nobfuscator.set_prime_multiplier(1.75)\nkey_after_override = obfuscator.get_key(123) # Example: RP\n```\n\nThere are predefined [alphabets][alphabets] that you can use, but Obfuskey allows you to\nspecify a custom one during instantiation.\n\n```python\nfrom obfuskey import Obfuskey\n\nobfuscator = Obfuskey('012345abcdef')\nkey = obfuscator.get_key(123) # Example: 022d43\n```\n\n## Usage - Obfusbit (v0.2.0+)\n\nObfusbit allows you to pack multiple integer values into a single obfuscated key string.\nYou define a schema where each field has a name and a specified number of bits. Obfusbit\nwill combine these values into a single large integer, which can then be obfuscated by\nan `Obfuskey` instance. This is ideal for compact identifiers that encode multiple pieces\nof information.\n\n### Basic Packing and Unpacking (Integer Output)\n\nDefine your schema and pack/unpack integers. This is useful if you want to store the\npacked integer in a database without obfuscation, or process it numerically.\n\n```python\nfrom obfuskey import Obfuskey, Obfusbit\n\n# Define your data schema with field names and bit lengths\nproduct_schema = [\n {\"name\": \"category_id\", \"bits\": 4}, # Max value 15\n {\"name\": \"item_id\", \"bits\": 20}, # Max value ~1 million\n {\"name\": \"status\", \"bits\": 3}, # Max value 7 (e.g., in_stock=0, low=1, out=2)\n]\n\n# Initialize Obfusbit without an Obfuskey instance if you only need the raw integer\n# (e.g., for storage in a database)\nobb_int_packer = Obfusbit(product_schema)\n\n# Values to pack (must be within the bit limits defined in the schema)\nvalues_to_pack = {\n \"category_id\": 5,\n \"item_id\": 123456,\n \"status\": 1, # Low stock\n}\n\n# Pack into a single integer (obfuscate=False for raw integer output)\npacked_id_int = obb_int_packer.pack(values_to_pack, obfuscate=False)\nprint(f\"Packed Integer ID: {packed_id_int}\") # Example: 809492485\n\n# Unpack back to original values\nunpacked_values = obb_int_packer.unpack(packed_id_int, obfuscated=False)\nprint(f\"Unpacked values: {unpacked_values}\") # Example: {'status': 1, 'item_id': 123456, 'category_id': 5}\n```\n\n### Determining Alphabet and Key Length for Obfusbit\n\nWhen using `Obfusbit` with an `Obfuskey` instance for obfuscation, it's crucial that the\n`Obfuskey` is configured to handle the maximum possible integer value that your schema\ncan produce.\n\n1. **Calculate Total Bits Required by Schema:** Sum the `bits` for all fields in your\n `Obfusbit` schema. This sum represents the total number of bits needed to represent\n the packed integer.\n - Example: `[{\"bits\": 4}, {\"bits\": 20}, {\"bits\": 3}]` = `4 + 20 + 3 = 27` total bits.\n2. **Calculate Maximum Value Represented by Schema:** The maximum integer value your\n schema can pack is `(2 ** total_bits) - 1`.\n - Example: For 27 total bits, the maximum value is `(2 ** 27) - 1 = 134,217,727`.\n3. **Determine `Obfuskey` Capacity:** The maximum value an `Obfuskey` instance can obfuscate\n is determined by its alphabet size and key length: `(len(alphabet) ** key_length) - 1`.\n - Example: Using `BASE58` (alphabet size 58) with `key_length=5` gives\n `(58 ** 5) - 1 = 656,356,799`.\n\n**The `Obfuskey`'s maximum capacity MUST be greater than or equal to the maximum value your\nschema can produce.** If it's smaller, `Obfusbit` will raise a `MaximumValueError` during\ninitialization.\n\n**Tips for Choosing:**\n\n- **`total_bits`:** This is fixed by your schema requirements.\n- **`alphabet`:**\n - **Smaller alphabets** (e.g., `BASE16`, `BASE36`) result in longer keys for the same\n `total_bits`. They are often easier to type or read.\n - **Larger alphabets** (e.g., `BASE58`, `BASE62`, `BASE64_URL_SAFE`, `BASE94`) result in shorter,\n more compact keys for the same `total_bits`. They might be less human-friendly but more\n efficient.\n- **`key_length`:** This is derived from your `total_bits` and chosen `alphabet`. You need\n to find the smallest `key_length` such that `(len(alphabet) ** key_length) - 1` covers\n your `(2 ** total_bits) - 1`.\n\n**To determine the minimum `key_length` required:**\n\nUse the following Python snippet. Just replace `YOUR_TOTAL_BITS` with the sum of bits from your schema and `YOUR_ALPHABET` with the desired alphabet string (e.g., `alphabets.BASE58`).\n\n```python\nimport math\nfrom obfuskey import alphabets # Assuming alphabets is directly importable\n\nYOUR_TOTAL_BITS = 144 # Example: Sum of bits from your Obfusbit schema\nYOUR_ALPHABET = alphabets.BASE58 # Example: Choose your desired alphabet (e.g., alphabets.BASE62, alphabets.BASE64_URL_SAFE)\n\n# Calculate the number of states your schema needs to represent (2^N possibilities)\nrequired_states = 2 ** YOUR_TOTAL_BITS\n\n# Determine the alphabet's length\nalphabet_length = len(YOUR_ALPHABET)\n\n# Calculate the minimum key length using logarithms\n# This formula is derived from: alphabet_length ** key_length >= 2 ** total_bits\n# Which simplifies to: key_length >= total_bits / log2(alphabet_length)\nif alphabet_length <= 1:\n raise ValueError(\"Alphabet length must be greater than 1.\")\n \n# math.log2 gives log base 2, suitable for this calculation\nminimum_key_length = math.ceil(YOUR_TOTAL_BITS / math.log2(alphabet_length))\n\nprint(f\"For {YOUR_TOTAL_BITS} total bits and alphabet (length {alphabet_length}):\")\nprint(f\"Minimum required key_length: {minimum_key_length}\")\n\n# Optional: Verify the capacity with this calculated key_length\nmax_obfuskey_value = (alphabet_length ** minimum_key_length) - 1\nmax_schema_value = required_states - 1\n \nprint(f\"Maximum value Obfuskey can represent with this key_length: {max_obfuskey_value}\")\nprint(f\"Maximum value schema can produce: {max_schema_value}\")\n \nif max_obfuskey_value >= max_schema_value:\n print(\"Obfuskey capacity is sufficient.\")\nelse:\n # This case should ideally not be reached if minimum_key_length is correctly calculated\n print(\"WARNING: Obfuskey capacity is NOT sufficient. This indicates an issue with the calculation.\")\n```\n\n### Packing and Unpacking with Obfuscation (String Output)\n\nTo get a human-readable, fixed-length obfuscated key string, you associate an `Obfuskey`\ninstance with `Obfusbit`. Ensure the `Obfuskey`'s `maximum_value` is large enough to\ncover the total bits in your schema, as checked during `Obfusbit` initialization.\n\n```python\nimport datetime\nimport uuid\nfrom obfuskey import Obfuskey, Obfusbit, alphabets\n\n# Define a more complex schema, including a UUID\n# UUIDs are 128-bit numbers.\ncomplex_id_schema = [\n {\"name\": \"entity_uuid\", \"bits\": 128},\n {\"name\": \"version\", \"bits\": 4}, # e.g., schema version (0-15)\n {\"name\": \"creation_day\", \"bits\": 9}, # Day of the year (1-366, needs 9 bits for 0-511)\n {\"name\": \"environment_id\", \"bits\": 2}, # e.g., 0=Dev, 1=Staging, 2=Prod (0-3)\n {\"name\": \"is_active\", \"bits\": 1}, # Boolean flag (0 or 1)\n]\n\n# Calculate required bits for this schema: 128 + 4 + 9 + 2 + 1 = 144 bits.\n# For BASE58 (alphabet length 58), you need `math.ceil(144 / math.log2(58))` which is 25.\n# Using key_length=26 provides a bit of buffer.\nobfuscator_large = Obfuskey(alphabets.BASE58, key_length=26)\n\n# Initialize Obfusbit with the schema and the Obfuskey instance\n# This will raise a MaximumValueError if obfuscator_large is too small for the schema.\nobb_obfuscated_packer = Obfusbit(complex_id_schema, obfuskey=obfuscator_large)\n\n# Prepare values for packing\ncurrent_uuid = uuid.uuid4()\ncurrent_day_of_year = datetime.datetime.now().timetuple().tm_yday\n\nvalues_to_pack_complex = {\n \"entity_uuid\": current_uuid.int, # Convert UUID object to its 128-bit integer\n \"version\": 1,\n \"creation_day\": current_day_of_year,\n \"environment_id\": 2, # Production\n \"is_active\": 1, # True\n}\n\n# Pack and obfuscate into a string\nobfuscated_code = obb_obfuscated_packer.pack(values_to_pack_complex, obfuscate=True)\nprint(f\"Obfuscated Complex ID: {obfuscated_code}\") # Example: T6ATbW8QpS3qBVACGganMCi4rU... (length 26)\n\n# Unpack and de-obfuscate\nunpacked_complex_values = obb_obfuscated_packer.unpack(obfuscated_code, obfuscated=True)\nprint(f\"Unpacked Complex Values: {unpacked_complex_values}\")\n# Example: {'entity_uuid': 230751111624891151670977227092809615560, 'version': 1, 'creation_day': 208, 'environment_id': 2, 'is_active': 1}\n\n# Convert the UUID integer back to a UUID object for verification\nreconstructed_uuid = uuid.UUID(int=unpacked_complex_values[\"entity_uuid\"])\nprint(f\"Reconstructed UUID: {reconstructed_uuid}\")\nprint(f\"Original UUID matches reconstructed: {reconstructed_uuid == current_uuid}\")\n\n# This will raise a BitOverflowError if any single value exceeds its allocated bits in the schema.\n```\n\n## Large Integer Support (`gmpy2`)\n\nIf you need to obfuscate or pack integers that are larger than 512-bit, you will need to\ninstall the optional [gmpy2][gmpy2] dependency. This library provides highly optimized\narbitrary-precision arithmetic.\n\n```code\n$ pip install gmpy2\n\n# OR, if using poetry with extras:\n$ poetry install --extras gmpy2\n```\n\n[basehash]: https://github.com/bnlucas/python-basehash\n[alphabets]: https://github.com/bnlucas/obfuskey/blob/main/obfuskey/alphabets.py\n[gmpy2]: https://pypi.org/project/gmpy2/\n[pypi]: https://pypi.python.org/pypi/Obfuskey\n[pypi-v]: https://img.shields.io/pypi/v/Obfuskey.svg\n[pypi-l]: https://img.shields.io/pypi/l/Obfuskey.svg\n[codecov]: https://codecov.io/gh/bnlucas/Obfuskey\n[codecov-i]: https://img.shields.io/codecov/c/github/bnlucas/Obfuskey/master.svg\n[workflow]: https://github.com/bnlucas/Obfuskey/actions?query=branch%3Amain+\n[workflow-i]: https://img.shields.io/github/workflow/status/bnlucas/Obfuskey/CI/main",
"bugtrack_url": null,
"license": "MIT",
"summary": "A small library for obfuscating integer values to key strings using a set length and alphabet.",
"version": "0.2.0",
"project_urls": {
"Homepage": "https://github.com/bnlucas/obfuskey",
"Repository": "https://github.com/bnlucas/obfuskey"
},
"split_keywords": [
"obfuskey",
" obfuscate",
" basehash",
" key"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "2db911c1547f0359f183008f88622a493f4b5b825768ef37d436c61c4a650465",
"md5": "2d7703f328384575f5817d247aed00dd",
"sha256": "b64708f09b826756309cab2594af40b692eb3d01d66d15a0d0f3419b34f90a2d"
},
"downloads": -1,
"filename": "obfuskey-0.2.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "2d7703f328384575f5817d247aed00dd",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": "<3.13,>=3.9",
"size": 19107,
"upload_time": "2025-07-27T22:26:53",
"upload_time_iso_8601": "2025-07-27T22:26:53.799454Z",
"url": "https://files.pythonhosted.org/packages/2d/b9/11c1547f0359f183008f88622a493f4b5b825768ef37d436c61c4a650465/obfuskey-0.2.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "00a60040f2697d22d3f948dbd7d35b7a3a856e0388c2e9a156a389afde56a1d4",
"md5": "07b055389cdcc0bed05f4ecbcecd3462",
"sha256": "515e48d0c6872eeb61b2bb8bfdab6c0eac5bd3a98abd39b9444a9bf7303bf81e"
},
"downloads": -1,
"filename": "obfuskey-0.2.0.tar.gz",
"has_sig": false,
"md5_digest": "07b055389cdcc0bed05f4ecbcecd3462",
"packagetype": "sdist",
"python_version": "source",
"requires_python": "<3.13,>=3.9",
"size": 19749,
"upload_time": "2025-07-27T22:26:54",
"upload_time_iso_8601": "2025-07-27T22:26:54.920765Z",
"url": "https://files.pythonhosted.org/packages/00/a6/0040f2697d22d3f948dbd7d35b7a3a856e0388c2e9a156a389afde56a1d4/obfuskey-0.2.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-07-27 22:26:54",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "bnlucas",
"github_project": "obfuskey",
"travis_ci": false,
"coveralls": true,
"github_actions": true,
"tox": true,
"lcname": "obfuskey"
}