PyHSM is a production-ready software Key Management Service (KMS) that securely stores encryption keys, signs data, manages key lifecycles, and keeps an auditable record of every operation so your applications are safer by design.
Stop embedding encryption keys in your code.
Stop building your own key management from scratch.
Give your applications a secure vault for their most valuable secrets.
pip install vectorguard-pyhsm
If those secrets are compromised, attackers can impersonate users, steal money, or decrypt sensitive information.
Most teams store these secrets in environment variables, config files, or worse — hardcoded in source code. One breach exposes everything.
PyHSM gives those secrets a secure home — encrypted at rest, access-controlled, audited, and lifecycle-managed.
See how teams use PyHSM to protect what matters most.
Protect the encryption keys securing customer accounts, transaction signatures, and payment data.
Safeguard patient data, digital identities, and comply with HIPAA encryption requirements.
Sign blockchain transactions without ever exposing private keys to application code or disk.
Securely store API credentials, webhook secrets, and per-tenant encryption keys at scale.
Protect model credentials, inference API secrets, and sensitive customer data used in pipelines.
Manage device certificates and signing keys across distributed deployments without cloud dependency.
cryptography Library?Python's cryptography library gives you primitives. PyHSM gives you a complete key management system.
| Capability | cryptography library |
PyHSM |
|---|---|---|
| Encrypt / Decrypt | Yes (you manage keys yourself) | Yes (keys managed for you) |
| Key storage & encryption at rest | Not included | Double-encrypted keystore (AES-GCM + AES-KWP) |
| Key rotation | Build it yourself | Built-in with version tracking |
| Access control & caller identity | Not included | Caller ACLs, rate limits, operation caps |
| Audit logging | Not included | HMAC-chained tamper-evident log |
| Key lifecycle policies | Not included | Expiration, archival, destruction |
| Process isolation | Not included | Separate OS process for key material |
| Memory zeroization | Not included | Deterministic byte-by-byte clearing |
| Shamir secret sharing | Not included | M-of-N key reconstruction |
The cryptography library is a toolbox. PyHSM is the locksmith. PyHSM knows how to use the tools securely, manages the keys, tracks who accessed what, and ensures nothing is left exposed.
A complete key management system, not a wrapper around a single crypto library.
Industry-standard authenticated encryption with Argon2id key derivation following OWASP recommendations.
Split master keys into shares with configurable thresholds. No single point of compromise.
Tamper-evident audit trail with cryptographic chaining. Every operation is recorded and verifiable.
Full feature parity across Python and TypeScript. Use whichever fits your stack.
Built-in key expiration, operation limits, caller ACLs, and automated rotation support.
Known-Answer Tests against RFC vectors run automatically. Crypto primitives are verified before any operation.
PyHSM is free and open source. Priority support gives you direct access to the creator for implementation guidance, code review, and more.
For teams building on PyHSM that want ongoing expert guidance and priority access to the creator.
PyHSM is free to use. Support plans give you a direct line to the expert behind the code.
Clone the repo or pip install vectorguard-pyhsm. The code is MIT licensed, so use it freely in any project.
Full documentation, test suite, README.md, and OPERATIONS.md cover every security decision. Read the source. Audit it. It's your code now.
When you need implementation guidance or code review, get Priority Support or request a one-time consultation.
Deploy with confidence knowing the creator of PyHSM is available to review, advise, and help when things get complex.
A complete walkthrough showing how PyHSM encrypts a private key, splits the master password with Shamir secret sharing, and recovers it using the default Anvil private key.
0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80. This is the default Anvil (Foundry) test private key. Never use test keys in production.
First, we create a keystore and generate an AES-256 encryption key inside it. Then we encrypt the Anvil private key using that key. The master password protects the entire keystore. Without it, the encrypted data is useless.
vectorguard-pyhsm --store demo-keystore.enc generate vault-key --type aes-256 -p "demo-master-password"
# → Generated aes-256 key: vault-key
vectorguard-pyhsm --store demo-keystore.enc encrypt vault-key \
-d "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" \
-p "demo-master-password"
# → 0200000001f383ad67000000009a3d48dfa78fe787...(ciphertext)
The private key is now encrypted inside the keystore. The ciphertext output is the AES-256-GCM encrypted form of the key; it's completely useless without the master password. Even if an attacker steals the keystore file, they cannot recover the private key.
Now we eliminate the single point of failure. Instead of one person holding the master password, we split it into 5 shares using Shamir's Secret Sharing. Any 3 shares can reconstruct the password, but 2 or fewer reveal zero information. This is mathematically proven, not just computationally hard.
# Each ASCII character becomes its 2-digit hex code:
# 'd' = 64, 'e' = 65, 'm' = 6d, 'o' = 6f, '-' = 2d, 'm' = 6d, 'a' = 61, ...
#
# Full breakdown of "demo-master-password":
# d=64 e=65 m=6d o=6f -=2d m=6d a=61 s=73
# t=74 e=65 r=72 -=2d p=70 a=61 s=73 s=73
# w=77 o=6f r=72 d=64
#
# You can verify this with Python:
python3 -c "print('demo-master-password'.encode().hex())"
# → 64656d6f2d6d61737465722d70617373776f7264
The split command operates on hex-encoded byte strings. The hex value 64656d6f2d6d61737465722d70617373776f7264 is simply the ASCII encoding of "demo-master-password" represented in hexadecimal. Each character maps to its hex byte value (e.g., 'd' → 64, 'e' → 65, 'm' → 6d). This is not encryption or hashing; it's a direct, reversible encoding that the Shamir split algorithm requires as input.
vectorguard-pyhsm split -k 3 -n 5 -s "64656d6f2d6d61737465722d70617373776f7264"
# → Share 1: {"index": 1, "data": "d18a992fabfb5eb8e53689284a0f69f734d3312b"}
# → Share 2: {"index": 2, "data": "0985e4adb3d6b7e7c3e9a8fba6d4a5958b7628ae"}
# → Share 3: {"index": 3, "data": "bc6a10ed3540882c52ba53fe9cbabf11c8ca6be1"}
# → Share 4: {"index": 4, "data": "ce2a97e3180640240fce01c779af615d67ae9ba0"}
# → Share 5: {"index": 5, "data": "7bc563a39e907fef9e9dfac243c17bd92412d8ef"}
Distribute one share to each of 5 custodians. No single custodian (or even any 2) can reconstruct the password. Each share should be stored in a separate location — different password managers, different physical safes, or different geographic regions depending on your threat model.
When you need to decrypt (sign a transaction, recover the key, rotate credentials, etc.), you gather any 3 of the 5 custodians. Each provides their share, and the master password is reconstructed.
vectorguard-pyhsm reconstruct \
--share '{"index": 1, "data": "d18a992fabfb5eb8e53689284a0f69f734d3312b"}' \
--share '{"index": 3, "data": "bc6a10ed3540882c52ba53fe9cbabf11c8ca6be1"}' \
--share '{"index": 5, "data": "7bc563a39e907fef9e9dfac243c17bd92412d8ef"}'
# → 64656d6f2d6d61737465722d70617373776f7264 (hex of "demo-master-password")
Notice we used shares 1, 3, and 5 (any combination of 3 works). The reconstruction outputs the hex-encoded master password which is then used to unlock the keystore.
With the reconstructed master password, unlock the keystore and decrypt the original private key.
vectorguard-pyhsm --store demo-keystore.enc decrypt vault-key \
-d "0200000001f383ad67...(ciphertext)" \
-p "demo-master-password"
# → 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
The original private key is recovered exactly as it was. The audit log records every operation with HMAC-chained tamper detection; so you have a permanent, verifiable record of who decrypted what and when.
The private key is never stored in plaintext anywhere
The master password doesn't exist as a single secret (it's split across 5 people)
Any 2 or fewer shares reveal zero information (information-theoretic, not computational)
Every encrypt/decrypt operation is permanently recorded in the audit log
If someone tampers with the keystore file, PyHSM detects it and refuses to open
MIT licensed. Read every line. Security-conscious developers trust what they can verify.
You own the code, the keys, and the deployment. No cloud dependency, no per-operation fees.
AES-256-GCM, Argon2id, HKDF, HMAC-SHA256. No custom cryptography — only proven standards.
HMAC-chained audit logs, caller ID tracking, and architecture review sessions provide evidence for auditors.
Architecture, security, and design questions about PyHSM.
Vault solves a different problem at a different scale. It's a secrets management platform — it manages database credentials, API tokens, PKI certificates, and dynamic secrets across an organization. It requires Consul for HA, needs dedicated operators, and the Enterprise license for features like HSM auto-unseal costs six figures.
PyHSM is a focused key management library. You pip install it, import it in your code, and you have key generation, signing, encryption, and audit logging in five lines. There's no cluster to manage, no Consul dependency, no operator UI to secure, no HCL policy language to learn.
Use Vault if: You need org-wide secrets management with 50 services and dynamic credential rotation.
Use PyHSM if: You need to encrypt data or sign transactions from your application with proper key lifecycle management — without the operational overhead.
Additional distinction: Vault's Transit engine doesn't support secp256k1. If you're signing Ethereum or Bitcoin transactions, Vault can't do it natively. PyHSM can.
Short answer: PyHSM doesn't claim the key is impossible to extract. It makes extraction as difficult as possible within software constraints, and makes all access auditable.
The layers of defense:
bytearray (Python) or Buffer (Node.js) and deterministically zeroized byte-by-byte after each operation.hsm.sign() and get a signature back. The private key is unwrapped internally, used, and zeroized.export_jwk() exists for interoperability, but it's a deliberate call that gets logged in the audit trail.What PyHSM cannot prevent: A root-level attacker with memory debugging tools attached to the running HSM process during the microseconds of signing. That's what hardware HSMs solve with a physical trust boundary.
Key rotation generates a new key version and archives the old one. Old ciphertexts remain decryptable because the version number is embedded in the ciphertext format.
Mechanically:
os.urandom(32))archived: trueencrypt() calls use the new versiondecrypt() reads the version prefix from the ciphertext header and selects the matching key version automaticallyThis means you can rotate keys without re-encrypting your entire database. Old data decrypts with the old version, new data uses the new version.
Rotation is currently supported for AES keys. Asymmetric keys (EC, RSA, Ed25519) don't rotate in-place — you generate a new key ID and transition callers.
Each audit entry contains an HMAC that chains to the previous entry — similar to a blockchain of log records.
To tamper with entry N, an attacker would need to recompute the HMAC for entries N, N+1, N+2, ... all the way to the end. And to compute any HMAC, they need the audit HMAC key — which is derived from the master password via HKDF.
Verification walks the chain and checks every HMAC against its predecessor. If any entry was modified, inserted, or deleted, the chain breaks and verification reports the exact sequence number where corruption occurred.
The log is append-only — entries are never modified or deleted during normal operation. Every operation (including denied ones) is recorded with timestamp, operation type, key ID, caller ID, and success/failure status.
PyHSM provides the following guarantees:
What is explicitly NOT guaranteed: Protection against kernel-level access, CPU side-channel attacks, physical access to hardware, or compromised underlying crypto libraries.
PyHSM defends against five classes of threat actors:
In-scope: Filesystem theft, application compromise, unauthorized key usage, silent key abuse, insider threats with partial access, keystore tampering, audit log manipulation.
Out-of-scope (acknowledged): Root attacker with debugger during signing, CPU side-channels, physical hardware access, compromised OS kernel.
It depends on your constraints. Neither is universally better.
Use AWS KMS if: You're in a regulated environment requiring FIPS certification, you're already all-in on AWS, you don't need secp256k1/Ed25519, and you're fine with per-operation costs and network latency.
Use PyHSM if: You need secp256k1/Ed25519 signing (blockchain), you want to avoid per-operation costs at scale, you require data sovereignty, you want zero vendor lock-in, or your latency budget can't tolerate network round-trips for every operation.
Key differences: AWS KMS costs $1/key/month + $0.03/10K API calls and adds 5–50ms latency per operation. PyHSM is free (MIT), runs locally with sub-millisecond crypto latency, supports secp256k1 and Ed25519 (which KMS doesn't), and has no vendor lock-in — you can export keys in standard JWK format.
They're not mutually exclusive: Some teams use AWS KMS for general infrastructure encryption and PyHSM specifically for blockchain transaction signing where AWS has no native support.
Process isolation is the highest security configuration PyHSM offers within software constraints. It separates key material into a dedicated OS process that communicates with your application over a Unix domain socket (IPC).
Why it matters: Without isolation, an attacker who achieves Remote Code Execution (RCE) in your application can read anything in that process's memory — including any key material that happens to be unwrapped at that moment. With process isolation, the keys live in a separate address space. The attacker would need a kernel exploit to cross that boundary.
How it works:
/run/pyhsm/pyhsm.sock).Authentication: The client authenticates each request using an HMAC over the message payload with a shared caller secret (PYHSM_CALLER_SECRET). This prevents other processes on the same host from issuing unauthorized commands to the socket.
Trade-offs: Process isolation adds IPC latency (typically <1ms on localhost) and operational complexity (two processes to manage instead of one). For most deployments, this is negligible compared to the security gain.
In production, you don't want a single person (or a single .env file) holding the master password that unlocks all keys. PyHSM implements Shamir's Secret Sharing over GF(256) to split the master password into N shares where any K shares can reconstruct it — but K-1 or fewer reveal zero information about the secret.
Typical setup (3-of-5):
Security properties:
PYHSM_SHARES as a comma-separated list of JSON objects — each provided by a different secrets manager or operator.When to use Shamir: Any deployment where the master password represents a single point of failure — production systems, multi-team environments, regulatory contexts requiring separation of duties, or anywhere you need to survive the "hit by a bus" scenario.
This is by design — it's a security property of Shamir Secret Sharing, not a bug.
Why the shares differ each time: Shamir Secret Sharing works by generating a random polynomial of degree K-1 (where K is your threshold). The secret is the constant term (the y-intercept), but the other coefficients are randomly chosen each time you run split.
For a 3-of-5 split, PyHSM generates a random degree-2 polynomial:
f(x) = secret + a1*x + a2*x² (over GF(256))
secret is fixed (your master password bytes)a1 and a2 are randomly generated each timeThe shares are points on this polynomial: Share 1 = f(1), Share 2 = f(2), etc. Different random coefficients produce a different polynomial, which produces different shares — but the same y-intercept (your secret).
Why reconstruction still works: Any 3 points on a degree-2 polynomial uniquely determine that polynomial, and therefore uniquely determine f(0) — the secret. Your shares and someone else's shares are from different polynomials that pass through the same point at x=0.
Visual intuition:
f(x) = secret + 7x + 3x² → shares A, B, C, D, Eg(x) = secret + 2x + 9x² → shares V, W, X, Y, ZBoth f(0) = g(0) = secret. But f(1) ≠ g(1), f(2) ≠ g(2), etc.
Why this matters for security: This randomness is critical. If the same secret always produced the same shares, an attacker who saw shares from two different split ceremonies could cross-reference them. The random coefficients ensure that every split is independent — even if you split the same secret 1,000 times, the shares are completely different each time and reveal nothing about each other.
Yes — blockchain signing is one of PyHSM's primary use cases and a key differentiator from cloud KMS solutions like AWS KMS or Google Cloud KMS, which don't support secp256k1 or Ed25519.
Supported blockchain ecosystems:
How it works in practice:
hsm.sign("eth-wallet", tx_hash).(r, s, v) and broadcasts.Security advantages over raw key files:
.env file — it's double-encrypted and requires the master password (or M-of-N Shamir shares) to unlock.max_operations policies prevent unlimited signing even if the application is compromised.Production considerations: Latency is ~103ms per sign operation (dominated by keystore persistence). For high-frequency use cases, consider the TypeScript layer's deferred persistence mode. For cold wallets or treasury keys, combine with Shamir 3-of-5 so no single operator can unlock the signing key.
Ready to secure your key management? Let's talk about which plan fits your team.
We respond to all inquiries within 1 business day.