-
Notifications
You must be signed in to change notification settings - Fork 301
Database Encryption
STATUS: 7 August 2014: This feature is experimental and checked in on a branch. The feature set and API are subject to change. We make no claims about the durability or security of the data. Use at your own risk.
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.
- 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.
- 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.
- Check out and build the
feature/encryptionbranch of thecouchbase-lite-iosrepo. - Change your app target to link with this framework instead of the stock CouchbaseLite.framework.
- Check out couchbaselabs/sqlcipher. This is a fork of the default SQLCipher repo that enables the FTS4 and RTree features of SQLite.
- Run the shell script
build.shin thesqlcipherdirectory. - 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 bothRelease-iphoneos/libsqlcipher.aandRelease-iphonesimulator/libsqlcipher.a. - Copy the library or libraries to your project's directory. (For iOS, give the two libraries different names, like
libsqlcipher-device.aandlibsqlcipher-sim.a.) - Add the library or libraries to your app target.
- Remove
libsqlite.dylibfrom the Link Binary With Libraries build phase of your app target. - Try building your app. It should build and run fine.
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.)
Typically you'll provide the key in the form of a password or passphrase contained in an NSString, as in the example. 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
SecRandomCopyBytesto 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.
Generally you retrieve attachments as NSData objects, but Couchbase Lite does have 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.)