Implementing Client-side Encryption with Azure Mobile Apps

4 minute read • July 15, 2016

Adrian Hall (MSFT)
Azure Mobile Apps provides an offline sync feature that makes it easy to build mobile apps that work without a network connection. When apps use this feature, end users can still create and modify data, even when the app is in an offline mode. The changes are saved to a local store and can be synced to your Mobile App backend when the app is back online. See Offline Data Sync in Azure Mobile Apps for more details. Offline sync uses a local store to persist data on the client device, where the specific storage implementation can be customized. The Mobile Apps client SDK provides local stores based on SQLite (Windows, Xamarin, and Android) and Core Data (iOS native).  SQLite does not have any built-in encryption support, but there are a number of extensions that provide encryption. One such extension is the SQLite Encryption Extension (SEE). SEE is an add-on to the public domain version of SQLite and does not require a custom local store implementation.  Note that SEE is not the only encryption option for Mobile Apps; For instance, you can define a local store that uses SQLCipher for encryption. This sample requires you to purchase a license for SEE.  This is not included as part of the Azure Mobile Apps Client SDK. In this article I will walk through a sample to show how to create an encrypted local store using SEE in a Xamarin.Android app - this can be done in three parts:
  1. Build the Quickstart for Xamarin.Android and enable offline sync
  2. Build sqlite3.dll with SEE for Android
  3. Update the Quickstart to use custom version of sqlite3
The Quickstart for Azure Mobile Apps builds a simple task list.  You can follow the Getting Started tutorial for Xamarin.Android and then Enable Offline Sync in your quickstart app.

Build SQLite with SEE Support for Android

The SQLite Encryption Extension is a commercial encryption product and you must buy a license for SEE before continuing.  After purchase, you may download the code for building SQLite for Android and build the native SQLite3 library with SEE.  By default, the native library is build for the armeabi platform - common for actual Android devices.  You will need to build the native app for an x86 platform if you wish to run your modified app on the Visual Studio Emulator for Android.  To do this, open a Visual Studio command prompt and do the following:
cd SQLite_Android_Bindings\sqlite3\src\main
ndk-build.cmd APP_ABI=x86
Adjust the paths above as appropriate for your environment. Once built, you can open your Quickstart project in Visual Studio and copy the generated native library for x86 from SQLite_Android_Bindings\sqlite3\src\main\libs\x86 to YourQuickstartProject\lib\x86. Finally, update the build action for the copied libsqliteX.so file to be AndroidNativeLibrary: 2016-07-06_15h45_34

Build and Run the Quickstart

Before we can build the Quickstart, we need to configure the build environment to include the modified sqliteX DLL instead of the normal sqlite3.dll system library that is a part of the Android platform. Add an app.config file to your project with the following:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <dllmap dll="sqlite3" target="libsqliteX.so" />
</configuration>
Any P/Invoke operations that would normally load the sqlite3.dll will now be mapped to load the libsqliteX.so file that we provide. The SQLitePCL library that is used by the Azure Mobile Apps Offline Client SDK uses P/Invoke to call the native methods within sqlite3.dll, so this will now automatically reference the sqliteX library. This configuration file needs to be included in the APK package. This only happens when the EmbedAssembliesIntoApk is set to true in your csproj file. This property is set to false by default when using a debug build. When debugging the app, ensure you set the EmbedAssembliesIntoApk to true. Edit the csproj file and add the following to it:
<EmbedAssembliesIntoApk>True</EmbedAssembliesIntoApk>
It's a good idea to do this edit from a normal text editor and then load it into Visual Studio. For an example, see the sample on GitHub. We can now create a local encrypted SQLite database protected by a password for use with offline sync. Create a MobileServiceSQLiteStore as normal, but specify a file Uri with a query parameter that includes the password. Here is the modified code that initialized the local store:
/// <summary>
/// Converts a string to a hex key
// </summary>
private string StringToHex(string hexstring) 
{ 
    var sb = new StringBuilder(); 
    foreach (char t in hexstring) 
    { 
        sb.Append(Convert.ToInt32(t).ToString("x") + " "); 
    } 
    return sb.ToString(); 
} 

private async Task InitLocalStoreAsync() 
{ 
    // WARNING: Do not hard code passwords in your application! 
    var password = "Hello"; 

    if (!Utils.MobileService.SyncContext.IsInitialized) 
    { 
        // Generate the URI to the offline cache file 
        var hexkey = StringToHex(password); 
        var offlineCacheUri = new System.Uri(Path.Combine(ApplicationData.Current.LocalFolder.Path,"testSee.db")); 
        string offlineCache = $"{offlineCacheUri.AbsoluteUri}?hexkey={hexkey}"; 

        // Set up the encrypted SQLite Store as normal 
        var store = new MobileServiceSQLiteStore(offlineCache); 
        store.DefineTable<TodoItem>(); 
        await Utils.MobileService.SyncContext.InitializeAsync(store); 
    } 

    // Synchronize the offline cache with the server 
    await SyncAsync(); 
}
Once the local database is created with a password, it is encrypted. If you try to use that database without providing a valid password, it would fail (throwing an Exception) with the error message ‘Error: file is encrypted or is not a database’. We've created a sample on GitHub that includes a solution for Xamarion.iOS and Universal Windows (UWP). The same technique will also work with Xamarin.Forms applications.

Useful links

Tips

The Android Debug Log shows detailed logs on location of the assemblies being loaded into the application. You can use this to verify the sqliteX that you built is loaded into the app. For Xamarin.Android, set the build configuration to match the native library architecture. A mismatch in the architecture will cause dll not found errors.

Getting in touch

As always, you can ask questions of the team via Stack Overflow or the Azure Forums.