本页面由葡萄牙语机器翻译,可能存在错误。葡萄牙语版本为准。
如何使用加密的 SQLite 数据库
目的。 通过加密数据库(借助 SQLite3MC)在磁盘上保护敏感数据。加密是 可选启用(opt-in) 的:没有密钥时数据库就是普通的 SQLite,不产生加密开销。有密钥时,CrossFly 会应用加密算法并 在打开时 验证密钥(尽早失败,而不是在第一次查询时才失败)。
使用的 API
SqliteDb.open(String filename, byte[] key)— 使用 默认加密算法Sqlite.Cipher.CHACHA20(ChaCha20-Poly1305)打开/创建加密数据库。SqliteDb.open(String filename, byte[] key, Sqlite.Cipher cipher)— 使用显式指定的加密算法打开。可选项:CHACHA20、SQLCIPHER(AES-256-CBC + HMAC)、AES128CBC、AES256CBC、RC4、ASCON128。SqliteDb.rekey(byte[] newKey)— 通过sqlite3_rekey更换密钥。传入null或 空 数组(new byte[0])会 移除 加密(“rekey to no key”)。SqliteException.code— 错误的数字代码。与Sqlite中的常量进行比较。密钥错误 / 文件不是数据库 ⇒code == Sqlite.NOTADB(26)。其他有用的常量:Sqlite.BUSY(5)、Sqlite.CONSTRAINT(19)。
错误密钥如何表现。 在带密钥的
open中,CrossFly 会选择加密算法、应用密钥并执行一次强制读取(SELECT count(*) FROM sqlite_master),以便在密钥错误时 立即 失败并关闭连接。你会捕获到code == Sqlite.NOTADB的SqliteException。
重新打开时注意加密算法。 要重新打开一个已存在的数据库,请使用它创建时所用的 相同加密算法。
CHACHA20(默认)只能解密CHACHA20数据库;一个SQLCIPHER数据库需要open(file, key, Sqlite.Cipher.SQLCIPHER)。
完整示例(复制、粘贴即可运行)
package com.exemplo;
import java.nio.charset.StandardCharsets;
import dev.crossfly.ui.*; // Window
import dev.crossfly.ui.layout.*; // VerticalLayout
import dev.crossfly.sqlite.*; // SqliteDb, Sqlite, SqliteException
/** 可执行的主界面。将 launcher 指向此类(classname)并运行:gradlew :lwjgl3:run */
public class MainWindow extends Window
{
@Override
public void onShow() throws Exception
{
super.onShow();
setLayout(new VerticalLayout());
byte[] key = "minha-senha-forte".getBytes(StandardCharsets.UTF_8);
// 打开/创建加密库(默认加密 CHACHA20)
try (SqliteDb db = SqliteDb.open("secure.db", key))
{
db.exec("CREATE TABLE IF NOT EXISTS secret(id INTEGER PRIMARY KEY, v TEXT)");
db.execute("INSERT INTO secret(v) VALUES(?)", "dado sensível");
// 更换密钥
byte[] novaKey = "senha-ainda-mais-forte".getBytes(StandardCharsets.UTF_8);
db.rekey(novaKey);
// db.rekey(new byte[0]); // <- 会移除加密
}
// 显式加密(兼容 SQLCipher)
try (SqliteDb db = SqliteDb.open("sqlcipher.db", key, Sqlite.Cipher.SQLCIPHER))
{
db.exec("SELECT count(*) FROM sqlite_master");
}
// 检测错误密钥
try (SqliteDb db = SqliteDb.open("secure.db", "chave-errada".getBytes(StandardCharsets.UTF_8)))
{
// 不会到达这里:验证已在 open 时失败
}
catch (SqliteException e)
{
if (e.code == Sqlite.NOTADB) // 26 = 密钥错误 / 不是数据库
System.out.println("Chave incorreta");
else
throw e;
}
}
}
下面的片段只展示 核心部分。要运行它,请把它放入上面的
MainWindow骨架中。
最小片段
// 已在源码核实:open(file,key), open(file,key,cipher), rekey, SqliteException.code == Sqlite.NOTADB
import dev.crossfly.sqlite.*;
import java.nio.charset.StandardCharsets;
byte[] key = "minha-senha-forte".getBytes(StandardCharsets.UTF_8);
// 打开/创建加密库(默认加密 CHACHA20)
try (SqliteDb db = SqliteDb.open("secure.db", key))
{
db.exec("CREATE TABLE IF NOT EXISTS secret(id INTEGER PRIMARY KEY, v TEXT)");
db.execute("INSERT INTO secret(v) VALUES(?)", "dado sensível");
// 更换密钥
byte[] novaKey = "senha-ainda-mais-forte".getBytes(StandardCharsets.UTF_8);
db.rekey(novaKey);
// db.rekey(new byte[0]); // <- 会移除加密
}
// 显式加密(兼容 SQLCipher)
try (SqliteDb db = SqliteDb.open("sqlcipher.db", key, Sqlite.Cipher.SQLCIPHER))
{
db.exec("SELECT count(*) FROM sqlite_master");
}
// 检测错误密钥
try (SqliteDb db = SqliteDb.open("secure.db", "chave-errada".getBytes(StandardCharsets.UTF_8)))
{
// 不会到达这里:验证已在 open 时失败
}
catch (SqliteException e)
{
if (e.code == Sqlite.NOTADB) // 26 = 密钥错误 / 不是数据库
System.out.println("Chave incorreta");
else
throw e;
}
深入了解
- 安全最佳实践 · SQLite 存储指南
- 相关姊妹篇:打开/创建数据库 · 参数化 CRUD
这个页面有帮助吗?感谢你的反馈!