Skip to content

Database Encryption

Jens Alfke edited this page Aug 7, 2014 · 12 revisions

You can optionally encrypt an entire database. The algorithm used is AES-256, which is highly secure. The database itself is encrypted using SQLCipher, a fork of SQLite, while attachments are individually encrypted in the filesystem.

STATUS: 7 August 2014: This feature is not yet available in released versions of Couchbase Lite. It is experimental and checked in on a branch. It's currently only implemented for iOS and OS X. The feature set and API are subject to change. We make no claims about the durability or security of the encrypted data. Use at your own risk.

Why to use it

  • If your iOS app needs to store private or confidential data, and you don't trust the users to enable passcodes on their iOS devices.
  • If you develop for OS X and want to store data securely.

Why not to use it

  • iOS's default filesystem encryption is good enough for most use cases: all app files are already encrypted with a key that's unavailable when the app isn't running, provided the user has set up a device passphrase. (OS X doesn't have this by default, though a user can opt into full-disk FileVault encryption.)
  • Key management can be annoying -- on iOS you'll probably have to prompt the user for a passphrase on launch, since if you don't trust the built-in security that means you don't trust the Keychain to hold the key.
  • Slight drop in performance -- SQLCipher claims about 5-15% overhead in database I/O.
  • Larger application size -- you have to embed a copy of SQLCipher instead of using the system's built-in SQLite library.

Building it

  1. Check out and build the feature/encryption branch of the couchbase-lite-ios repo.
  2. Change your app target to link with this framework instead of the stock CouchbaseLite.framework.
  3. Check out couchbaselabs/sqlcipher. This is a fork of the default SQLCipher repo that enables the FTS4 and RTree features of SQLite.
  4. Run the shell script build.sh in the sqlcipher directory.
  5. Find the libraries in the build output directory (whose location depends on your Xcode preferences.) For OS X you want Release/libsqlcipher.a. For iOS you want both Release-iphoneos/libsqlcipher.a and Release-iphonesimulator/libsqlcipher.a.
  6. Copy the library or libraries to your project's directory. (For iOS, give the two libraries different names, like libsqlcipher-device.a and libsqlcipher-sim.a.)
  7. Add the library or libraries to your app target.
  8. Remove libsqlite.dylib from the Link Binary With Libraries build phase of your app target.
  9. Try building your app. It should build and run fine.

Enabling encryption

At this point, Couchbase Lite won't work any differently. Databases are still unencrypted by default.

Before creating or opening an encrypted database, you need to register its password or key:

    CBLManager* mgr = [CBLManager sharedInstance];
    [mgr registerEncryptionKey: @"password123456" forDatabaseNamed: @"launch-codes"];
    CBLDatabase* db = [mgr databaseNamed: @"launch-codes"];

The encryption key is applied when the database is created, i.e. the first time databaseNamed: is called. After that, the same key needs to be registered before the database can be re-opened. (It's not yet possible to add encryption to an existing database, or to change or remove the key afterwards.)

Using raw keys

Typically you'll provide the key in the form of a password or passphrase contained in an NSString, as in the example. Behind the scenes, the passphrase will be converted into a 256-bit key using the PBKDF2 algorithm.

Alternatively, you can pass a raw AES key in the form of an NSData object. It must be exactly 32 bytes (256 bits) long. (Any 32 bytes will work as a valid key.)

  • Do call SecRandomCopyBytes to generate a random key.
  • Don't use a general-purpose random number generator like random -- it's not random enough for cryptography.
  • Don't try to convert a password string into a key yourself unless you know a lot about crypto, understand what PBKDF2 is and how it works, and think you can do better.

No more attachment file access

Generally you retrieve attachments as NSData objects, but Couchbase Lite does provide one or two ways to get the path (or URL) of the file containing an attachment. If you're doing the latter, it won't work with an encrypted database, because the attachment files are encrypted. Instead, CBLAttachment.contentURL will be nil, and a HEAD call to an attachment URL in the REST API will not include a Location: header giving the path of the file.

However, we've added a new way to read large attachments efficiently. -[CBLAttachment openContentStream] returns an NSInputStream object through which you can read the decrypted contents of the attachment. (Just make sure to close the stream when you're done.)