Code Monkey home page Code Monkey logo

Comments (10)

John-He-928 avatar John-He-928 commented on May 20, 2024 1

首先你需要明白几点:

  1. ATTACH 操作本身就会打开 DB,因此 ATTACH 之前不需要打开,如果 db2 是你之前已经用 open 等接口打开并得到的 SQLiteDatabase 对象,那这没有必要,直接传路径就行了。
  2. sqlcipher_export 接受的参数是打开或 ATTACH 的名称,而不是路径,ATTACH上去的,名称就是你自己起的名称(比如你的 unencrypted,或者例子里的 old),如果是主DB(open时传入路径直接打开的),那它有一个固定的名称 'main'。
  3. sqlcipher_export 的作用是 将第二个参数的 DB 的内容,完整复制到第一个参数的 DB 里面,是导出还是导入,是加密还是解密,完全取决于这两个 DB 的配置。
  4. WCDB 的 execSQL 函数只能执行 INSERT、UPDATE、DELETE 等命令,不能执行 SELECT,因为 SELECT 一般是返回结果的。你可以换一个调用方式解决这个问题,最简单是例子里的
DatabaseUtils.stringForQuery(db, "SELECT sqlcipher_export('main', 'old');", null);

它的意思是查询并返回一个字符串,实际上 sqlcipher_export 并不会返回字符串,但不需要理会,忽略返回值即可,里面的语句已经执行了。

所以我觉得你可以这么操作:

// 先open了加密DB,得到 "db" 对象

// 将非加密DB挂载到 "db"
String sql = String.format("ATTACH DATABASE %s AS old KEY '';",
    DatabaseUtils.sqlEscapeString(oldDbFile.getPath()));
db.execSQL(sql);

// 将数据从 "main"(加密db) 迁移到 "old"(非加密db)
db.beginTransaction();
DatabaseUtils.stringForQuery(db, "SELECT sqlcipher_export('old', 'main');", null);
db.setTransactionSuccessful();
db.endTransaction();

// 将old脱离
db.execSQL("DETACH DATABASE old;");

有没有觉得很像例子?其实就是将sqlcipher_export两个参数调换一下。

from wcdb.

John-He-928 avatar John-He-928 commented on May 20, 2024

这个跟原来一样的,执行这些SQL语句就能解密

from wcdb.

weilixin avatar weilixin commented on May 20, 2024

你好,我尝试解密数据库还是失败,烦请帮忙看一下原因,多谢!

打开wcdb加密数据库代码如下:
db = com.tencent.wcdb.database.SQLiteDatabase.openDatabase(originalFile.getAbsolutePath(),
(isDecode ? password.getBytes() : null/* 无密 */), cipher, null,
SQLiteDatabase.OPEN_READWRITE, new DatabaseErrorHandler() {
@OverRide
public void onCorruption(com.tencent.wcdb.database.SQLiteDatabase dbObj) {
LogUtil.e(TAG, "CipherDB::startDataBaseMigration2::onCorruption1");
}
});

创建临时文件暂存代码:
newFile = File.createTempFile(ENCRYPTED_DATABASE_PREFIX, TEMP_ENCRYPTED_DATABASE_PREFIX,
context.getCacheDir());

数据迁移代码:
try {
// db.rawExecSQL("PRAGMA cipher_default_kdf_iter = 4000;");
db.execSQL(String.format("ATTACH DATABASE '%s' AS encrypted KEY '%s';",
newFile.getAbsolutePath(), (isDecode ? ""/* 无密 */ : password)));
db.execSQL("SELECT sqlcipher_export('encrypted')");
db.execSQL("DETACH DATABASE encrypted;");
db.close();
} catch (Exception e) {
LogUtil.e(TAG, "CipherDB::startDataBaseMigration OMG ...DataMigration has exception. "
+ e.getMessage());
throw new StopRequestException(DATA_TRANSFER_DATA_MIGRATION_ERROR, e);
}

异常日志,如下:

