Skip to main content

Asherah application-layer encryption for Python with automatic key rotation, powered by the native Rust implementation.

Project description

asherah

Python bindings for the Asherah envelope encryption and automatic key rotation library.

Prebuilt wheels for Python 3.8+ (stable ABI): Linux x64/ARM64 (manylinux + musl), macOS universal2, Windows x64/ARM64.

Installation

pip install asherah

Quick Start (Static API)

The static API manages a global session factory internally. Call setup() once, then encrypt/decrypt with partition-scoped functions.

import os
os.environ["STATIC_MASTER_KEY_HEX"] = "22" * 32  # testing only

import asherah

asherah.setup({
    "ServiceName": "my-service",
    "ProductID": "my-product",
    "Metastore": "memory",    # testing only — use "rdbms" or "dynamodb" in production
    "KMS": "static",          # testing only — use "aws" in production
    "EnableSessionCaching": True,
})

ciphertext = asherah.encrypt_string("partition-1", "sensitive data")
plaintext = asherah.decrypt_string("partition-1", ciphertext)
print(plaintext)  # "sensitive data"

asherah.shutdown()

Session-Based API

The SessionFactory class reads configuration from environment variables (set them before construction). Each Session is scoped to a partition. Both support context managers.

import os
os.environ["SERVICE_NAME"] = "my-service"
os.environ["PRODUCT_ID"] = "my-product"
os.environ["Metastore"] = "memory"  # testing only
os.environ["KMS"] = "static"       # testing only
os.environ["STATIC_MASTER_KEY_HEX"] = "22" * 32
os.environ["SESSION_CACHE"] = "1"

import asherah

with asherah.SessionFactory() as factory:
    with factory.get_session("partition-1") as session:
        ciphertext = session.encrypt_bytes(b"secret")
        plaintext = session.decrypt_bytes(ciphertext)
        print(plaintext)  # b"secret"

        # Text variants
        ct = session.encrypt_text("hello")
        pt = session.decrypt_text(ct)
        print(pt)  # "hello"

Async API

Async wrappers dispatch to the default thread pool executor via asyncio.run_in_executor. The GIL is released during the native call.

import asyncio
import os
os.environ["STATIC_MASTER_KEY_HEX"] = "22" * 32

import asherah

async def main():
    await asherah.setup_async({
        "ServiceName": "my-service",
        "ProductID": "my-product",
        "Metastore": "memory",
        "KMS": "static",
    })

    ciphertext = await asherah.encrypt_string_async("partition-1", "data")
    plaintext = await asherah.decrypt_string_async("partition-1", ciphertext)
    print(plaintext)  # "data"

    await asherah.shutdown_async()

asyncio.run(main())

Async Behavior

  • The event loop is not blocked -- work runs on a thread pool thread.
  • The GIL is released during the native Rust call.
  • Overhead: ~37 us vs ~1 us sync (hot cache, 64B payload).
  • Best for: I/O-bound asyncio applications that need non-blocking encryption.

For CPU-bound batch encryption, use the sync API directly.

Configuration

The setup() function accepts a dict (or any JSON-serializable object) with PascalCase keys matching the Go canonical API:

Key Type Required Description
ServiceName str Yes Service identifier for key hierarchy
ProductID str Yes Product identifier for key hierarchy
Metastore str Yes "rdbms", "dynamodb", "memory" (testing)
KMS str No "static" (default) or "aws"
ConnectionString str Conditional Required for sqlite and rdbms metastores
RegionMap dict Conditional Required for aws KMS. Maps preferred region to ARN.
PreferredRegion str No Preferred AWS region for KMS
EnableRegionSuffix bool No Append region suffix to system key IDs
EnableSessionCaching bool No Enable session caching (default: true)
SessionCacheMaxSize int No Max cached sessions
SessionCacheDuration int No Cache TTL in seconds
ExpireAfter int No Key expiration in seconds
CheckInterval int No Revocation check interval in seconds
DynamoDBEndpoint str No Custom DynamoDB endpoint URL
DynamoDBRegion str No DynamoDB region
DynamoDBSigningRegion str No Signing region (overrides DynamoDBRegion)
DynamoDBTableName str No DynamoDB table name
ReplicaReadConsistency str No DynamoDB read consistency
SQLMetastoreDBType str No "mysql" or "postgres" hint for rdbms
Verbose bool No Enable verbose logging
EnableCanaries bool No Enable canary buffer overflow detection
NullDataCheck bool No Enable null data validation
DisableZeroCopy bool No Disable zero-copy optimization

AWS KMS Example

