Sqlite returned: error code = 26, msg = file is encrypted or is not a database

I have an encrypted database code that works about 80-90% of the time. Problem is that 10-20% of the time, the db fails to load. The error message is

I/Database(19951): sqlite returned: error code = 26, msg = file is encrypted or is not a database
E/Database(19951): CREATE TABLE android_metadata failed
E/Database(19951): Failed to setLocale() when constructing, closing the database
E/Database(19951): net.sqlcipher.database.SQLiteException: file is encrypted or is not a database

I’ve read to augment the Java code as follows. The password is printed into the log properly, but it does not seem to open the database. I have checked manually, and the key is correct.

        Log.v("info", "Open sqlite db 0: " + dbfile.getAbsolutePath() + " 1:" + password);

        SQLiteDatabaseHook hook = new SQLiteDatabaseHook(){
            public void preKey(SQLiteDatabase database){
                database.rawExecSQL("PRAGMA kdf_iter = 5000");
            }
            public void postKey(SQLiteDatabase database){}
        };

/***
        SQLiteDatabase mydb = SQLiteDatabase.openOrCreateDatabase(dbfile, null);
***/
        SQLiteDatabase mydb = SQLiteDatabase.openOrCreateDatabase(dbfile, password, null, hook);

Where do I go next?

Hello @pearsosj

Are you able to retrieve the database file from the device and inspect it further? If so, can you try opening the database file with the SQLCipher command line shell and inspect the contents of the database? Are you able to reboot the device and subsequently open the database?

I have not been able to retrieve the database file. Because it was encrypted prior to the event (at least in theory), it’s unlikely that I can view its contents. In other words, my Android/data/edu.vanderbilt.XXX directories are empty. Is there somewhere else that I should look?

Rebooting used to work, but no longer.

@pearsosj

The database would typically exist within the /data/data/edu.vanderbilt.XXX/databases folder, do you not see anything in that location? Also, I see you are using a preKey hook to adjust the kdf_iter value used when computing the key from the provided password, are you certain the database was previously encrypted with the non-default kdf_iter value you are providing?

There are two directories in the edu.vanderbilt.XXX (cache and files), but no databases directory. The above code did not work on a new database. Frankly, I do not understand what the kdf_iter is doing.

Thanks for your attention.

So does it fail to create the database every time you execute that code? Have you verified that you included the icudt46l.zip file within the assets directory of your application?

PRAGMA kdf_iter provides a means to adjust the iteration length used by PBKDF2 for computing the key from the provided password. The default iteration length is 64,000, so you are weakening the security when using a smaller iteration length. If you wish to adjust the iteration length you should be executing that in the postKey function of the SQLiteDatabaseHook, not in preKey. Could you try moving that and let us know if that addresses your issue?

The database is created successfully every time.
The file is in the assets directory.
The issue is in re-opening the database.

I’ll try the kdf_iter reduction and see what happens. Will post soon.

Still fails. We might have to resort to a encrypt-each-value strategy.

Hello @pearsosj

Can you verify the absolute path you have to the database when you attempt to reopen the database? Does that file exist? Also, can you verify whether or not you originally created the database with an adjusted kdf_iter of 5000, or did it use the default kdf_iter? If you were previously attempting to set the kdf_iter to 5000 in the preKey, it would have ignored that value (as it needs to be set in postKey) and would have defaulted to 64,000 - thus if you moved setting the kdf_iter to postKey on an existing database, it would not be able to open the database. You might try completely removing the line where you attempt to adjust the kdf_iter value. Are you always creating the database on device? Finally, you might want to take a look at the SQLCipher for Android test suite as it contains examples of existing databases that are loaded to run various tests on device. This may provide you with something to compare your project integration with.