我正在使用
rustqlite
并尝试将其配置为通过 Cargo 功能使用 sqlcipher
。在通常情况下,rustqlite
具有包含bundled
源的sqlite
功能。当更改为 sqlcipher
时,源不再捆绑。
在本地,我能够安装
sqlcipher
并编译我的项目(在 Mac 上通过 brew install sqlcipher
安装)。
生成的二进制文件动态链接到本地
sqlcipher
安装,因此我无法再将二进制文件分发给客户
如何将库
libsqlcipher.0.dylib
嵌入到二进制文件中?不能指望客户自行安装 sqlcipher
。
作为参考,查看虚拟项目的链接库:
/tmp/try-sqlite/cipher$ otool -L target/release/cipher
target/release/cipher:
/usr/local/opt/sqlcipher/lib/libsqlcipher.0.dylib (compatibility version 9.0.0, current version 9.6.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1292.60.1)
/usr/lib/libresolv.9.dylib (compatibility version 1.0.0, current version 1.0.0)
我的项目很简单:
Cargo.toml
[package]
name = "cipher"
version = "0.1.0"
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
[dependencies.rusqlite]
version = "0.24.2"
features = ["sqlcipher"]
main.rs
use rusqlite::{params, Connection, Result, NO_PARAMS};
use std::thread::sleep;
#[derive(Debug)]
struct Person {
id: i32,
name: String,
data: Option<Vec<u8>>,
}
fn main() -> Result<()> {
let conn = Connection::open("/tmp/enc2.db")?;
conn.execute("PRAGMA KEY='passphrase'", NO_PARAMS);
conn.execute(
"CREATE TABLE IF NOT EXISTS person (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
data BLOB
)",
NO_PARAMS,
)?;
let me = Person {
id: 0,
name: "Steven".to_string(),
data: None,
};
conn.execute(
"INSERT INTO person (name, data) VALUES (?1, ?2)",
params![me.name, me.data],
)?;
let mut stmt = conn.prepare("SELECT id, name, data FROM person")?;
let person_iter = stmt.query_map(NO_PARAMS, |row| {
Ok(Person {
id: row.get(0)?,
name: row.get(1)?,
data: row.get(2)?,
})
})?;
for person in person_iter {
println!("Found person {:?}", person.unwrap());
}
Ok(())
}
编辑
我通过导出对静态链接有部分解决方案(尚未经过严格测试)
SQLCIPHER_STATIC=1
otool -L /private/tmp/try-sqlite/cypher/target/debug/cypher
/private/tmp/try-sqlite/cypher/target/debug/cypher:
/usr/lib/libz.1.dylib (compatibility version 1.0.0, current version 1.2.11)
/usr/local/opt/[email protected]/lib/libcrypto.1.1.dylib (compatibility version 1.1.0, current version 1.1.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1292.60.1)
/usr/lib/libresolv.9.dylib (compatibility version 1.0.0, current version 1.0.0)
未解决的问题
toml
配置 / build.rs
- 仍在研究中)sqlcipher
安装在开发机器上(通过 build.rs
/ toml dev
等配置)目前在 crates.io
上发布的版本似乎
不可能。
但是有一个开放的 Pull Request 您可能可以使用它。
首先在本地克隆工作分支,然后将其用作Cargo.toml
中的
补丁,如下所示:
[dependencies]
rusqlite = { version = "0.24.2", features = ["bundled-sqlcipher"] }
[patch.crates-io]
rusqlite = { path = "../path/to/your_patch" }
请注意,我没有对此进行测试,因为该功能仅存在于补丁中,因此您可能需要像这样包含功能分支:
[dependencies]
rusqlite = { path = "../path/to/your_patch", features = ["bundled-sqlcipher"] }
警告: 正如 PR 中所述,尚不清楚 zetetic(
sqlcipher
的供应商)是否可以接受,因此在使用它时应谨慎(尤其是在商业产品中)。
这个问题/评论也相关。
自从 @frankenapps 发布了他们的答案后,
rusqlite
在 master 分支中添加了对 sqlcipher
的支持。
在你的
Cargo.toml
:
[dependencies]
rusqlite = { version = "0.32", features = ["bundled-sqlcipher"] }
use rusqlite::Connection;
const ENCRYPTION_KEY: &str = "your-encryption-key";
fn main() -> Result<(), Box<dyn Error>> {
let conn = Connection::open(path)?;
conn.pragma_update(None, "KEY", ENCRYPTION_KEY)?;
Ok(())
}