{"id":43931336,"url":"https://github.com/godaddy/asherah-ffi","last_synced_at":"2026-04-28T02:04:53.074Z","repository":{"id":317423573,"uuid":"1067354492","full_name":"godaddy/asherah-ffi","owner":"godaddy","description":"Application-layer envelope encryption with automatic key rotation. Rust core with bindings for Node.js, Python, .NET, Java, Ruby, and Go.","archived":false,"fork":false,"pushed_at":"2026-04-26T19:32:47.000Z","size":47554,"stargazers_count":0,"open_issues_count":6,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-26T20:28:55.665Z","etag":null,"topics":["cryptography","dotnet","encryption","envelope-encryption","ffi","go","java","key-rotation","nodejs","python","ruby","rust","security"],"latest_commit_sha":null,"homepage":"https://github.com/godaddy/asherah-ffi","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/godaddy.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":"NOTICE","maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2025-09-30T18:32:43.000Z","updated_at":"2026-04-15T18:31:26.000Z","dependencies_parsed_at":"2026-04-02T12:14:34.389Z","dependency_job_id":null,"html_url":"https://github.com/godaddy/asherah-ffi","commit_stats":null,"previous_names":["godaddy/asherah-ffi"],"tags_count":101,"template":false,"template_full_name":null,"purl":"pkg:github/godaddy/asherah-ffi","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/godaddy%2Fasherah-ffi","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/godaddy%2Fasherah-ffi/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/godaddy%2Fasherah-ffi/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/godaddy%2Fasherah-ffi/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/godaddy","download_url":"https://codeload.github.com/godaddy/asherah-ffi/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/godaddy%2Fasherah-ffi/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32361521,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-27T20:07:02.737Z","status":"ssl_error","status_checked_at":"2026-04-27T20:07:00.910Z","response_time":128,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cryptography","dotnet","encryption","envelope-encryption","ffi","go","java","key-rotation","nodejs","python","ruby","rust","security"],"created_at":"2026-02-07T00:04:51.260Z","updated_at":"2026-04-28T02:04:53.068Z","avatar_url":"https://github.com/godaddy.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Asherah\n\nApplication-layer encryption with automatic key rotation. Rust implementation\nwith bindings for Node.js, Python, .NET, Java, Ruby, and Go.\n\n## What is Asherah?\n\nAsherah implements envelope encryption: data is encrypted with a random data key,\nwhich is itself encrypted with an intermediate key, which is encrypted by a\nmaster key held in a KMS. Keys rotate automatically based on configurable\nintervals, and old keys remain accessible for decryption while new data is always\nencrypted with fresh keys.\n\nThis design means application code never handles raw master keys, key rotation\nhappens transparently, and compromise of a single data key exposes only one\nrecord.\n\n**KMS backends:** AWS KMS (recommended), [HashiCorp Vault Transit](docs/vault-transit-kms.md) (on-prem), [AWS Secrets Manager](docs/secrets-manager-kms.md) (migration only), static (testing only)\n\n**Metastores:** DynamoDB, MySQL, Postgres, SQLite, in-memory (testing only)\n\n## Language Bindings\n\n| Language | Package | Docs |\n|----------|---------|------|\n| Node.js | [`asherah`](https://www.npmjs.com/package/asherah) on npm | [README](asherah-node/) |\n| Python | [`asherah`](https://pypi.org/project/asherah) on PyPI | [README](asherah-py/) |\n| .NET | `GoDaddy.Asherah.AppEncryption` on [GitHub Packages](https://github.com/godaddy/asherah-ffi/packages) | [README](asherah-dotnet/) |\n| Java | `com.godaddy.asherah:appencryption` on [GitHub Packages](https://github.com/godaddy/asherah-ffi/packages) | [README](asherah-java/) |\n| Ruby | `asherah` on [GitHub Packages](https://github.com/godaddy/asherah-ffi/packages) | [README](asherah-ruby/) |\n| Go | [`github.com/godaddy/asherah-ffi/asherah-go`](https://pkg.go.dev/github.com/godaddy/asherah-ffi/asherah-go) | [README](asherah-go/) |\n\n## Platform Support\n\n| Platform | Architecture | Status |\n|----------|-------------|--------|\n| Linux | x86_64 (glibc) | Supported |\n| Linux | x86_64 (musl) | Supported |\n| Linux | ARM64 (glibc) | Supported |\n| Linux | ARM64 (musl) | Supported |\n| macOS | x86_64 | Supported |\n| macOS | ARM64 (Apple Silicon) | Supported |\n| Windows | x64 | Supported |\n| Windows | ARM64 | Supported |\n\n## Quick Start\n\n```js\nconst asherah = require('asherah');\n\nasherah.setup({\n  serviceName: 'my-service',\n  productId: 'my-product',\n  metastore: 'memory',   // testing only — use 'rdbms' or 'dynamodb' in production\n  kms: 'static',         // testing only — use 'aws' in production\n});\n\nconst ct = asherah.encryptString('partition', 'secret data');\nconst pt = asherah.decryptString('partition', ct);\n\nasherah.shutdown();\n```\n\nSee each binding's README for complete examples including async APIs,\nsession-based usage, and production configuration.\n\n## Input contract\n\nThere are two argument categories with different rules:\n\n- **Partition ID** (the tenancy/isolation identifier): `null`, `nil`,\n  `undefined`, and the empty string `\"\"` are **always programming errors**.\n  Bindings reject them at the API boundary with the language-native\n  exception type — no row is ever written to the metastore under a\n  degenerate ID. (Stricter than canonical asherah-csharp / asherah-java,\n  which silently accept null and persist `_IK__service_product` rows.)\n- **Plaintext** (input to encrypt): `null`/`nil`/`undefined` is rejected\n  as a programming error. Empty `String` and empty byte array are\n  **valid** plaintexts that produce a real `DataRowRecord` envelope and\n  round-trip back to empty on decrypt. **Do not short-circuit empty\n  plaintext encryption in caller code** — empty data is real data,\n  encrypting it is a real cryptographic operation, and skipping it leaks\n  the fact that the value was empty as a side channel.\n- **Ciphertext** (input to decrypt): `null`/`nil`/`undefined` and empty\n  string/bytes are all rejected — empty input cannot be a valid\n  `DataRowRecord` JSON envelope.\n\nSee [docs/input-contract.md](docs/input-contract.md) for the full\nper-binding behavior matrix, exception types, and rationale.\n\n## Performance\n\nThe Rust core delivers sub-microsecond encrypt/decrypt. All language bindings\nstay under 2μs for sync operations. The table includes both sync and async\nvariants, plus head-to-head comparison with the canonical Go/C#/Java\nimplementations:\n\n![Benchmark results — hot cache, Apple M4 Max](docs/images/benchmark-hot-cache.png)\n\nSee each binding's README for detailed async behavior and per-metastore\nperformance characteristics.\n\n## Architecture: Key Hierarchy and Secure Caching\n\nAsherah uses a four-level key hierarchy with envelope encryption:\n\n```\n+------------------------------------------------------+\n|                   KMS Backend                        |\n|       (AWS KMS / HashiCorp Vault Transit API)        |\n|                                                      |\n| Master Key -- never exposed, encrypt/decrypt via API |\n+------------------+-----------------------------------+\n                   | encrypts\n+------------------v-----------------------------------+\n|             System Key (SK)                          |\n| Stored in metastore, cached in memory, auto-rotated  |\n+------------------+-----------------------------------+\n                   | encrypts\n+------------------v-----------------------------------+\n|         Intermediate Key (IK)                        |\n| Per-partition, stored in metastore, auto-rotated     |\n+------------------+-----------------------------------+\n                   | encrypts\n+------------------v-----------------------------------+\n|          Data Row Key (DRK)                          |\n| Unique per write -- effectively rotated every time   |\n+------------------+-----------------------------------+\n                   | encrypts\n                   v\n              Your Data\n```\n\n### Secure Memory and Tiered Key Cache\n\nKeys are protected at rest by a three-tier cache with hardware-enforced\nmemory protection:\n\n```\nTIER 1: mlock'd Slab (hot cache, ~400ns access)\n========================================================\n\n  Guard Page [PROT_NONE -- segfaults on access]\n  +----------------------------------------------------+\n  | mlock'd Page (4KB, pinned in RAM, never swapped)   |\n  |                                                    |\n  | Slot 0: Coffer Left  (XOR'd master key half)       |\n  | Slot 1: Coffer Right (random, key derivation)      |\n  |         [neither half alone reveals the key]       |\n  |                                                    |\n  | Slot 2: SK decrypt key  \u003c-- hot cache (LRU)        |\n  | Slot 3: IK decrypt key  \u003c-- hot cache (LRU)        |\n  | Slot 4: [transient op]  \u003c-- acquired/released      |\n  | ...                                                |\n  | Slot N: [free]                                     |\n  +----------------------------------------------------+\n  Guard Page [PROT_NONE -- segfaults on access]\n\n  Canary bytes between guard pages and data detect\n  buffer overflows at runtime.\n\nTIER 2: Encrypted Enclaves (cold cache, ~1us access)\n========================================================\n\n  Regular heap memory (not mlock'd, can be swapped)\n  +----------------------------------------------------+\n  | Enclave { id, ciphertext, data_len }               |\n  |   ciphertext = AES-256-GCM(key, coffer_master)     |\n  |   On access: decrypt into Tier 1 slab slot         |\n  |   Promoted to hot cache after first use            |\n  +----------------------------------------------------+\n  Each CryptoKey holds an Enclave. When the hot cache\n  is full, LRU eviction frees a slab slot. The evicted\n  key remains safe in its Enclave (encrypted at rest).\n\nTIER 3: Metastore (persistent, ~1ms access)\n========================================================\n\n  DynamoDB / MySQL / Postgres / SQLite\n  +----------------------------------------------------+\n  | EnvelopeKeyRecord { id, created, encrypted_key }   |\n  |   encrypted_key = AES-256-GCM(key, parent_key)     |\n  |   Loaded on cold start or cache miss               |\n  |   Decrypted through the key hierarchy (IK-\u003eSK-\u003eKMS)|\n  +----------------------------------------------------+\n```\n\n**Tier 1 hit** (typical encrypt/decrypt): The decrypted key is already in\nan mlock'd slab slot — zero crypto overhead, just a pointer read. This is\nwhy hot-cache encrypt is ~400ns.\n\n**Tier 1 miss, Tier 2 hit**: The key's Enclave (AES-256-GCM encrypted\nciphertext in heap memory) is decrypted using the Coffer master key from\nthe slab, placed in a free slot, and promoted to the hot cache.\n\n**Tier 2 miss** (cold start): The key is loaded from the metastore,\ndecrypted through the key hierarchy (KMS decrypts SK, SK decrypts IK),\nsealed into an Enclave, and promoted into the slab hot cache.\n\n**Coffer**: The master key for Enclave encryption is split across two\nmlock'd slots using XOR + hash derivation. Neither slot alone reveals the\nkey. Initialized once at startup with OS entropy.\n\n### Session and Key Caches\n\nAbove the memory tiers, Asherah maintains logical caches with\nstale-while-revalidate to prevent thundering herd on cache expiry:\n\n```\nRequest --\u003e Session Cache (LRU, per-factory)\n                | miss\n                v\n            IK Cache (stale-while-revalidate)\n                | miss\n                v\n            SK Cache (shared, stale-while-revalidate)\n                | miss\n                v\n            Metastore load --\u003e Tier 2/1 promotion\n```\n\nOn cache expiry, the stale key is returned immediately while a background\nrefresh loads the latest version from the metastore.\n\n## Testing\n\n- **127 Rust unit tests** covering core encryption engine, key management,\n  metastore adapters, and memory protection\n- **64 .NET tests** (34 core + 30 compatibility layer) across net8.0 and net10.0\n- **49 Node.js tests** including async context, unicode, binary edge cases, and\n  Factory/Session API\n- **21 Go tests** covering Factory/Session API and compatibility layer\n- **21 Python tests** including session-based and async APIs\n- **16 Java tests** including JNI lifecycle and async CompletableFuture\n- **74 Ruby tests** including thread safety, session lifecycle, and async\n  callbacks\n- **5 cross-language interop tests** verifying Python, Node.js, Rust, and Ruby\n  encrypt/decrypt compatibility\n- **6 fuzz targets** for Cargo-fuzz continuous fuzzing\n- **Memory safety**: Miri (undefined behavior detection), AddressSanitizer, and\n  Valgrind on every PR\n- **12 publish dry-run jobs** that replicate every unique compilation path in the\n  release pipeline\n- **56+ CI jobs** on every pull request across x86_64 and ARM64\n\n```bash\n# Run all tests\nscripts/test.sh --all\n\n# Individual test modes\nscripts/test.sh --unit\nscripts/test.sh --integration    # requires Docker (MySQL, Postgres, DynamoDB)\nscripts/test.sh --bindings       # requires language toolchains\nscripts/test.sh --interop\nscripts/test.sh --lint\nscripts/test.sh --sanitizers     # Miri, AddressSanitizer, Valgrind\nscripts/test.sh --fuzz           # requires nightly\n```\n\n## Project Structure\n\n| Directory | Description |\n|-----------|-------------|\n| `asherah/` | Rust core library |\n| `asherah-node/` | Node.js bindings |\n| `asherah-py/` | Python bindings |\n| `asherah-dotnet/` | .NET bindings |\n| `asherah-java/` | Java bindings (JNI) |\n| `asherah-ruby/` | Ruby bindings |\n| `asherah-go/` | Go bindings (purego, no CGO) |\n| `asherah-ffi/` | C ABI for language bindings |\n| `asherah-server/` | gRPC sidecar server |\n| `samples/` | Usage examples for each language |\n| `benchmarks/` | Cross-language benchmark suite |\n\n## Security\n\n- **mlock'd memory**: All key material lives in pages pinned to RAM\n  (`mlock`), preventing the OS from swapping secrets to disk\n- **Guard pages**: Buffer overflows and underflows are caught by\n  hardware-enforced guard pages around protected memory regions\n- **Canary bytes**: Optional buffer overflow detection via randomized\n  canary values at buffer boundaries\n- **Wipe-on-free**: All key material is cryptographically scrubbed\n  before memory is released — no residual secrets in freed pages\n- **Core dump protection**: Disabled at process initialization to\n  prevent secrets from appearing in crash dumps\n- **Coffer key splitting**: The Enclave master key is split across two\n  mlock'd slots using XOR + hash derivation — neither slot alone reveals\n  the key\n- **AES-256-GCM Enclaves**: Keys at rest in regular memory are encrypted\n  with authenticated encryption; only the mlock'd Coffer can decrypt them\n\n## License\n\n[Apache-2.0](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgodaddy%2Fasherah-ffi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgodaddy%2Fasherah-ffi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgodaddy%2Fasherah-ffi/lists"}