wcdb使用筆記

本地數(shù)據(jù)加密

由于項目涉及到一些用戶隱私數(shù)據(jù)的存儲,所以需要對保存在客戶端本地的數(shù)據(jù)進行加密葵硕,以防止用戶隱私數(shù)據(jù)在設備被root的情況下出現(xiàn)泄漏。目前android的本地數(shù)據(jù)存儲基本分為file季惩,sharepreference和database御蒲,所以對數(shù)據(jù)的加密操作分為了兩種:文件加密和文件內(nèi)的數(shù)據(jù)加密。文件加密就是在打開該文件的時候需要獲得正確的加密秘鑰才能從該文件中讀取數(shù)據(jù)或者寫入數(shù)據(jù)到該文件中垦梆,這種方式相對簡單匹颤。文件內(nèi)數(shù)據(jù)加密就是打開文件時不需要解密,但是從文件中讀取出來的數(shù)據(jù)是加密過的密文托猩,需要對其進行解密才能識別和使用印蓖,同樣在寫入數(shù)據(jù)到文件的時候,也需要先將數(shù)據(jù)進行加密然后再寫入到文件京腥,這種方式相比第一種復雜一些赦肃,但是安全性更高,對數(shù)據(jù)保護的粒度更細公浪。file和sharepreference使用上述兩種方式實現(xiàn)的成本差異并不明顯他宛,database使用文件內(nèi)數(shù)據(jù)比如列字段加密相比文件加密要更加復雜,所以database通常使用文件加密的方式來實現(xiàn)欠气,比如有名的sqlcipher就是采用的這種方式厅各,今天我們將要提到的wcdb也是采用的這種方式來保護數(shù)據(jù)的。

WCDB

wcdb是微信團隊貢獻的一個開源項目预柒,是一個高效易用的數(shù)據(jù)庫框架队塘,并且支持多個平臺。關于wcdb的更多介紹以及如何集成和使用WCDB請參考Tencent/wcdb宜鸯,這里不再贅述憔古。下面主要介紹一下我在將WCDB集成到原有項目(Android客戶端)的過程中遇到的一些問題以及解決方案。因為我也是在使用WCDB的過程中不斷查找資料淋袖,發(fā)現(xiàn)了一些別人沒有遇到或者別人遇到了自己也遇到了但是沒有清楚答案的問題鸿市,所以才想記錄下來,以作備忘适贸。

混淆

通常我們在引入一些知名的第三方庫的時候灸芳,都需要在proguard中加入一些規(guī)則來屏蔽對該庫的混淆,因為混淆可能會導致該庫的部分功能異常拜姿,比如glide的項目介紹上就有如下說明:

image

但是我們在wcdb的項目上沒有看到關于混淆這一塊的介紹烙样,剛開始我以為不需要,后來打了一個release包后發(fā)現(xiàn)wcdb運行報錯蕊肥,才知道這里還是有必要加一下的谒获。內(nèi)容如下:

-keep class com.tencent.wcdb.** {*;}

關于在proguard中如何加入第三方庫的放混淆配置蛤肌,可以使用以下方法。在android studio的project視圖下的External Libraries中找到對應的庫名字批狱,比如wcdb裸准,然后就可以看到這個庫的完整包路徑了。如下圖:


image

加密已有數(shù)據(jù)

由于我的項目以前是使用android原生的sqlite儲存數(shù)據(jù)赔硫,現(xiàn)在要遷移到wcdb上炒俱,就必須考慮到版本兼容的問題,當老版本升級到新版本后確保老版本上保存在本地的數(shù)據(jù)能無縫遷移到新版本上面來爪膊。那么對于已有數(shù)據(jù)的加密权悟,wcdb的項目里面也提供了一個例子,我將核心代碼貼出來:

File oldDbFile = mContext.getDatabasePath(OLD_DATABASE_NAME);
if (oldDbFile.exists()) {
    // SQLiteOpenHelper begins a transaction before calling onCreate().
    // We have to end the transaction before we can attach a new database.
    db.endTransaction();

    // Attach old database to the newly created, encrypted database.
    String sql = String.format("ATTACH DATABASE %s AS old KEY '';",
            DatabaseUtils.sqlEscapeString(oldDbFile.getPath()));
    db.execSQL(sql);

    // Export old database.
    db.beginTransaction();
    DatabaseUtils.stringForQuery(db, "SELECT sqlcipher_export('main', 'old');", null);
    db.setTransactionSuccessful();
    db.endTransaction();

    // Get old database version for later upgrading.
    int oldVersion = (int) DatabaseUtils.longForQuery(db, "PRAGMA old.user_version;", null);

    // Detach old database and enter a new transaction.
    db.execSQL("DETACH DATABASE old;");

    // Old database can be deleted now.
    oldDbFile.delete();
}

