From cf128ac800e335d4b37b10ee43e01f8828eab9b7 Mon Sep 17 00:00:00 2001 From: Marcel Ball Date: Wed, 25 Jul 2018 17:24:57 -0300 Subject: [PATCH 01/10] Added configuration option to set cipher_page_size on connection * Defaults to 1024 - which is the default in SQLCipher --- GRDB/Core/Configuration.swift | 12 ++++++++++++ GRDB/Core/Database.swift | 16 ++++++++++++++++ Tests/GRDBTests/EncryptionTests.swift | 24 ++++++++++++++++++++++++ 3 files changed, 52 insertions(+) diff --git a/GRDB/Core/Configuration.swift b/GRDB/Core/Configuration.swift index fac576893d..78e19c19ee 100644 --- a/GRDB/Core/Configuration.swift +++ b/GRDB/Core/Configuration.swift @@ -81,6 +81,18 @@ public struct Configuration { /// /// Default: nil public var passphrase: String? + + public enum CipherPageSize: Int { + case ps1024 = 1024 + case ps2048 = 2048 + case ps4096 = 4096 + case ps8192 = 8192 + case ps16384 = 16384 + case ps32768 = 32768 + case ps65536 = 65536 + } + + public var cipherPageSize: CipherPageSize = .ps1024 #endif diff --git a/GRDB/Core/Database.swift b/GRDB/Core/Database.swift index 8d50b0dcf2..f71f2c729e 100644 --- a/GRDB/Core/Database.swift +++ b/GRDB/Core/Database.swift @@ -173,6 +173,7 @@ public final class Database { try Database.validateSQLCipher(sqliteConnection) if let passphrase = configuration.passphrase { try Database.set(passphrase: passphrase, forConnection: sqliteConnection) + try Database.set(cipherPageSize: configuration.cipherPageSize, forConnection: sqliteConnection) } #endif try Database.validateDatabaseFormat(sqliteConnection) @@ -261,6 +262,21 @@ extension Database { throw DatabaseError(resultCode: code, message: String(cString: sqlite3_errmsg(sqliteConnection))) } } + + private static func set(cipherPageSize: Configuration.CipherPageSize, forConnection sqliteConnection: SQLiteConnection) throws { + var sqliteStatement: SQLiteStatement? = nil + let code = sqlite3_prepare_v2(sqliteConnection, "PRAGMA cipher_page_size = \(cipherPageSize.rawValue)", -1, &sqliteStatement, nil) + guard code == SQLITE_OK else { + throw DatabaseError(resultCode: code, message: String(cString: sqlite3_errmsg(sqliteConnection))) + } + defer { + sqlite3_finalize(sqliteStatement) + } + let step = sqlite3_step(sqliteStatement) + if step != SQLITE_DONE { + throw DatabaseError(resultCode: .SQLITE_MISUSE, message: "Unable to set cipher_page_size") + } + } #endif private static func validateDatabaseFormat(_ sqliteConnection: SQLiteConnection) throws { diff --git a/Tests/GRDBTests/EncryptionTests.swift b/Tests/GRDBTests/EncryptionTests.swift index bfe96d34a8..d21ba8ea75 100644 --- a/Tests/GRDBTests/EncryptionTests.swift +++ b/Tests/GRDBTests/EncryptionTests.swift @@ -333,6 +333,30 @@ class EncryptionTests: GRDBTestCase { } } + func testCipherPageSize() throws { + do { + dbConfiguration.passphrase = "secret" + dbConfiguration.cipherPageSize = .ps8192 + + let dbQueue = try makeDatabaseQueue(filename: "test.sqlite") + try dbQueue.inDatabase({ db in + XCTAssertEqual(try Int.fetchOne(db, "PRAGMA cipher_page_size")!, 8192) + }) + } + + do { + dbConfiguration.cipherPageSize = .ps4096 + + let dbQueue = try makeDatabasePool(filename: "testpool.sqlite") + try dbQueue.read({ db in + XCTAssertEqual(try Int.fetchOne(db, "PRAGMA cipher_page_size")!, 4096) + }) + try dbQueue.write({ db in + XCTAssertEqual(try Int.fetchOne(db, "PRAGMA cipher_page_size")!, 4096) + }) + } + } + func testExportPlainTextDatabaseToEncryptedDatabase() throws { // See https://discuss.zetetic.net/t/how-to-encrypt-a-plaintext-sqlite-database-to-use-sqlcipher-and-avoid-file-is-encrypted-or-is-not-a-database-errors/868?source_topic_id=939 do { From 090eea99233ea7f3e905bc6e17f6d963a9f5739e Mon Sep 17 00:00:00 2001 From: Marcel Ball Date: Wed, 6 Mar 2019 20:41:01 -0400 Subject: [PATCH 02/10] Update naming for the enumeration to be clearer --- GRDB/Core/Configuration.swift | 16 ++++++++-------- Tests/GRDBTests/EncryptionTests.swift | 14 ++++++++++---- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/GRDB/Core/Configuration.swift b/GRDB/Core/Configuration.swift index 78e19c19ee..0fb00fe421 100644 --- a/GRDB/Core/Configuration.swift +++ b/GRDB/Core/Configuration.swift @@ -83,16 +83,16 @@ public struct Configuration { public var passphrase: String? public enum CipherPageSize: Int { - case ps1024 = 1024 - case ps2048 = 2048 - case ps4096 = 4096 - case ps8192 = 8192 - case ps16384 = 16384 - case ps32768 = 32768 - case ps65536 = 65536 + case pageSize1K = 1024 + case pageSize2K = 2048 + case pageSize4K = 4096 + case pageSize8K = 8192 + case pageSize16K = 16384 + case pageSize32K = 32768 + case pageSize64K = 65536 } - public var cipherPageSize: CipherPageSize = .ps1024 + public var cipherPageSize: CipherPageSize = .pageSize1K #endif diff --git a/Tests/GRDBTests/EncryptionTests.swift b/Tests/GRDBTests/EncryptionTests.swift index d21ba8ea75..ac69d6c648 100644 --- a/Tests/GRDBTests/EncryptionTests.swift +++ b/Tests/GRDBTests/EncryptionTests.swift @@ -336,7 +336,7 @@ class EncryptionTests: GRDBTestCase { func testCipherPageSize() throws { do { dbConfiguration.passphrase = "secret" - dbConfiguration.cipherPageSize = .ps8192 + dbConfiguration.cipherPageSize = .pageSize8K let dbQueue = try makeDatabaseQueue(filename: "test.sqlite") try dbQueue.inDatabase({ db in @@ -345,15 +345,21 @@ class EncryptionTests: GRDBTestCase { } do { - dbConfiguration.cipherPageSize = .ps4096 + dbConfiguration.cipherPageSize = .pageSize4K let dbQueue = try makeDatabasePool(filename: "testpool.sqlite") - try dbQueue.read({ db in + try dbQueue.write({ db in XCTAssertEqual(try Int.fetchOne(db, "PRAGMA cipher_page_size")!, 4096) + try db.execute("CREATE TABLE data(value INTEGER)") + try db.execute("INSERT INTO data(value) VALUES(1)") }) - try dbQueue.write({ db in + try dbQueue.read({ db in XCTAssertEqual(try Int.fetchOne(db, "PRAGMA cipher_page_size")!, 4096) + XCTAssertEqual(try Int.fetchOne(db, "SELECT value FROM data"), 1) }) + + } + } } } From d4eb7ba27b256afa526a6dc8b63b8d5e72a0677f Mon Sep 17 00:00:00 2001 From: Marcel Ball Date: Wed, 6 Mar 2019 20:41:38 -0400 Subject: [PATCH 03/10] Added configuration options to GRDBcipher for kdf_iterations --- GRDB/Core/Configuration.swift | 2 ++ GRDB/Core/Database.swift | 16 ++++++++++++++ Tests/GRDBTests/EncryptionTests.swift | 32 +++++++++++++++++++++++++++ 3 files changed, 50 insertions(+) diff --git a/GRDB/Core/Configuration.swift b/GRDB/Core/Configuration.swift index 0fb00fe421..53d0544d07 100644 --- a/GRDB/Core/Configuration.swift +++ b/GRDB/Core/Configuration.swift @@ -93,6 +93,8 @@ public struct Configuration { } public var cipherPageSize: CipherPageSize = .pageSize1K + + public var cipherKDFIterations: Int = 64000 #endif diff --git a/GRDB/Core/Database.swift b/GRDB/Core/Database.swift index f71f2c729e..6e78de44a2 100644 --- a/GRDB/Core/Database.swift +++ b/GRDB/Core/Database.swift @@ -174,6 +174,7 @@ public final class Database { if let passphrase = configuration.passphrase { try Database.set(passphrase: passphrase, forConnection: sqliteConnection) try Database.set(cipherPageSize: configuration.cipherPageSize, forConnection: sqliteConnection) + try Database.set(kdfIterations: configuration.cipherKDFIterations, forConnection: sqliteConnection) } #endif try Database.validateDatabaseFormat(sqliteConnection) @@ -277,6 +278,21 @@ extension Database { throw DatabaseError(resultCode: .SQLITE_MISUSE, message: "Unable to set cipher_page_size") } } + + private static func set(kdfIterations: Int, forConnection sqliteConnection: SQLiteConnection) throws { + var sqliteStatement: SQLiteStatement? = nil + let code = sqlite3_prepare_v2(sqliteConnection, "PRAGMA kdf_iter = \(kdfIterations)", -1, &sqliteStatement, nil) + guard code == SQLITE_OK else { + throw DatabaseError(resultCode: code, message: String(cString: sqlite3_errmsg(sqliteConnection))) + } + defer { + sqlite3_finalize(sqliteStatement) + } + let step = sqlite3_step(sqliteStatement) + if step != SQLITE_DONE { + throw DatabaseError(resultCode: .SQLITE_MISUSE, message: "Unable to set kdf_iter") + } + } #endif private static func validateDatabaseFormat(_ sqliteConnection: SQLiteConnection) throws { diff --git a/Tests/GRDBTests/EncryptionTests.swift b/Tests/GRDBTests/EncryptionTests.swift index ac69d6c648..7d00dc73d7 100644 --- a/Tests/GRDBTests/EncryptionTests.swift +++ b/Tests/GRDBTests/EncryptionTests.swift @@ -360,6 +360,38 @@ class EncryptionTests: GRDBTestCase { } } + + func testCipherKDFSettings() throws { + do { + dbConfiguration.passphrase = "secret" + dbConfiguration.cipherKDFIterations = 128000 + + var dbQueue: DatabaseQueue? = try makeDatabaseQueue(filename: "test.sqlite") + try dbQueue!.inDatabase { db in + XCTAssertEqual(try Int.fetchOne(db, "PRAGMA kdf_iter"), 128000) + } + + dbQueue = nil + print("Closed") + } + + do { + dbConfiguration.cipherKDFIterations = 128000 + + var dbQueue: DatabasePool? = try makeDatabasePool(filename: "testpool.sqlite") + try dbQueue!.write { db in + XCTAssertEqual(try Int.fetchOne(db, "PRAGMA kdf_iter"), 128000) + try db.execute("CREATE TABLE data(value INTEGER)") + try db.execute("INSERT INTO data(value) VALUES(1)") + } + + try dbQueue!.read { db in + XCTAssertEqual(try Int.fetchOne(db, "PRAGMA kdf_iter"), 128000) + XCTAssertEqual(try Int.fetchOne(db, "SELECT value FROM data"), 1) + } + + dbQueue = nil + print("Closed") } } From 8415e8c2a07f7b9fcb8cf5226dbaef2adb9acfbf Mon Sep 17 00:00:00 2001 From: Marcel Ball Date: Wed, 6 Mar 2019 20:58:29 -0400 Subject: [PATCH 04/10] Rename parameter to better align with the SQLCipher PRAGMA --- GRDB/Core/Configuration.swift | 2 +- GRDB/Core/Database.swift | 2 +- Tests/GRDBTests/EncryptionTests.swift | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/GRDB/Core/Configuration.swift b/GRDB/Core/Configuration.swift index 53d0544d07..dfe799e6fc 100644 --- a/GRDB/Core/Configuration.swift +++ b/GRDB/Core/Configuration.swift @@ -94,7 +94,7 @@ public struct Configuration { public var cipherPageSize: CipherPageSize = .pageSize1K - public var cipherKDFIterations: Int = 64000 + public var KDFIterations: Int = 64000 #endif diff --git a/GRDB/Core/Database.swift b/GRDB/Core/Database.swift index 6e78de44a2..dd0e01b480 100644 --- a/GRDB/Core/Database.swift +++ b/GRDB/Core/Database.swift @@ -174,7 +174,7 @@ public final class Database { if let passphrase = configuration.passphrase { try Database.set(passphrase: passphrase, forConnection: sqliteConnection) try Database.set(cipherPageSize: configuration.cipherPageSize, forConnection: sqliteConnection) - try Database.set(kdfIterations: configuration.cipherKDFIterations, forConnection: sqliteConnection) + try Database.set(kdfIterations: configuration.KDFIterations, forConnection: sqliteConnection) } #endif try Database.validateDatabaseFormat(sqliteConnection) diff --git a/Tests/GRDBTests/EncryptionTests.swift b/Tests/GRDBTests/EncryptionTests.swift index 7d00dc73d7..7ada6d1ec2 100644 --- a/Tests/GRDBTests/EncryptionTests.swift +++ b/Tests/GRDBTests/EncryptionTests.swift @@ -364,7 +364,7 @@ class EncryptionTests: GRDBTestCase { func testCipherKDFSettings() throws { do { dbConfiguration.passphrase = "secret" - dbConfiguration.cipherKDFIterations = 128000 + dbConfiguration.KDFIterations = 128000 var dbQueue: DatabaseQueue? = try makeDatabaseQueue(filename: "test.sqlite") try dbQueue!.inDatabase { db in @@ -376,7 +376,7 @@ class EncryptionTests: GRDBTestCase { } do { - dbConfiguration.cipherKDFIterations = 128000 + dbConfiguration.KDFIterations = 128000 var dbQueue: DatabasePool? = try makeDatabasePool(filename: "testpool.sqlite") try dbQueue!.write { db in From 349ef328c7278d359db5acbfc3709f138a6b88ae Mon Sep 17 00:00:00 2001 From: Marcel Ball Date: Wed, 6 Mar 2019 21:01:08 -0400 Subject: [PATCH 05/10] Updated documentation to cover new configuration options --- README.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/README.md b/README.md index 413d8786a7..d19568439e 100644 --- a/README.md +++ b/README.md @@ -7303,6 +7303,30 @@ try clearDBQueue.inDatabase { db in // Now the copy is done, and the clear-text database can be deleted. ``` +**Advanced configuration options for SQLCipher** +There are two advanced configuration options that you can set for configuring SQLCipher that control aspects of the encryption and key generation process. + +```swift +var configuartion = Configuration() +configuration.passphrase = "secret" +configuration.cipherPageSize = .pageSize4K +configuration.KDFIterations = 128000 +let dbQueue = try DatabaseQueue(path: "...", configuration: configuration) +``` +***cipherPageSize*** +The `cipherPageSize` is used to adjust the page size for the encrypted database (this corresponds to the SQLCipher `PRAGMA cipher_page_size` configuration option). Increasing the page size can noticeably improve performance for certain queries that access large numbers of pages. + +WARNING: The same `cipherPageSize` must be supplied every time that the database file is open; attempting to access the database without setting the proper `cipherPageSize` will result in the `SQLite error 26: file is encrypted or is not a database` error being thrown. + +The default `cipherPageSize` in the current version of SQLCipher used in GRDB.swift is `.pageSize1K`. + +***KDFIterations*** +The `KDFIterations` value is used to adjust the number of iterations that the PBKDF2 key derivation is run to derive the key from the `passphrase` supplied (this corresponds to the SQLCipher `PRAGMA kdf_iter` configuration option). + +WARNING: The same `KDFIterations` must be supplied every time that the database file is open; attempting to access the database without setting the proper `KDFIterations` will result in the `SQLite error 26: file is encrypted or is not a database` error being thrown. + +The default `KDFIterations` in the current version of SQLCipher used in GRDB.swift is `64000`. It is not recommend to reduce the number of iterations used from the default. + ## Backup From 47f9b0f4a90bc95c38268a425025fb581d9d0df4 Mon Sep 17 00:00:00 2001 From: Marcel Ball Date: Wed, 6 Mar 2019 21:21:43 -0400 Subject: [PATCH 06/10] Added inline comments for new configuration options. --- GRDB/Core/Configuration.swift | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/GRDB/Core/Configuration.swift b/GRDB/Core/Configuration.swift index dfe799e6fc..6139f420e4 100644 --- a/GRDB/Core/Configuration.swift +++ b/GRDB/Core/Configuration.swift @@ -82,6 +82,7 @@ public struct Configuration { /// Default: nil public var passphrase: String? + // Valid options for the cipher_page_size setting public enum CipherPageSize: Int { case pageSize1K = 1024 case pageSize2K = 2048 @@ -92,8 +93,14 @@ public struct Configuration { case pageSize64K = 65536 } + /// The cipher_page_size for encrypted databases + /// + /// Default: .pageSize1K - this corresponds to the default used until now in SQLCipher/GRDBCipher 3 public var cipherPageSize: CipherPageSize = .pageSize1K + /// The kdf_iter setting for encrypted database + /// + /// Default: 64000 - this corresponds to the default used until now in SQLCipher/GRDBCipher 3 public var KDFIterations: Int = 64000 #endif From 8ca983943364bfd5b43b72e6cb5a1800222fd3bc Mon Sep 17 00:00:00 2001 From: Marcel Ball Date: Wed, 6 Mar 2019 21:31:37 -0400 Subject: [PATCH 07/10] Cleanup of some things leftover from debugging/testing --- Tests/GRDBTests/EncryptionTests.swift | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/Tests/GRDBTests/EncryptionTests.swift b/Tests/GRDBTests/EncryptionTests.swift index 7ada6d1ec2..3b0a3d71b5 100644 --- a/Tests/GRDBTests/EncryptionTests.swift +++ b/Tests/GRDBTests/EncryptionTests.swift @@ -366,19 +366,16 @@ class EncryptionTests: GRDBTestCase { dbConfiguration.passphrase = "secret" dbConfiguration.KDFIterations = 128000 - var dbQueue: DatabaseQueue? = try makeDatabaseQueue(filename: "test.sqlite") + let dbQueue: DatabaseQueue? = try makeDatabaseQueue(filename: "test.sqlite") try dbQueue!.inDatabase { db in XCTAssertEqual(try Int.fetchOne(db, "PRAGMA kdf_iter"), 128000) } - - dbQueue = nil - print("Closed") } do { dbConfiguration.KDFIterations = 128000 - var dbQueue: DatabasePool? = try makeDatabasePool(filename: "testpool.sqlite") + let dbQueue: DatabasePool? = try makeDatabasePool(filename: "testpool.sqlite") try dbQueue!.write { db in XCTAssertEqual(try Int.fetchOne(db, "PRAGMA kdf_iter"), 128000) try db.execute("CREATE TABLE data(value INTEGER)") @@ -389,9 +386,6 @@ class EncryptionTests: GRDBTestCase { XCTAssertEqual(try Int.fetchOne(db, "PRAGMA kdf_iter"), 128000) XCTAssertEqual(try Int.fetchOne(db, "SELECT value FROM data"), 1) } - - dbQueue = nil - print("Closed") } } From 6543d75f6d1df7fa1450743f85006ce3696778f3 Mon Sep 17 00:00:00 2001 From: Marcel Ball Date: Thu, 7 Mar 2019 17:51:16 -0400 Subject: [PATCH 08/10] Updated based upon feedback from @groue - Renamed `KDFIternations` to `kdfIterations` to better fit naming conventions - In case of errors setting values return the sqlite error code and message instead of .SQLITE_MISUSE and a generic message - Fixed formatting/typos in documentation --- GRDB/Core/Configuration.swift | 2 +- GRDB/Core/Database.swift | 18 +++++++++--------- README.md | 21 ++++++++++++--------- Tests/GRDBTests/EncryptionTests.swift | 4 ++-- 4 files changed, 24 insertions(+), 21 deletions(-) diff --git a/GRDB/Core/Configuration.swift b/GRDB/Core/Configuration.swift index 6139f420e4..91b1782714 100644 --- a/GRDB/Core/Configuration.swift +++ b/GRDB/Core/Configuration.swift @@ -101,7 +101,7 @@ public struct Configuration { /// The kdf_iter setting for encrypted database /// /// Default: 64000 - this corresponds to the default used until now in SQLCipher/GRDBCipher 3 - public var KDFIterations: Int = 64000 + public var kdfIterations: Int = 64000 #endif diff --git a/GRDB/Core/Database.swift b/GRDB/Core/Database.swift index dd0e01b480..41711c0133 100644 --- a/GRDB/Core/Database.swift +++ b/GRDB/Core/Database.swift @@ -174,7 +174,7 @@ public final class Database { if let passphrase = configuration.passphrase { try Database.set(passphrase: passphrase, forConnection: sqliteConnection) try Database.set(cipherPageSize: configuration.cipherPageSize, forConnection: sqliteConnection) - try Database.set(kdfIterations: configuration.KDFIterations, forConnection: sqliteConnection) + try Database.set(kdfIterations: configuration.kdfIterations, forConnection: sqliteConnection) } #endif try Database.validateDatabaseFormat(sqliteConnection) @@ -266,31 +266,31 @@ extension Database { private static func set(cipherPageSize: Configuration.CipherPageSize, forConnection sqliteConnection: SQLiteConnection) throws { var sqliteStatement: SQLiteStatement? = nil - let code = sqlite3_prepare_v2(sqliteConnection, "PRAGMA cipher_page_size = \(cipherPageSize.rawValue)", -1, &sqliteStatement, nil) + var code = sqlite3_prepare_v2(sqliteConnection, "PRAGMA cipher_page_size = \(cipherPageSize.rawValue)", -1, &sqliteStatement, nil) guard code == SQLITE_OK else { throw DatabaseError(resultCode: code, message: String(cString: sqlite3_errmsg(sqliteConnection))) } defer { sqlite3_finalize(sqliteStatement) } - let step = sqlite3_step(sqliteStatement) - if step != SQLITE_DONE { - throw DatabaseError(resultCode: .SQLITE_MISUSE, message: "Unable to set cipher_page_size") + code = sqlite3_step(sqliteStatement) + if code != SQLITE_DONE { + throw DatabaseError(resultCode: code, message: String(cString: sqlite3_errmsg(sqliteConnection))) } } private static func set(kdfIterations: Int, forConnection sqliteConnection: SQLiteConnection) throws { var sqliteStatement: SQLiteStatement? = nil - let code = sqlite3_prepare_v2(sqliteConnection, "PRAGMA kdf_iter = \(kdfIterations)", -1, &sqliteStatement, nil) + var code = sqlite3_prepare_v2(sqliteConnection, "PRAGMA kdf_iter = \(kdfIterations)", -1, &sqliteStatement, nil) guard code == SQLITE_OK else { throw DatabaseError(resultCode: code, message: String(cString: sqlite3_errmsg(sqliteConnection))) } defer { sqlite3_finalize(sqliteStatement) } - let step = sqlite3_step(sqliteStatement) - if step != SQLITE_DONE { - throw DatabaseError(resultCode: .SQLITE_MISUSE, message: "Unable to set kdf_iter") + code = sqlite3_step(sqliteStatement) + if code != SQLITE_DONE { + throw DatabaseError(resultCode: code, message: String(cString: sqlite3_errmsg(sqliteConnection))) } } #endif diff --git a/README.md b/README.md index d19568439e..0697fc2856 100644 --- a/README.md +++ b/README.md @@ -7303,29 +7303,32 @@ try clearDBQueue.inDatabase { db in // Now the copy is done, and the clear-text database can be deleted. ``` -**Advanced configuration options for SQLCipher** +## Advanced configuration options for SQLCipher + There are two advanced configuration options that you can set for configuring SQLCipher that control aspects of the encryption and key generation process. ```swift -var configuartion = Configuration() +var configuration = Configuration() configuration.passphrase = "secret" configuration.cipherPageSize = .pageSize4K -configuration.KDFIterations = 128000 +configuration.kdfIterations = 128000 let dbQueue = try DatabaseQueue(path: "...", configuration: configuration) ``` -***cipherPageSize*** -The `cipherPageSize` is used to adjust the page size for the encrypted database (this corresponds to the SQLCipher `PRAGMA cipher_page_size` configuration option). Increasing the page size can noticeably improve performance for certain queries that access large numbers of pages. +### cipherPageSize + +The `cipherPageSize` is used to adjust the page size for the encrypted database (this corresponds to the [SQLCipher `PRAGMA cipher_page_size`](https://www.zetetic.net/sqlcipher/sqlcipher-api/#cipher_page_size) configuration option). Increasing the page size can noticeably improve performance for certain queries that access large numbers of pages. WARNING: The same `cipherPageSize` must be supplied every time that the database file is open; attempting to access the database without setting the proper `cipherPageSize` will result in the `SQLite error 26: file is encrypted or is not a database` error being thrown. The default `cipherPageSize` in the current version of SQLCipher used in GRDB.swift is `.pageSize1K`. -***KDFIterations*** -The `KDFIterations` value is used to adjust the number of iterations that the PBKDF2 key derivation is run to derive the key from the `passphrase` supplied (this corresponds to the SQLCipher `PRAGMA kdf_iter` configuration option). +### kdfIterations + +The `kdfIterations` value is used to adjust the number of iterations that the PBKDF2 key derivation is run to derive the key from the `passphrase` supplied (this corresponds to the [SQLCipher `PRAGMA kdf_iter`](https://www.zetetic.net/sqlcipher/sqlcipher-api/#kdf_iter) configuration option). -WARNING: The same `KDFIterations` must be supplied every time that the database file is open; attempting to access the database without setting the proper `KDFIterations` will result in the `SQLite error 26: file is encrypted or is not a database` error being thrown. +WARNING: The same `kdfIterations` must be supplied every time that the database file is open; attempting to access the database without setting the proper `kdfIterations` will result in the `SQLite error 26: file is encrypted or is not a database` error being thrown. -The default `KDFIterations` in the current version of SQLCipher used in GRDB.swift is `64000`. It is not recommend to reduce the number of iterations used from the default. +The default `kdfIterations` in the current version of SQLCipher used in GRDB.swift is `64000`. It is not recommend to reduce the number of iterations used from the default. ## Backup diff --git a/Tests/GRDBTests/EncryptionTests.swift b/Tests/GRDBTests/EncryptionTests.swift index 3b0a3d71b5..c913cc001c 100644 --- a/Tests/GRDBTests/EncryptionTests.swift +++ b/Tests/GRDBTests/EncryptionTests.swift @@ -364,7 +364,7 @@ class EncryptionTests: GRDBTestCase { func testCipherKDFSettings() throws { do { dbConfiguration.passphrase = "secret" - dbConfiguration.KDFIterations = 128000 + dbConfiguration.kdfIterations = 128000 let dbQueue: DatabaseQueue? = try makeDatabaseQueue(filename: "test.sqlite") try dbQueue!.inDatabase { db in @@ -373,7 +373,7 @@ class EncryptionTests: GRDBTestCase { } do { - dbConfiguration.KDFIterations = 128000 + dbConfiguration.kdfIterations = 128000 let dbQueue: DatabasePool? = try makeDatabasePool(filename: "testpool.sqlite") try dbQueue!.write { db in From c46dbdd97e4a14949d5067341872d3269efc83f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gwendal=20Roue=CC=81?= Date: Fri, 8 Mar 2019 08:25:02 +0100 Subject: [PATCH 09/10] Turn WARNING into a Note --- README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 0697fc2856..8311bccbe6 100644 --- a/README.md +++ b/README.md @@ -7314,22 +7314,23 @@ configuration.cipherPageSize = .pageSize4K configuration.kdfIterations = 128000 let dbQueue = try DatabaseQueue(path: "...", configuration: configuration) ``` + ### cipherPageSize The `cipherPageSize` is used to adjust the page size for the encrypted database (this corresponds to the [SQLCipher `PRAGMA cipher_page_size`](https://www.zetetic.net/sqlcipher/sqlcipher-api/#cipher_page_size) configuration option). Increasing the page size can noticeably improve performance for certain queries that access large numbers of pages. -WARNING: The same `cipherPageSize` must be supplied every time that the database file is open; attempting to access the database without setting the proper `cipherPageSize` will result in the `SQLite error 26: file is encrypted or is not a database` error being thrown. - The default `cipherPageSize` in the current version of SQLCipher used in GRDB.swift is `.pageSize1K`. +> :point_up: **Note**: the same `cipherPageSize` must be supplied every time that the database file is open; attempting to access the database without setting the proper `cipherPageSize` will result in the `SQLite error 26: file is encrypted or is not a database` error being thrown. + ### kdfIterations The `kdfIterations` value is used to adjust the number of iterations that the PBKDF2 key derivation is run to derive the key from the `passphrase` supplied (this corresponds to the [SQLCipher `PRAGMA kdf_iter`](https://www.zetetic.net/sqlcipher/sqlcipher-api/#kdf_iter) configuration option). -WARNING: The same `kdfIterations` must be supplied every time that the database file is open; attempting to access the database without setting the proper `kdfIterations` will result in the `SQLite error 26: file is encrypted or is not a database` error being thrown. - The default `kdfIterations` in the current version of SQLCipher used in GRDB.swift is `64000`. It is not recommend to reduce the number of iterations used from the default. +> :point_up: **Note**: he same `kdfIterations` must be supplied every time that the database file is open; attempting to access the database without setting the proper `kdfIterations` will result in the `SQLite error 26: file is encrypted or is not a database` error being thrown. + ## Backup From 53d2e6b895413bf89650a27b894cade1a3b37d37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gwendal=20Roue=CC=81?= Date: Fri, 8 Mar 2019 08:26:18 +0100 Subject: [PATCH 10/10] Fix typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8311bccbe6..869bf80d52 100644 --- a/README.md +++ b/README.md @@ -7329,7 +7329,7 @@ The `kdfIterations` value is used to adjust the number of iterations that the PB The default `kdfIterations` in the current version of SQLCipher used in GRDB.swift is `64000`. It is not recommend to reduce the number of iterations used from the default. -> :point_up: **Note**: he same `kdfIterations` must be supplied every time that the database file is open; attempting to access the database without setting the proper `kdfIterations` will result in the `SQLite error 26: file is encrypted or is not a database` error being thrown. +> :point_up: **Note**: the same `kdfIterations` must be supplied every time that the database file is open; attempting to access the database without setting the proper `kdfIterations` will result in the `SQLite error 26: file is encrypted or is not a database` error being thrown. ## Backup