Wednesday, August 8, 2012

Trying SQLCipher with Cordova iOS SQLitePlugin

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 directions posted on my new blog.

I have already documented running the Cordova SQLitePlugin PhoneGap/Cordova SQLitePlugin for Android with SQLCipher for Android here and here for rebuilding SQLite for Android from source. Here I document the steps I am taking to run SQLCipher with the Cordova-SQLitePlugin PhoneGap-SQLitePlugin for iOS.

The first step is to create the (test) app project. I created a Cordova 2.0 project using the command line tool create as documented here and here.

Next I follow the directions from SQLCipher for iOS integration to build the project with SQLCipher (hold off on the integration code for now). For this case I am using OpenSSL 1.0.1c. Download from http://www.openssl.org/source/ and extract.

Under the project folder, git clone git://github.com/sqlcipher/sqlcipher.git and git://github.com/sqlcipher/openssl-xcode.git

Now open the app project, open Xcode --> Preferences menu, Locations, Source Trees, then add the setting OPENSSL_SRC that points to the location of the extracted OpenSSL source tree.

Add the subproject references for the sqlcipher xcodeproject and openssl-xcode/openssl.xcodeproj. I selected the top-level project item and alt-command-a to add each subproject reference.

Configure build dependencies: select the app target, click the build phases tab, and add the target dependencies both openssl/crypto and sqlcipher. Under link binary with libraries section add libcrypto.a and libsqlcipher.a but make sure there is no libsqlite3 library.

Holding off on setting build architectures and CFLAGS for now. Under other C flags add
-DSQLITE_HAS_CODEC for both debug and release projects. It should now be possible to build the project.

Building with SQLitePlugin: add the SQLitePlugin.[hm] to the Xcode project Plugins folder and the project should still build. Make the following patch to SQLitePlugin.m:


$ git diff Plugins/SQLitePlugin.m
diff --git a/iOS/Plugins/SQLitePlugin.m b/iOS/Plugins/SQLitePlugin.m
index 444a78b..65b5b61 100644
--- a/iOS/Plugins/SQLitePlugin.m
+++ b/iOS/Plugins/SQLitePlugin.m
@@ -70,7 +70,10 @@
         [self respond:callback withString:@"{ message: 'Unable to open DB' }" withType:@"error"];
         return;
     }
-    
+
+    const char* key = [@"BIGSecret" UTF8String];
+    sqlite3_key(db, key, strlen(key));
+
     NSValue *dbPointer = [NSValue valueWithPointer:db];
     [openDBs setObject:dbPointer forKey: dbPath];
     [self respond:callback withString: @"{ message: 'Database opened' }" withType:@"success"];


and build should still be working. Add SQLitePlugin to Cordova.plist resources, Install SQLitePlugin.js into the www directory, add a small test program using the SQLitePlugin, and try running.

To be honest, I do not really like the number of external projects that have to be assembled and cobbled together to make SQLCipher work with the Cordova-SQLitePlugin for a Cordova project. I would like to find a solution that allows someone to just setup a simple project, add some files as necessary, and run.

Tuesday, August 7, 2012

Rebuilding SQLite/SQLCipher for Android on OSX

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 directions for both OSX and Linux on my new blog.

From a previous post I have already built and run the Cordova SQLitePlugin with SQLCipher. The next task is to rebuild SQLCipher for Android from source. Note that the android-database-sqlcipher project repository includes the sub-repository and tasks to rebuild a special version of the sqlite C library itself.

From SQLCipher for Android the first task is to install the Android NDK (assuming that Android SDK and Java have been installed). Their directions tell you to install the Android ndk-build in a special directory and add it to your path. However, for OSX I believe there is an easy way if you are using Homebrew.

The assumption is that you have already installed the Android SDK using Homebrew. If not, make sure Homebrew is installed then install the Android SDK using:
$ brew install android (see my Notes on Running Cordova/PhoneGap on Android without Eclipse posting).

To install the Android NDK, simply: $ brew install android-ndk

The next step is to follow the directions for SQLCipher for Android to rebuild SQLCipher for Android from source. I made a special subdirectory and cloned the android-database-sqlcipher project like:
$ git clone git://github.com/sqlcipher/android-database-sqlcipher.git

Inside the android-database-sqlcipher directory the next step is to do
$ make init to update/init the git submodules and run an android update project command.

To start the build process: $ make

There seems to be an issue with the Makefile that tries to copy libstlport_shared.so from the wrong place. To fix:

$ git diff Makefile
diff --git a/Makefile b/Makefile
index b8067f2..d8b4883 100644
--- a/Makefile
+++ b/Makefile
@@ -42,7 +42,7 @@ copy-libs:
        cp ${JNI_DIR}/libs/armeabi/libdatabase_sqlcipher.so \
                ${LIBRARY_ROOT}/armeabi && \
        cp ${CURDIR}/bin/classes/sqlcipher.jar ${LIBRARY_ROOT} && \
-       cp ${ANDROID_NDK_ROOT}/sources/cxx-stl/stlport/libs/armeabi/libstlport_shared.so \
+       cp ${EXTERNAL_DIR}/libs/armeabi/libstlport_shared.so \
                 ${LIBRARY_ROOT}/armeabi

 copy-libs-dist:

Then to start the build process: $make

The libraries should show up under the libs subdirectory.

To test with a Cordova/PhoneGap project with Cordova-SQLitePlugin: follow the previous post for trying SQLCipher with Cordova-SQLitePlugin but copy the contents of the project libs directory from the newly-built libs subdirectory (and keep cordova-x.x.x.jar but remove commons-codec.jar). The test should now continue be working OK.

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.