Key-value storage suits tokens. Records, such as a reader's private notes, belong in a database, and @capacitor-community/sqlite (8.1.1, MIT, github.com/capacitor-community/sqlite (https://github.com/capacitor-community/sqlite 663 )) encrypts whole databases with SQLCipher 4.17.0 566,000 on Android. With CapacitorSQLite: { androidIsEncryption: true } in capacitor.config.ts, a connection opened in secret mode is encrypted with a passphrase the plugin keeps for you:
const sqlite = new SQLiteConnection(CapacitorSQLite);
export async function vault() {
const { result: hasSecret } = await sqlite.isSecretStored();
if (!hasSecret) await sqlite.setEncryptionSecret(crypto.randomUUID()); // kept by the plugin
const db = await sqlite.createConnection('notes', true, 'secret', 1, false);
await db.open();
await db.execute('CREATE TABLE IF NOT EXISTS notes (id INTEGER PRIMARY KEY, text TEXT)');
await db.run('INSERT INTO notes (text) VALUES (?)', ['Lend Salt and Saffron to Sam']);
const { values } = await db.query('SELECT count(*) AS notes FROM notes');
await sqlite.closeConnection('notes', false);
return show('vault', values[0]);
}Two taps logged LAB vault {"notes":1} and {"notes":2}. A plain SQLite 4,756 file starts with the text SQLite format 3; this one does not, and the note is nowhere in it:
DB="run-as com.example.booknest cat databases/notesSQLite.db"
adb -s emulator-5558 exec-out $DB | head -c 48 | xxd
adb -s emulator-5558 exec-out $DB | grep -c Sam00000000: b369 7d97 d5e9 6e61 e625 9e05 8cbe 54bd .i}...na.%....T. 00000010: f622 bc5b 188d 4aa4 9cfe 0803 2947 2c28 .".[..J.....)G,( 00000020: f76f 1f41 4a49 ce43 5624 1b8b a672 d769 .o.AJI.CV$...r.i 0
The random passphrase sits in sqlite_encrypted_shared_prefs.xml, written through the deprecated EncryptedSharedPreferences (security-crypto 1.1.0-alpha06 in the plugin's build.gradle), which works but is worth watching in the plugin's changelog.
For secrets that need the user's presence, the key itself must require authentication: the same plugin's androidBiometric: { biometricAuth: true } builds its master key with setUserAuthenticationRequired, and Capawesome 178,914 's Vault and the MIT @aparajita/capacitor-biometric-auth (10.0.0) offer the same (not run here: no enrolled fingerprint). A biometric prompt alone, without such a key, is a UI check a patched app can skip.