如何使用rusqlite连接SEE加密SQLite数据库?含静态链接方案
问题描述
持有SQLite Encryption Extensions(SEE),尝试在Rust程序中通过rusqlite操作加密SQLite数据库,但在Linux工作站及Docker生产环境均无法正常工作。程序可成功构建,但执行查询时返回file is not a database错误。
测试代码如下:
main.rs
use rusqlite::{Connection, Result}; fn main() { let cn = Connection::open("test.db").unwrap(); cn.pragma_update(None, "key", "aes256:mysupersecretkey").unwrap(); // 执行任何查询都会返回“file is not a database”错误。 // ... }
Cargo.toml
[package] name = "sqlite_encryption" version = "0.1.0" edition = "2021" [dependencies] rusqlite = "0.30.0"
自定义构建脚本(用于指定库和头文件路径):
#!/bin/bash # Contains libsqlite3.so export SQLITE3_LIB_DIR=pathto/sqlitelibs export SQLITE3_INCLUDE_DIR=pathto/see-sources cargo run
需求:不使用rusqlite的bundled选项,自行提供带SEE的SQLite(而非SQLCipher),需解决连接问题,或提供静态链接自定义SQLite的示例。
解决方案
1. 确保SQLite SEE编译正确
首先要确认编译的SQLite库已正确集成SEE扩展,编译时需启用加密相关宏:
- 编译静态库示例:
# 进入see-sources目录 cd pathto/see-sources # 编译目标文件,启用SEE gcc -c sqlite3.c -o sqlite3.o -DSQLITE_HAS_CODEC -fPIC # 生成静态库 ar rcs libsqlite3.a sqlite3.o # 复制静态库到指定目录(比如pathto/sqlitelibs) cp libsqlite3.a pathto/sqlitelibs/
- 编译动态库示例:
gcc -shared -fPIC sqlite3.o -o libsqlite3.so -DSQLITE_HAS_CODEC cp libsqlite3.so pathto/sqlitelibs/
2. 调整rusqlite依赖配置
修改Cargo.toml,禁用rusqlite默认的bundled特性,避免自动拉取标准SQLite:
[package] name = "sqlite_encryption" version = "0.1.0" edition = "2021" [dependencies] rusqlite = { version = "0.30.0", default-features = false }
3. 修正密钥设置逻辑
file is not a database错误通常是因为打开加密数据库时未及时提供密钥,导致SQLite无法识别文件格式。需在打开数据库时就传入密钥,或打开后立即执行密钥设置并验证:
方法1:打开时通过pragma指定密钥
use rusqlite::{Connection, OpenFlags, Result}; fn main() -> Result<()> { // 打开数据库时指定密钥 let mut conn = Connection::open_with_flags_and_pragma( "test.db", OpenFlags::SQLITE_OPEN_READ_WRITE | OpenFlags::SQLITE_OPEN_CREATE, &[("key", "aes256:mysupersecretkey")], )?; // 测试查询 let count: i32 = conn.query_row("SELECT 1", [], |row| row.get(0))?; println!("Query result: {}", count); Ok(()) }
方法2:打开后立即设置密钥(适用于已加密数据库)
use rusqlite::{Connection, Result}; fn main() -> Result<()> { let conn = Connection::open("test.db")?; // 立即设置密钥 conn.pragma_update(None, "key", "aes256:mysupersecretkey")?; // 验证连接有效性 let _: i32 = conn.query_row("SELECT 1", [], |row| row.get(0))?; Ok(()) }
4. 静态链接自定义SQLite的示例
如果需要静态链接你编译的带SEE的SQLite库,可通过build.rs实现:
新建build.rs文件
use std::env; use std::path::Path; fn main() { // 指定头文件目录 let include_dir = env::var("SQLITE3_INCLUDE_DIR").unwrap_or_else(|_| "./see-sources".to_string()); // 指定库文件目录 let lib_dir = env::var("SQLITE3_LIB_DIR").unwrap_or_else(|_| "./sqlitelibs".to_string()); // 告诉rustc头文件路径 println!("cargo:include={}", include_dir); // 告诉rustc库路径 println!("cargo:rustc-link-search=native={}", lib_dir); // 静态链接libsqlite3.a println!("cargo:rustc-link-lib=static=sqlite3"); // 若依赖系统库(如dl),需额外链接 println!("cargo:rustc-link-lib=dylib=dl"); }
调整构建脚本
确保环境变量指向正确路径:
#!/bin/bash export SQLITE3_LIB_DIR=pathto/sqlitelibs export SQLITE3_INCLUDE_DIR=pathto/see-sources cargo run
内容的提问来源于stack exchange,提问作者CTaylor
相关产品推荐
相关产品推荐