這里很多第一次使用wcdb的童鞋推盛,如果沒有細看這個例子中的代碼會比較容易犯一個錯誤峦阁,就是將

DatabaseUtils.stringForQuery(db, "SELECT sqlcipher_export('main', 'old');", null);

不小心寫成了

db.execSQL("SELECT sqlcipher_export('encrypted')");

然后發(fā)現(xiàn)怎么運行都會報異常。針對這個問題在項目里面還有一個issue:集成WCDB后希望能實現(xiàn)解密數(shù)據(jù)庫 #36耘成。我也遇到了榔昔,后面找了好久才發(fā)現(xiàn)是這里的問題,原因是wcdb的execSQL不支持select瘪菌,但是原生的sqlite以及sqlcipher都是支持撒会,所以在第一次用的時候就會覺得很奇怪,這條語句語法看上去完全沒問題控嗜,運行就是行不通茧彤。

數(shù)據(jù)解密

有時為了方便定位問題,需要查看database的數(shù)據(jù)疆栏,如果是debug包可以直接聯(lián)調(diào)查看,但如果是release包那么就必須手動導出db文件然后進行解密查看了惫谤。這里有兩種方式解密:

  1. db文件拷貝到電腦上面壁顶,然后安裝sqlcipher工具進行解密
  2. 在手機上使用wcdb sdk來解密

電腦端使用sqlcipher解密

首先在電腦端安裝sqlcipher工具(鏈接:https://pan.baidu.com/s/1_yCOoqZJTersQ6KmkZb13w
提取碼:jorr ),這里以windows為例溜歪,下載該工具后進入sqlcipher-3.0.1\bin\目錄下若专,打開命令行工具,輸入以下命令蝴猪,如下圖:

image
image

其中123456為加密秘鑰调衰,encrypt.db為加密的數(shù)據(jù)庫文件,這里有幾個地方需要注意:

  1. wcdb默認加密后的db文件的pagesize為4096自阱,所以這里如果不設置cipher_page_size或者設置的值與你在使用wcdb加密時設置的pagesize一致的話嚎莉,就會報錯,這一點我網(wǎng)上找了很久都沒發(fā)現(xiàn)有人提到沛豌,有的文章上設置的是1024趋箩,但是我試過就是不行,后來找了一個未加密的db文件看了下pagesize的值才發(fā)現(xiàn)不對。
  2. 在進行任何操作之前需要先使用pragma key=...來解密數(shù)據(jù)庫叫确,否則可能會報錯“Error: file is encrypted or is not a database”跳芳,這里網(wǎng)上也有很多人跟我一樣遇到。
  3. wcdb使用了sqlcipher來加密的竹勉,在加解密的時候必須使用一致的版本飞盆,比如我們使用sqlcipher3.x加密的,那么在解密的時候也必須使用3.x版本次乓,否則就會解密失敗桨啃。

有時在命令行里面解密和查看數(shù)據(jù)不太方便,我們可以將加密db中的數(shù)據(jù)導出到一個未加密的db中檬输,首先我們在命令行工具中使用sqlcipher打開encrypt.db文件照瘾,然后輸入如下命令:

pragma key='123456';
pragma cipher_page_size=4096;
attach database 'plaintext.db' as plaintext key '';
select sqlcipher_export('plaintext');
detach database plaintext;

其中123456為加密秘鑰,palintext.db為解密后的db文件丧慈。執(zhí)行完上述命令后析命,我們就會在當前目錄下看到一個解密后的plaintext.db文件了,然后使用其他的數(shù)據(jù)庫工具如sqlite expert等就可以正常打開查看里面的數(shù)據(jù)了逃默。

wcdb sdk解密

使用wcdb sdk解密數(shù)據(jù)與之前提到的加密數(shù)據(jù)的過程是相識的鹃愤,這里結(jié)合代碼來詳細說明。

SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(getDataBase("encrypt.db"), "123456".getBytes(), null, null);
//將要生成的未加密db文件完域,這里可以根據(jù)自己的需要放在sd目錄中方便導出查看
File plainDbFile = mContext.getDatabasePath("plaintext.db");
// Attach database 
String sql = String.format("ATTACH DATABASE %s AS plaintext KEY ';",
        DatabaseUtils.sqlEscapeString(plainDbFile.getPath()));
db.execSQL(sql);

