Bailey is a small, opinionated Clojure library for managing server-side encryption keys with strong operational safety.
Bailey was originally developed to meet the internal security and operational requirements of Sturdy Statistics. It is published as open source to support transparency, auditability, and reuse, but its design is intentionally conservative and driven by real production needs. We may not accept feature requests that dilute its focus.
It is designed for applications that need:
Bailey does not implement cryptographic primitives. It uses the well-reviewed library Tempel to implement a robust, auditable key lifecycle.
Add to deps.edn:
{:deps {com.sturdystats/bailey {:mvn/version "VERSION"}}}
Bailey is built around a few explicit goals:
Separation of mechanism and policy Bailey provides how keys are managed, not who owns them or where secrets come from.
Recoverability without fragility
Routine encrypted data remains recoverable if the server or its TPM-bound password is lost, provided the caller retains an intact backup of the encrypted server keychain. Data encrypted with encrypt-critical remains recoverable even if every copy of the server keychain is lost.
Operational clarity All key material has a clear lifecycle:
Auditability The logic for key handling is small, explicit, and readable. This library is intended to simplify security reviews, not complicate them.
Bailey manages three distinct layers of keys:
This key can recover an intact encrypted server keychain without its TPM-bound password.
It can also recover encrypt-critical ciphertext directly if the server keychain is lost.
This keychain is recoverable using the offline backup key. The caller is responsible for backing up the encrypted keychain file. Ordinary ciphertext cannot be recovered if every copy of this file is deleted or irreparably corrupted.
Bailey assumes you control:
Bailey deliberately supports a narrow deployment model:
init! exactly once during JVM startup. A repeated call is rejected, and any initialization failure must be treated as fatal to application startup.If an application needs active/active access to shared key files, non-POSIX portability, or embedded backup-key administration, Bailey is not currently the right lifecycle manager.
Bailey is designed with the following assumptions:
encrypt-critical data remains recoverable without the server keychainRun once, offline from a trusted workstation, in a dedicated process:
(bailey.core/generate-backup-keys!
{:secrets-dir "secrets" ;; secure, offline storage
:resources-dir "resources"}) ;; public key embedded in app
(bailey.core/init!
{:keychain-path "var/bailey/keychain.encrypted"
:read-server-password!!
(fn []
;; must return a fresh byte[] each call; result zero'd in place after use
(read-tpm-sealed-secret))})
This will:
Call init! exactly once in a JVM lifecycle.
A second call is rejected.
If initialization throws for any reason, abort application startup rather than continuing without Bailey.
(def ciphertext
(bailey.core/encrypt (.getBytes "secret data")))
(def plaintext
(bailey.core/decrypt ciphertext))
Ordinary encryption uses the symmetric keys in the server keychain. The caller must keep a durable backup of the encrypted keychain file; the offline key can unlock that backup if the TPM password or server is lost.
For especially critical data:
(bailey.core/encrypt-critical (.getBytes "critical config"))
This adds asymmetric backup encryption so the data is recoverable even if every copy of the server keychain is lost or corrupted. It incurs significant ciphertext-size overhead, so use it when recovery without the keychain is required.
(bailey.core/rotate-keys! read-tpm-sealed-secret)
Bailey provides explicit recovery tools intended for offline, administrative use.
Given:
You can recover the server keychain and decrypt protected data without access to the original server.
The encrypted server keychain is a required recovery artifact for ordinary ciphertext.
Bailey does not back it up; the caller must retain an intact copy on durable storage.
encrypt-critical ciphertext is the exception and can be recovered directly with the offline backup keychain and password.
This is a deliberate, manual process by design.
Apache License 2.0
Copyright © Sturdy Statistics
Can you improve this documentation?Edit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |