v1.0.0 · Zero Dependencies · Python 3.10+

I implemented AES from scratch and built a secrets vault around it.

VaultLite is a lightweight HashiCorp Vault alternative. Every byte of the AES-128 cipher is hand-coded from the NIST spec. No cryptography, no pycryptodome — just Python stdlib.

Wait, you wrote AES by hand?

Every transformation. S-Box substitution from the GF(2⁸) inversion table. ShiftRows and MixColumns with explicit Galois Field arithmetic. Key expansion from 16 bytes into 11 round keys. Validated against the NIST FIPS 197 Appendix B test vector — the same spec Intel follows for AES-NI.

# NIST FIPS 197 Appendix B — the standard AES-128 test vector
key       = 2b7e1516 28aed2a6 abf71588 09cf4f3c
plaintext = 3243f6a8 885a308d 313198a2 e0370734
expected  = 3925841d 02dc09fb dc118597 196a0b32  ✓ matches
AES-128 CBC Mode PKCS7 Padding HMAC-SHA256 PBKDF2 Envelope Encryption

What does VaultLite actually do?

It manages secrets the way production systems do. Envelope encryption gives each secret its own key. The seal/unseal ceremony protects the master key by splitting it into shares. Token-based auth, path-based policies, TTL leases, version history, and a hash-chained audit trail that detects tampering.

┌─────────────────────────────────────────────────────────┐
│                    HTTP API (25+ endpoints)              │
├─────────────────────────────────────────────────────────┤
│                    Vault Orchestrator                    │
├─────────┬─────────┬─────────┬─────────┬─────────────────┤
│  Auth   │ Policy  │ Audit   │ Lease   │  Versioning     │
│ Tokens  │ ACL     │ Hash    │ TTL     │  History        │
│ AppRole │ Glob    │ Chain   │ Renewal │  Soft-delete    │
├─────────┴─────────┴─────────┴─────────┴─────────────────┤
│              Seal Manager (XOR key splitting)            │
├─────────────────────────────────────────────────────────┤
│          Envelope Encryption (AES-128 from scratch)     │
├─────────────────────────────────────────────────────────┤
│       Memory Store  │  File Store  │  SQLite Store       │
└─────────────────────────────────────────────────────────┘

How do I use it?

Three lines to start. Initialize the vault, unseal it with your key shares, then write and read secrets. Works as a library or as an HTTP server.

from vaultlite.vault import Vault

vault = Vault()
result = vault.initialize(shares=3, threshold=3)

for share in result.unseal_keys:
    vault.unseal(share)

vault.write("secret/db/prod", {
    "password": "s3cur3_p@ss!",
}, result.root_token)

secret = vault.read("secret/db/prod", result.root_token)
print(secret["data"]["password"])  # s3cur3_p@ss!

What about access control?

Path-based policies with glob matching. Create a read-only policy for your database team, a full-access policy for admins. Tokens inherit their parent's policies. Revoke a parent and all children get revoked too.

# Create a read-only policy
db_reader = Policy(
    name="db-reader",
    rules=[Rule(path="secret/database/*", capabilities=["read", "list"])]
)
vault.put_policy("db-reader", db_reader, root_token)

# Create a token with that policy
reader = vault.create_token(root_token, policies=["db-reader"])

# This works
vault.read("secret/database/prod", reader.token_id)

# This raises AuthorizationError
vault.write("secret/database/prod", {...}, reader.token_id)

Is there an audit trail?

Every operation is logged with a SHA-256 hash chain. Each entry contains the hash of the previous entry — like a blockchain for your audit log. Tamper with any entry and verify_chain() catches it.

entries = vault.audit_log(token, limit=10)
# [write] secret/database/prod  → allow  (by hvs.root-xyz...)
# [read]  secret/database/prod  → allow
# [read]  secret/api/stripe     → deny   (no 'read' capability)

integrity = vault.verify_audit_chain(token)
# {"valid": True, "total_entries": 47}

By the numbers

0 Dependencies
258 Tests Passing
22 Source Modules
25+ API Endpoints
10 AES Rounds
3 Storage Backends