SQLite.Encrypted for Apple Platforms
The SQLiteEncrypted Swift package re-exports SQLite.swift and links the SEE XCFramework for iOS, macOS, and Mac Catalyst.
Core rule: Call
activateSEE(activationKey:)before constructing aConnectionwithkey:.
Codec support: SQLite.Encrypted currently supports only
aes256ofb. Omit the codec or passnilto useaes256ofb; any codec argument supplied to akeyorrekeycall must beaes256ofb. Keyed initializers use the sameaes256ofbdefault.
Install
In Xcode, choose File > Add Package Dependencies, enter the SQLiteEncrypted package URL, select the required release, and add the SQLiteEncrypted product to the application target.
A Package.swift dependency has the following form:
dependencies: [
.package(
url: "https://packages.sourcegear.com/swift/publisher/SQLiteEncrypted.git",
from: "<version>"
),
]
Add the product to the target:
.target(
name: "Application",
dependencies: [
.product(
name: "SQLiteEncrypted",
package: "SQLiteEncrypted"
)
]
)
Open an encrypted database
Prefer the keyed initializer or open a connection and immediately call key(key:). Both routes use sqlite3_key_v3 and throw when the native key operation fails. Use PRAGMA primarily for compatibility with an existing integration.
Open with API calls
import SQLiteEncrypted
try activateSEE(activationKey: processActivationKey)
let database = try Connection(
"/path/to/application.sqlite3",
key: databaseKey
)
Activation is idempotent. The keyed initializer reports a failed native key operation as SQLiteEncryptedError.keyFailed. Omit key: for a plaintext database.
Open with PRAGMA
Open a connection without a key, then execute both PRAGMAs before reading the schema. Verify that the key PRAGMA returns ok. Escape apostrophes in the database key before placing it in SQL text.
import SQLiteEncrypted
enum DatabaseOpenError: Error {
case keyNotAccepted
}
let database = try Connection("/path/to/application.sqlite3")
let escapedKey = databaseKey.replacingOccurrences(of: "'", with: "''")
try database.run(
"PRAGMA activate_extensions = 'see-\(processActivationKey)'"
)
let keyResult = try database.scalar(
"PRAGMA key = '\(escapedKey)'"
) as? String
guard keyResult == "ok" else {
throw DatabaseOpenError.keyNotAccepted
}
On a build without encryption support, or when SEE cannot load the key, the key PRAGMA returns no value. Ignoring that result can leave the application using a connection whose encryption key was never applied.
Create, insert, and query
The ordinary SQLite.swift API is unchanged.
let notes = Table("notes")
let id = Expression<Int64>("id")
let body = Expression<String>("body")
try database.run(notes.create(ifNotExists: true) { table in
table.column(id, primaryKey: .autoincrement)
table.column(body)
})
try database.run(notes.insert(body <- "hello"))
for note in try database.prepare(notes.order(id)) {
print("\(note[id]): \(note[body])")
}
Text, binary, and null keys
The overload that accepts String? uses SEE text-key semantics. The Data overload sends the exact bytes and byte count.
try database.key(key: "initial text key")
let binaryKey = Data([0x01, 0x00, 0x7f, 0xff])
try database.rekey(key: binaryKey)
try database.rekey(key: "replacement text key")
Passing nil removes encryption. Give nil a type so Swift selects the desired overload.
try database.rekey(key: nil as String?)
The database name and codec are optional. Supply the database name when working with an attached database. If the codec is supplied explicitly, the only supported value is aes256ofb.
try database.rekey(
"main",
key: "replacement key",
codec: "aes256ofb"
)
Native C, Objective-C, and C++ callers
The XCFramework includes sqlite3.h and sqlite3_see.h. Include the SEE header for activation, key, and rekey declarations.
#include <sqlite3.h>
#include <sqlite3_see.h>
Do not define SQLITE_HAS_CODEC in the application build. The distributed header and native library expose the required declarations.