Android SQLcipher PRAGMA problems - android

Hey guys I am having a some problems with SQLcipher db for android
The documentation is not too descriptive so I could not figure it out.
I am trying to modify the default number of iterations on sqlcipher for android,
I am editing the notecipher app provided as demo app with sqlcipher, and want to increase the kdf_iter to i.e. 5000
By overriding the getWritableDatabase() method in the database helper i enter the pragma value just after the file is open with the password.
I can open and initialize the database, but I cannot re-open the db if I do a database.close() call.
whenever I close the database on the next open() call I get a :
I/Database(807): sqlite returned: error code = 26, msg = file is encrypted or is not a database
E/Database(807): CREATE TABLE android_metadata failed
E/Database(807): Failed to setLocale() when constructing, closing the database
E/Database(807): info.guardianproject.database.sqlcipher.SQLiteException: file is encrypted or is not a database

You'll want to use a SQLiteDatabaseHook object to call the kdf_iter pragma. This will ensure that the pragma is called immediately after the database is opened, but before it is used.
SQLiteDatabaseHook hook = new SQLiteDatabaseHook(){
public void preKey(SQLiteDatabase database){
database.rawExecSQL("PRAGMA kdf_iter = 5000");
}
public void postKey(SQLiteDatabase database){}
}
SQLiteDatabase database = SQLiteDatabase.openOrCreateDatabase(databasePath, password, null, hook);

#Stephen answer is only partially correct, because according to the documentation:
PRAGMA kdf_iter must be called after PRAGMA key and before the first actual database operation or it will have no effect.
So the line:
database.rawExecSQL("PRAGMA kdf_iter = 5000");
Must be inserted in the postKey() method, and NOT in preKey().
This worked for me.

Related

Providing my android app with a DB encrypted with sqlcipher doesn't work, can't open it

My android app works with a provided DB populated and located on the asset folder. I recently had to start adding private datas in it so I used sqlcipher to encrypt it. So before starting:
The encryption goes well, since I can decrypt it easily and read it back. This is done with sqlcipher shell.
Everything was working like a charm with the db not crypted
What I was doing was, on the first launch of my app, creating a blank db on my phone, copy and past the content of the provided db in it and then, the user was able to have his own db on his phone without having to recreate it each time ( the db is pretty big ). Indeed, if the user already has the db on his phone for the further launch, he won't have to recreate it this way.
But with sqlcipher, it's not working anymore.
Important: When using sqlcipher with a non crypted db ( using "" as parameter for the related method like openDatabase ), it was working as well.
But when I try with the crypted db and with the password, what I have is the error
file is encrypted or is not a database: create locale table failed
This happens after I created a blank db using this:
//By calling this method and empty database will be created into the default system path
//of your application so we are gonna be able to overwrite that database with our database.
this.getReadableDatabase("password").close();
I then try to open it with the following instruction:
//Open the database
String myPath = DB_PATH + DATABASE_NAME;
myDataBase = SQLiteDatabase.openDatabase(myPath, "password", null, SQLiteDatabase.OPEN_READWRITE);
And then happens the error. Someone has an idea please? I'm saddly not an android expert, using a db was already difficult but as you can guess it's getting on another level now. Any help would be welcome. Thanks in advance !
Finally solve my problem after a long search following this link: Sqlcipher __ CREATE TABLE android_metadata failed
The error was coming from the way I was opening my db, which changes whether you use sqlcipher or sqlite.
Old way to open the db using sqlite:
myDataBase = SQLiteDatabase.openDatabase(myPath, "password", null, SQLiteDatabase.OPEN_READWRITE);
New way using sqlcipher, with a SQLiteDatabaseHook:
SQLiteDatabaseHook hook = new SQLiteDatabaseHook() {
public void preKey(SQLiteDatabase database) {
}
public void postKey(SQLiteDatabase database) {
database.rawExecSQL("PRAGMA cipher_migrate;");
}
};
myDataBase = SQLiteDatabase.openOrCreateDatabase(myPath, "password", null, hook);

Is there a memory cache for SQLite in Android and how to release or clear it?

Firstly, I create a database called "mydb" in my Android app:
DBHelper dbHelper = new DBHelper(context, "mydb", null, 1);//DBHelper is my custom class
And write some data into it's table:
SQLiteDatabase db = dbHelper.getReadableDatabase();
db.execSQL("insert into mytable(name, text) values ('allen','hello')");
Here, everything is ok. But then, i delete this database manually not by programming, with a software "R.E. explore" (Certainly on a rooted device).
Then, in my code, i read this table of the database. What is astonishing is that i still could get the data I stored.
Cursor cursor = db.query("mytable", new String[]{"name","text"}, null, null, null, null, null);
Why?
Quoting from the Android Developers reference website:
Once opened successfully, the database is cached, so you can call
this method every time you need to write to the database. (Make sure
to call close() when you no longer need the database.)
This is from the description of the getWritableDatabase() method, however both getReadableDatabase() and getWritableDatabase() return basically the same object for reading the database.
Please note that you should use getWritableDatabase() if you want to persist the changes you make to the database on the device's internal memory. Otherwise they will be valid only for the duration of the application's runtime and will be discarded once the app is closed. If you wish to delete the database completely, you should call the SQLiteDatabase's close() method in order to invalidate the cache.
use SQLiteDatabase.deleteDatabase(File file) API to delete the database
Deletes a database including its journal file and other auxiliary files that may have been created by the database engine.
Make sure you have closed all the connections that are open.
In case you are not able to do that,
just cal the deleteDatabase followed by kill process.. - not recommended
You need to delete the app from your phone then install again

