Encrypting data on the device

To enable the encryption of local data stores on mobile devices, you must make updates to your application to include encryption capabilities and create encrypted data stores.

Encrypting data on iOS devices

Procedure

  1. Obtain the encryption capabilities with CocoaPods.
    1. Open your Podfile and add the following line:

      BEFORE (with IMFData/CloudantToolkit):

      pod 'IMFDataLocal/SQLCipher'
      AFTER (with Cloudant Sync):
      pod 'CDTDatastore/SQLCipher'
      For more information, see the CDTDatastore encryption documentation.
    2. Run the following command to add the dependencies to your application.
      pod install
  2. To use the encryption feature within a Swift application, add the following imports to the associated bridging header for the application: BEFORE (with IMFData/CloudantToolkit):
    #import <CloudantSync.h>
    #import <CloudantSyncEncryption.h>
    #import <CloudantToolkit/CloudantToolkit.h>
    #import <IMFData/IMFData.h> 
    AFTER (with Cloudant Sync):
    #import <CloudantSync.h>
    #import <CloudantSyncEncryption.h>
  3. Initialize your local store for encryption with a key provider.
    Warning: If you change the password after creating the database, an error occurs because the existing database cannot be decrypted. You cannot change your password after the database has been encrypted. You must delete the database to change passwords.
    BEFORE (with IMFData/CloudantToolkit):
    //Get reference to data manager
    IMFDataManager *manager = [IMFDataManager sharedInstance];
    NSString *name = @"automobiledb";
    NSError *error = nil;
    
    // Initalize a key provider
    id<CDTEncryptionKeyProvider> keyProvider = [CDTEncryptionKeychainProvider providerWithPassword: @"passw0rd" forIdentifier: @"identifier"];
    
    //Initialize local store
    CDTStore *localStore = [manager localStore: name withEncryptionKeyProvider: keyProvider error: &error];
    let manager = IMFDataManager.sharedInstance()
    let name = "automobiledb"
    
    let keyProvider = CDTEncryptionKeychainProvider(password: "passw0rd", forIdentifier: "identifier")
    var store:CDTStore?
    do {
        store = try manager.localStore(name, withEncryptionKeyProvider: keyProvider)
    } catch let error as NSError {
        // Handle error
    }
    AFTER (with Cloudant Sync):
    // Get reference to datastore manager
    CDTDatastoreManager *datastoreManager = existingDatastoreManager;
    NSString *name = @"automobiledb";
    NSError *error = nil;
    
    // Create KeyProvider
    id<CDTEncryptionKeyProvider> keyProvider = [CDTEncryptionKeychainProvider providerWithPassword: @"passw0rd" forIdentifier: @"identifier"];
    
    //Create local store
    CDTDatastore *datastore = [datastoreManager datastoreNamed:name withEncryptionKeyProvider:keyProvider error:&error];
    // Get reference to datastore manager
    let datastoreManager:CDTDatastoreManager = existingDatastoreManager
    let name:String  = "automobiledb"
    
    //Create local store
    var datastore:CDTDatastore?
    let keyProvider = CDTEncryptionKeychainProvider(password: "passw0rd", forIdentifier: "identifier")
    do{
        datastore = try datastoreManager.datastoreNamed(name, withEncryptionKeyProvider: keyProvider)
    }catch let error as NSError{
        // Handle error
    }
  4. When you are replicating data with an encrypted local store, you must initialize the CDTPullReplication and CDTPushReplication methods with a key provider.
    BEFORE (with IMFData/CloudantToolkit):
    //Get reference to data manager
    IMFDataManager *manager = [IMFDataManager sharedInstance];
    NSString *databaseName = @"automobiledb";
    
    // Initalize a key provider
    id<CDTEncryptionKeyProvider> keyProvider = [CDTEncryptionKeychainProvider providerWithPassword:@"password" forIdentifier:@"identifier"];
    
    // pull replication
    CDTPullReplication *pull = [manager pullReplicationForStore: databaseName withEncryptionKeyProvider: keyProvider];
    
    
    // push replication
    CDTPushReplication *push = [manager pushReplicationForStore: databaseName withEncryptionKeyProvider: keyProvider];
    //Get reference to data manager
    let manager = IMFDataManager.sharedInstance()
    let databaseName = "automobiledb"
    
    // Initalize a key provider
    let keyProvider = CDTEncryptionKeychainProvider(password: "password", forIdentifier: "identifier")
    
    // pull replication
    let pull:CDTPullReplication = manager.pullReplicationForStore(databaseName, withEncryptionKeyProvider: keyProvider)
    
    
    // push replication
    let push:CDTPushReplication = manager.pushReplicationForStore(databaseName, withEncryptionKeyProvider: keyProvider)
    AFTER (with Cloudant Sync):

    Replication with an encrypted database requires no changes from replication with an unencrypted database.

