-
Notifications
You must be signed in to change notification settings - Fork 298
Database Encryption
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.
- 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/encryption
branch of thecouchbase-lite-ios
repo. - 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.sh
in thesqlcipher
directory. - 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.a
andRelease-iphonesimulator/libsqlcipher.a
. - Copy the library or libraries to your project's directory. (For iOS, give the two libraries different names, like
libsqlcipher-device.a
andlibsqlcipher-sim.a
.) - Add the library or libraries to your app target.
- Remove
libsqlite.dylib
from 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. 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.
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.)