Skip to content

Commit 23f4aa4

Browse files
author
Svetlana Korosteleva
committed
Add interface to perform migration to new major SQLCipher immediately after setting a key
This change adds `keyAndMigrate` methods which perform "PRAGMA cipher_migrate;" call immediately after calling `sqlite3_key_v2` This call is needed to open the database files created in older major SQLCipher version (e.g. 3.x.x) by newer SQLCipher version (e.g. 4.x.x). These calls should be performed only once, when opening older database files for the first time. See https://www.zetetic.net/sqlcipher/sqlcipher-api/#cipher_migrate and https://discuss.zetetic.net/t/upgrading-to-sqlcipher-4/3283 for more details regarding SQLCipher upgrade
1 parent 0a9893e commit 23f4aa4

File tree

1 file changed

+32
-1
lines changed

1 file changed

+32
-1
lines changed

Sources/SQLite/Extensions/Cipher.swift

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,25 @@ extension Connection {
3232
try _key_v2(db: db, keyPointer: key.bytes, keySize: key.bytes.count)
3333
}
3434

35+
/// Same as `key(_ key: String, db: String = "main")`, running "PRAGMA cipher_migrate;"
36+
/// immediately after calling `sqlite3_key_v2`, which performs the migration of
37+
/// SQLCipher database created by older major version of SQLCipher, to be able to
38+
/// open this database with new major version of SQLCipher
39+
/// (e.g. to open database created by SQLCipher version 3.x.x with SQLCipher version 4.x.x).
40+
/// As "PRAGMA cipher_migrate;" is time-consuming, it is recommended to use this function
41+
/// only after failure of `key(_ key: String, db: String = "main")`, if older versions of
42+
/// your app may ise older version of SQLCipher
43+
/// See https://www.zetetic.net/sqlcipher/sqlcipher-api/#cipher_migrate
44+
/// and https://discuss.zetetic.net/t/upgrading-to-sqlcipher-4/3283
45+
/// for more details regarding SQLCipher upgrade
46+
public func keyAndMigrate(_ key: String, db: String = "main") throws {
47+
try _key_v2(db: db, keyPointer: key, keySize: key.utf8.count, migrate: true)
48+
}
49+
50+
/// Same as `[`keyAndMigrate(_ key: String, db: String = "main")` accepting byte array as key
51+
public func keyAndMigrate(_ key: Blob, db: String = "main") throws {
52+
try _key_v2(db: db, keyPointer: key.bytes, keySize: key.bytes.count, migrate: true)
53+
}
3554

3655
/// Change the key on an open database. If the current database is not encrypted, this routine
3756
/// will encrypt it.
@@ -47,8 +66,20 @@ extension Connection {
4766
}
4867

4968
// MARK: - private
50-
private func _key_v2(db: String, keyPointer: UnsafePointer<UInt8>, keySize: Int) throws {
69+
private func _key_v2(db: String,
70+
keyPointer: UnsafePointer<UInt8>,
71+
keySize: Int,
72+
migrate: Bool = false) throws {
5173
try check(sqlite3_key_v2(handle, db, keyPointer, Int32(keySize)))
74+
if migrate {
75+
// Run "PRAGMA cipher_migrate;" immediately after `sqlite3_key_v2`
76+
// per recommendation of SQLCipher authors
77+
let migrateResult = try scalar("PRAGMA cipher_migrate;")
78+
if (migrateResult as? String) != "0" {
79+
// "0" is the result of successfull migration
80+
throw Result.error(message: "Error in cipher migration, result \(migrateResult.debugDescription)", code: 1, statement: nil)
81+
}
82+
}
5283
try cipher_key_check()
5384
}
5485

0 commit comments

Comments
 (0)