I'm building an app that uses room database and I use SQLCipher to encrypt it. How can I check if the data is really encrypted because it's my first time to use encryption and I don't know if I did it correctly.
-
1Did you tried using the database inspector tool provided in android studio ? – AgentP Oct 28 '21 at 15:07
-
Agreed: if your objective is to do a one-off check to see if the database is encrypted, try opening the database in a SQLite client that does not support encryption. If your objective is to write an instrumented test, try opening the database in Room without the `openHelperFactory()` that you are using for SQLCipher -- if you can open and read the database without SQLCipher, then the database is not encrypted. – CommonsWare Oct 28 '21 at 15:15
1 Answers
Assuming that you want to check if the database is or is not encrypted within the App then you have to be a little careful.
Suggestions of checking by opening the database via room without using the key will result in loss of the data if the database is encrypted.
This is because when room tries to open the database when it is encrypted it will be considered a corrupted database as the entire file is encrypted and thus not a valid database file (the header string will not be the required header string "SQLite format 3\000"). Room will then delete the corrupted database and then invoke the onCreate method to provide a valid new database that has no data.
I would suggest that you consider opening the file, not as a database, but as a file and checking if the first 16 bytes are "SQLite format 3\000".
If it is "SQLite format 3\000" then the database has not been encrypted, if it is not "SQLite format 3\000" then the database (if the file is in fact a/the database file) may be encrypted.
Perhaps consider something along the lines of :-
/**
* Check to see if the database is encrypted
*
* NOTE assumes encrypted if the database header string is not the required SQLite header string
* WARNING any invalid file would be considered encrypted
*/
fun isEncryptedDatabase(context: Context, databaseName: String): Boolean {
var rv = false
// SQlite header String 16 bytes as SQLite format 3\000
// hex representation is 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00
val requiredSQLiteFileHeaderString: ByteArray
= byteArrayOf(0x53,0x51,0x4c,0x69,0x74,0x65,0x20,0x66,0x6F,0x72,0x6D,0x72,0x61,0x74,0x20,0x33,0x0)
var dbFileHeader = ByteArray(requiredSQLiteFileHeaderString.size)
var i: InputStream
try {
i = FileInputStream(context.getDatabasePath(databaseName))
i.read(dbFileHeader)
if(!dbFileHeader.equals(requiredSQLiteFileHeaderString)) {
rv = true
}
i.close()
} catch (e: IOException) {
rv = true;
}
return rv
}
}
You would use this outside of Room and before Room opens the database. Considering that the above uses the Context's getDatabasePath method then it is highly likely that a true result (the database is encrypted) is due to the database being encrypted rather than being another type of file.
Here's an example of the use of the above code embedded within the @Database class (based upon using the code used for the answer of the link above). The Activity code being :-
class MainActivity : AppCompatActivity() {
lateinit var db: TheDatabase
lateinit var dao: AllDao
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
if (!TheDatabase.isEncryptedDatabase(this,TheDatabase.DATABASENAME)) {
//.... handle un-encrypted database here
}
db = TheDatabase.getInstance(this)
dao = db.getAllDao()
....
}
}
- note for convenience and brevity the above uses the main thread (i.e.
.allowMainThreadQueries()
has been coded in the databaseBuilder)

- 51,415
- 16
- 49
- 68
-
"and before Room opens the database". I use HILT for dependency injection, how do I open it before Room opens the database? – Mox4 Oct 30 '21 at 07:21
-
@Mox4 if you look at the `isEncryptedDatabase` all it requires is a context and the database name. So that's all you need to call it. So anywhere before you get the database. – MikeT Oct 30 '21 at 07:43