SQLite是一個(gè)進(jìn)程庫反粥,實(shí)現(xiàn)了一個(gè) 自包含的卢肃, 無服務(wù)器, 零配置才顿, 事務(wù)性 的SQL數(shù)據(jù)庫引擎莫湘。SQLite是一個(gè)開源的項(xiàng)目,由于其小巧郑气,靈活幅垮,高效等特點(diǎn),在終端設(shè)備上使用非常廣泛尾组。
以下主要介紹一下SQLite3的加密框架忙芒。
原生設(shè)計(jì)
SQLite自身沒有加密的實(shí)現(xiàn),但提供了對(duì)外的加密接口讳侨,通過關(guān)鍵字SQLITE_HAS_CODEC來控制加密模塊的開啟和關(guān)閉呵萨。實(shí)現(xiàn)這些接口
了解加密API的最簡單的方法,就是跟著SQLITE_HAS_CODEC查看sqlite3.c跨跨,框架就一目了然了潮峦。
加密入口
如上圖所示為SQLite加密的基礎(chǔ)API接口,其中藍(lán)色部分為已有的模塊歹叮,灰色部門是需要開發(fā)者去實(shí)現(xiàn)的部分跑杭。
sqlite3_key是加密的入口,需要在調(diào)用sqlite3_open打開數(shù)據(jù)庫后立刻調(diào)用咆耿。
sqlite3_key和sqlite3_key_v2本質(zhì)是一樣的德谅,區(qū)別是前者默認(rèn)選擇main db,后者可以通過名字選擇db文件萨螺。
sqlite3_rekey用于修改密碼窄做,使用前必須先調(diào)用sqlite3_key解密愧驱。
page加密
如上圖所示為SQLite實(shí)現(xiàn)page密碼的框架。
SQLIte使用pager來管理頁面椭盏,pager預(yù)留了三個(gè)函數(shù)指針组砚,分別為xCodec(核心函數(shù),負(fù)責(zé)page的加解密)掏颊,xCodeSizeChng(page大小變化的回調(diào))糟红,xCodecFree(釋放函數(shù)),同時(shí)預(yù)留了指針pCodec用于保存加解密的
上下文乌叶。
SQLite已經(jīng)提供了函數(shù)調(diào)用的實(shí)現(xiàn)盆偿,開發(fā)者只需實(shí)現(xiàn)圖片下方的函數(shù)即可。
讀寫加解密
如上圖所示為加解密時(shí)API的具體調(diào)用准浴。
執(zhí)行寫操作時(shí)進(jìn)行數(shù)據(jù)的加密事扭,此時(shí)會(huì)調(diào)用CODE2函數(shù),執(zhí)行讀操作是進(jìn)行數(shù)據(jù)的解密乐横,此時(shí)會(huì)調(diào)用CODEC1函數(shù)求橄,
而最終調(diào)用的都是sqlite3Codec這個(gè)函數(shù),主要通過傳入的參數(shù)來控制葡公。
//此處為wxSQlite的加解密實(shí)現(xiàn)
void* sqlite3Codec(void* pCodecArg, void* data, Pgno nPageNum, int nMode)
{
Codec* codec = NULL;
int pageSize;
if (pCodecArg == NULL)
{
return data;
}
codec = (Codec*) pCodecArg;
if (!CodecIsEncrypted(codec))
{
return data;
}
pageSize = sqlite3BtreeGetPageSize(CodecGetBtree(codec));
switch(nMode)
{
case 0: /* Undo a "case 7" journal file encryption */
case 2: /* Reload a page */
case 3: /* Load a page */
if (CodecHasReadKey(codec))
{
CodecDecrypt(codec, nPageNum, (unsigned char*) data, pageSize);
}
break;
case 6: /* Encrypt a page for the main database file */
if (CodecHasWriteKey(codec))
{
unsigned char* pageBuffer = CodecGetPageBuffer(codec);
memcpy(pageBuffer, data, pageSize);
data = pageBuffer;
CodecEncrypt(codec, nPageNum, (unsigned char*) data, pageSize, 1);
}
break;
case 7: /* Encrypt a page for the journal file */
/* Under normal circumstances, the readkey is the same as the writekey. However,
when the database is being rekeyed, the readkey is not the same as the writekey.
The rollback journal must be written using the original key for the
database file because it is, by nature, a rollback journal.
Therefore, for case 7, when the rollback is being written, always encrypt using
the database's readkey, which is guaranteed to be the same key that was used to
read the original data.
*/
if (CodecHasReadKey(codec))
{
unsigned char* pageBuffer = CodecGetPageBuffer(codec);
memcpy(pageBuffer, data, pageSize);
data = pageBuffer;
CodecEncrypt(codec, nPageNum, (unsigned char*) data, pageSize, 0);
}
break;
}
return data;
}
現(xiàn)有方案
下面介紹一下主要的幾種SQLite加密的實(shí)現(xiàn):
- SEE SQLite官方實(shí)現(xiàn)的版本罐农,有加密的功能,不過要收費(fèi)匾南。
- wxSQlite wxWidgets 中實(shí)現(xiàn)了加密的功能啃匿,開源免費(fèi),比較輕量的實(shí)現(xiàn)蛆楞。
- SQLCipher 目前最主流的方案,開源免費(fèi)夹厌,安全性比較好豹爹,可以自由選擇加密方式,但體積較大矛纹。
- SQLiteCrypto 主要使用了AES-256和SHA256來加密臂聋,也是收費(fèi)的版本。
SQLiteCipher實(shí)現(xiàn)原理
上圖為sqlCipher的實(shí)現(xiàn)原理或南,加密流程為以下步驟:
- 傳入密鑰
- 通過Rand_bytes算法生成16個(gè)字節(jié)的salt孩等,并存儲(chǔ)在數(shù)據(jù)庫第一頁的頭部(SQLite3的db文件,頭部前16個(gè)字節(jié)固定為SQLite 3 format采够,所以可以利用文件頭來存儲(chǔ)一些數(shù)據(jù))肄方。
- 通過PKCS5_PBKDF2_HMAC_SHA1算法將密鑰和salt一起加密并多次迭代,生成AES加密所用的key蹬癌;此處是對(duì)key的加密权她,即使原始的密碼泄露虹茶,也無法解密數(shù)據(jù)。
- 通過AES對(duì)稱加密算法對(duì)每一頁的文件內(nèi)容(有效的內(nèi)容隅要,不包含文件頭和reserved字段)進(jìn)行加密蝴罪。
- 加密時(shí),文件執(zhí)行過AES加密后步清,對(duì)文件內(nèi)容要门,通過Hmac算法,獲取文件校驗(yàn)碼廓啊,填充在page尾部(SQLite3提供了reserved字段暂衡,自動(dòng)在page尾部預(yù)留一段空間)。
- 解密時(shí)崖瞭,先調(diào)用Hmac算法獲取文件標(biāo)識(shí)碼狂巢,與page尾部的數(shù)據(jù)進(jìn)行對(duì)比,如果數(shù)據(jù)一致书聚,則證明文件沒有被篡改過唧领,不然證明文件已經(jīng)被篡改,則拋出異常雌续。
PS:以上為默認(rèn)的算法斩个,sqlCipher沒有固定算法,用戶可以自己設(shè)置驯杜。
wxSQLite實(shí)現(xiàn)原理
上圖為wxSQLite加密部分的實(shí)現(xiàn)原理受啥,大致實(shí)現(xiàn)與sqlCipher類似,區(qū)別是沒有添加salt鸽心,沒有生成HMAC碼滚局。
具體差異
硬件加密
OpenSSL的加密庫提供了硬件加速的功能,在執(zhí)行加密算法的時(shí)候顽频,可以通過匯編代碼藤肢,直接操作寄存器,來優(yōu)化加密的速度糯景。本質(zhì)上是使用了SIMD的技術(shù)嘁圈。
單指令流多數(shù)據(jù)流(英語:Single Instruction Multiple Data,縮寫:SIMD)是一種采用一個(gè)控制器來控制多個(gè)處理器蟀淮,同時(shí)對(duì)一組數(shù)據(jù)(又稱“數(shù)據(jù)向量”)中的每一個(gè)分別執(zhí)行相同的操作從而實(shí)現(xiàn)空間上的并行性的技術(shù)最住。
下圖為架構(gòu)圖
下面兩張圖可以表明SIMD和普通調(diào)用CPU,GPU的區(qū)別
結(jié)束語
文章寫得比較簡單,大部分直接貼圖了怠惶,如果有什么問題涨缚,歡迎一起探討。