//導出加密數(shù)據(jù)庫到未加密數(shù)據(jù)庫中软吐,sqlcipher_export這個方法有兩個參數(shù),第一個參數(shù)plaintext代表新生成的未加密數(shù)據(jù)庫吟税,第二個參數(shù)main代表已加密的數(shù)據(jù)庫凹耙,也可以不使用第二個參數(shù),那么默認將使用db關聯(lián)的數(shù)據(jù)庫導出到plaintext中肠仪。詳細使用可以查看wcdb開源項目的android demo
db.beginTransaction();
DatabaseUtils.stringForQuery(db, "SELECT sqlcipher_export('plaintext', 'main');", null);
db.setTransactionSuccessful();
db.endTransaction();

// Detach plaintext database
db.execSQL("DETACH DATABASE plaintext;");

這樣我們就將一個加密數(shù)據(jù)庫導出到了plaintext.db中肖抱。

總結(jié)

本文算是自己在項目中使用WCDB過程中一些使用心得和問題總結(jié),WCDB在使用這一塊其實還有更多高級的用法异旧,這里并沒有提到意述,后面有時間了再做詳述。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末吮蛹,一起剝皮案震驚了整個濱河市荤崇,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌潮针,老刑警劉巖术荤,帶你破解...
    沈念sama閱讀 206,602評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異然低,居然都是意外死亡喜每,警方通過查閱死者的電腦和手機务唐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來带兜,“玉大人枫笛,你說我怎么就攤上這事「照眨” “怎么了刑巧?”我有些...
    開封第一講書人閱讀 152,878評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長无畔。 經(jīng)常有香客問我啊楚,道長,這世上最難降的妖魔是什么浑彰? 我笑而不...
    開封第一講書人閱讀 55,306評論 1 279
  • 正文 為了忘掉前任恭理,我火速辦了婚禮,結(jié)果婚禮上郭变,老公的妹妹穿的比我還像新娘颜价。我一直安慰自己,他們只是感情好诉濒,可當我...
    茶點故事閱讀 64,330評論 5 373
  • 文/花漫 我一把揭開白布周伦。 她就那樣靜靜地躺著,像睡著了一般未荒。 火紅的嫁衣襯著肌膚如雪专挪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,071評論 1 285
  • 那天片排,我揣著相機與錄音寨腔,去河邊找鬼。 笑死划纽,一個胖子當著我的面吹牛脆侮,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播勇劣,決...
    沈念sama閱讀 38,382評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼潭枣!你這毒婦竟也來了比默?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,006評論 0 259
  • 序言:老撾萬榮一對情侶失蹤盆犁,失蹤者是張志新(化名)和其女友劉穎命咐,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體谐岁,經(jīng)...
    沈念sama閱讀 43,512評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡醋奠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,965評論 2 325
  • 正文 我和宋清朗相戀三年榛臼,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片窜司。...
    茶點故事閱讀 38,094評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡沛善,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出塞祈,到底是詐尸還是另有隱情金刁,我是刑警寧澤,帶...
    沈念sama閱讀 33,732評論 4 323
  • 正文 年R本政府宣布议薪,位于F島的核電站尤蛮,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏斯议。R本人自食惡果不足惜产捞,卻給世界環(huán)境...
    茶點故事閱讀 39,283評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望哼御。 院中可真熱鬧坯临,春花似錦、人聲如沸艇搀。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽焰雕。三九已至衷笋,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間矩屁,已是汗流浹背辟宗。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留吝秕,地道東北人泊脐。 一個月前我還...
    沈念sama閱讀 45,536評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像烁峭,于是被迫代替她去往敵國和親容客。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,828評論 2 345

推薦閱讀更多精彩內(nèi)容

  • 22年12月更新:個人網(wǎng)站關停约郁,如果仍舊對舊教程有興趣參考 Github 的markdown內(nèi)容[https://...
    tangyefei閱讀 35,160評論 22 257
  • ORA-00001: 違反唯一約束條件 (.) 錯誤說明:當在唯一索引所對應的列上鍵入重復值時缩挑,會觸發(fā)此異常。 O...
    我想起個好名字閱讀 5,176評論 0 9
  • 關于Mongodb的全面總結(jié) MongoDB的內(nèi)部構(gòu)造《MongoDB The Definitive Guide》...
    中v中閱讀 31,898評論 2 89
  • 今天是復盤李笑來老師《通往財富自由之路》的第二周鬓梅,這周主題是人生最寶貴的財富是什么供置? 如果先前有人問...
    張占杰閱讀 307評論 0 0
  • 17.癡情人,誤入天機山 秋風绽快,惱人的秋風芥丧,古人云:"自古逢秋悲寂寥紧阔。"原本寂寥的秋,再加上這一縷秋風续担,更...
    柏谷閱讀 332評論 0 0