前言
应用使用 SQLite 来存储数据,很多时候需要对一部分的数据进行加密。常见的做法是对要存储的内容加密后存到数据库中,使用的时候对数据进行解密。这样就会有大量的性能消耗在数据的加密解密上。
SQLite 本身是支持加密功能的 (免费版本不提供加密功能,商业版本是支持加密模块)。SQLCipher 是一个开源的 SQLite 加密的扩展,支持对 db 文件进行 256位的 AES 加密。
加密与非加密的数据库对比
打开 Terminal 输入以下内容,
1 2 3 4 5 6 7 | ~ $ sqlite3 sqlcipher.db sqlite> PRAGMA KEY=’test123′; sqlite> CREATE TABLE t1(a,b); sqlite> INSERT INTO t1(a,b) VALUES ('one for the money’, 'two for the show’); sqlite> .quit ~$ hexdump -C sqlite.db |
结果:
配置步骤
1、到 github 上下载 SQLCipher 插件,并存放到项目根目录下。
2、sqlcipher.xcodeproj 以 static library 的方式添加到项目里面。
3、关联新添加的静态库 (注意,这里不能包含系统的 libsqlite3.dylib)
4、设置 Build Setting
"Header Search Path" 添加,"../sqlcipher/src",这里需要注意路径的关系。
"Other C Flags" 添加 "-DSQLITE_HAS_CODEC"
由于 SQLCipher 是支持 Mac OSX, iOS, WatchOS, TVOS 等多个平台,所以必要的时候,需要修改 sqlcipher.project 的配置文件,否则会引起编译或者 linking 错误,修改如下:
项目中使用示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | #import <sqlite3.h> - ( void )openDB2 { NSString *documentPath = NSSearchPathForDirectoriesInDomains ( NSDocumentDirectory , NSUserDomainMask , YES )[0]; NSString *db2Path = [documentPath stringByAppendingPathComponent:db2Name]; if (sqlite3_open([db2Path UTF8String], &database2) == SQLITE_OK) { const char * key = [@ "eileen" UTF8String]; sqlite3_key(database2, key, strlen(key)); // if (sqlite3_exec(database2, (const char*) "CREATE TABLE t1 (a, b);", NULL, NULL, NULL) == SQLITE_OK) { // NSLog(@"password is correct, or, database has been initializ"); // // } else { // NSLog(@"incorrect password!"); // } // sqlite3_close(database2); if (sqlite3_exec(database2, "INSERT INTO t1(a, b) VALUES('qqqqqqq', 'pppppp')" , NULL , NULL , NULL )==SQLITE_OK) { NSLog (@ "密码正确" ); } else { NSLog (@ "密码错误" ); } sqlite3_stmt *statement = NULL ; sqlite3_prepare_v2(database2, "SELECT a,b FROM t1" , -1, &statement, NULL ); while (sqlite3_step(statement) == SQLITE_ROW) { char *field0 = ( char *)sqlite3_column_text(statement, 0); NSString *field0Str = @ "" ; if (field0) { field0Str = [ NSString stringWithUTF8String:field0]; } char *field1 = ( char *)sqlite3_column_text(statement, 1); NSString *field1Str = @ "" ; if (field1) { field1Str = [ NSString stringWithUTF8String:field1]; } NSLog (@ "a = %@, b = %@;" , field0Str, field1Str); } sqlite3_finalize(statement); } else { sqlite3_close(database2); } } |
Terminal 上安装 SQLCipher
总的来说在 Terminal 执行以下 2句即可,参照:
1 2 | $ ./configure --enable-tempstore=yes CFLAGS= "-DSQLITE_HAS_CODEC" LDFLAGS= "-lcrypto" ;# Run the configure script $ make ;# Run the makefile. |
1、cd 到下载好的 sqlcipher 目录下,并执行
1 | $ ./configure --enable-tempstore=yes CFLAGS= "-DSQLITE_HAS_CODEC" LDFLAGS= "-lcrypto" |
2、输入
1 | $ make |
2.1、发生了错误,
sqlite3.c:18280:10: fatal error: 'openssl/rand.h' file not found
#include <openssl/rand.h>
见下图:
解决方法,输入:
1 | $ brew link openssl --force |
2.2、发生错误,“-bash: brew: command not found”,证明 OS 尚未安装 Homebrew。(安装 Homebrew 的前提下是安装了 Xcode, 并且 Command Line Tools 已安装, Terminal 输入 "gcc --version" 检查)
解决方法,输入:
1 | $ -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" |
2.3、安装好 Homebrew 后,重新执行
1 | $ brew link openssl --force |
发生了错误:Error: No such keg: /usr/local/Cellar/openssl
解决方法,使用 brew 安装 openssl,输入:
1 | $ brew install openssl |
2.4、安装完 openssl 后,重新执行
1 | $ brew link openssl --force |
执行完后,再重新执行
1 | $ make |
多次执行 make 操作会发生错误 “make: Nothing to be done for `all'”,解决方法,输入:
1 2 3 4 5 | $ make clean // 重新执行 $ make |
3、执行完前面 2 步,sqlcipher 目录下会多了一个 sqlcipher 文件,用于 Terminal 中管理数据库。
Terminal 查看和修改数据库的密码管理
cd 到刚才新生成的 sqlcipher 文件的目录下,执行以下的操作,参照。
1、使用 SQLCipher 加密已经存在的数据库
1 2 3 4 | $ ./sqlcipher plaintext.db sqlite> ATTACH DATABASE 'encrypted.db' AS encrypted KEY 'testkey' ; sqlite> SELECT sqlcipher_export( 'encrypted' ); sqlite> DETACH DATABASE encrypted; |
2、解除使用 SQLCipher 加密的数据库密码
1 2 3 4 5 | $ ./sqlcipher encrypted.db sqlite> PRAGMA key = 'testkey' ; sqlite> ATTACH DATABASE 'plaintext.db' AS plaintext KEY '' ; -- empty key will disable encryption sqlite> SELECT sqlcipher_export( 'plaintext' ); sqlite> DETACH DATABASE plaintext; |
注意
有些软件的加密方式是不公开的,例如 Mac SQLiteManager 生成的加密的 .db 文件没法在程序里面解密打开。程序里面生成的加密的 .db 文件也没法用 Mac 上的 SQLiteManager 打开。
免费版本的项目代码不提供以下的功能:
数据库创建的时候,没有使用 sqlite3_key 设置密码,之后不能添加密码管理;
对创建时已经设置了密码管理的数据库,不能取消其密码管理,只能重新设置新的密码;
联系客服