Android

Encrypting data on Android devices

To encrypt data on an Android device, obtain encryption capabilities by including the correct libraries in your application. Then, you can initialize your local store for encryption and replicate data.

Procedure

  1. Add the Cloudant Toolkit library as a dependency in your build.gradle file: BEFORE (with IMFData/CloudantToolkit):
    repositories {
        mavenCentral()
    }
    
    dependencies {
        compile 'com.ibm.mobile.services:cloudant-toolkit-local:1.0.0'
    }
    AFTER (with Cloudant Sync):
    repositories {
        mavenLocal()
        maven { url "http://cloudant.github.io/cloudant-sync-eap/repository/" }
        mavenCentral()
    }
    
    dependencies {
        compile group: 'com.cloudant', name: 'cloudant-sync-datastore-core', version:'0.13.2'
        compile group: 'com.cloudant', name: 'cloudant-sync-datastore-android', version:'0.13.2'
        compile group: 'com.cloudant', name: 'cloudant-sync-datastore-android-encryption', version:'0.13.2'
    }
  2. Download the SQLCipher for Android v3.2 .jar and .so binary files and include them in your application in the appropriate folders within your app structure:
    1. Add libraries. Add the shared library files and SQLCipher archive to the jniLibs folder under your Android app directory.
    2. Add the required ICU compressed file to the assets folder in your app.
    3. Add sqlcipher.jar as a file dependency. From the app folder menu in Android studio, select the Dependencies tab under Open Module Settings.
  3. Initialize your local store for encryption with a key provider.
    Warning: If you change the password after you create the database, an error occurs because the existing database cannot be decrypted. You cannot change your password after the database is encrypted. You must delete the database to change passwords.
    BEFORE (with IMFData/CloudantToolkit):Android
    // Get reference to DataManager
    DataManager manager = DataManager.getInstance();
    
    // Initalize a key provider
    KeyProvider keyProvider = new AndroidKeyProvider(getContext(),"password","identifier");
    
    // Create local store
    String databaseName = "automobiledb";
    Task<Store> storeTask = manager.localStore(databaseName, keyProvider);
    storeTask.continueWith(new Continuation<Store, Void >() {
        @Override
        public Void then(Task<Store> task) throws Exception {
            if (task.isFaulted()) {
                // Handle error
            } else {
                // Do something with Store
                Store store = task.getResult();
            }
            return null;
         }
    });
    AFTER (with Cloudant Sync):Android
    // Load SQLCipher libs
    SQLiteDatabase.loadLibs(context);
    
    // Create DatastoreManager
    File path = context.getDir("databasedir", Context.MODE_PRIVATE);
    DatastoreManager manager = new DatastoreManager(path.getAbsolutePath());
    
    // Create encrypted local store
    String name = "automobiledb";
    
    KeyProvider keyProvider = new AndroidKeyProvider(context,"passw0rd","identifier");
    Datastore datastore = manager.openDatastore(name, keyProvider);
  4. When you are replicating data with an encrypted local store, you must pass a KeyProvider object into the pullReplicationForStore() or pushReplicationForStore() method.
    BEFORE (with IMFData/CloudantToolkit):Android
    //Get reference to data manager
    DataManager manager = DataManager.getInstance();
    String databaseName = "automobiledb";
    
    // Initalize a key provider
    KeyProvider keyProvider = new AndroidKeyProvider(getContext(),"password","identifier");
    
    // pull replication
    Task<PushReplication> pullTask = manager.pullReplicationForStore(databaseName, keyProvider);
    
    // push replication
    Task<PushReplication> pushTask = manager.pushReplicationForStore(databaseName, keyProvider);
    AFTER (with Cloudant Sync):

    Replication with an encrypted database requires no changes from replication with an unencrypted database.