SQLite3加密原理

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跨跨,框架就一目了然了潮峦。

加密入口

api-1.png

如上圖所示為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加密

api-2.png

如上圖所示為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ù)即可。

讀寫加解密

api.png

如上圖所示為加解密時(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.png

上圖為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.png

上圖為wxSQLite加密部分的實(shí)現(xiàn)原理受啥,大致實(shí)現(xiàn)與sqlCipher類似,區(qū)別是沒有添加salt鸽心,沒有生成HMAC碼滚局。

具體差異

compare.png

硬件加密

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)圖


SIMD2.svg.png

下面兩張圖可以表明SIMD和普通調(diào)用CPU,GPU的區(qū)別

Non-SIMD_cpu_diagram1.svg.png
SIMD_cpu_diagram1.svg.png

結(jié)束語

文章寫得比較簡單,大部分直接貼圖了怠惶,如果有什么問題涨缚,歡迎一起探討。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末甚疟,一起剝皮案震驚了整個(gè)濱河市仗岖,隨后出現(xiàn)的幾起案子逃延,更是在濱河造成了極大的恐慌,老刑警劉巖轧拄,帶你破解...
    沈念sama閱讀 211,290評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件揽祥,死亡現(xiàn)場離奇詭異,居然都是意外死亡檩电,警方通過查閱死者的電腦和手機(jī)拄丰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來俐末,“玉大人料按,你說我怎么就攤上這事∽矿铮” “怎么了载矿?”我有些...
    開封第一講書人閱讀 156,872評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長烹卒。 經(jīng)常有香客問我闷盔,道長,這世上最難降的妖魔是什么旅急? 我笑而不...
    開封第一講書人閱讀 56,415評(píng)論 1 283
  • 正文 為了忘掉前任逢勾,我火速辦了婚禮,結(jié)果婚禮上藐吮,老公的妹妹穿的比我還像新娘溺拱。我一直安慰自己,他們只是感情好谣辞,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,453評(píng)論 6 385
  • 文/花漫 我一把揭開白布迫摔。 她就那樣靜靜地躺著,像睡著了一般潦闲。 火紅的嫁衣襯著肌膚如雪攒菠。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,784評(píng)論 1 290
  • 那天歉闰,我揣著相機(jī)與錄音,去河邊找鬼卓起。 笑死和敬,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的戏阅。 我是一名探鬼主播昼弟,決...
    沈念sama閱讀 38,927評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼奕筐!你這毒婦竟也來了舱痘?” 一聲冷哼從身側(cè)響起变骡,我...
    開封第一講書人閱讀 37,691評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎芭逝,沒想到半個(gè)月后塌碌,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,137評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡旬盯,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,472評(píng)論 2 326
  • 正文 我和宋清朗相戀三年台妆,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片胖翰。...
    茶點(diǎn)故事閱讀 38,622評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡接剩,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出萨咳,到底是詐尸還是另有隱情懊缺,我是刑警寧澤,帶...
    沈念sama閱讀 34,289評(píng)論 4 329
  • 正文 年R本政府宣布培他,位于F島的核電站鹃两,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏靶壮。R本人自食惡果不足惜怔毛,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,887評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望腾降。 院中可真熱鬧拣度,春花似錦、人聲如沸螃壤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽奸晴。三九已至冤馏,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間寄啼,已是汗流浹背逮光。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留墩划,地道東北人涕刚。 一個(gè)月前我還...
    沈念sama閱讀 46,316評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像乙帮,于是被迫代替她去往敵國和親杜漠。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,490評(píng)論 2 348

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