-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
SQLCipher encryption not activating with v1.14.28 despite SQLCipher v4.5.6 and CGO flags #1337
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Thanks for creating go-sqlite3. I'm still facing issues getting SQLCipher encryption to activate correctly and wanted to provide an update based on further debugging, incorporating suggestions from others. Summary of Latest Findings:
Conclusion: Could this be related to how Go 1.23 handles CGO linking in this configuration, or is there a known interaction I might be missing? |
Following up on the previous debugging steps, I have a critical update: Minimal CGO Test SUCCEEDS: I created a minimal Go program (code below/attached) that bypasses database/sql and go-sqlite3 entirely, using only direct CGO calls (sqlite3_open_v2, sqlite3_exec for PRAGMA key, sqlite3_exec for CREATE TABLE, sqlite3_close, etc.) with the same CGO flags (#cgo CFLAGS: -DSQLITE_HAS_CODEC -I/usr/local/include, #cgo LDFLAGS: -lsqlite3 -lcrypto). Result: This minimal test successfully creates an encrypted database (file header is not "SQLite format 3") and correctly fails when attempting to read data after re-opening with the wrong key (returns SQLITE_NOTADB error code 26 after internal HMAC check failures). This proves the compiled SQLCipher v4.7.0 library, CGO linking, and runtime library loading (LD_LIBRARY_PATH) are functioning correctly at a basic level. go-sqlite3 Test STILL FAILS: Running the original test using database/sql and go-sqlite3 (v1.14.28), even with the Open function performing an explicit PRAGMA key and a subsequent write/read check (using a TEMP table), still results in an unencrypted database being created (header is "SQLite format 3") and allows reads with the wrong key. Conclusion: Environment Recap: Could there be an issue with how the driver handles SQLITE_EXTRA_INIT, or some other initialization step required for SQLCipher v4 that's being missed when used through database/sql? cgo_test/main.go
internal/sqlite/securedb.go
|
Here's the terminal from building the container and immediately running these tests. vscode ➜ /workspaces/n1 (main) $ ls -l /usr/local/lib/libsqlite* --- Step 1: Creating and writing to DB --- --- Step 2: Verifying file header --- --- Step 3: Reopening with WRONG key --- --- TEST SUCCEEDED (Encryption likely working at CGO level) --- |
Further testing provides more specific insight, isolating the issue to reopening databases with the libsqlite3 tag. Summary: Conclusion: This strongly suggests an issue within the go-sqlite3 driver's initialization or state management specific to the libsqlite3 build path when dealing with existing encrypted databases, as the direct CGO approach works fine for both creation and reopening. |
This may be relevant: #1109 |
Uh oh!
There was an error while loading. Please reload this page.
Environment:
Go: go version: go1.23.8 linux/amd64
mattn/go-sqlite3: github.com/mattn/go-sqlite3 v1.14.28
OS/Environment: Debian Bookworm (via mcr.microsoft.com/devcontainers/go:1.23 Docker image)
SQLCipher: 3.44.2 2023-11-24 11:41:44 ebead0e7230cd33bcec9f95d2183069565b9e709bf745c9b5db65cc0cbf9alt1 (64-bit) (SQLCipher 4.5.6 community) Built from source
Build Tool: go test
Problem:
Attempts to create or open an encrypted SQLite database using mattn/go-sqlite3 with SQLCipher support enabled result in an unencrypted database file, even when SQLCipher v4.5.6 is correctly built, installed, and discoverable by the linker. Both DSN parameters (_pragma_key=) and explicit PRAGMA key = '...' execution after opening fail to enable encryption.
Code & CGO Flags:
File: internal/sqlite/securedb.go
//go:build cgo
package sqlite
/*
#cgo CFLAGS: -DSQLITE_HAS_CODEC
#cgo LDFLAGS: -lsqlcipher
*/
import (
"database/sql"
"fmt"
)
// Open returns an encrypted handle. Relies on PRAGMA key.
func Open(path string, key []byte) (*sql.DB, error) {
// DSN without key parameter.
dsn := fmt.Sprintf(
"file:%s?_pragma_cipher_page_size=4096&_busy_timeout=10000",
path,
)
}
File: internal/sqlite/securedb_test.go
package sqlite
import (
"bytes"
"fmt"
"os" // Import os for file reading
"path/filepath"
"testing"
)
// --- Keep your existing Open function in securedb.go (Simplified version above) ---
func TestEncryptionEndToEnd(t *testing.T) {
tmpDir := t.TempDir()
dbPath := filepath.Join(tmpDir, "vault_e2e.db")
mk, _ := crypto.Generate(32)
t.Logf("Database path: %s", dbPath)
}
Steps to Reproduce:
Set up a Debian Bookworm environment (e.g., using mcr.microsoft.com/devcontainers/go:1.23).
Install build dependencies and build+install SQLCipher v4.5.6 from source (ensuring ldconfig registers /usr/local/lib).
Simplified example from devcontainer postCreateCommand
sudo apt-get update && sudo apt-get install -y build-essential tclsh libssl-dev git sqlite3
cd /tmp && git clone --depth 1 --branch v4.5.6 https://github.com/sqlcipher/sqlcipher.git
cd sqlcipher && ./configure CFLAGS="-DSQLITE_HAS_CODEC" LDFLAGS="-lcrypto" --with-crypto-lib=openssl && make -j$(nproc) && sudo make install && sudo ldconfig
Use the Go code provided above (internal/sqlite/securedb.go and internal/sqlite/securedb_test.go).
Run go test -v ./... in the project root.
Actual Results:
The test fails at the require.Error assertion in step 2.
Reading the header of the database file created in step 1 confirms it starts with SQLite format 3\0, indicating it is not encrypted. (Diagnostic check added to test code confirms this).
The PRAGMA key = ... command in the Open function does not return an error but does not result in an encrypted database or prevent reads with an incorrect key.
Expected Results:
The database file created in step 1 should have an encrypted header (not starting with SQLite format 3\0).
The call to dbReadWrong.QueryRow(...).Scan(...) in step 2 should return an error (e.g., "file is not a database", "bad parameter or other API misuse", etc.) because the wrong key was used.
The require.Error(t, queryErrWrong, ...) assertion should pass.
The overall test TestEncryptionEndToEnd should pass.
Troubleshooting Already Attempted:
Verified SQLCipher v4.5.6 installation (sqlcipher --version) and linker path (ldconfig -p).
Verified CGO flags (-DSQLITE_HAS_CODEC, -lsqlcipher) are present in verbose build logs (go test -x).
Tried both DSN _pragma_key and explicit PRAGMA key after sql.Open.
Attempted static linking (-tags=sqlite_static with appropriate LDFLAGS), which also resulted in an unencrypted database.
Downgraded to v1.14.22 and v1.14.17 with no change in test results.
Any guidance on why encryption might not be activating under these conditions would be appreciated.
The text was updated successfully, but these errors were encountered: