fix: set SQLCipher cipher_page_size BEFORE first database access
Previously cipher_page_size was set AFTER the verification SELECT, making it a no-op (SQLCipher locks page size on first access). This caused two bugs: 1. Databases were created with the default page size regardless of the setting, then flushed on close using misaligned 4KB mmap pages on 16KB kernel → corrupted file → SQLITE_NOTADB on reopen. 2. Reopening an existing DB used default (potentially wrong) page size for the initial read → decryption failure. Fix: batch all cipher settings (key, page_size, kdf_iter, algorithms) into a single execute_batch call BEFORE the first SELECT. This ensures: - New databases are created with 16KB pages (aligned to Asahi kernel) - Existing 16KB-page databases are reopened with the correct page size - Close/flush operations use properly aligned mmap → no corruption Note: existing 4KB-page databases (from v0.1.0) remain incompatible and must be deleted once on upgrade. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
9c3f924f27
commit
66de8f71cb
@ -3,17 +3,20 @@ use std::path::Path;
|
||||
|
||||
pub fn open_encrypted_db(path: &Path, key: &str) -> anyhow::Result<Connection> {
|
||||
let conn = Connection::open(path)?;
|
||||
// Set SQLCipher encryption key
|
||||
conn.execute_batch(&format!("PRAGMA key = '{}';", key.replace('\'', "''")))?;
|
||||
// Verify the key works by running a simple query
|
||||
conn.execute_batch("SELECT count(*) FROM sqlite_master;")?;
|
||||
// Set SQLCipher settings for AES-256
|
||||
conn.execute_batch(
|
||||
"PRAGMA cipher_page_size = 16384; \
|
||||
PRAGMA kdf_iter = 256000; \
|
||||
PRAGMA cipher_hmac_algorithm = HMAC_SHA512; \
|
||||
// ALL cipher settings MUST be set before the first database access.
|
||||
// cipher_page_size in particular must precede any read/write so it takes
|
||||
// effect for both creation (new DB) and reopening (existing DB).
|
||||
// 16384 matches 16KB kernel page size (Asahi Linux / Apple Silicon aarch64).
|
||||
conn.execute_batch(&format!(
|
||||
"PRAGMA key = '{}';\
|
||||
PRAGMA cipher_page_size = 16384;\
|
||||
PRAGMA kdf_iter = 256000;\
|
||||
PRAGMA cipher_hmac_algorithm = HMAC_SHA512;\
|
||||
PRAGMA cipher_kdf_algorithm = PBKDF2_HMAC_SHA512;",
|
||||
)?;
|
||||
key.replace('\'', "''")
|
||||
))?;
|
||||
// Verify the key and settings work
|
||||
conn.execute_batch("SELECT count(*) FROM sqlite_master;")?;
|
||||
Ok(conn)
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user