06-19 16:17:22.214 7185-7185/com.wlx.debug W/wlx: main:SqliteCipherLogic [LOGIN_READLY]: CipherDB::onItemClick: common_new
06-19 16:17:22.215 7185-7185/com.wlx.debug D/wlx: main:SqliteCipherLogic [LOGIN_READLY]: CipherDB::startDataBaseMigration starting... databaseName: common_new
06-19 16:17:22.215 7185-7185/com.wlx.debug D/wlx: main:SqliteCipherLogic [LOGIN_READLY]: CipherDB::startDataBaseMigration originalFile path: /data/user/0/com.wlx.debug/databases/common_new

06-19 16:17:22.215 7185-7185/com.wlx.debug I/WCDB.SQLiteConnectionPool: Max connection pool size is 1.
06-19 16:17:22.216 7185-7185/com.wlx.debug I/WCDB: Initialize SQLite connection module 'MMFTS'...
06-19 16:17:22.216 7185-7185/com.wlx.debug I/WCDB.SQLiteConnection: Opened connection 0x9b8f6808 with label '/data/user/0/com.wlx.debug/databases/common_new'
06-19 16:17:22.216 7185-7185/com.wlx.debug I/WCDB.SQLiteConnection: sqlite3_key verification passed.

06-19 16:17:22.254 7185-7185/com.wlx.debug W/WCDB.SQLite: [SQLite ErrCode: 5] statement aborts at 1: [PRAGMA journal_mode=PERSIST] database is locked
06-19 16:17:22.255 7185-7185/com.wlx.debug W/WCDB.SQLiteConnectionPool: Connections: 0 active, 0 idle, 0 available.
06-19 16:17:22.257 7185-7185/com.wlx.debug I/WCDB.SQLiteConnection: executeForString took 1ms - failed, sql="PRAGMA journal_mode=PERSIST", exception="database is locked (code 5, errno 0): "
06-19 16:17:22.257 7185-7185/com.wlx.debug W/WCDB.SQLiteConnection: Could not change the database journal mode of '/data/user/0/com.wlx.debug/databases/common_new' from 'wal' to 'PERSIST' because the database is locked. This usually means that there are other open connections to the database which prevents the database from enabling or disabling write-ahead logging mode. Proceeding without changing the journal mode.
06-19 16:17:22.258 7185-7185/com.wlx.debug D/wlx: main:SqliteCipherLogic [LOGIN_READLY]: CipherDB::startDataBaseMigration originalFile version: 65
06-19 16:17:22.266 7185-7185/com.wlx.debug D/wlx: main:SqliteCipherLogic [LOGIN_READLY]: CipherDB::startDataBaseMigration newFile path: /data/user/0/com.wlx.debug/cache/tmp_common

06-19 16:17:23.852 7185-7185/com.wlx.debug I/WCDB.SQLiteConnection: executeForChangedRowCount took 1584ms - failed, sql="SELECT sqlcipher_export('encrypted')", exception="unknown error (code 0, errno -1): Queries can be performed using SQLiteDatabase query or rawQuery methods only.", changedRows=0

06-19 16:17:23.852 7185-7185/com.wlx.debug E/wlx: main:SqliteCipherLogic [LOGIN_READLY]: CipherDB::startDataBaseMigration OMG ...DataMigration has exception. unknown error (code 0, errno -1): Queries can be performed using SQLiteDatabase query or rawQuery methods only.
06-19 16:17:23.852 7185-7185/com.wlx.debug E/wlx: main:SqliteCipherLogic [LOGIN_READLY]: CipherDB::startDataBaseMigration --- > Aborting request for database migration common_new: com.tencent.wcdb.database.SQLiteException: unknown error (code 0, errno -1): Queries can be performed using SQLiteDatabase query or rawQuery methods only.
06-19 16:17:23.853 7185-7185/com.wlx.debug D/wlx: main:SqliteCipherLogic [LOGIN_READLY]: CipherDB::startDataBaseMigration finally --- > 103

from wcdb.

John-He-928 avatar John-He-928 commented on May 20, 2024

