Class KeyringStore
- All Implemented Interfaces:
AutoCloseable, Destroyable
A keyring uses PBKDF2-HMAC-SHA-256 to unwrap one random 256-bit store master key. Every entry and the ordered manifest are independently protected by AES-256-GCM. Java class names are neither persisted nor resolved. Import mappings come exclusively from a closed mapping to the immutable algorithm registry. Provider names are not persisted: standard key encodings are reconstructed by the current runtime's canonical importer. HMAC persistence admits only HmacSHA256, HmacSHA384, and HmacSHA512.
The keyring exclusively owns its filesystem path from successful
create(Path, KeyringPassword) or
open(Path, KeyringPassword) until close(). Only POSIX
filesystems on which owner-only permissions and ownership can be verified are
supported. Mutations replace a complete encrypted image atomically.
The nonce-reservation sidecar is authenticated independently from AES entry
and manifest encryption. Its 256-bit MAC key is derived from the store master
key and binary store UUID with HKDF-HMAC-SHA-256 and the fixed domain label
zeroecho:keyring:nonce-reservation-mac:v1. The derived key is
retained only while the store is open and is cleared on close. Previous
sidecar versions are rejected.
Instances are thread-safe. Reads may proceed concurrently; mutations and close are exclusive. Closing clears the master and sidecar MAC keys and makes all subsequent operations fail. The pre-release plaintext format is rejected and is not migrated.
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic enumStandard encoded key forms supported by the encrypted store.static enumKey classifications supported by the encrypted store.static final recordAlgorithm identifier paired with an imported private key.static final recordAlgorithm identifier paired with an imported public key.static final recordAlgorithm identifier paired with an imported secret key. -
Method Summary
Modifier and TypeMethodDescriptionaliases()Returns aliases in their persisted order.voidclose()Closes the keyring, clearing its master key.booleanReports whether an alias is present.static KeyringStorecreate(Path path, KeyringPassword password) Creates a new encrypted keyring with the standard protection policy.static KeyringStorecreate(Path path, KeyringPassword password, KeyringProtection protection) Creates a new encrypted keyring.voiddestroy()Clears the master and nonce-reservation MAC keys and releases filesystem ownership.generateStatefulKey(String alias, String algorithmId, LocalStatefulSigningAuthority authority) Generates and enrolls a new default LMS or XMSS key under an independently preserved local authority.getPrivate(String alias) Resolves a private key.getPrivateWithId(String alias) Resolves a private key and its canonical algorithm identifier.Resolves a public key.getPublicWithId(String alias) Resolves a public key and its canonical algorithm identifier.Resolves a secret key.getSecretWithId(String alias) Resolves a secret key and its canonical algorithm identifier.booleanReports whether the keyring has been destroyed.static KeyringStoreopen(Path path, KeyringPassword password) Opens an encrypted keyring with the standard protection policy.static KeyringStoreopen(Path path, KeyringPassword password, KeyringProtection protection) Opens an encrypted keyring.voidputKeyPairIfAbsent(String alias, String algorithmId, KeyPair pair) Inserts both canonical key encodings in one durable encrypted snapshot.voidputPrivate(String alias, String algorithmId, PrivateKey key) Adds or replaces an encoded private key and persists the mutation.voidAdds or replaces an encoded public key and persists the mutation.voidAdds or replaces an encoded secret key and persists the mutation.booleanremoveAlias(String alias) Removes one logical secret alias or all existing components of its pair in one durable snapshot, preserving all other entries and their order.statefulSigner(String alias, LocalStatefulSigningAuthority authority) Resolves an explicit durable signing capability for an enrolled key.byte[]zeroEchoSigningConfigurationTag(String workflowId, Duration operationHorizon, String keyRefPrefix, boolean requireComponentSuffix) Computes the stable ZeroEcho signing-configuration tag for this keyring.
-
Method Details
-
create
public static KeyringStore create(Path path, KeyringPassword password) throws IOException, GeneralSecurityException Creates a new encrypted keyring with the standard protection policy.- Parameters:
path- new keyring filepassword- borrowed unlock password; the caller remains responsible for destroying it- Returns:
- open encrypted keyring
- Throws:
IOException- if secure creation or durable persistence failsGeneralSecurityException- if cryptographic initialization fails
-
create
public static KeyringStore create(Path path, KeyringPassword password, KeyringProtection protection) throws IOException, GeneralSecurityException Creates a new encrypted keyring.- Parameters:
path- new keyring filepassword- borrowed unlock passwordprotection- operational protection policy- Returns:
- open encrypted keyring
- Throws:
IOException- if secure creation or durable persistence failsGeneralSecurityException- if cryptographic initialization fails
-
open
public static KeyringStore open(Path path, KeyringPassword password) throws IOException, GeneralSecurityException Opens an encrypted keyring with the standard protection policy.- Parameters:
path- keyring filepassword- borrowed unlock password- Returns:
- open encrypted keyring
- Throws:
IOException- if the format, filesystem, or authentication check failsGeneralSecurityException- if cryptographic initialization fails
-
open
public static KeyringStore open(Path path, KeyringPassword password, KeyringProtection protection) throws IOException, GeneralSecurityException Opens an encrypted keyring.- Parameters:
path- keyring filepassword- borrowed unlock passwordprotection- operational protection policy- Returns:
- open encrypted keyring
- Throws:
IOException- if the format, filesystem, or authentication check failsGeneralSecurityException- if cryptographic initialization fails
-
generateStatefulKey
public PublicKey generateStatefulKey(String alias, String algorithmId, LocalStatefulSigningAuthority authority) throws IOException, GeneralSecurityException Generates and enrolls a new default LMS or XMSS key under an independently preserved local authority. Existing aliases and imported keys cannot enroll. The caller owns the authority; the keyring never closes it. Enrollment is fenced before key insertion and becomes usable only after both key entries and the READY authority record are durable. Partial enrollment fails closed. Keep the authority outside the keyring directory and every backup root. Only the algorithm's default key-generation parameters are supported by this enrollment API. Exhaustion durably removes the private entry while preserving the public key for verification; private-key retrieval then becomes unavailable. Existing imported keys cannot be enrolled.- Parameters:
alias- unused logical alias without a key-type suffixalgorithmId- registered stateful algorithm identifierauthority- open independent local authority- Returns:
- generated public key; the private key is retained by the keyring
- Throws:
IOException- if enrollment or durable persistence failsGeneralSecurityException- if generation or authentication failsIllegalArgumentException- if the alias already exists or is invalidNullPointerException- if authority is null
-
statefulSigner
public StatefulSigner statefulSigner(String alias, LocalStatefulSigningAuthority authority) throws IOException, GeneralSecurityException Resolves an explicit durable signing capability for an enrolled key. No missing authority record is created or reconstructed. Each future operation revalidates the current state under both ownership locks.- Parameters:
alias- enrolled logical aliasauthority- same independently preserved authority used for generation- Returns:
- handle borrowing this keyring and authority
- Throws:
IOException- if enrollment is missing, stale, pending or mismatchedGeneralSecurityException- if key import/authentication fails
-
putPublic
public void putPublic(String alias, String algorithmId, PublicKey key) throws IOException, GeneralSecurityException Adds or replaces an encoded public key and persists the mutation.- Parameters:
alias- logical aliasalgorithmId- canonical registered algorithm identifierkey- exportable public key- Throws:
IOException- if validation or durable persistence failsGeneralSecurityException- if entry encryption fails
-
putPrivate
public void putPrivate(String alias, String algorithmId, PrivateKey key) throws IOException, GeneralSecurityException Adds or replaces an encoded private key and persists the mutation.- Parameters:
alias- logical aliasalgorithmId- canonical registered algorithm identifierkey- exportable private key- Throws:
IOException- if validation or durable persistence failsGeneralSecurityException- if entry encryption fails
-
putSecret
public void putSecret(String alias, String algorithmId, SecretKey key) throws IOException, GeneralSecurityException Adds or replaces an encoded secret key and persists the mutation.- Parameters:
alias- logical aliasalgorithmId- canonical registered algorithm identifierkey- exportable secret key- Throws:
IOException- if validation or durable persistence failsGeneralSecurityException- if entry encryption fails
-
putKeyPairIfAbsent
public void putKeyPairIfAbsent(String alias, String algorithmId, KeyPair pair) throws IOException, GeneralSecurityException Inserts both canonical key encodings in one durable encrypted snapshot. Both keys and the registered algorithm are validated before reserving any nonce. Validation checks canonical representation, not mathematical pairing. Existing single-component put methods retain their replacement semantics.Only nonblank unsuffixed logical aliases are accepted. Any existing entry in the alias's suffix namespace (including incomplete pairs and legacy mixed suffix chains) makes it occupied. No existing entry is replaced. Mutations and close are serialized; readers cannot observe a partial pair. A failed prepublication write leaves no component visible; after uncertain publication this instance refuses further use until reopened. Reopening exposes either the entire pair or neither component.
- Parameters:
alias- unused logical alias, without .pub or .priv suffixalgorithmId- canonical registered asymmetric algorithm identifierpair- pair with non-null, exportable public and private keys- Throws:
IllegalArgumentException- if the alias is null, blank, suffixed or occupiedNullPointerException- if the pair or either component is nullIOException- if alias or metadata UTF-8 limits are exceeded (KEYRING_LIMIT_EXCEEDED), validation, nonce reservation or persistence fails; KEYRING_CLOSED after close, KEYRING_DURABILITY_UNCONFIRMED on an uncertain publication (the caller must close and reopen)GeneralSecurityException- if canonical validation or encryption fails
-
removeAlias
Removes one logical secret alias or all existing components of its pair in one durable snapshot, preserving all other entries and their order. This is logical deletion; old storage blocks and backups are not erased.Accepts only nonblank aliases without .pub or .priv suffixes. Legacy suffix chains or conflicting secret/pair entries make the namespace ambiguous and are rejected without mutation. Stateful signing algorithms, including exhausted public-only entries, require a separate authority contract and cannot be removed here. Mutations and close are serialized. On uncertain I/O the instance refuses further use until reopened; reopening exposes either the original alias or its complete removal.
- Parameters:
alias- unsuffixed logical alias- Returns:
- true if an alias was durably removed; false if absent, with no write
- Throws:
IllegalArgumentException- if the alias is null, blank, suffixed or its namespace is ambiguousIOException- if the alias UTF-8 limit is exceeded (KEYRING_LIMIT_EXCEEDED), persistence fails, the store is closed (KEYRING_CLOSED), or stateful authority is required (KEYRING_STATEFUL_RECOVERY_REQUIRED); uncertain publication reports KEYRING_DURABILITY_UNCONFIRMED and requires close and reopenGeneralSecurityException- if reindexing encryption fails
-
contains
Reports whether an alias is present.- Parameters:
alias- logical or suffixed alias- Returns:
trueif a matching entry exists- Throws:
IllegalStateException- after close
-
aliases
Returns aliases in their persisted order.- Returns:
- independent alias list
- Throws:
IllegalStateException- after close
-
zeroEchoSigningConfigurationTag
public byte[] zeroEchoSigningConfigurationTag(String workflowId, Duration operationHorizon, String keyRefPrefix, boolean requireComponentSuffix) throws GeneralSecurityException Computes the stable ZeroEcho signing-configuration tag for this keyring.The tag is HMAC-SHA-256 under a store-specific key derived from the keyring master key and store UUID. Its canonical transcript binds the resolved workflow identifier, operation horizon, key-reference prefix, component-suffix policy, and the ordered identities, metadata, ciphertext lengths, and ciphertext digests of all effective keyring entries. Paths, passwords, salts, nonces, counters, timestamps, plaintext keys, and raw ciphertext are excluded.
The returned 32-byte array is newly owned by the caller. This method is thread-safe, runs in O(n + b) time for
nentries andbbytes of included metadata, and uses O(b) temporary memory. All temporary transcript and derived-key bytes are cleared before return.- Parameters:
workflowId- stable resolved workflow identifier; never blankoperationHorizon- resolved positive operation horizonkeyRefPrefix- resolved non-blank key-reference prefixrequireComponentSuffix- resolved component-suffix policy- Returns:
- newly owned 32-byte signing-configuration tag
- Throws:
IllegalArgumentException- if an effective configuration value is invalidIllegalStateException- if the keyring is closed or poisonedGeneralSecurityException- if HMAC-SHA-256 is unavailable
-
getPublicWithId
public KeyringStore.PublicWithId getPublicWithId(String alias) throws IOException, GeneralSecurityException Resolves a public key and its canonical algorithm identifier.- Parameters:
alias- logical alias- Returns:
- imported key and algorithm
- Throws:
IOException- if the entry cannot be authenticatedGeneralSecurityException- if decryption or import fails
-
getPrivateWithId
public KeyringStore.PrivateWithId getPrivateWithId(String alias) throws IOException, GeneralSecurityException Resolves a private key and its canonical algorithm identifier.- Parameters:
alias- logical alias- Returns:
- imported key and algorithm
- Throws:
IOException- if the entry cannot be authenticatedGeneralSecurityException- if decryption or import fails
-
getSecretWithId
public KeyringStore.SecretWithId getSecretWithId(String alias) throws IOException, GeneralSecurityException Resolves a secret key and its canonical algorithm identifier.- Parameters:
alias- logical alias- Returns:
- imported key and algorithm
- Throws:
IOException- if the entry cannot be authenticatedGeneralSecurityException- if decryption or import fails
-
getPublic
Resolves a public key.- Parameters:
alias- logical alias- Returns:
- imported public key
- Throws:
IOException- if the entry cannot be authenticatedGeneralSecurityException- if decryption or import fails
-
getPrivate
Resolves a private key.- Parameters:
alias- logical alias- Returns:
- imported private key
- Throws:
IOException- if the entry cannot be authenticatedGeneralSecurityException- if decryption or import fails
-
getSecret
Resolves a secret key.- Parameters:
alias- logical alias- Returns:
- imported secret key
- Throws:
IOException- if the entry cannot be authenticatedGeneralSecurityException- if decryption or import fails
-
destroy
Clears the master and nonce-reservation MAC keys and releases filesystem ownership.Concurrent calls are safe and cleanup occurs exactly once.
- Specified by:
destroyin interfaceDestroyable- Throws:
DestroyFailedException- if resource release fails
-
isDestroyed
public boolean isDestroyed()Reports whether the keyring has been destroyed.- Specified by:
isDestroyedin interfaceDestroyable- Returns:
trueafter close or destruction
-
close
public void close()Closes the keyring, clearing its master key.- Specified by:
closein interfaceAutoCloseable
-