跳到内容
CrossFly 是 100% 开源在 GitHub 关注我们
CrossFlyCrossFly
开始使用

本页面由葡萄牙语机器翻译,可能存在错误。葡萄牙语版本为准。

如何使用加密的 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;
}

深入了解

这个页面有帮助吗?