You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用sqlite-jdbc-crypt加密现有SQLite数据库报unsupported file format错误

问题描述

我有一个已存在的数据库,希望使用sqlite-jdbc-crypt驱动对其进行加密保护。我使用的代码如下,分别尝试了代码中标记为action=1、2、3、4的四种实现方案,但要么抛出SQLITE_ERROR missing database (unsupported file format)错误;如果注释标记<1>的代码行则不会触发异常,但数据库文件也不会被加密。

static void LockPlainDatabase()
{
    Connection conn = null;
    Statement stmt = null;
    try {
        int action = 3;
        //Using Chacha20
        SQLiteMCChacha20Config cfg;
        if (action == 1) {
            cfg = SQLiteMCChacha20Config.getDefault();
            conn = cfg.createConnection("jdbc:sqlite:E:/sqlitedata/plain2cryptdb.sqlite3");
            cfg.setPragma(Pragma.KEY, "myKey"); // <1>
            cfg.apply(conn);
            // 上述代码行抛出SQLITE_ERROR missing database (unsupported file format)
            stmt = conn.createStatement();
            stmt.execute("PRAGMA key='myKey'");
        }
        else if (action == 2) {
            cfg = SQLiteMCChacha20Config.getDefault();
            conn = cfg.createConnection("jdbc:sqlite:E:/sqlitedata/plain2cryptdb.sqlite3");
            cfg.withKey("myKey");   // <1>
            cfg.apply(conn);
            // 上述代码行抛出SQLITE_ERROR missing database (unsupported file format)
            stmt = conn.createStatement();
            stmt.execute("PRAGMA key='myKey'");
        }
        else if (action == 3) {
            cfg = SQLiteMCChacha20Config.getDefault();
            conn = cfg.createConnection("jdbc:sqlite:E:/sqlitedata/plain2cryptdb.sqlite3");
            stmt = conn.createStatement();
            cfg.setPragma(Pragma.KEY, "myKey");
            cfg.applyCipherParameters(conn, stmt);
            //
            //  该代码段无任何异常抛出
            //  但也没有对数据库完成加密保护
            //
        }
        else if (action == 4) {
            conn = SQLiteMCChacha20Config.getDefault()
                    .createConnection("jdbc:sqlite:E:/sqlitedata/plain2cryptdb.sqlite3");
            stmt = conn.createStatement();
            stmt.execute("PRAGMA key='Used2be1'");
            //
            //  该代码段无任何异常抛出
            //  但也没有对数据库完成加密保护
            //
        }
    } catch (SQLException e) {
        e.printStackTrace();
    }
    finally
    {
        try {
            if (stmt != null)
                stmt.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        finally
        {
            try {
                if (conn != null)
                    conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

补充测试情况

  1. 成功创建带加密保护的新数据库,测试代码如下:
conn = SQLiteMCChacha20Config.getDefault().withKey("myKey")
        .createConnection("jdbc:sqlite:E:/sqlitedata/cryptdb.sqlite3");
stmt = conn.createStatement();
stmt.execute("PRAGMA key='myKey'");
stmt.executeUpdate("CREATE TABLE ATBL (COL1 VARCHAR (100))");
stmt.executeUpdate("INSERT INTO ATBL (COL1) VALUES ('SELECT COUNT(*) FROM DATA1')");
stmt.executeUpdate("INSERT INTO ATBL (COL1) VALUES ('INSERT INTO DATA2 (DC1) VALUES (''SQLITE JDBC CRYPT DRIVER TEST'')')");
ResultSet rs = stmt.executeQuery("SELECT * FROM ATBL");
while(rs.next()) {
    System.out.println(rs.getString("COL1"));
}
rs.close();
stmt.close();
conn.close();

测试完成后将cryptdb.sqlite3复制为crypt2plaindb.sqlite3。
2. 成功移除加密数据库的密码保护,测试代码如下:

conn = SQLiteMCChacha20Config.getDefault().withKey("myKey")
        .createConnection("jdbc:sqlite:E:/sqlitedata/crypt2plaindb.sqlite3");
stmt = conn.createStatement();
stmt.execute("PRAGMA key='myKey'");
stmt.execute("PRAGMA rekey=''");
stmt.close();
conn.close();

操作完成后将crypt2plaindb.sqlite3复制为plain2cryptdb.sqlite3。
3. 尝试给无密码的plain2cryptdb.sqlite3重新加密,代码执行无异常,但数据库未被加密,测试代码如下:

conn = SQLiteMCChacha20Config.getDefault()
            .createConnection("jdbc:sqlite:E:/sqlitedata/plain2cryptdb.sqlite3");
stmt = conn.createStatement();
stmt.execute("PRAGMA key='myKey'");
stmt.close();
conn.close();

解决方案

你的核心错误是指令使用不当:PRAGMA key='xxx'是打开加密数据库时传入解密密码的指令,不会触发加密操作;给未加密的数据库设置密码、或者修改已有加密数据库的密码,需要使用PRAGMA rekey='xxx'指令。
之前方案的错误点:

  • action1/2:创建未加密数据库连接时直接传入密码参数,驱动会默认当前是加密数据库,尝试用你传入的密码解密未加密的文件,就会报文件格式不支持错误
  • action3/4:仅传入PRAGMA key指令,不会触发全库加密逻辑,所以没有效果
    正确的加密代码如下:
// 第一步:无密码打开未加密的目标数据库
SQLiteMCChacha20Config cfg = SQLiteMCChacha20Config.getDefault();
Connection conn = cfg.createConnection("jdbc:sqlite:E:/sqlitedata/plain2cryptdb.sqlite3");
Statement stmt = conn.createStatement();
// 第二步:调用rekey指令设置密码,触发全库加密
stmt.execute("PRAGMA rekey='myKey'");
// 操作完成关闭连接
stmt.close();
conn.close();

内容的提问来源于stack exchange,提问作者Rupesh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 21:57:03