Fatal Exception: net.sqlcipher.database.SQLiteException file is not a database: , while compiling: select count(*) from sqlite_master;

Hi,
I have a plain room db in my application, i used “net.zetetic:android-database-sqlcipher:4.4.0” to encrypt the database it working fine in development phase, but after application released into the market getting random crashes as saying “Fatal Exception: net.sqlcipher.database.SQLiteException file is not a database: , while compiling: select count(*) from sqlite_master;”, and we are not able reproduce the same in our end. i checked that Passphrase also correct, no where it is getting changed. Any help you can give would be greatly appreciated.

I used the below code to encrypt the data base

@Throws(IOException::class)
private fun encrypt(context: Context, databaseName: String, passphrase: ByteArray) {
val originalFile = getCurrentDBPath(context, databaseName)
if (originalFile.exists()) {
val newFile = File.createTempFile(“xyz_room_db”, “tmp”,
context.cacheDir)
var db = SQLiteDatabase.openDatabase(originalFile.absolutePath,
“”, null, SQLiteDatabase.OPEN_READWRITE)
val version = db.version
SlLog.i(“SL_DATABASE”, “DB version ${version}”)
db.close()
db = SQLiteDatabase.openDatabase(newFile.absolutePath, passphrase, null, SQLiteDatabase.OPEN_READWRITE, null, null)
val st: SQLiteStatement = db.compileStatement(“ATTACH DATABASE ? AS plaintext KEY ‘’”)
st.bindString(1, originalFile.absolutePath)
st.execute()
db.rawExecSQL(“SELECT sqlcipher_export(‘main’, ‘plaintext’)”)
db.rawExecSQL(“DETACH DATABASE plaintext”)
db.version = version
st.close()
db.close()
originalFile.delete()
newFile.renameTo(originalFile)
SlLog.i(“SL_DATABASE”, “DB encrypted successfully”)
} else {
throw FileNotFoundException(originalFile.absolutePath + " not found")
}
}

Fatal Exception: net.sqlcipher.database.SQLiteException

file is not a database: , while compiling: select count(*) from sqlite_master;

net.sqlcipher.database.SQLiteCompiledSql.native_compile (SQLiteCompiledSql.java)

net.sqlcipher.database.SQLiteCompiledSql.compile (SQLiteCompiledSql.java:89)

net.sqlcipher.database.SQLiteCompiledSql. (SQLiteCompiledSql.java:62)

net.sqlcipher.database.SQLiteProgram. (SQLiteProgram.java:91)

net.sqlcipher.database.SQLiteQuery. (SQLiteQuery.java:48)

net.sqlcipher.database.SQLiteDirectCursorDriver.query (SQLiteDirectCursorDriver.java:60)

net.sqlcipher.database.SQLiteDatabase.rawQueryWithFactory (SQLiteDatabase.java:2016)

net.sqlcipher.database.SQLiteDatabase.rawQuery (SQLiteDatabase.java:1902)

net.sqlcipher.database.SQLiteDatabase.keyDatabase (SQLiteDatabase.java:2669)

net.sqlcipher.database.SQLiteDatabase.openDatabaseInternal (SQLiteDatabase.java:2612)

net.sqlcipher.database.SQLiteDatabase.openDatabase (SQLiteDatabase.java:1247)

net.sqlcipher.database.SQLiteDatabase.openOrCreateDatabase (SQLiteDatabase.java:1322)

net.sqlcipher.database.SQLiteOpenHelper.getWritableDatabase (SQLiteOpenHelper.java:166)

net.sqlcipher.database.SupportHelper.getWritableDatabase (SupportHelper.java:83)

androidx.room.RoomDatabase.inTransaction (RoomDatabase.java:476)

arrow_drop_down

androidx.room.RoomDatabase.assertNotSuspendingTransaction (RoomDatabase.java:281)

com.mobile.newArch.room.dao.NotificationListDao_Impl.insert (NotificationListDao_Impl.java:189)

com.mobile.newArch.room.dao.NotificationListDao_Impl.insert (NotificationListDao_Impl.java:24)

com.mobile.newArch.utils.NotificationDbOperationsUtil.saveNotificationData (NotificationDbOperationsUtil.java:38)

com.mobile.newArch.utils.PushNotifications.onPushNotificationShown (PushNotifications.java:29)

com.webengage.sdk.android.i$5.run (i.java:10)

1 Like

Hi @Jayakrishna

This code appears to be exporting to a plaintext database file, not encrypting it; note the blank key you are using in the ATTACH statement. Example # 1 for encrypting a plaintext database file shows the proper usage here.

One additional consideration you might make in your application is to capture the return value of your call to the following:

newFile.renameTo(originalFile)

If for some reason renameTo returns false, your code currently ignores that, leaving the originalFile deleted.

1 Like

But, after executing this statements, i exported the DB and tried to open in sqlite broswer. while opening the DB in sqlite broswer it asked me to enter the “passphrase” that i have used to encrypt the DB file. You can see in the below code i m creating the db object with “passphrase” and after that i m attaching the the plaintext database.

db = SQLiteDatabase.openDatabase(newFile.absolutePath, passphrase, null, SQLiteDatabase.OPEN_READWRITE, null, null)
val st: SQLiteStatement = db.compileStatement(“ATTACH DATABASE ? AS plaintext KEY ‘’”)
st.bindString(1, originalFile.absolutePath)
st.execute()

Hi @Jayakrishna

Sorry, I saw you were opening without a password above and didn’t see the reuse of the variable name to open a different connection with passphrase. I would still recommend checking the result of your call to renameTo. Additionally, you might consider adjusting your application logic to catch that exception, and when it occurs, attempt to open the database without a passphrase.

I was getting the same error as OP, and like OP it would only happen from an app installed from the google play store, and only certain devices. In my case a Pixel 3 would crash, but not a samsung s20 or note 10. We use room with sqlCipher though.
The fix was as simple as adding a “.db” file extension to the database name. When the name was “database” the app would crash when installed and ran on a Pixel 3 from the google play store (internal testing). Changing to “database.db” resolved it.

val supportFactory = SupportFactory(passphrase)
val instance = Room.databaseBuilder(
                    context.applicationContext,
                    CgmDatabase::class.java, "database.db"
                ).openHelperFactory(supportFactory).build()
1 Like

Hello @Dan_Patterson - thanks for making that suggestion. Are you sure there wasn’t already a file named “database” on the device you were getting an error on? The exception in question is thrown when a file exists but SQLCipher is not able to open it using the provided key.

I’m not sure of a mechanism where changing the file extension would change that behavior, unless a file already existed at the original path. It is certainly possible that the Android OS or play store distribution is doing something under the hood to interfere with SQLCipher when using the filename “database”, but we haven’t had any other reports of that behavior.

sqlcipher 4.5.2

I’m seeing this error in very rare circumstances (less than 1% of the time). Devices encountered so far: Redmi Note 11, Galaxy A13, Galaxy Z Fold4, Galaxy A72. All running Android 12.

What’s interesting is that my database is not encrypted.

The error occurs when executing:

SupportSQLiteDatabase.execSQL("ATTACH DATABASE '$path' AS $handle")

where path is an absolute path.