asherah.setup({
    "ServiceName": "my-service",
    "ProductID": "my-product",
    "Metastore": "dynamodb",
    "KMS": "aws",
    "RegionMap": {
        "us-west-2": "arn:aws:kms:us-west-2:123456789012:key/mrk-abc123"
    },
    "PreferredRegion": "us-west-2",
    "DynamoDBTableName": "EncryptionKey",
    "EnableSessionCaching": True,
})

Performance

Approximate latency on Apple M4 Max (hot cache, 64-byte payload):

Operation Latency
Encrypt ~1,049 ns
Decrypt ~791 ns

This Rust-backed implementation replaces the Go Cobhan-based canonical asherah PyPI package. Run scripts/benchmark.sh for head-to-head comparisons.

API Reference

Static Functions

Function Description
setup(config) Initialize the global session factory from a config dict
shutdown() Shut down the global session factory and release resources
get_setup_status() Returns True if setup() has been called
encrypt_bytes(partition_id, data) Encrypt bytes, returns JSON str (DataRowRecord)
encrypt_string(partition_id, text) Encrypt str, returns JSON str (DataRowRecord)
decrypt_bytes(partition_id, drr) Decrypt JSON DataRowRecord, returns bytes
decrypt_string(partition_id, drr) Decrypt JSON DataRowRecord, returns str
setenv(env_dict) Set environment variables from a dict (both os.environ and Rust)
set_metrics_hook(callback) Register a callback for metrics events, or None to clear
set_log_hook(callback) Register a callback for log events, or None to clear
version() Returns the native library version string

Async Functions

Function Description
setup_async(config) Async version of setup()
shutdown_async() Async version of shutdown()
encrypt_bytes_async(partition_id, data) Async version of encrypt_bytes()
encrypt_string_async(partition_id, text) Async version of encrypt_string()
decrypt_bytes_async(partition_id, drr) Async version of decrypt_bytes()
decrypt_string_async(partition_id, drr) Async version of decrypt_string()

Classes

SessionFactory

Constructed from environment variables (not a config dict). Supports context manager protocol.

Method Description
SessionFactory() Create from env vars
SessionFactory.from_env() Same as constructor
get_session(partition_id) Create a Session for the given partition
close() Release resources

Session

Scoped to a single partition. Supports context manager protocol.

Method Description
encrypt_bytes(data) Encrypt bytes, returns JSON str
encrypt_text(text) Encrypt str, returns JSON str
decrypt_bytes(drr) Decrypt JSON DataRowRecord, returns bytes
decrypt_text(drr) Decrypt JSON DataRowRecord, returns str
close() Release resources

Hooks

Metrics Hook

def on_metric(event):
    # event is a dict with "type" and additional fields
    # type: "encrypt", "decrypt", "store", "load" -> has "duration_ns"
    # type: "cache_hit", "cache_miss" -> has "name"
    print(event)

asherah.set_metrics_hook(on_metric)
asherah.set_metrics_hook(None)  # clear

Log Hook

def on_log(record):
    # record is a dict with "level", "message", "target"
    print(f"[{record['level']}] {record['target']}: {record['message']}")

asherah.set_log_hook(on_log)
asherah.set_log_hook(None)  # clear

Cross-Language Compatibility

Ciphertext produced by any Asherah implementation (Go, Node.js, Java, .NET, Ruby) can be decrypted by any other, as long as they share the same metastore and KMS configuration. The DataRowRecord JSON format is the interchange format.

License

Licensed under the Apache License, Version 2.0.

Project details


Release history Release notifications | RSS feed

Download files

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

Source Distribution

asherah-0.5.31.tar.gz (200.9 kB view details)

Uploaded Source

Built Distributions

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

asherah-0.5.31-cp38-abi3-win_arm64.whl (7.9 MB view details)

Uploaded CPython 3.8+Windows ARM64

asherah-0.5.31-cp38-abi3-win_amd64.whl (8.2 MB view details)

Uploaded CPython 3.8+Windows x86-64

asherah-0.5.31-cp38-abi3-musllinux_1_2_x86_64.whl (13.2 MB view details)

Uploaded CPython 3.8+musllinux: musl 1.2+ x86-64

asherah-0.5.31-cp38-abi3-musllinux_1_2_aarch64.whl (13.3 MB view details)

Uploaded CPython 3.8+musllinux: musl 1.2+ ARM64

asherah-0.5.31-cp38-abi3-manylinux_2_28_x86_64.whl (12.3 MB view details)

Uploaded CPython 3.8+manylinux: glibc 2.28+ x86-64

asherah-0.5.31-cp38-abi3-manylinux_2_28_aarch64.whl (12.8 MB view details)

Uploaded CPython 3.8+manylinux: glibc 2.28+ ARM64

asherah-0.5.31-cp38-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl (19.0 MB view details)

