CDTDatastore is able to create encrypted datastores.
To do so, first edit your Podfile
and replace:
pod "CDTDatastore"
With:
pod "CDTDatastore/SQLCipher"
This change will bring in the SQLCipher library, which is used to encrypted the SQLite databases used to store JSON and index data.
Once you've re-run pod install
, you're able to create encrypted datastores.
To create an encrypted datastore, you initialise a datastore with a class conforming to the CDTEncryptionKeyProvider protocol. We include conforming classes with the library (see below), or you can implement your own if the included classes are unsuitable. The protocol defines a single method:
- (CDTEncryptionKey *)encryptionKey;
This method should return a CDTEncryptionKey instance. The
main purpose of the CDTEncryptionKey
class is to ensure that the key has the
right size (256 bits).
We include two classes conforming to CDTEncryptionKeyProvider
with the library.
- CDTEncryptionKeychainProvider. This is the recommended key provider. It handles generating a strong, 256-bit key from a user-provided password and stores it safely in the keychain, encrypted with a key generated from a provided password using PBKDF2.
- CDTEncryptionKeySimpleProvider. This class
implements the protocol
CDTEncryptionKeyProvider
and it is initialised with a raw key of 256-bits. Its behaviour is quite simple: whenever the methodCDTEncryptionKeyProvider:encryptionKey
is called, it returns the key. However, in this case you are responsible for creating a strong key and storing it safely.
If you decide to implement your own class, keep in mind that if
CDTEncryptionKeyProvider:encryptionKey
returns nil
, the datastore won't be
encrypted regardless of the subspec defined in your Podfile
.
Once you have a key provider, call
CDTDatastoreManager:datastoreNamed:withEncryptionKeyProvider:error:
to create encrypted
datastores. Datastores created in this manner behave identically to unencrypted
datastores from the perspective of the API.
Below is an example of creating an encrypted and unencrypted datastore using the encryption-enabled podspec.
#import "AppDelegate.h"
#import <CloudantSync.h>
#import <CloudantSyncEncryption.h>
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
// Create a CDTDatastoreManager using application internal storage path
NSError *error = nil;
NSFileManager *fileManager= [NSFileManager defaultManager];
NSURL *documentsDir = [[fileManager URLsForDirectory:NSDocumentDirectory
inDomains:NSUserDomainMask] lastObject];
NSURL *storeURL = [documentsDir URLByAppendingPathComponent:@"cloudant-sync-datastore"];
NSString *path = [storeURL path];
CDTDatastoreManager *manager =
[[CDTDatastoreManager alloc] initWithDirectory:path
error:&error];
// To create an encrypted datastore, create your datastore using an object
// implementing the CDTKeyProvider protocol
CDTEncryptionKeychainProvider *provider = [CDTEncryptionKeychainProvider
providerWithPassword:@"blahblah"
forIdentifier:@"default"];
CDTDatastore *encrypted = [manager datastoreNamed:@"encrypted_datastore"
withEncryptionKeyProvider:provider
error:&error];
// To create an *un*encrypted datastore, just leave out the CDTKeyProvider
CDTDatastore *unencrypted = [manager datastoreNamed:@"unencrypted_datastore"
error:&error];
// Use the encrypted store just the same as an unencrypted datastore
CDTDocumentRevision *rev = [CDTDocumentRevision revisionWithDocId:@"doc1"];
rev.body = @{@"description": @"Buy milk",
@"completed": @NO,
@"type": @"com.cloudant.sync.example.task"
};
// Save the document to the database
CDTDocumentRevision *revision = [encrypted createDocumentFromRevision:rev
error:&error];
// Read a document
NSString *docId = revision.docId;
CDTDocumentRevision *retrieved = [encrypted getDocumentWithId:docId
error:&error];
NSLog(@"%@", retrieved);
return YES;
}
@end
Notice that below #import <CloudantSync.h>
there is a extra import:
#import <CloudantSyncEncryption.h>
.
CloudantSyncEncryption.h imports all the classes
and methods that you need to encrypt a datastore. These methods will not be
visible until you import this file.
Data in Cloudant Sync is stored in two formats:
- In SQLite databases, for JSON data and Query indexes.
- In binary blobs on disk, for document attachments.
Both of these are encrypted using AES in CBC mode. We currently only support using 256-bit keys. SQLite databases are encrypted using SQLCipher. Attachment data is encrypted using Apple’s CommonCrypto library, built into iOS and OS X.
Our implementation is not currently FIPS 140-2 compliant.
We use Common Crypto library to encrypt the attachments before saving to disk. Databases are automatically encrypted with SQLCipher, this library requires to include its BSD-style license and copyright in your application and documentation.
Thefore, if you use the subspec CDTDatastore/SQLCipher
, please follow the
instructions mentioned here.