Skip to content

Commit

Permalink
Merge pull request #1089 from shiena/sqlcipher/setrekey
Browse files Browse the repository at this point in the history
Add SetReKey for SQLCipher
  • Loading branch information
praeclarum committed Mar 27, 2024
2 parents df96ed1 + bbdb422 commit e79dd0e
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 2 deletions.
30 changes: 28 additions & 2 deletions src/SQLite.cs
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,7 @@ static string Quote (string unsafeString)
/// if your database is encrypted.
/// This only has an effect if you are using the SQLCipher nuget package.
/// </summary>
/// <param name="key">Ecryption key plain text that is converted to the real encryption key using PBKDF2 key derivation</param>
/// <param name="key">Encryption key plain text that is converted to the real encryption key using PBKDF2 key derivation</param>
void SetKey (string key)
{
if (key == null)
Expand All @@ -477,7 +477,7 @@ void SetKey (string key)
/// if your database is encrypted.
/// This only has an effect if you are using the SQLCipher nuget package.
/// </summary>
/// <param name="key">256-bit (32 byte) ecryption key data</param>
/// <param name="key">256-bit (32 byte) encryption key data</param>
void SetKey (byte[] key)
{
if (key == null)
Expand All @@ -488,6 +488,32 @@ void SetKey (byte[] key)
ExecuteScalar<string> ("pragma key = \"x'" + s + "'\"");
}

/// <summary>
/// Change the encryption key for a SQLCipher database with "pragma rekey = ...".
/// </summary>
/// <param name="key">Encryption key plain text that is converted to the real encryption key using PBKDF2 key derivation</param>
public void SetReKey (string key)
{
if (key == null)
throw new ArgumentNullException(nameof(key));
var q = Quote(key);
ExecuteScalar<string>("pragma rekey = " + q);
}

/// <summary>
/// Change the encryption key for a SQLCipher database.
/// </summary>
/// <param name="key">256-bit (32 byte) or 384-bit (48 bytes) encryption key data</param>
public void SetReKey (byte[] key)
{
if (key == null)
throw new ArgumentNullException(nameof(key));
if (key.Length != 32 && key.Length != 48)
throw new ArgumentException ("Key must be 32 bytes (256-bit) or 48 bytes (384-bit)", nameof (key));
var s = String.Join("", key.Select(x => x.ToString("X2")));
ExecuteScalar<string>("pragma rekey = \"x'" + s + "'\"");
}

/// <summary>
/// Enable or disable extension loading.
/// </summary>
Expand Down
66 changes: 66 additions & 0 deletions tests/SQLite.Tests/SQLCipherTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -148,5 +148,71 @@ public void CheckJournalModeForNonKeyed ()
Assert.AreEqual ("wal", db.ExecuteScalar<string> ("PRAGMA journal_mode;"));
}
}

[Test]
public void ResetStringKey ()
{
string path;

var key = "SecretPassword";
var reKey = "SecretKey";

using (var db = new TestDb (key: key)) {
db.SetReKey (reKey);
path = db.DatabasePath;

db.CreateTable<TestTable> ();
db.Insert (new TestTable { Value = "Hello" });
}

using (var db = new TestDb (path, key: reKey)) {
var r = db.Table<TestTable> ().First ();

Assert.AreEqual ("Hello", r.Value);
}
}

[Test]
public void ResetByteKey ()
{
string path;

var rand = new Random ();
var key = new byte[32];
rand.NextBytes (key);
var reKey = new byte[32];
rand.NextBytes (reKey);

using (var db = new TestDb (key: key)) {
db.SetReKey (reKey);
path = db.DatabasePath;

db.CreateTable<TestTable> ();
db.Insert (new TestTable { Value = "Hello" });
}

using (var db = new TestDb (path, key: reKey)) {
var r = db.Table<TestTable> ().First ();

Assert.AreEqual ("Hello", r.Value);
}
}

[Test]
public void ResetBadKey ()
{
var key = new byte[] { 42 };

try
{
using (var db = new TestDb ()) {
db.SetReKey (key);
}

Assert.Fail ("Should have thrown");
}
catch (ArgumentException) {
}
}
}
}

0 comments on commit e79dd0e

Please sign in to comment.