Encrypted databases
Skill almasumdev/awesome-mobile-security-agent-skills/.github/skills/storage/encrypted-databases
Agent skills for securing mobile apps: storage, transport, auth, obfuscation, and hardening.
npx -y skills add almasumdev/awesome-mobile-security-agent-skills --skill encrypted-databasesAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 2 stars2 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Encrypting local databases on mobile with SQLCipher, Room + EncryptedFile, or Realm encryption. Use when persisting structured sensitive data on device.
SKILL.md
3.8 KB, as published. Nobody here has run it
Encrypted Databases on Mobile
Instructions
Plain SQLite and plain Realm files are readable by anyone with filesystem access — including forensic tools and, on rooted/jailbroken devices, other apps. Encrypt at rest for anything sensitive.
1. When to Encrypt
Encrypt when the DB contains:
- Session tokens, refresh tokens, or API credentials.
- PII (email, phone, address, national IDs).
- Financial / health records.
- User-generated content marked private.
Do not encrypt purely public / cached content; it wastes CPU and complicates debugging.
2. Key Management (The Actual Hard Part)
- Generate a random 256-bit key once per install.
- Wrap it with a keystore-backed key (Android Keystore / iOS Keychain).
- Store the wrapped blob in
EncryptedSharedPreferences/ Keychain. - Never derive the DB key from a constant string or from
android_id.
3. Android: Room + SQLCipher
// build.gradle.kts
// implementation("net.zetetic:sqlcipher-android:4.6.1")
// implementation("androidx.sqlite:sqlite:2.4.0")
val passphrase: ByteArray = KeyStoreHelper.loadOrCreateDbKey() // 32 bytes
val factory = SupportOpenHelperFactory(passphrase, null, false)
val db = Room.databaseBuilder(ctx, AppDatabase::class.java, "app.db")
.openHelperFactory(factory)
.build()
// Zero the passphrase as soon as Room has it.
passphrase.fill(0)
4. Android: Room + EncryptedFile (Alternative)
For small stores where full-text queries are not required, use Jetpack EncryptedFile:
val file = EncryptedFile.Builder(
ctx, File(ctx.filesDir, "notes.bin"), masterKey,
EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB,
).build()
file.openFileOutput().use { it.write(payload) }
This is simpler than SQLCipher but loses SQL query capabilities.
5. iOS: SQLCipher via GRDB
var config = Configuration()
config.prepareDatabase { db in
let key = try KeychainHelper.loadOrCreateDbKey() // 32-byte Data
try db.usePassphrase(key)
}
let dbQueue = try DatabaseQueue(path: path, configuration: config)
For Core Data, wrap the store with NSPersistentStoreFileProtectionKey: FileProtectionType.complete — NOT equivalent to SQLCipher, but acceptable when the device is locked.
6. Realm
val config = RealmConfiguration.Builder(schema = setOf(User::class))
.name("user.realm")
.encryptionKey(KeyStoreHelper.loadOrCreateRealmKey()) // 64 bytes
.build()
val realm = Realm.open(config)
Realm requires a 64-byte key. Losing it means the DB is unrecoverable — plan for re-sync from server on key loss.
7. Migration From Plaintext
If you inherit a plaintext DB:
- Open it plaintext.
- Attach a new encrypted DB with the new key.
INSERT INTO encrypted.table SELECT * FROM plain.table;for each table.- Close, delete the plaintext file, rename encrypted → canonical path.
- Run on a background thread with progress UI; this can take minutes on large DBs.
8. Debug vs Release
- In debug builds you may want to disable encryption to allow inspection with DB Browser / Stetho. Gate this on
BuildConfig.DEBUG/#if DEBUGso it cannot ship. - Never commit a debug key that also unlocks production dumps.
Checklist
- The DB key is random (not derived from a constant or device ID).
- The DB key is wrapped by Keystore / Keychain and never stored plaintext on disk.
- SQLCipher / Realm encryption is enabled on any DB containing PII or credentials.
- A documented migration exists for moving users from plaintext to encrypted DBs.
- Key-loss UX is handled (re-sync or re-login) rather than silent data corruption.
- Debug-only relaxations cannot ship to production.