之前文章网络安全-密码存储 有提过对敏感信息数据尤其是密码信息,需要加密存储。
加密存储,一般方式就是将敏感数据在写入数据库之前先进行加密操作,然后将密文再写入到数据库中。还有一种方式则是直接对整个数据库进行整体加密,这样就不用总想着哪些字段是敏感数据,避免考虑不全,而未做加密存储。
不过整体加密肯定会带来性能上的开销,如官网说的,很多操作会增加 5~15% 的性能开销。同时加密数据库比起明文数据库也会有所增大,且数据库加密后,就无法进行压缩处理,对于 flash 紧张的嵌入式设备还是需要考虑是否要支持。
SQLCipher 是基于 SQLite 做的开源扩展软件,支持对数据库文件进行整体 AES256 加密。下面针对编译和加密相关操作进行说明。
一、编译
SQLCipher 需要依赖于 openssl 库,对于 openssl 库的编译操作,可以参看openssl交叉编译,sqlcipher 编译时需要注意版本的选择,如依赖的 openssl 库是1.1.* 版本的,则 sqlcipher 需选择 3.4.1 版本以上的,因为此版本才开始支持 openssl 1.1.* 相关接口。
我这边选择当前最新的 4.4.3 版本下载,在本地解压缩之后,将之前 openssl 编译安装的成果物拷贝到了 sqlcipher 目录下,然后执行如下命令进行编译
./configure --enable-tempstore=yes CFLAGS="-DSQLITE_HAS_CODEC -I`pwd`/openssl/include" LDFLAGS="-L`pwd`/openssl/lib -lcrypto" CC=arm-linux-gnueabihf-gcc --prefix=`pwd`/tmp --host=arm-linux
make
make install
–host 用于指定你所要编译的成果物想要运行的平台,如果不清楚该怎么填写,可以使用源码目录下的 config.guess 脚本在目标机上运行下。
二、数据库加解密
对于一开始就是用 sqlite3 代码来实现的数据库操作,切到 sqlcipher 进行数据库加密是很简单的,只需要在 sqlite3_open 操作后,仅跟着 sqlite3_key 接口即可,其他操作逻辑都不需要修改,这样新创建的数据库就是经过加密了的。
但如果需要考虑低版本升级到高版本这样的兼容性问题,则还需要进行明文数据库迁移到加密数据库操作。
对应的执行语句,官方也给了详细的操作语句,如下:
Example 1: Encrypt a Plaintext Database
$ ./sqlcipher plaintext.db
sqlite> ATTACH DATABASE 'encrypted.db' AS encrypted KEY 'testkey';
sqlite> SELECT sqlcipher_export('encrypted');
sqlite> DETACH DATABASE encrypted;
Example 2: Decrypt a SQLCipher database to a Plaintext Database
$ ./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;
对应的语句在 C 代码中都可以通过 sqlite3_exec 接口进行执行实现。