Sunday, August 5, 2012

Trying SQLCipher with Cordova SQLitePlugin for Android

NOTICE (June 2015): These instructions are completely out-of-date, the following Cordova plugin supports sqlcipher out-of-the-box: https://github.com/litehelpers/Cordova-sqlcipher-adapter

UPDATE (OLD): Please see the updated instructions on my new blog.

The project chbrody/Cordova-SQLitePlugin brodyspark / PhoneGap-SQLitePlugin-Android provides a native interface to the built-in sqlite library for Cordova/PhoneGap applications on Android and iOS. However, I think a better future is to provide a plugin to use a custom-built version of the sqlite library, and this can provide several benefits including native compression and encryption. Another benefit for the Android is to support all result parameters including rowsAffected for UPDATE and DELETE for all versions of the Android SDK.

In this test, the idea is to use the Java classes for SQLite from SQLCipher for Android instead of the built-in SQLiteDatabase API. The other part is to recompile the sqlite C library itself UPDATE: the next step is to rebuild SQLCipher for Android, including the special version of the C library. This post was written as I tried the steps myself, using Cordova/PhoneGap version 2.0 (with some trial-and-error).

The first step is to make a sample project with the PhoneGap-SQLitePlugin-Android with the quick test, but do not compile yet (see the Android section of Installing in PhoneGap-sqlitePlugin-Android/README.md). This includes installing the Plugin Javascript and Java files, updating res/xml/config.xml, and adding the test program to index.html. (The android update project command can wait for now.)

This test is done only with the binaries of SQLCipher for Android, rebuilding from source will be saved for another posting. In this test, version 2.0.8 is used from https://github.com/sqlcipher/android-database-sqlcipher/downloads though any recent version should be OK. I make a separate directory before opening the ZIP file to make it easier to cleanup afterwards. (When you uncompress the ZIP file you get an extra __MACOSX directory, which should be safe to ignore, in addition to the SQLCipher\ for\ Android\ 2.0.8.)

To install the SQLCipher libraries:
$ cp -Rv path-to-sqlcipher-for-android/libs/* libs
but remove libs/commons-codec.jar since it is already part of Cordova/PhoneGap. Also you have to install ICU file icudt46l.zip for lower Android distro/SDK versions:
$ cp path-to-sqlcipher-for-android/assets/icudt46l.zip assets

The next step is to modify the Plugin Java code to use the classes from SQLCipher instead of the built-in SQLiteDatabase classes. Make sure the android update project is done to compile with the desired Android API.

Remove the lines to import classes from android.database.sqlite but keep the import of android.database.Cursor and import the SQLCipher version of the database classes along with java.io.File like:

//import android.database.sqlite.*;
import net.sqlcipher.database.*;

import java.io.File;

(maybe better to import the database classes by name in the future)

In the SQLitePlugin() constructor beginning of openDatabase() add code to initialize the SQLCipher like:
SQLiteDatabase.loadLibs(this.cordova.getActivity());

and fix the following lines in openDatabase():

//this.myDb = this.cordova.getActivity().getApplicationContext().openOrCreateDatabase(db + ".db", Context.MODE_PRIVATE, null);

String dbfile = db + ".db";

File databaseFile = this.cordova.getActivity().getDatabasePath(db + ".db");
databaseFile.mkdirs();

databaseFile.delete();

this.myDb = SQLiteDatabase.openOrCreateDatabase(databaseFile, "test123", null);

In processResults() please comment out the lines for android.os.Build.VERSION.SDK_INT >= 11 since abstract function Cursor.getType() is not implemented by the SQLCipher for Android.

The quick-test from the Android subsection of Installing should now be working.

Next steps include rebuilding SQLCipher for Android from source, re-compiling sqlite C library for Android using NDK and updating the using SQLCipher for iOS.