iOS and Mac OS X Integration Tutorial

SQLite is already a popular API for persistent data storage on the iPhone so the upside for development is obvious. As a programmer you work with a stable and well documented API. All security concerns are cleanly decoupled from application code and managed by the underlying framework

The framework code of the SQLCipher and OpenSSL projects are both open source, so users can be confident that an application isn't using insecure or proprietary security code. In addition, these projects can be compiled and under Mac OS X, Windows, and even Linux to support Desktop applications.

Using SQLCipher in an iPhone application is straightforward once you setup your project properly. This document describes the integration SQLCipher into an iOS XCode project is using the Community Edition source code build process. This tutorial assumes some familiarity with basic iOS application development and a working install of the iOS SDK and XCode 4.2. The same basic steps should also work with Mac OS X applications.

Important Note: Commercial Edition SQLCipher static libraries are also available for iOS and Mac OS X. These static libraries provide the exact same features, but are easier to setup, built with a modern version of OpenSSL, and much faster for each build cycle. Learn more »

Prerequisites

XCode command line tools are required for building SQLCipher and OpenSSL, but they are no longer installed by default. After XCode installation the Command Line Tools must be installed from the Downloads section of Xcode's preferences.

OpenSSL

SQLCipher uses the widely trusted and peer-reviewed OpenSSL library for all cryptographic functions including the AES-256 algorithm, pseudo random number generation, and PBKDF2 key derivation. OpenSSL isn't framework that is usable directly on the iPhone so we will setup our project to build and link against it as a static library.

Download the 1.0.x stable version from http://www.openssl.org/source/ and extract it to a folder on your system. Since the same OpenSSL source tree may be shared across multiple SQLCipher projects, it's a good idea to place this in some shared location outside of your project folder. Justs make a note of the source directory path for later.

% cd ~/Documents/code
% curl -o openssl-1.0.0e.tar.gz http://www.openssl.org/source/openssl-1.0.0e.tar.gz
% tar xzf openssl-1.0.0e.tar.gz

Be sure to verify the PGP and/or SHA1 signature of the archive before use.

SQLCipher

Switch into your project's root directory and checkout the SQLCipher project code

% cd ~/Documents/code/SQLCipherApp
% git clone https://github.com/sqlcipher/sqlcipher.git

OpenSSL-XCode

OpenSSL can be tricky to compile properly from source. It's even more complex when you're dealing with multiple target architectures (iOS development targets i386 for the simulator but armv6 and armv7 for a device)

The OpenSSL XCode project includes a project template that relies on the OpenSSL configure and make system to build the libraries. However, it automatically detects the appropriate build settings for architecture (i386, x86_64, arvm6, armv7), build tools, and SDK. This makes it ideal for inclusion in an iPhone project.

Switch into your project's root directory and checkout the OpenSSL XCode project

% cd ~/Documents/code/SQLCipherApp
% git clone https://github.com/sqlcipher/openssl-xcode.git

XCode Setup

SQLCipher uses sub-projects to manage build dependencies and static linking. Before writing code to use SQLCipher you must setup XCode, and your project, to build SQLCipher.

Add OpenSSL Source Tree

Start by opening the XCode project, Choose the XCode Menu, Preferences, Locations tab, and Source Trees screen. Add a variable named OPENSSL_SRC that references the path to the extracted OpenSSL source code.

OpenSSL Source Tree

Add subproject references

Now that the XCode global preferences are setup we will move on to the project configuration.

In the application project, click on the top level Project item. Right click on the project and choose "Add Files to "Project"", or press option-command-a, to add a resource. Navigate to the project directory, inside the sqlcipher folder, and add the sqlcipher.xcodeproj. If you have multiple targets, be sure to add the file to both. Repeat the same step for openssl-xcode/openssl.xcodeproj.

Project References

Configure build dependencies

We must add build dependencies to ensure that SQLCipher is compiled before the application code. Select your application target and open the Info panel. Under the Build Phases tab, in the Target Dependencies section, we will add both openssl/crypto and sqlcipher/sqlcipher. Use Command-click to select both at once.

Build Dependencies

Then, under the Link Binary With Libraries section, add libcrypto.a and libsqlcipher.a.

Link Binary

Make sure that libsqlite3.dylib is not selected as a link dependency.

Add the same set of dependencies and link settings to any other targets in your project that will depend on SQLCipher, i.e. unit tests.

Set build architectures and CFLAGS

Select the top level project and choose the Build Settings Tab, and expand the Architectures setting. Leave the Debug setting as the default. Ensure the Release architectures are correct (e.g. armv7 and armv7s for iOS, x86_64 for MacOS). Change them if necessary. This will ensure that all dependent projects will be deployable on all desired architectures.

Build Architectures

Next, locate the Header Search Paths setting, and add "sqlcipher" as a search path. This will ensure that XCode can find the required header for the SQLCipher library. Ensure that the "recursive" box is not checked on the includes, or the build may fail.

Finally, under "Other C Flags", add -DSQLITE_HAS_CODEC to the Debug and Release C Flag settings. This will ensure that the SQLite key management functions are defined for use by the application.

C Flags

