Expand description
Overridable, per-platform secure storage for a node key.
NodeKey::save/load
write an owner-only key file, which suits a server or a desktop. A mobile
app keeps its key in the platform’s secure store instead: this module is
a small KeyStore trait plus KeyringStore, a
default implementation backed by the keyring crate, which selects the
actual native secure store per target automatically —
Keychain (Security.framework) on macOS and iOS, Secret Service (D-Bus)
on Linux, Credential Manager on Windows, and the Android Keystore (via
JNI) on Android. Nothing in this crate branches on target platform
itself; keyring’s own Cargo.toml does that selection via per-target
optional dependencies (see keyring = 4.2.0’s manifest), and the
backend that ends up linked is what actually runs.
KeyStore itself is deliberately not tied to keyring at all — a
caller with a different secure-storage requirement (a hardware security
module, a different vault) can implement the trait directly and hand it
to NodeKey::save_to_keystore/
load_from_keystore —
“overridable per target platform” is a property of the trait boundary,
not something wired into this crate’s own logic.
§Android setup, required once per app, not something this crate can do for you
android-native-keyring-store (the backend keyring links in for
Android, confirmed via its own Cargo.toml: jni + ndk-context)
needs the embedding app to hand it a JNI Context once at startup,
because Android’s Keystore is a Java API with no NDK surface — there is
no way for Rust code alone to reach it. That crate ships its own JNI
export for exactly this (confirmed in its README, not assumed): once
this crate is linked into an Android .so, that export is present
automatically, and the Kotlin side calls it once, e.g. from
MainActivity.onCreate:
package io.crates.keyring
class Keyring {
companion object {
init { System.loadLibrary("your_actual_library_name") }
external fun initializeNdkContext(context: Context)
}
}
// in onCreate:
Keyring.initializeNdkContext(this.applicationContext)No custom UniFFI foreign-trait bridge is needed for Android or iOS —
both have first-party keyring backends, confirmed by reading
keyring 4.2.0’s own Cargo.toml target-cfg dependency blocks
directly, not assumed from the crate’s name.
§A second Linux backend, LinuxKeyutilsStore
KeyringStore’s Linux path (keyring’s v1 API) unconditionally uses
the D-Bus Secret Service, which requires a running provider
(gnome-keyring, KWallet) — absent on headless boxes, containers, and
this crate’s own dev sandbox (confirmed directly: a D-Bus session
socket exists here, but no org.freedesktop.secrets provider is
listening on it, so KeyringStore::new returns
KeyStoreError::Backend with NoDefaultStore). LinuxKeyutilsStore
uses the kernel’s own keyutils facility instead, always available on
Linux — this is exactly what lets this module’s own tests verify a
real save/load/delete round trip in this environment.
Structs§
- Keyring
Store - The default
KeyStore: the platform-native secure storekeyringselects for the current target (see this module’s own doc).serviceandaccountare the same two strings everykeyringconsumer already uses to address one credential — pick values scoped to this application, e.g.("com.example.myapp", "macula-identity"), since the underlying stores are shared OS-wide facilities, not sandboxed to this crate. - Linux
Keyutils Store - A second, independently-selectable
KeyStorebackend — proof that the trait boundary is genuinely overridable, not merely declared to be: the kernel’s ownkeyutilsfacility, no D-Bus/secret-service daemon required. This is whatKeyringStore’s underlyingkeyringdependency itself recommends for headless Linux (containers, CI, a sandboxed dev box with nognome-keyring/kwalletdrunning) — seelinux-keyutils-keyring-store’s own module doc, which states this outright.
Enums§
Traits§
- KeyStore
- Secure storage for one node key, as the bytes of its key file (the seed
form: the ML-DSA-87 seed, and in pq_hybrid the RSA-PSS key too, a few KiB).
Implement this directly for a backend other than
KeyringStore(a hardware security module, a different vault) — this is the override point “per target platform” hangs off, not a platform enum this crate switches on internally.