使用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(); } } } }
补充测试情况
- 成功创建带加密保护的新数据库,测试代码如下:
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
相关产品推荐
相关产品推荐