NOTE: If you choose to change either the build architectures or the compiler used, you must apply the same changes to the build settings under the openssl.xcodeproj and sqlcipher.xcodeproj. The three settings must match across all projects.

At this point you should be able to build the XCode project without errors. Note that the first time you build the application for a particular architecture (Simulator for instance), it will take much longer than usual. This is because SQLCipher and OpenSSL are compiled from source for the specific architecture. You can keep track of the status under Build Results. Subsequent builds for the same platform will be much quicker since the libraries don’t need to be recompiled.

Integration Code

Now that the SQLCipher library is incorporated into the project you can start using the system immediately. Telling SQLCipher to encrypt a database is as easy as opening a database and using the sqlite3_key function.

#import <sqlite3.h>

...
NSString *databasePath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0] 
                          stringByAppendingPathComponent: @"sqlcipher.db"];
sqlite3 *db;
if (sqlite3_open([databasePath UTF8String], &db) == SQLITE_OK) {
    const char* key = [@"BIGSecret" UTF8String];
    sqlite3_key(db, key, strlen(key));
    if (sqlite3_exec(db, (const char*) "SELECT count(*) FROM sqlite_master;", NULL, NULL, NULL) == SQLITE_OK) {
        // password is correct, or, database has been initialized

    } else {
        // incorrect password!
    }

    sqlite3_close(db);
}

Note that it is also possible to initialize the database by calling PRAGMA key, as follows, but this is not recommended unless code is in place to handle potential escaping issues.

PRAGMA key = 'BIGSecret';

The call to sqlite3_key or "PRAGMA key" should occur as the first operation after opening the database. In most cases SQLCipher uses PBKDF2, a salted and iterated key derivation function, to obtain the encryption key. Alternately, an application can tell SQLCipher to use a specific binary key in blob notation (note that SQLCipher requires exactly 256 bits of key material), i.e.

PRAGMA key = "x'2DD29CA851E7B56E4697B0E1F08507293D761A05CE4D1B628663F411A8086D99'";

Once the key is set SQLCipher will automatically encrypt all data in the database! Note that if you don't set a key then SQLCipher will operate identically to a standard SQLite database.

After the application is wired up to use SQLCipher, take a peek at the resulting data files to make sure everything is in order. An ordinary SQLite database will look something like the following under hexdump. Note that the file type, schema, and data are clearly readable.

% hexdump -C plaintext.db 
00000000  53 51 4c 69 74 65 20 66  6f 72 6d 61 74 20 33 00  |SQLite format 3.|
00000010  04 00 01 01 00 40 20 20  00 00 00 04 00 00 00 00  |.....@  ........|
...
000003b0  00 00 00 00 24 02 06 17  11 11 01 35 74 61 62 6c  |....$......5tabl|
000003c0  65 74 32 74 32 03 43 52  45 41 54 45 20 54 41 42  |et2t2.CREATE TAB|
000003d0  4c 45 20 74 32 28 61 2c  62 29 24 01 06 17 11 11  |LE t2(a,b)$.....|
000003e0  01 35 74 61 62 6c 65 74  31 74 31 02 43 52 45 41  |.5tablet1t1.CREA|
000003f0  54 45 20 54 41 42 4c 45  20 74 31 28 61 2c 62 29  |TE TABLE t1(a,b)|
...
000007d0  00 00 00 14 02 03 01 2d  02 74 77 6f 20 66 6f 72  |.......-.two for|
000007e0  20 74 68 65 20 73 68 6f  77 15 01 03 01 2f 01 6f  | the show..../.o|
000007f0  6e 65 20 66 6f 72 20 74  68 65 20 6d 6f 6e 65 79  |ne for the money|

Fire up the SQLCipher application in simulator and look for the application database files under /Users/sjlombardo/Library/Application Support/iPhone Simulator/5.0/Applications/<Instance ID>/Documents. Try running hexdump on the application database. With SQLCipher the output should looks completely random, with no discerning characteristics at all.

% hexdump -C sqlcipher.db 
00000000  1b 31 3c e3 aa 71 ae 39  6d 06 f6 21 63 85 a6 ae  |.1<..q.9m..!c...|
00000010  ca 70 91 3e f5 a5 03 e5  b3 32 67 2e 82 18 97 5a  |.p.>.....2g....Z|
00000020  34 d8 65 95 eb 17 10 47  a7 5e 23 20 21 21 d4 d1  |4.e....G.^# !!..|
...
000007d0  af e8 21 ea 0d 4f 44 fe  15 b7 c2 94 7b ee ca 0b  |..!..OD.....{...|
000007e0  29 8b 72 93 1d 21 e9 91  d4 3c 99 fc aa 64 d2 55  |).r..!...<...d.U|
000007f0  d5 e9 3f 91 18 a9 c5 4b  25 cb 84 86 82 0a 08 7f  |..?....K%.......|
00000800

See Also

All applications that make use of cryptography, including those that use SQLCipher or iOS internal libraries like CommonCrypto and Keychain, must provide documentation to Apple that demonstrates review by the Department of Commerce (DOC) Bureau of Industry and Security (BIS) and classification of the application a mass market encryption item.

Information on the PBKDF2 key derivation function is available at http://en.wikipedia.org/wiki/PBKDF2