加密你的SQLite

轉自王中周的個人博客

 

關於SQLite

SQLite是一個輕量的、跨平臺的、開源的數據庫引擎,它的在讀寫效率、消耗總量、延遲時間和整體簡單性上具有的優越性,使其成爲移動平臺數據庫的最佳解決方案(如iOS、Android)。
 
然而免費版的SQLite有一個致命缺點:不支持加密。這就導致存儲在SQLite中的數據可以被任何人用任何文本編輯器查看到。比如國內某團購iOS客戶端的DB緩存數據就一覽無餘: 
 
SQLite加密方式
對數據庫加密的思路有兩種:
 
1. 將內容加密後再寫入數據庫
這種方式使用簡單,在入庫/出庫只需要將字段做對應的加解密操作即可,一定程度上解決了將數據赤裸裸暴露的問題。
 
不過這種方式並不是徹底的加密,因爲數據庫的表結構等信息還是能被查看到。另外寫入數據庫的內容加密後,搜索也是個問題。
 
2. 對數據庫文件加密
將整個數據庫整個文件加密,這種方式基本上能解決數據庫的信息安全問題。目前已有的SQLite加密基本都是通過這種方式實現的。
 
SQLite加密工具
目前網上查詢到iOS平臺可用的SQLite加密工具有以下幾種:
 
事實上SQLite有加解密接口,只是免費版本沒有實現而已。而SQLite Encryption Extension (SEE)是SQLite的加密版本,提供以下加密方式:

  1. RC4 
  2. AES-128 in OFB mode 
  3. AES-128 in CCM mode 
  4. AES-256 in OFB mode 
 
SQLite Encryption Extension (SEE)版本是收費的。
 
使用AES加密,其原理是實現了開源免費版SQLite沒有實現的加密相關接口。
 
SQLiteEncrypt是收費的。
 
使用256-bit AES加密,其原理和SQLiteEncrypt一樣,都是實現了SQLite的加密相關接口。
 
SQLiteCrypt也是收費的。
 
首先需要說明的是,SQLCipher是完全開源的,代碼託管在Github上。
 
SQLCipher使用256-bit AES加密,由於其基於免費版的SQLite,主要的加密接口和SQLite是相同的,但也增加了一些自己的接口,詳情見這裏
 
SQLCipher分爲收費版本和免費版本,官網介紹的區別爲:
asier to setup, saving many steps in project configuration
pre-built with a modern version of OpenSSL, avoiding another external dependency
much faster for each build cycle because the library doesn't need to be built from scratch on each compile (build time can be up to 95% faster with the static libraries)
 
 
只是集成起來更簡單,不用再添加OpenSSL依賴庫,而且編譯速度更快,從功能上來說沒有任何區別。僅僅爲了上述一點便利去花費幾百美刀,對於我等苦逼RD來說太不值了,還好有一個免費版本。
 
鑑於上述SQLite加密工具中,只有SQLCiper有免費版本,下面將將着重介紹下SQLCiper。
 
在項目中使用SQLCipher
在項目中集成免費版的SQLCipher略顯複雜,還好官網以圖文的方式介紹的非常詳細,集成過程請參考官網教程
 
使用SQLCipher初始化數據庫
下面這段代碼來自官網,其作用是使用SQLCipher創建一個新的加密數據庫,或者打開一個使用SQLCipher創建的數據庫。

  1. NSString *databasePath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0] 
  2.                               stringByAppendingPathComponent: @"cipher.db"]; 
  3.     sqlite3 *db; 
  4.     if (sqlite3_open([databasePath UTF8String], &db) == SQLITE_OK) { 
  5.         const char* key = [@"BIGSecret" UTF8String]; 
  6.         sqlite3_key(db, key, strlen(key)); 
  7.         int result = sqlite3_exec(db, (const char*) "SELECT count(*) FROM sqlite_master;", NULL, NULL, NULL); 
  8.         if (result == SQLITE_OK) { 
  9.             NSLog(@"password is correct, or, database has been initialized"); 
  10.         } else { 
  11.             NSLog(@"incorrect password! errCode:%d",result); 
  12.         } 
  13.          
  14.         sqlite3_close(db); 
  15.     } 
 
需要注意的是,在使用sqlite3_open打開或創建一個數據庫,在對數據庫做任何其它操作之前,都必須先使用sqlite3_key輸入密碼,否則會導致數據庫操作失敗,報出sqlite錯誤碼SQLITE_NOTADB。
 
在sqlite3_open打開數據庫成功,而且用sqlite3_key輸入密碼以後,就可以正常的對數據庫進行增、刪、改、查等操作了。
 
使用SQLCipher加密已存在的數據庫
SQLCipher提供了sqlcipher_export()函數,該函數可以方便的對一個普通數據庫導入到SQLCipher加密加密的數據庫中,操作方式如下:

  1. $ ./sqlcipher plaintext.db  
  2. sqlite> ATTACH DATABASE 'encrypted.db' AS encrypted KEY 'testkey';  
  3. sqlite> SELECT sqlcipher_export('encrypted');  
  4. sqlite> DETACH DATABASE encrypted;  
 
解除使用SQLCipher加密的數據庫密碼
sqlcipher_export()函數同樣可以將SQLCipher加密後的數據庫內容導入到未加密的數據庫中,從而實現解密,操作方式如下:

  1. $ ./sqlcipher encrypted.db  
  2. sqlite> PRAGMA key = 'testkey';  
  3. sqlite> ATTACH DATABASE 'plaintext.db' AS plaintext KEY '';  -- empty key will disable encryption 
  4. sqlite> SELECT sqlcipher_export('plaintext');  
  5. sqlite> DETACH DATABASE plaintext;  
 
總體來說,SQLCipher是一個使用方便,靈活性高的數據庫加密工具。
 
另外,我寫了個SQLCipherDemo工程放到了CSDN上,有需要的同學請自行下載。
 
參考文檔
 
 
 
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章