Two snippets below. I ran the first version to create the database and the second to test after updating to 4.2.0. This is analogous to our production code.
Before (reference to sqlcipher-xamarin-android 3.4.2)
try
{
var key = new byte[] { 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F };
var filename = Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal), "test.sqlcipher");
using (var c = new Mono.Data.Sqlcipher.SqliteConnection($"data source={filename}"))
{
c.SetPassword(key);
c.Open();
using (var cmd = c.CreateCommand())
{
cmd.CommandText = "PRAGMA cipher_version;";
var cipherVersion = cmd.ExecuteScalar() as string;
cmd.CommandText = "create table test ( forename text );"; cmd.ExecuteNonQuery();
cmd.CommandText = "insert into test ( forename ) values ( 'simon' );"; cmd.ExecuteNonQuery();
cmd.CommandText = "select count(*) rows from test";
var rows = cmd.ExecuteScalar() as long?;
}
}
}
catch (Exception e)
{
var message = e.Message;
}
After: (references to zetetic-sqlcipher-android 4.2.0 and Microsoft.Data.Sqlite 2.2.6)
try
{
var key = new byte[] { 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F };
var filename = Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal), "test.sqlcipher");
using (var c = new Microsoft.Data.Sqlite.SqliteConnection($"data source={filename}"))
{
c.Open();
using (var cmd = c.CreateCommand())
{
var blob = BitConverter.ToString(key).Replace("-", "");
cmd.CommandText = $"PRAGMA key = \"x'{blob}'\";"; cmd.ExecuteNonQuery();
cmd.CommandText = "PRAGMA cipher_compatibility = 3;"; cmd.ExecuteNonQuery();
cmd.CommandText = "PRAGMA cipher_version;";
var cipherVersion = cmd.ExecuteScalar() as string;
cmd.CommandText = "select count(*) rows from test";
var rows = cmd.ExecuteScalar() as long?;
}
}
}
catch (Exception e)
{
var message = e.Message;
}
Edit: The keys are randomly generated:
using (var rngCryptoServiceProvider = new System.Security.Cryptography.RNGCryptoServiceProvider())
{
var randomBytes = new byte[32];
rngCryptoServiceProvider.GetBytes(randomBytes);
return randomBytes;
}
Edit 2: I think you’re right about the key. I used “PRAGMA rekey” at the end of the first version and the second version can now use the database. Obviously the first version using SetPassword() no longer works after doing this.