Skip to main content

Pseudonymisation/anonymisation engine with encrypted mapping storage

Project description

cloakdf

Install

pip install cloakdf

How to use

We’ll demonstrate cloakdf using the Northwind dataset. A classic sample database with customers, orders, and employees tables that share keys across them.

#| eval: false
import httpx
from pathlib import Path

base = "https://raw.githubusercontent.com/neo4j-contrib/northwind-neo4j/refs/heads/master/data"
files = ["customers.csv", "orders.csv", "employees.csv"]
data = Path("../data")
data.mkdir(exist_ok=True)

for f in files:
    (data/f).write_bytes(httpx.get(f"{base}/{f}").content)

1. Define your table configuration

Each table’s config specifies two kinds of columns:

  • id groups (e.g. id1, id2) — key columns that are shared across tables. Columns in the same group get consistent pseudonyms: customerID in both customers and orders maps to the same UUID, preserving referential integrity.

Note: All id columns must be string dtype before encoding — cast with .astype(str) if needed. - mask — sensitive columns to replace with opaque hex tokens. These are stored in a shared vault, so identical values (e.g. the same address appearing twice) get the same token.

tables = {
    'customers': {
        'id1': 'customerID',
        'mask': ['contactName', 'address', 'phone', 'companyName', 'fax', 'city']
    },
    'orders': {
        'id1': 'customerID',
        'id2': 'employeeID',
        'mask': ['shipName', 'shipAddress']
    },
    'employees': {
        'id2': 'employeeID',
        'mask': ['firstName', 'lastName', 'address', 'homePhone', 'birthDate', 'notes']
    },
}

2. Encode your DataFrames

import pandas as pd
from pathlib import Path

data = Path("../data")
unk = CloakDF(tables)

originals, encoded = {}, {}
for name in tables:
    df = pd.read_csv(data/f"{name}.csv", on_bad_lines='skip')
    for k, v in tables[name].items():
        if k.startswith('id'): df[v] = df[v].astype(str)
    originals[name] = df
    encoded[name] = unk.encode(name, df)

encoded['customers'].head(3)
<style scoped> .dataframe tbody tr th:only-of-type { vertical-align: middle; } .dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; } </style>
customerID companyName contactName contactTitle address city region postalCode country phone fax
0 9eb2c3d4-32d3-434c-863c-44d8ac4067d9 9288db060f26 5c1dfdfc8f62 Sales Representative 80e2676376a1 c1f7bd6a22f0 NaN 12209 Germany 715e53fda07f cd0efa7df34e
1 82d494d5-a9e7-4690-b5ec-3104dad5b87d 18db1aa91f8c 3c4420341c1a Owner 135d66291b39 42d81129a68e NaN 05021 Mexico a5611db2c349 25fabc23caa4
2 fa465d8d-ead0-4d03-ae91-8a65715c7fd1 9458f0d21f98 08b3087d3dda Owner a93f1f586e03 42d81129a68e NaN 05023 Mexico 2a648576b9be NaN

3. Save encrypted mappings

The mapping dictionaries (key_maps and vault) are the sensitive artefacts — they allow de-anonymisation. Generate a Fernet key and encrypt them at rest. You can store the key to a file or an environment variable:

⚠️ Never commit your Fernet key or encrypted mappings to version control. Ensure your .gitignore includes key files and *.enc files (e.g. *.key, *.enc, data/).

import os

key = CloakDF.generate_key()
unk.save(data/"mappings.enc", key)

# Optionally store the key in an environment variable
os.environ['CLOAKDF_KEY'] = key.decode()
print("✓ Mappings saved and key stored in env var")
✓ Mappings saved and key stored in env var

4. Load and decode

Load the encrypted mappings (using the key directly or from an environment variable) and reverse the encoding:

# Load key from env var (or pass `key` directly)
loaded_key = CloakDF.load_key(env_var='CLOAKDF_KEY')
# loaded_key = CloakDF.load_key(path="path/to/keyfile")  # alternative: from file

unk2 = CloakDF.load(data/"mappings.enc", loaded_key, tables)

for name in tables:
    decoded = unk2.decode(name, encoded[name])
    pd.testing.assert_frame_equal(decoded, originals[name])
    print(f"✓ {name} round-trip OK")

decoded.head(3)
✓ customers round-trip OK
✓ orders round-trip OK
✓ employees round-trip OK
<style scoped> .dataframe tbody tr th:only-of-type { vertical-align: middle; } .dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; } </style>
employeeID lastName firstName title titleOfCourtesy birthDate hireDate address city region postalCode country homePhone extension photo notes reportsTo photoPath
0 1 Davolio Nancy Sales Representative Ms. 1948-12-08 00:00:00.000 1992-05-01 00:00:00.000 507 - 20th Ave. E. Apt. 2A Seattle WA 98122 USA (206) 555-9857 5467 0x151C2F00020000000D000E0014002100FFFFFFFF4269... Education includes a BA in psychology from Col... 2.0 http://accweb/emmployees/davolio.bmp
1 2 Fuller Andrew Vice President, Sales Dr. 1952-02-19 00:00:00.000 1992-08-14 00:00:00.000 908 W. Capital Way Tacoma WA 98401 USA (206) 555-9482 3457 0x151C2F00020000000D000E0014002100FFFFFFFF4269... Andrew received his BTS commercial in 1974 and... NaN http://accweb/emmployees/fuller.bmp
2 3 Leverling Janet Sales Representative Ms. 1963-08-30 00:00:00.000 1992-04-01 00:00:00.000 722 Moss Bay Blvd. Kirkland WA 98033 USA (206) 555-3412 3355 0x151C2F00020000000D000E0014002100FFFFFFFF4269... Janet has a BS degree in chemistry from Boston... 2.0 http://accweb/emmployees/leverling.bmp

5. Compare encoded vs decoded

Here’s what the employees table looks like — encoded (pseudonymised) vs decoded (original):

cols = ['employeeID', 'firstName', 'lastName', 'title', 'address', 'homePhone']
display(encoded['employees'][cols].head(3))
display(decoded[cols].head(3))

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

cloakdf-0.0.3.tar.gz (10.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

cloakdf-0.0.3-py3-none-any.whl (10.6 kB view details)

Uploaded Python 3

File details

Details for the file cloakdf-0.0.3.tar.gz.

File metadata

  • Download URL: cloakdf-0.0.3.tar.gz
  • Upload date:
  • Size: 10.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.13

File hashes

Hashes for cloakdf-0.0.3.tar.gz
Algorithm Hash digest
SHA256 3eb8e3b06484c02818f1dad525d296c373c56a6e524ff750e4e7138493188f99
MD5 88f86f3686243c2dd36a9a1c0680d427
BLAKE2b-256 a451f6962b9b26e643512b78fb35c8ee7586880eefda09c92217397212228969

See more details on using hashes here.

File details

Details for the file cloakdf-0.0.3-py3-none-any.whl.

File metadata

  • Download URL: cloakdf-0.0.3-py3-none-any.whl
  • Upload date:
  • Size: 10.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.13

File hashes

Hashes for cloakdf-0.0.3-py3-none-any.whl
Algorithm Hash digest
SHA256 5ee4c61f349cfec08026e6484cd638acbd7dce3f5d88cde93b6f60dc6ae40cc6
MD5 e39bcc04f43680b33a0191bb1fd20a08
BLAKE2b-256 99d4b07c7782f80704764b473076253a23d44921cb0c77059ba0dab9d27d36b8

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page