Uploaded CPython 3.8+macOS 10.12+ universal2 (ARM64, x86-64)macOS 10.12+ x86-64macOS 11.0+ ARM64

File details

Details for the file asherah-0.5.31.tar.gz.

File metadata

  • Download URL: asherah-0.5.31.tar.gz
  • Upload date:
  • Size: 200.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.15

File hashes

Hashes for asherah-0.5.31.tar.gz
Algorithm Hash digest
SHA256 20736d33dfc4abbb6841304f6be4255bd5644caca111d191aff43be4e8112a54
MD5 04991041646fbde76983b61182e32035
BLAKE2b-256 1db6707554e71e58dc9e6c854c3eb5172e91531b6b499e668cf798e31c19a474

See more details on using hashes here.

File details

Details for the file asherah-0.5.31-cp38-abi3-win_arm64.whl.

File metadata

  • Download URL: asherah-0.5.31-cp38-abi3-win_arm64.whl
  • Upload date:
  • Size: 7.9 MB
  • Tags: CPython 3.8+, Windows ARM64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.15

File hashes

Hashes for asherah-0.5.31-cp38-abi3-win_arm64.whl
Algorithm Hash digest
SHA256 f2b2f4ee49e64f73466ed55eb91e23c3915fe08a0c1a9192e341a175977957b4
MD5 ecd9cd95296f2490bb1e49f0e901b6a6
BLAKE2b-256 f57ed975efc4d26e4adcf48af14257be324956dcc1ef6c4dd940e6c81b5d7090

See more details on using hashes here.

File details

Details for the file asherah-0.5.31-cp38-abi3-win_amd64.whl.

File metadata

  • Download URL: asherah-0.5.31-cp38-abi3-win_amd64.whl
  • Upload date:
  • Size: 8.2 MB
  • Tags: CPython 3.8+, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.15

File hashes

Hashes for asherah-0.5.31-cp38-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 bf3ac7552ebe431df5e78a08e610c1e9d52faa64d016a65fbc0dadf88562752c
MD5 948044b94b06efa3035c1d5f60908cd4
BLAKE2b-256 8b9663ed21bee0c67d39f47b37dccb55dcc3115872a0f6a5233c480b8959aa64

See more details on using hashes here.

File details

Details for the file asherah-0.5.31-cp38-abi3-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for asherah-0.5.31-cp38-abi3-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 1a3babccbbab0152ae756e74f228ae65730908228925e6c28df25a1848e8224a
MD5 3f6693eb684f8d3c85c3bc00c33047e8
BLAKE2b-256 e335f545cb08e347d39314d8c2e9641306cc1b0c173548dc964abd8fe1d859a8

See more details on using hashes here.

File details

Details for the file asherah-0.5.31-cp38-abi3-musllinux_1_2_aarch64.whl.

File metadata

File hashes

Hashes for asherah-0.5.31-cp38-abi3-musllinux_1_2_aarch64.whl
Algorithm Hash digest
SHA256 2b3f6ddfd3e7827a94eb5e54f64c98d10f8698bd076edcfae22bfeb048a15777
MD5 99e27ba48b009a96d14c511732ac7062
BLAKE2b-256 12e22219d252a196dd096df8973c01319756bc1f436311ef629d570266469766

See more details on using hashes here.

File details

Details for the file asherah-0.5.31-cp38-abi3-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for asherah-0.5.31-cp38-abi3-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 abdfa85e90d3c598abd3e5acfa531eb62b6399e08b1fef9fc706b5d29a88b313
MD5 f5980e118f1ccbc3eeb15d7d6febe355
BLAKE2b-256 0bfc73403b123c1ad0fb850942532047cb7fdf563bbcbc1c4a1a39d8e8ed0e9d

See more details on using hashes here.

File details

Details for the file asherah-0.5.31-cp38-abi3-manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for asherah-0.5.31-cp38-abi3-manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 76b4dd1b276314ad216b4b01041d34acd749772728be216e2620f124ac3b0ac2
MD5 af3b7df2360df6a2ab7ad051225b1477
BLAKE2b-256 696d0385dd6916c7941a6a327c25080cb29ce83f45970d079a3c5a3d8ce371e1

See more details on using hashes here.

File details

Details for the file asherah-0.5.31-cp38-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl.

File metadata

File hashes

Hashes for asherah-0.5.31-cp38-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl
Algorithm Hash digest
SHA256 7958220a1d0e9508edb1dc7ce78c778065547d9ad2031a88b47be95d32870bee
MD5 624f2a5091a4eb3e27d39086ddbdcdfd
BLAKE2b-256 feda01253ce879a333535f635577cb093ef8cb2ed90442dbd88dc21645647e9a

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