Bring Your Own Key (BYOK) Secure Storage
Relevant source files
The following files were used as context for generating this wiki page:
- README.md
- VOXTRAL_KEYBOARD_PLAN.md
- VOXTRAL_FEATURE_SCOPE.md
- app/src/main/kotlin/dev/patrickgold/florisboard/app/settings/advanced/BackupScreen.kt
- app/src/main/res/values/strings.xml
- app/src/main/kotlin/dev/patrickgold/florisboard/ime/text/dictation/VoxtralSecretsStore.kt
- app/src/main/kotlin/dev/patrickgold/florisboard/ime/text/rewrite/LlmRewriteSecretsStore.kt
Ownkey Keyboard implements a privacy-first "Bring Your Own Key" (BYOK) model, allowing users to integrate their own AI service providers for features like ASR (Automatic Speech Recognition) and LLM-based text rewriting. To maintain high security standards, these sensitive API keys are never stored in plaintext and are protected by hardware-backed encryption.
The secure storage system ensures that while the keyboard can access networked AI services, the user's credentials remain local, encrypted, and isolated from standard application backups to prevent accidental leakage.
Sources: README.md:10-15, VOXTRAL_KEYBOARD_PLAN.md:14-22
Secure Storage Architecture
The architecture relies on the Android Keystore system to provide encrypted preferences. Sensitive secrets are managed by dedicated store classes that interface with hardware-backed security modules when available.
Secret Management Classes
The system utilizes specialized singleton objects to manage different types of AI credentials:
VoxtralSecretsStore: Manages API keys for Mistral Voxtral ASR and voice dictation services.LlmRewriteSecretsStore: Manages API keys for LLM rewriting features (e.g., OpenAI, Anthropic, or Mistral).
Sources: app/src/main/kotlin/dev/patrickgold/florisboard/ime/text/dictation/VoxtralSecretsStore.kt, app/src/main/kotlin/dev/patrickgold/florisboard/ime/text/rewrite/LlmRewriteSecretsStore.kt
Storage Mechanism Flow
The following diagram illustrates the flow of a secret from user input to secure local storage:
Data Protection and Sanitization
A critical pillar of the secure storage system is the prevention of secret leakage during data export or migration.
Backup Sanitization
When a user generates a backup archive of keyboard settings, the backup engine explicitly identifies and filters out sensitive preference keys. This ensures that API keys are not included in the exported .zip files.
| Component | Target Secret Key | Action during Backup |
|---|---|---|
| Voxtral ASR | voxtral__api_key | Stripped from backup |
| LLM Rewrite | llm_rewrite__api_key | Stripped from backup |
Sources: app/src/main/kotlin/dev/patrickgold/florisboard/app/settings/advanced/BackupScreen.kt:47-58
Code Implementation: Sanitization Logic
// From BackupScreen.kt
private val SENSITIVE_PREF_KEYS = setOf(
"voxtral__api_key",
)
fun sanitizeJetprefBackupFile(file: java.io.File) {
if (!file.exists()) return
val sanitized = file.readLines().filterNot { line ->
SENSITIVE_PREF_KEYS.any { key -> line.startsWith("s;$key;") }
}
file.writeText(sanitized.joinToString(separator = "\n", postfix = "\n"))
}
Sources: app/src/main/kotlin/dev/patrickgold/florisboard/app/settings/advanced/BackupScreen.kt:47-64
User Interface and Feedback
The settings UI is designed to communicate the secure nature of the storage to the user, providing clear status updates without ever revealing the saved key.
Configuration Elements
| UI Label | Description | Secure Behavior |
|---|---|---|
| API key | Text field for entering the provider key. | Input is hidden after saving; cannot be viewed again. |
| Status: Saved | "API key is saved securely." | Displayed when a valid key is present in encrypted storage. |
| Clear Action | Button to remove the key. | Completely wipes the ciphertext from the secure preferences. |
Sources: app/src/main/res/values/strings.xml:444-453, app/src/main/res/values/strings.xml:466-473
Privacy Model Sequence
The following sequence diagram shows the interaction between the user and the secure storage during the setup of a new AI provider:
Summary of Secured Components
The secure storage module currently handles the following credentials:
- Mistral API Keys: Used for the default Voxtral ASR path (
/v1/audio/transcriptions). - Generic LLM Keys: Used for selected-text rewrite functionality across various providers.
- Legacy Migrations: The system automatically detects legacy plaintext keys from previous versions, migrates them to the secure store, and removes the original plaintext values.
Sources: README.md:33-35, VOXTRAL_KEYBOARD_PLAN.md:27-35, VOXTRAL_FEATURE_SCOPE.md:46-50