Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

android.database.sqlite.SQLiteException - file is not a database (code 26) #32

Open
UKMIITB opened this issue Feb 20, 2024 · 11 comments
Open

Comments

@UKMIITB
Copy link

UKMIITB commented Feb 20, 2024

Fatal Exception: android.database.sqlite.SQLiteException: file is not a database (code 26): , while compiling: SELECT COUNT(*) FROM sqlite_schema;
#################################################################
Error Code : 26 (SQLITE_NOTADB)
Caused By : File opened that is not a database file or encrypted.
	(file is not a database (code 26): , while compiling: SELECT COUNT(*) FROM sqlite_schema;)
#################################################################
       at net.zetetic.database.sqlcipher.SQLiteConnection.nativePrepareStatement(SQLiteConnection.java)
       at net.zetetic.database.sqlcipher.SQLiteConnection.acquirePreparedStatement(SQLiteConnection.java:973)
       at net.zetetic.database.sqlcipher.SQLiteConnection.executeForLong(SQLiteConnection.java:628)
       at net.zetetic.database.sqlcipher.SQLiteConnection.open(SQLiteConnection.java:240)
       at net.zetetic.database.sqlcipher.SQLiteConnection.open(SQLiteConnection.java:202)
       at net.zetetic.database.sqlcipher.SQLiteConnectionPool.openConnectionLocked(SQLiteConnectionPool.java:474)
       at net.zetetic.database.sqlcipher.SQLiteConnectionPool.open(SQLiteConnectionPool.java:189)
       at net.zetetic.database.sqlcipher.SQLiteConnectionPool.open(SQLiteConnectionPool.java:181)
       at net.zetetic.database.sqlcipher.SQLiteDatabase.openInner(SQLiteDatabase.java:1028)
       at net.zetetic.database.sqlcipher.SQLiteDatabase.open(SQLiteDatabase.java:1013)
       at net.zetetic.database.sqlcipher.SQLiteDatabase.openDatabase(SQLiteDatabase.java:840)
       at net.zetetic.database.sqlcipher.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:359)
       at net.zetetic.database.sqlcipher.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:278)
       at net.zetetic.database.sqlcipher.SupportHelper.getWritableDatabase(SupportHelper.java:60)
       at androidx.room.RoomDatabase.inTransaction(RoomDatabase.kt:638)
       at androidx.room.RoomDatabase.assertNotSuspendingTransaction(RoomDatabase.kt:457)
       at androidx.room.RoomDatabase.query(RoomDatabase.kt:486)
       at androidx.room.util.DBUtil.query(DBUtil.kt:75)

I am getting this crash in production.
Its not happening for all users & not reproducible. But in production this is happening.

This is the code for initialisation.

    @Singleton
    @Provides
    fun providesAppEncryptedDatabase(
        @ApplicationContext context: Context
    ): AppEncryptedDatabase {
        var passphrase =
            PreferenceManager.getSecureStringApp(KEY_DB_ENCRYPTION)
                ?.toByteArray(Charsets.ISO_8859_1)
        if (passphrase == null) {
            passphrase =CommonUtils.generatePassphrase()
            PreferenceManager.saveStringSecurelyApp(
                key = KEY_DB_ENCRYPTION,
                value = passphrase.toString(Charsets.ISO_8859_1)
            )
        }
        try {
            SplitInstallHelper.loadLibrary(context, "sqlcipher")
        } catch (e: Exception) {
            e.log()
            try {
                System.loadLibrary("sqlcipher")
            } catch (e: Exception) {
                e.log()
            }
        }

        val sqlCipherOpenerFactory = SupportOpenHelperFactory(passphrase, null, true)
        return Room.databaseBuilder(
                context,
                AppEncryptedDatabase::class.java,
                ENCRYPTED_DATABASE_NAME
            )
            .openHelperFactory(sqlCipherOpenerFactory)
            .build()
    }

So here once passphrase is generated same passphrase is getting used. And we donot clear that passphrase from shared preference, so the case of trying to open from another passphrase would not happen.

@sjlombardo
Copy link
Member

Hello @UKMIITB In this case something is causing the key mismatch. There is not enough information to determine what, but that error is thrown when the incorrect key is used. You should check all the various edge cases, e.g. the implementations for your secured preferences, and any ways that a database could be used without a corresponding preference (e.g. restore from backup, transfer onto a different device, generation of passphrase, etc).

@GrenderG
Copy link

GrenderG commented May 14, 2024

I was able to reproduce this issue with a 100% "success" rate, @sjlombardo. I'm testing this on a Pixel 7A with Android API 34 and version 4.5.7 of the library. I'm using Room with a hardcoded password, so the issue isn't related to password mismatches.

Essentially, in my case, the application always crashes if I try to insert an item and I have never performed any SELECT statement before.

@developernotes
Copy link
Member

Hi @GrenderG,

Can you post a public repo with a small test reproduction of the behavior you are seeing? We would be happy to investigate this further with a test case. Thanks!

@GrenderG
Copy link

Hello, I can try to do that this week. However, it should be very simple to test; basically you just need to open the app for the first time, then try to insert data without having performed any SELECT query before.

For the record, this is how I get the instance:

public static synchronized DummyDatabase getInstance(Context context) {
    System.loadLibrary("sqlcipher");
    return Room.databaseBuilder(context.getApplicationContext(),
                    DummyDatabase.class, Constants.DATABASE_NAME)
            .fallbackToDestructiveMigration()
            .setAutoCloseTimeout(60, TimeUnit.SECONDS)
            .openHelperFactory(new SupportOpenHelperFactory(
                    Constants.DB_DEFAULT_PASSWORD.getBytes(StandardCharsets.UTF_8)))
            .build();
}

To note:

  • All calls are being done inside AsyncTasks, in case it matters.
  • INSERT, SELECT actions are done through Room DAOs.

@sjlombardo
Copy link
Member

@GrenderG - in the scenario you are describing, does does the database already exist, or is the application creating a new database?

@GrenderG
Copy link

@GrenderG - in the scenario you are describing, does does the database already exist, or is the application creating a new database?

The application is creating a new database.

@developernotes
Copy link
Member

Hi @GrenderG,

Can you take a look at this small demo application and compare with what you are seeing locally?

@GrenderG
Copy link

GrenderG commented Jun 2, 2024

Hello, I tried it and the crash wasn't happening (my app is made with Java, not Kotlin, probably not relevant though). However, I found a way to avoid the crash in my scenario: if I use ExecutorService instead of a normal AsyncTask, it will work fine.

@developernotes
Copy link
Member

Hi @GrenderG,

Thanks for the update, glad to hear you were able to resolve the issue.

@mandrachek
Copy link

mandrachek commented Jul 22, 2024

I am experiencing the same issue. In my case, it appears to be an already existing database. We're storing the key in encrypted shared preferences for several different databases, and setting the key if it doesn't exist. I wonder if we're hitting an odd race condition in shared prefs, or if it's something internal to sqlcipher?

@EpariNigam
Copy link

Hey @mandrachek a thread is going on for your use case

#34

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants