由於專案涉及到一些使用者隱私資料的儲存,所以需要對儲存在客戶端本地的資料進行加密,以防止使用者隱私資料在裝置被root的情況下出現洩漏。目前android的本地資料儲存基本分為file,sharepreference和database,所以對資料的加密操作分為了兩種:檔案加密和檔案內的資料加密。檔案加密就是在開啟該檔案的時候需要獲得正確的加密秘鑰才能從該檔案中讀取資料或者寫入資料到該檔案中,這種方式相對簡單。檔案內資料加密就是開啟檔案時不需要解密,但是從檔案中讀取出來的資料是加密過的密文,需要對其進行解密才能識別和使用,同樣在寫入資料到檔案的時候,也需要先將資料進行加密然後再寫入到檔案,這種方式相比第一種複雜一些,但是安全性更高,對資料保護的粒度更細。file和sharepreference使用上述兩種方式實現的成本差異並不明顯,database使用檔案內資料比如列欄位加密相比檔案加密要更加複雜,所以database通常使用檔案加密的方式來實現,比如有名的sqlcipher就是採用的這種方式,今天我們將要提到的wcdb也是採用的這種方式來保護資料的。
混淆通常我們在引入一些知名的第三方庫的時候,都需要在proguard中加入一些規則來遮蔽對該庫的混淆,因為混淆可能會導致該庫的部分功能異常,比如glide的專案介紹上就有如下說明:
但是我們在wcdb的專案上沒有看到關於混淆這一塊的介紹,剛開始我以為不需要,後來打了乙個release包後發現wcdb執行報錯,才知道這裡還是有必要加一下的。內容如下:
-keep class com.tencent.wcdb.**
複製**
關於在proguard中如何加入第三方庫的放混淆配置,可以使用以下方法。在android studio的project檢視下的external libraries中找到對應的庫名字,比如wcdb,然後就可以看到這個庫的完整包路徑了。如下圖:
加密已有資料
由於我的專案以前是使用android原生的sqlite儲存資料,現在要遷移到wcdb上,就必須考慮到版本相容的問題,當老版本公升級到新版本後確保老版本上儲存在本地的資料能無縫遷移到新版本上面來。那麼對於已有資料的加密,wcdb的專案裡面也提供了乙個例子,我將核心**貼出來:
file olddbfile = mcontext.getdatabasepath(old_database_name);
if (olddbfile.exists())
複製**
這裡很多第一次使用wcdb的童鞋,如果沒有細看這個例子中的**會比較容易犯乙個錯誤,就是將
databaseutils.stringforquery(db, "select sqlcipher_export('main', 'old');", null);
複製**
不小心寫成了
db.execsql("select sqlcipher_export('encrypted')");
複製**
然後發現怎麼執行都會報異常。針對這個問題在專案裡面還有乙個issue:整合wcdb後希望能實現解密資料庫 #36。我也遇到了,後面找了好久才發現是這裡的問題,原因是wcdb的execsql不支援select,但是原生的sqlite以及sqlcipher都是支援,所以在第一次用的時候就會覺得很奇怪,這條語句語法看上去完全沒問題,執行就是行不通。
資料解密
有時為了方便定位問題,需要檢視database的資料,如果是debug包可以直接聯調查看,但如果是release包那麼就必須手動匯出db檔案然後進行解密檢視了。這裡有兩種方式解密:
db檔案拷貝到電腦上面,然後安裝sqlcipher工具進行解密
在手機上使用wcdb sdk來解密
電腦端使用sqlcipher解密
其中123456為加密秘鑰,encrypt.db為加密的資料庫檔案,這裡有幾個地方需要注意:
wcdb預設加密後的db檔案的pagesize為4096,所以這裡如果不設定cipher_page_size或者設定的值與你在使用wcdb加密時設定的pagesize一致的話,就會報錯,這一點我網上找了很久都沒發現有人提到,有的文章上設定的是1024,但是我試過就是不行,後來找了乙個未加密的db檔案看了下pagesize的值才發現不對。
在進行任何操作之前需要先使用pragma key=...來解密資料庫,否則可能會報錯「error: file is encrypted or is not a database」,這裡網上也有很多人跟我一樣遇到。
wcdb使用了sqlcipher來加密的,在加解密的時候必須使用一致的版本,比如我們使用sqlcipher3.x加密的,那麼在解密的時候也必須使用3.x版本,否則就會解密失敗。
有時在命令列裡面解密和檢視資料不太方便,我們可以將加密db中的資料匯出到乙個未加密的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檔案。執行完上述命令後,我們就會在當前目錄下看到乙個解密後的plaintext.db檔案了,然後使用其他的資料庫工具如sqlite expert等就可以正常開啟檢視裡面的資料了。
wcdb sdk解密
使用wcdb sdk解密資料與之前提到的加密資料的過程是相識的,這裡結合**來詳細說明。
sqlitedatabase db = sqlitedatabase.openorcreatedatabase(getdatabase("encrypt.db"), "123456".getbytes(), null, null);
//將要生成的未加密db檔案,這裡可以根據自己的需要放在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);
//匯出加密資料庫到未加密資料庫中,sqlcipher_export這個方法有兩個引數,第乙個引數plaintext代表新生成的未加密資料庫,第二個引數main代表已加密的資料庫,也可以不使用第二個引數,那麼預設將使用db關聯的資料庫匯出到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;");
複製**
這樣我們就將乙個加密資料庫匯出到了plaintext.db中。 Vim 使用筆記
set hlsearch set nohlsearch 搜尋後清除上次的加亮 nohl nohlsearch 拷貝 很有用的一句話,規定了格式選項,讓它換行不自動空格 set formatoptions tcrqn set fo r set noautoindent 再 shift insert 正...
xemacs使用筆記
xemacs使用筆記 xemacs emacs的下一代,由lucid原創 from debian參考手冊.由於不知道什麼時候刪掉了emacs的乙個重要檔案.每次都沒法安裝好.突然發現了xemacs,於是決定使用看看.本人還是菜鳥,僅供交流 我使用的ubuntu系統,所以就直接apt get inst...
TreeView使用筆記
treeview由節點構成,建樹通過對treeview.items屬性進行操作。items是乙個ttreenodes物件,這是乙個ttreenode集。一 針對ttreenodes,也就是 treeview.items,有這些屬性 1 count,節點個數。2 item index 通過index得...