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

Uploaded CPython 3.8+Windows ARM64

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

Uploaded CPython 3.8+Windows x86-64

asherah-0.5.30-cp38-abi3-musllinux_1_2_x86_64.whl (13.1 MB view details)

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

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

Uploaded CPython 3.8+musllinux: musl 1.2+ ARM64

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

Uploaded CPython 3.8+manylinux: glibc 2.28+ ARM64

asherah-0.5.30-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.30.tar.gz.

File metadata

  • Download URL: asherah-0.5.30.tar.gz
  • Upload date:
  • Size: 188.1 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.30.tar.gz
Algorithm Hash digest
SHA256 2bd587659084fbbdced0c0d09e59417fd10615acb90e165c31b0c074987b23c6
MD5 3c8f6e7e531487c606193f20a09470e6
BLAKE2b-256 4d52e1e6c22f3b32e6b230cdf10f983a32611f49580148e82d19996ed971723c

See more details on using hashes here.

File details

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

File metadata

  • Download URL: asherah-0.5.30-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.30-cp38-abi3-win_arm64.whl
Algorithm Hash digest
SHA256 56b8ae12759d3bd90bae3fa6a470072a908ffbce170e7423aab536c751b499e1
MD5 c67b02d443c70e9abe5c30a985644f33
BLAKE2b-256 87258d3263677c213158e4579e0050ba21d60a194b1a4581d9335a04e388c153

See more details on using hashes here.

File details

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

File metadata

  • Download URL: asherah-0.5.30-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.30-cp38-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 7feecaf9171ece514f163dbe222f1d054124f8a73e20c96e787f8bbd95d6ea6b
MD5 c8f3da3d79f302ce2c371c22c282517d
BLAKE2b-256 914fadb731db6a582e8dadf3dcecb67da4a80f1b65d6d57975be74fc372cf7db

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for asherah-0.5.30-cp38-abi3-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 9bd1bdd23a427d0ad87bb8e2fab33f68f7b7bbd18c356596d48acd1a18572084
MD5 edbcd06e95bd83c448e34e0aede263df
BLAKE2b-256 a00732aa774cacd954da7bb347a5810fc86884bb60a036d01d46ed1fdfb0efd2

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for asherah-0.5.30-cp38-abi3-musllinux_1_2_aarch64.whl
Algorithm Hash digest
SHA256 ab1cfdcb510dff8824c1f2b80ea717fef39748132e0dc2df7b9a1121df2dfbb6
MD5 02639d5c7e30a5b7ab91b060c618c577
BLAKE2b-256 073e55a9ab40d8ce4030b4d7e30daededfe0d505b1cba1b961904dc5e1e2519d

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for asherah-0.5.30-cp38-abi3-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 c4a6cba3c344765b10c43852944b067176190306fcca06cc771468d71fd5483b
MD5 6cded74f012809ad6de7c544516f668c
BLAKE2b-256 ae5f5b94ec4dbe7d7c35fa2ca9daaa691ee88808bc2da2c2a94ff6586c12f8f6

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for asherah-0.5.30-cp38-abi3-manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 acaf178391b3b3f862584c2a1772c485fbe19bc6ba2136ac4858089f4ff775cf
MD5 23eb43962bba574e5a2bd2f1dca95248
BLAKE2b-256 e7a63e7e460acf629c4d088592d305bce0c70baa67fc21ed663449a8d103b87e

See more details on using hashes here.

File details

Details for the file asherah-0.5.30-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.30-cp38-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl
Algorithm Hash digest
SHA256 5a560a85718a8be41afa72ba842f3657c55effaff7d5214103c8340500ba1f8a
MD5 1ad7f9d9ab6f0a446bf55d83cf383321
BLAKE2b-256 10c3bb28834a81655a0063db7c0ff7527ab05228884069c227106ae254dd2508

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