Why is this an issue?
Storing data locally is a common task for mobile applications. There are many convenient solutions that allow storing data persistently, for
example SQLiteDatabase and Realm. These systems can be initialized with a secret key in order to store the data encrypted.
The encryption key is meant to stay secret and should not be hard-coded in the application as it would mean that:
- All user would use the same encryption key.
- The encryption key would be known by anyone who as access to the source code or the application binary code.
- Data stored encrypted in the database would not be protected.
There are different approaches how the key can be provided to encrypt and decrypt the database. One of the most convinient way to is to rely on
EncryptedSharedPreferences
to store encryption keys. It can also be provided dynamically by the user of the application or fetched from a
remote server.
Noncompliant code example
SQLCipher
val key = "gb09ym9ydoolp3w886d0tciczj6ve9kszqd65u7d126040gwy86xqimjpuuc788g"
val db = SQLiteDatabase.openOrCreateDatabase("test.db", key, null) // Noncompliant
Realm
val key = "gb09ym9ydoolp3w886d0tciczj6ve9kszqd65u7d126040gwy86xqimjpuuc788g"
val config = RealmConfiguration.Builder()
.encryptionKey(key.toByteArray()) // Noncompliant
.build()
val realm = Realm.getInstance(config)
Compliant solution
SQLCipher
val db = SQLiteDatabase.openOrCreateDatabase("test.db", getKey(), null)
Realm
val config = RealmConfiguration.Builder()
.encryptionKey(getKey())
.build()
val realm = Realm.getInstance(config)
Resources