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.32.tar.gz (205.5 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.32-cp38-abi3-win_arm64.whl (7.9 MB view details)

Uploaded CPython 3.8+Windows ARM64

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

Uploaded CPython 3.8+Windows x86-64

asherah-0.5.32-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.32-cp38-abi3-musllinux_1_2_aarch64.whl (13.3 MB view details)

Uploaded CPython 3.8+musllinux: musl 1.2+ ARM64

asherah-0.5.32-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.32-cp38-abi3-manylinux_2_28_aarch64.whl (12.8 MB view details)

Uploaded CPython 3.8+manylinux: glibc 2.28+ ARM64

asherah-0.5.32-cp38-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl (19.1 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.32.tar.gz.

File metadata

  • Download URL: asherah-0.5.32.tar.gz
  • Upload date:
  • Size: 205.5 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.32.tar.gz
Algorithm Hash digest
SHA256 72f8ee2a91654fac14dbfd1edaf75e3429c9ed84bd713cc11b4104b246959e44
MD5 0925d929ef12c149c4d49537c1256f06
BLAKE2b-256 350c657bd46324e01aba6b9dd7d9ccf2bb2797dae4cd9faa7cff8e99c9dfa5f9

See more details on using hashes here.

File details

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

File metadata

  • Download URL: asherah-0.5.32-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.32-cp38-abi3-win_arm64.whl
Algorithm Hash digest
SHA256 a76d094ca188ae090e77736c6a861f4596cc8049ded1b2e119766875bb9b18f4
MD5 8465a2929d698b97dec4dd9da347d143
BLAKE2b-256 a1c7ce1cf77b3c10aa3d05566d24c408588a8df20d28c4cfa7611387b82e3a41

See more details on using hashes here.

File details

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

File metadata

  • Download URL: asherah-0.5.32-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.32-cp38-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 508358087f32bcc33f933d30cab8ba0d041ead38b349e4583477fcda0acdbb8c
MD5 0a3d8e4a9acd2a7cefd207edd8bef93a
BLAKE2b-256 137f18168e4aa9c2545ffecc4919c43b582897325bbe74283100308b62f5e423

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for asherah-0.5.32-cp38-abi3-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 0c1be92b7975ed350b26fab73ea56d84247deec1328021c3e65c0b0e3268041d
MD5 791129ab85d2fb91989663725f189323
BLAKE2b-256 41e2ba4b18818b51e7660e4ed349b6be2be0463be2e3061cedfa3472bdc41eb1

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for asherah-0.5.32-cp38-abi3-musllinux_1_2_aarch64.whl
Algorithm Hash digest
SHA256 13bc541b716f724305bb2c561c42b88ee76a332f4214f9d499312e2a41c09b9f
MD5 dbf7d7dc123c173a0ab318d66a2e768a
BLAKE2b-256 ca30193672a5535538efd16028e663ae5fbf430aab0c7b6687968f2c4e7b03ad

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for asherah-0.5.32-cp38-abi3-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 2239be01d5483432c25c021a3a6463e32fa2eedf4da1f105ac110012191bbd9c
MD5 0f731dd2e7719c57804dc9b689cb6849
BLAKE2b-256 3f1e514d05d8916b023f375de5a29ec7ad816032bec55a4b8cf437db765dfe1f

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for asherah-0.5.32-cp38-abi3-manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 22a7245883db96b5e28b0befdcef5416e36b40975e0897a43738d040f8d0f211
MD5 bfaee9639c8b9d42154370e94692a84f
BLAKE2b-256 8b05cf1ca52252c816a451c300e3c4a607f0c534bd7fc2b368a75e964a584e59

See more details on using hashes here.

File details

Details for the file asherah-0.5.32-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.32-cp38-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl
Algorithm Hash digest
SHA256 423411b344c0ea13d8276ffbae521a4f7bfabd72e985b651e97cea25c0d07692
MD5 5cadc8a27b457c509d3efca61255b400
BLAKE2b-256 91c903fd1cd0a69adf9d264a841ffc439993c7ea692a0591eb59c8b5d168e759

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