@weilixin 你可以参看以下 sample-encryptdbEncryptedDBHelper.onCreate() 里演示了如何迁移数据库,这个对加密和非加密都是一样的,你可以正常打开加密 DB,ATTACH 一个空的非加密 DB,然后用
sqlcipher_export来迁移。

WCDB的 sqlcipher_export 经过扩展支持两个参数,分别是 导出到哪个DB从哪个DB导出,例子里是从非加密到加密,把参数反过来即可解密。

WCDB接口和限制跟 Android Framework 一致,和 SQLCipher Android 在限制上有一点点不同,但原理是一样的(包括 kdf_iter 等参数),SQL语句不用改,可能要稍微改一下调用代码。

from wcdb.

weilixin avatar weilixin commented on May 20, 2024

@John-He-928 感谢帮助,还是有些问题。
String sql = String.format("ATTACH DATABASE %s AS encrypted KEY '%s';",
DatabaseUtils.sqlEscapeString(originalFile.getPath()), password);
db.execSQL(sql);

PS:失败原因应该是密码不对,但实际密码没问题,肯定正确,传入字符串还是byte数组呢?

异常日志,如下: (密码肯定正确,58位数字大小写英文混合)
06-20 10:00:38.310 28755-28755/com.wlx.debug W/WCDB.SQLite: [SQLite ErrCode: 26] statement aborts at 4: [ATTACH DATABASE '/data/user/0/com.wlx.debug/databases/common_new' AS encrypted KEY '733491015b519f491fc2601654c44de8sIO5reWAbAsR1Pbq13ws567612';] file is encrypted or is not a
06-20 10:00:38.311 28755-28755/com.wlx.debug I/WCDB.SQLiteConnection: executeForChangedRowCount took 253ms - failed, sql="ATTACH DATABASE '/data/user/0/com.wlx.debug/databases/common_new' AS encrypted KEY '733491015b519f491fc2601654c44de8sIO5reWAbAsR1Pbq13ws567612';", exception="file is encrypted or is not a database (code 26, errno 0): ", changedRows=0
06-20 10:00:38.316 28755-28755/com.wlx.debug E/wlx: main:SqliteCipherLogic [LOGIN_READLY]: CipherDB::startDataBaseMigration2::onCorruption

from wcdb.

John-He-928 avatar John-He-928 commented on May 20, 2024

你可以打开加密的,然后attach没加密的,然后export

from wcdb.

weilixin avatar weilixin commented on May 20, 2024

@John-He-928 感谢支持!
抱歉,按照你提示的做法尝试还是失败了,麻烦再帮看一下。数据库迁移代码如下:(db2是非加密的数据库,db是加密的数据库)
// 开始数据迁移
try {
db.execSQL(String.format("ATTACH DATABASE '%s' AS unencrypted KEY '%s';",
db2.getPath(), ""));
db.execSQL(String.format("SELECT sqlcipher_export('unencrypted', '%s')",
db.getPath()));
db.execSQL("DETACH DATABASE unencrypted;");
db.close();
} catch (Exception e) {
LogUtil.e(TAG, "CipherDB::startDataBaseMigration OMG ...DataMigration has exception. "
+ e.getMessage());
throw new StopRequestException(DATA_TRANSFER_DATA_MIGRATION_ERROR, e);
}

