Upgrading to SQLCipher 4 for .NET applications using the SQlite-net API


#1

Starting with version 4, SQLCipher Commercial and Enterprise packages for Microsoft .NET feature a completely revamped client API. This new integration approach adds features and new supported interfaces, however, it does require some changes for applications using the “SQLite-net” API.

Releases of SQLCipher prior to 4 were based on the SQLite.Net-PCL adapter. Unfortunately, over time, the project was abandoned and development stopped. As a result, SQLCipher 4 has switched to a new and more modern sqlite-net compatible package based on the official praeclarum/sqlite-net project. The new packages provide a very similar API, so only minor changes are required to convert an application. As an added benefit, applications that migrate to the new API can take advantage of improved support for .NET Standard and .NET Core.

This document provides guidance on the specific steps a developer should follow to convert an application from Zetetic’s SQLCipher 3’s .NET packages to SQLCipher 4’s packages.

Step 1. Remove SQLCipher 3.x NuGet Packages
Start by removing any SQLCipher NuGet packages from the application that were provided as part of the SQLCipher 3 distribution. This may include a number of local packages. Make sure to both remove the NuGet project references, and also to remove the underlying .nupkg files from the Solution folders.

Step 2. Remove any references to SQLite.Net.Core-PCL

If your application has any direct NuGet dependencies on SQLite.Net.Core-PCL (e.g. from a shared data access project library), make sure all the NuGet packages are removed from every project in the Solution.

Step 3. Remove SQLCipher 3.x VSIX Packages

From References, select any SQLCipher VSIX package references and remove them from the Project. Note that this step will only apply to Microsoft Windows 10 UAP and Windows Runtime packages.

Step 4. Add Local nuget.config file and SQLCipher 4 packages

Copy the appropriate SQLCipher 4 .nupkg files into a folder under the root of the application Solution. The folder should include:

  1. Any platform specific SQLCipher providers required for your solution (one each per platform, e.g. zetetic-sqlcipher-windows-uap.4.0.0.nupkg)
  2. The sqlite-net compatible API implementation, zetetic-sqlite-net-base-X.X.X.nupkg

Create a simple nuget.config file in the same directory as the .sln and .nupkg file that points a package source to the directory where the .nupkg file(s) are located. The following example nuget.config will add a local package source pointing to the current directory where the nuget.config and .sln file are located:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <packageSources>
    <add key="Local" value="." />
  </packageSources>
</configuration>

After setting up the nuget.config (if it doesn’t already exist), add NuGet dependencies as follow:

  1. All projects that use the SQLite-net interface should declare a depedency on zetetic-sqlite-net-base
  2. Application projects (e.g. specifically targeting UAP, Xamarin.iOS, or Xamain.Android should declare a dependency on the applicable platform-specific SQLCipher package, e.g. zetetic-sqlcipher-windows-uap

Step 5. Replace using Directives

Any source files that reference SQLite.Net or SQLite.Net.Platform.SQLCipher.* via using statements should replace those dependencies with using SQLite;. For example, delete the following lines from source files:

using SQLite.Net;
using SQLite.Net.Platform.SQLCipher.WinRT;

Replace them with:

using SQLite;

Step 6. Minor Code Changes

With the old constructor the key would be passed to an instance of the platform-specific provider, which would then be provided to the SQLiteConnection along with the target database path, e.g.

var connection = new SQLiteConnection(new SQLitePlatformWinRT(key), databasePath);

With the new API, the database path and key are provided to the constructor, but there is no platform-specific provider - that is determined at runtime. The second parameter indicates that the SQLite-net API should use expanded dates instead of storing time as ticks, which is required for applications that stored date and time values using the old API (if this doesn’t apply to your application, pass true as the second parameter).

var connection = new SQLiteConnection(databasePath, false, key);

Each constructor invocation should be changed accordingly.

Next, to ensure that the SQLCipher package appropriate for you platform is used, add the following early in your application’s startup lifecycle code:

SQLitePCL.Batteries_V2.Init();

For Xamarin.iOS you will also need to call one additional method, SQLitePCL.lib.embedded.Init(), to instruct the Xamarin linker to properly bundle SQLCipher, i.e.

SQLitePCL.lib.embedded.Init(); /* required on iOS to link SQLCipher library */.
SQLitePCL.Batteries_V2.Init();

Step 7. Migrate Database (Optional)

With these changes in place, it should be possible to build and execute your application. However, if your application is dealing with databases created with older versions of SQLCipher, it may be necessary to migrate databases or enable compatibility mode.

Step 8. Testing

While the new library provides a similar API, we still strongly recommend performing a thorough test of your application to ensure there are not regressions resulting from the migration. Ideally testing should include operation with existing databases and new databases. Special attention should be paid to logic surrounding the code changes (i.e. constructor logic), verification on all deployed platforms, and validation of date / timestamp storage and processing.

Additional Support

If you run into any trouble with these migration steps, please contact us for additional assistance.


#2