【问题标题】:sqlcipher_export didn't export my tablessqlcipher_export 没有导出我的表
【发布时间】:2014-01-16 15:17:48
【问题描述】:

我正在使用带有 android 的 sqlciper 来加密现有的 sqlite db,并遇到了一个问题,即加密的 db 不包含我的表,它只包含 sqlite_master 和 android_metadata。

我原来的数据库是这样的:

shell@umts_spyder:/sdcard $ sqlite3 d000000.dat
sqlite3 d000000.dat
SQLite version 3.7.4
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> select * from sqlite_master;
select * from sqlite_master;
table|android_metadata|android_metadata|2|CREATE TABLE android_metadata (locale TEXT)
table|PageData|PageData|3|CREATE TABLE PageData(File_Path TEXT NOT NULL UNIQUE, File_Content BLOB)
index|sqlite_autoindex_PageData_1|PageData|4|

我在下面粘贴我的加密代码,使用空密钥(“”)打开普通数据库,如果使用 null,则会引发 NullPointerException(对于我在帖子末尾提到的两个普通数据库):

File plain = new File(mDbPath); /* /sdcard/d0000000.dat */
File encrypt = new File(plain.getParent(), "encrypted.dat");
encrypt.delete();
SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(mDbPath, "", null);
String sql = String.format("ATTACH DATABASE '%s' AS encrypted KEY '%s'", encrypt.getPath(), mvKey.getText().toString()); // key is qqqqqqqq
db.execSQL(sql);
db.rawQuery("SELECT sqlcipher_export('encrypted')", null);
db.execSQL("DETACH DATABASE encrypted");

下面是我用来测试加密数据库的代码,输出中只有“android_metadata”,我的表PageData丢失了。如果我直接使用“select * from PageData”,它不会引发这样的表异常:

File file = new File(Environment.getExternalStorageDirectory(), "encrypted.dat");
if(!file.exists())
{
    mvBrowse.setText("not exist");
    return;
}
String key = mvKey.getText().toString();
SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(file, key, null);
Cursor cursor = db.rawQuery("SELECT * FROM sqlite_master", null);
String str = new String();
while(cursor.moveToNext())
{
    str += cursor.getString(1)+", ";
}
mvBrowse.setText(str); // output is "android_metadata, "
cursor.close();
db.close();

加密应该起作用,因为如果我用空(“”)密钥打开 encrypted.dat,它会引发“文件已加密或不是数据库”异常,但我可以使用正确的密钥读取 sqlite_master 和 android_metadata 表。

我确认我测试的路径与我写入加密的路径相同;

测试通过 sqlcipher 创建普通数据库,使用空密钥:

SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(file, "", null); /* /sdcard/d000000.dat */
db.execSQL("CREATE TABLE PageData(File_Path TEXT NOT NULL UNIQUE, File_Content BLOB)");

除了通过标准的 sqlite 工具创建它(SQLite Export Professional,在这种情况下我没有使用 BLOB 字段,只使用 TEXT 和 INTEGER);

并使用两个 API 版本进行测试,“SQLCipher for Android v2.2.2”和“SQLCipher for Android v3.0.0”。

我还尝试将http://sqlcipher.net/sqlcipher-api/ 中描述的解密程序应用于加密的数据库。

以上都得到了相同的结果。有人会帮助我吗?我相信里面有一些小错误,但我无法弄清楚。

【问题讨论】:

    标签: android sqlite encryption


    【解决方案1】:

    最后,通过向https://github.com/sqlcipher/sqlcipher-android-tests/blob/master/src/main/java/net/zetetic/tests/ImportUnencryptedDatabaseTest.java 学习,我解决了这个问题。 (感谢@avlacatus,链接已移至:https://github.com/sqlcipher/sqlcipher-android-tests/blob/master/app/src/main/java/net/zetetic/tests/ImportUnencryptedDatabaseTest.java)。问题是,在执行加密过程时,不能使用 execSQL 或 rawQuery,而是使用新引入的方法“rawExecSQL。要清楚,以下代码可以正常工作:

        String sql = String.format("ATTACH DATABASE '%s' AS encrypted KEY '%s'", encrypt.getPath(), mvKey.getText().toString());
        db.rawExecSQL(sql);
        db.rawExecSQL("SELECT sqlcipher_export('encrypted')");
        db.rawExecSQL("DETACH DATABASE encrypted");
    

    【讨论】:

    • 谢谢,这对我有用。 rawExecSQL 方法解决了这个问题。
    • 我想使用 SQLCipher 加密我的当前数据库,我尝试使用上面的方法,但我无法复制 Db 内的数据,只能复制表结构
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-02
    • 1970-01-01
    相关资源
    最近更新 更多