How to disable Android SQLite Journal file?

I am using transactions to insert multiple rows into table. But, I still see temporary sqlite-journal file being created on SD Card along with sqlite table.
How do I disable creation of journal file?
Thanks
You can elect to keep the journal in memory so that no -journal file is created:
pragma journal_mode=memory;
Note that you need to run this each time you open the database.
I recommend that you read the following to get a better idea of what is going on:
http://www.sqlite.org/pragma.html#pragma_journal_mode
The journal is an internal SQLite file that is used when running transactions (to ensure roll back). You cannot disable it, and you don't want to.
Please remind, the statement PRAGMA journal_mode=OFF or PRAGMA journal_mode=memory is valid per transaction base. You need to set it for every transaction.
You can delete journal file using below code
#Override
public void onOpen(SQLiteDatabase db) {
Cursor cc = db.rawQuery("PRAGMA journal_mode=DELETE",null);
Log.i(TAG,"--- cursor count " + cc.getCount());
super.onOpen(db);
}
You need to use cursor. Cursor is a interface provides random read-write access to the result set returned by a database query.
The journal file will get delete if you use cursor.

Android onUpgrade() fails because database is locked, what should I do differently?

I have a project with a set of classes that are responsible for their respective database tables.
Each table managing class contains CRUD methods that follow the pattern of get connection, run crud operation, close connection:
public class PersonManager {
SQLiteDatabase db;
DbAdapter dbAdapter; //This is a subclass of SQLiteOpenHelper
public void addPerson(Person person)
{
ContentValues contentValues = new ContentValues();
contentValues.put("email", person.email);
contentValues.put("first_name", person.firstName);
db = dbAdapter.getWritableDatabase();
db.insert("person", null, contentValues);
db.close();
}
...other crud/utility methods omitted...
}
Now that I am upgrading my database via onUpgrade(), I run into database locked issues.
The exact error message follows:
CREATE TABLE android_metadata failed
Failed to setLocale() when constructing, closing the database
android.database.sqlite.SQLiteException: database is locked
It appears that onUpgrade is either meant to:
1 run db.execSQL() calls or
2 use helper classes that use onUpgrade()'s SQLiteDatabase rather than their own
It would be much easier to use my table managing classes to migrate data in onUpgrade() than db.execSQL() statements, or rewrite all my CRUD methods to take onUpgrade()'s SQLiteDatabase.
Am I setting up my database access correctly? If the above code follows the correct pattern, what should I do to fix this issue?
Thanks!
Here's your problem:
db = dbAdapter.getWritableDatabase();
When you're in onUpgrade(), you have to use the SQLiteDatabase handle that onUpgrade() provides you. So your solution is to rewrite your addPerson function to take one more argument -- an SQLiteDatabase handle:
public void addPerson(Person person, SQLiteDatabase db) {...}
If you need to call addPerson() from elsewhere in your project, then keep your current addPerson(Person person) function, have it do that
db = dbAdapter.getWritableDatabase()
call, and pass db to your two-argument version of addPerson().
I didn't get any answers, so I asked on a dev hangout.
According to the Android Developer Hangout Team, onUpgrade is only meant for structure alterations, not really for data migration/manipulation.

Android does not update SQLite database

I am experiencing some trouble with an SQLIte database in my Android application.
The issue is that the database is never updated, not even on multiple restarts of the emulator, of Eclipse or after deletion from DDMS.
This is my onCreate method, located in a class that extends SQLiteOpenHelper:
public void onCreate(SQLiteDatabase database) {
try {
database.execSQL(ESSENCE_TABLE_CREATE);
database.execSQL(PACCO_TABLE_CREATE);
database.execSQL(TAVOLE_TABLE_CREATE);
database.rawQuery("insert into essenza values(1, 'Rovere')",
null); // added later
} catch (SQLException e) {
Log.e("DB", e.getMessage());
}
}
After instantiating the helper, I request a reference to the database:
helper = new DBHelper(context, dbpath + "/" + DATABASE_NAME);
database = helper.getWritableDatabase();
It seems that the rawQuery statement (which was added at a later time) is not executed and that the database in use is instead cached from a previous version. I also tried to change the version of the database, but it did not work. Am I missing something? Thanks in advance.
You have two options:
Use DDMs to delete the database file from your device (look in /data/data/). This will force Android to run onCreate again.
In your constructor, increment the database version you pass to SQLiteOpenHelper. Add your raw query to onUpgrade.
You probably want option 1. Option 2 is better if you have users of your app whose databases you want to update.

Categories

Resources