Implement the Android Keystore secure-secret adapter for Rust storage #93

Open
opened 2026-08-17 19:10:20 +00:00 by hugo · 0 comments
Owner

Goal

Provide Android-native protected storage for HTTPS Git credentials and optional GPG-passphrase enrollment while leaving identity, protection policy, and secret lifecycle decisions in crates/storage.

Scope

  • Implement a narrow Kotlin platform adapter backed by Android Keystore AES-GCM keys and app-private ciphertext records; expose it to Rust through the reviewed UniFFI callback boundary.
  • Map storage protection classes to Android behavior: device-unlocked storage for Git application credentials, explicit user-presence/current-biometric-set protection for enrolled OpenPGP passphrases, and unsupported-policy errors when the device cannot meet the contract.
  • Use KeyGenParameterSpec, KeyProperties, KeyguardManager, and authentication-bound cipher operations. Prefer StrongBox only when available and tested; absence must not make supported devices unusable.
  • Bind protected GPG-passphrase keys to the current biometric enrollment and secure lock state so enrollment changes or lock-screen removal invalidate them and require manual recovery.
  • Store no secret in DataStore, SharedPreferences, Room, config TOML, logs, saved state, Bundle, clipboard, or generated Kotlin record longer than the operation requires.
  • Define create/retrieve/replace/delete, alias derivation, corruption, duplicate, cancellation, denial, invalidation, device migration/restore, and orphan cleanup semantics.
  • Zero/minimize transient byte arrays on both sides where APIs permit and ensure errors/debug strings are redacted.
  • Do not use deprecated AndroidX Security Crypto EncryptedSharedPreferences or MasterKey.

Acceptance criteria

  • Git credentials can be retrieved while the device meets the device-unlocked policy without exposing them to UI code.
  • Enrolled passphrase retrieval requires the configured biometric/user-presence flow and cannot silently fall back to weaker authentication.
  • Adding/removing biometrics, removing the secure lock screen, backup restore without the Keystore key, cancellation, lockout, and ciphertext tampering fail closed with typed Rust-visible errors.
  • Disabling biometric unlock deletes its protected record; replacing a token never creates a readable ordinary-settings copy.
  • Rust mock tests and Android instrumented Keystore tests cover all operations and policy mappings.

Depends on #88, the platform-neutral contract issue, and Android private-path integration. Part of #87.

## Goal Provide Android-native protected storage for HTTPS Git credentials and optional GPG-passphrase enrollment while leaving identity, protection policy, and secret lifecycle decisions in `crates/storage`. ## Scope - Implement a narrow Kotlin platform adapter backed by Android Keystore AES-GCM keys and app-private ciphertext records; expose it to Rust through the reviewed UniFFI callback boundary. - Map storage protection classes to Android behavior: device-unlocked storage for Git application credentials, explicit user-presence/current-biometric-set protection for enrolled OpenPGP passphrases, and unsupported-policy errors when the device cannot meet the contract. - Use `KeyGenParameterSpec`, `KeyProperties`, `KeyguardManager`, and authentication-bound cipher operations. Prefer StrongBox only when available and tested; absence must not make supported devices unusable. - Bind protected GPG-passphrase keys to the current biometric enrollment and secure lock state so enrollment changes or lock-screen removal invalidate them and require manual recovery. - Store no secret in DataStore, SharedPreferences, Room, config TOML, logs, saved state, Bundle, clipboard, or generated Kotlin record longer than the operation requires. - Define create/retrieve/replace/delete, alias derivation, corruption, duplicate, cancellation, denial, invalidation, device migration/restore, and orphan cleanup semantics. - Zero/minimize transient byte arrays on both sides where APIs permit and ensure errors/debug strings are redacted. - Do not use deprecated AndroidX Security Crypto `EncryptedSharedPreferences` or `MasterKey`. ## Acceptance criteria - Git credentials can be retrieved while the device meets the device-unlocked policy without exposing them to UI code. - Enrolled passphrase retrieval requires the configured biometric/user-presence flow and cannot silently fall back to weaker authentication. - Adding/removing biometrics, removing the secure lock screen, backup restore without the Keystore key, cancellation, lockout, and ciphertext tampering fail closed with typed Rust-visible errors. - Disabling biometric unlock deletes its protected record; replacing a token never creates a readable ordinary-settings copy. - Rust mock tests and Android instrumented Keystore tests cover all operations and policy mappings. Depends on #88, the platform-neutral contract issue, and Android private-path integration. Part of #87.
hugo added this to the 06 - Implement an Android version of the software milestone 2026-08-17 19:10:20 +00:00
hugo added the enhancement label 2026-08-17 19:10:20 +00:00
Sign in to join this conversation.