失败日志如下:
// db-tmp是非加密数据库, common_new是加密的数据库。希望将common_new数据转移到非加密的库db-tmp
06-21 10:19:18.942 21700-21700/com.wlx.debug I/WCDB.SQLiteConnection: Opened connection 0x939aca08 with label '/data/user/0/com.wlx.debug/cache/db-tmp'
06-21 10:19:18.944 21700-21700/com.wlx.debug D/wlx: main:SqliteCipherLogic [CONNECTION_OK]: CipherDB::startDataBaseMigration newFile path: /data/user/0/com.wlx.debug/cache/db-tmp
06-21 10:19:18.947 21700-21700/com.wlx.debug W/WCDB.SQLite: [SQLite ErrCode: 1] near "/": syntax error
06-21 10:19:18.947 21700-21700/com.wlx.debug W/WCDB.SQLite: [SQLite ErrCode: 1] statement aborts at 1: [SELECT sqlcipher_export('unencrypted', '/data/user/0/com.wlx.debug/databases/common_new')] SQL logic error or missing database
06-21 10:19:18.948 21700-21700/com.wlx.debug I/WCDB.SQLiteConnection: executeForChangedRowCount took 1ms - failed, sql="SELECT sqlcipher_export('unencrypted', '/data/user/0/com.wlx.debug/databases/common_new')", exception="SQL logic error or missing database (code 1, errno 0): ", changedRows=0
06-21 10:19:18.948 21700-21700/com.wlx.debug E/wlx: main:SqliteCipherLogic [CONNECTION_OK]: CipherDB::startDataBaseMigration OMG ...DataMigration has exception. SQL logic error or missing database (code 1, errno 0):

from wcdb.

weilixin avatar weilixin commented on May 20, 2024

可以了,感谢John细致耐心讲解。赞!!!

from wcdb.

Guang1234567 avatar Guang1234567 commented on May 20, 2024

@John-He-928

可以通过 sqlcipher_export 来改密码吗?

// 先open了加密DB,得到 "db" 对象

// 将加密DB (old)挂载到 "db"
String sql = String.format("ATTACH DATABASE %s AS old KEY 'I am new password';",
DatabaseUtils.sqlEscapeString(oldDbFile.getPath()));
db.execSQL(sql);

// 将数据从 "main"(加密db) 迁移到 "old"(加密db)
db.beginTransaction();
DatabaseUtils.stringForQuery(db, "SELECT sqlcipher_export('old', 'main');", null);
db.setTransactionSuccessful();
db.endTransaction();

// 将old脱离
db.execSQL("DETACH DATABASE old;");

from wcdb.

1716574336 avatar 1716574336 commented on May 20, 2024

你好,我最近也开始使用WCDB,在集成时出现了个问题,所以向您请教下。
我这边有个本地的数据库文件 local.db,通过 WCDB 加密后得出的 encrypted.db,这时用 sample-encryptdb demo 中的 EncryptedDBHelper 来处理没问题。然后把 encrypted.db 从设备导出来,放到项目里面做一个加密的数据库文件,然后进行解密操作并读取由 encrypted.db 解密迁移到的明文数据库 plaintext.db,这时用获取到的 plaintext.db 的 SQLiteDatabase 对象来进行数据库操作会报错,错误信息说没有这样的表(no such table),然后看了下文件大小,发现原来的 local.db 和 encrypted.db 都是3.2M,而这个 plaintext.db 为 4kb,所以想请教下这要如何处理,代码如下:

this.dealTempDB()
USER_DATA_BASE = SQLiteDatabase.openOrCreateDatabase(mContext.getDatabasePath(“plaintext.db”), null, null, null)

private fun dealTempDB() {
// 先 open了加密DB,得到 "db" 对象
val encryptedDB = SQLiteDatabase.openOrCreateDatabase(mContext.getDatabasePath("encrypted.db"),
"password".toByteArray(), null, null)
// 将非加密DB挂载到 "db"
val sql = String.format("ATTACH DATABASE %s AS unencrypted KEY '';",
DatabaseUtils.sqlEscapeString(File(“data/data/com.xxx.xxx” + “plaintext.db”).path))
encryptedDB.execSQL(sql)
// 将数据从 "main"(加密db) 迁移到 "unencrypted"(非加密db)
encryptedDB.beginTransaction()
DatabaseUtils.stringForQuery(encryptedDB, "SELECT sqlcipher_export('unencrypted', 'main');", null)
encryptedDB.setTransactionSuccessful()
encryptedDB.endTransaction()
// 将 unencrypted 脱离
encryptedDB.execSQL("DETACH DATABASE unencrypted;")
encryptedDB.close()
}

from wcdb.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.