关于SQLite,SQLCipher和FMDB

  SQLite是一个轻量的、跨平台的、开源的数据库引擎,它的在读写效率、消耗总量、延迟时间和整体简单性上具有的优越性,使其成为移动平台数据库的最佳解决方案(如iOS、Android)。然而免费版的SQLite有一个致命缺点:不支持加密。这就导致存储在SQLite中的数据可以被任何人用任何文本编辑器查看到。

  如果我们想要使得自己的数据库加密,解决方案就是使用另一款开源的加密数据库SQLCipher,SQLCipher使用256-bit AES加密,由于其基于免费版的SQLite,主要的加密接口和SQLite是相同的,当然也增加了一些自己的接口,如在新建和打开数据库时,给数据库设置秘钥之类的操作。

  FMDB是一个开源的类库,它对sqlite数据库操作进行了很不错的封装,而且也增加了对sqlcipher的支持,也就是说,我们不直接用sqlcihper也能完成加解密操作,而且FMDB在操作sqlite方面方便得多。现在的APP开发如果涉及到数据库操作,FMDB基本上是首选。

  下面内容主要是针对一些在初期忽略了数据库私密性,而到了中期需要让数据库进行升级加密的App的简单方案介绍和代码实现。如果读者没有使用FMDB,直接使用了sqlite,那本文也有一定参考性,只是关于SQLCipher的配置,并没有介绍,因为虽然FDMB的加密也是使用SQLCipher,但是不需要进行配置的。

  具有加密功能的FMDB版本

  加密的FMDB其实是一个分支,也就是说,如果你需要替换FMDB。Github上关于该分支的安装只提供了cocospod的安装方式。

  Github上FMDB的地址:https://github.com/ccgus/fmdb

  

  举个例子,如果你以前是如下写的

pod 'FMDB'

  如果想换成有加密功能的,就改成

pod 'FMDB/SQLCipher'

  升级数据库代码实现

  得到对的版本后,我们需要在代码里做一些处理,让旧数据库升级。这里升级包括两点:

  1 是我们前面所说的,将数据库加密。

  2 把旧数据库的表和数据迁移到新数据库中。

  sqlcipher的使用和sqlite没有多大的区别,有一点值得注意便是每次当[dp open]成功后,需要给数据库配上口令,即[db setKey:DB_SECRETKEY], DB_SECRETKEY是我们的一个自定义宏。这之后,我们才能读出数据库的内容。

FMDatabase *_db = [FMDatabase databaseWithPath:[cachePath stringByAppendingString:dbFileName]];
if (![_db open]) {
_db = nil;
return;
}else{
[_db setKey:DB_SECRETKEY];
}

  然后我们需要判断数据库是否需要升级,当使用sqlchipher打开用sqlite生成的源数据库时,[dp goodConnection]是为NO,即使上面[db open]操作是YES。

if(![_db goodConnection]){ //无效连接
[self upgradeDatabase:dbpath];
}

  接下来,便是数据迁移,path是我们的源数据库路径,假设我们的源数据库名字为DBName,changeDatabasePath即将我们的数据库A改名为DBName.tmp,接下来便是,新建数据库B,因为A在前面已经进行了改名为DBName.tmp,并且已经B将来就是我们要取代A的数据库,所以此处的B名字便是DBName。最后将DBName.tmp的数据复制到DBName中,再删除DBName.tmp,致此,我们的数据库便升级完成了。

- (void)upgradeDatabase:(NSString *)path{
NSString *tmppath = [self changeDatabasePath:path];
if(tmppath){
const char* sqlQ = [[NSString stringWithFormat:@"ATTACH DATABASE '%@' AS encrypted KEY '%@';",path,DB_SECRETKEY] UTF8String]; sqlite3 *unencrypted_DB;
if (sqlite3_open([tmppath UTF8String], &unencrypted_DB) == SQLITE_OK) { // Attach empty encrypted database to unencrypted database
sqlite3_exec(unencrypted_DB, sqlQ, NULL, NULL, NULL); // export database
sqlite3_exec(unencrypted_DB, "SELECT sqlcipher_export('encrypted');", NULL, NULL, NULL); // Detach encrypted database
sqlite3_exec(unencrypted_DB, "DETACH DATABASE encrypted;", NULL, NULL, NULL); sqlite3_close(unencrypted_DB); //delete tmp database
[self removeDatabasePath:tmppath];
}
else {
sqlite3_close(unencrypted_DB);
NSAssert1(NO, @"Failed to open database with message '%s'.", sqlite3_errmsg(unencrypted_DB));
}
}
}
- (NSString *)changeDatabasePath:(NSString *)path{
NSError * err = NULL;
NSFileManager * fm = [[NSFileManager alloc] init];
NSString *tmppath = [NSString stringWithFormat:@"%@.tmp",path];
BOOL result = [fm moveItemAtPath:path toPath:tmppath error:&err];
if(!result){
NSLog(@"Error: %@", err);
return nil;
}else{
return tmppath;
}
}

  经过上面步骤,我们知道虽然sqlchipher是基于sqlite的,但到底还是不一样的,我们没办法直接将sqlite的数据库升级为sqlchipher,只能用sqlchipher新建一个数据库,再重新写入数据。  

  以上代码仅仅是范例,各个App的数据存储模型不尽相同,这里我也没办法给出模板。虽然代码不一定是适用的,但是在数据库升级时,代码执行的先后顺序是肯定的:打开数据库open -> 设置秘钥 setkey -> 查看连接 goodConnection -> 新建数据库并迁移数据 upgrade。

iOS 使用FMDB SQLCipher给数据库加密的更多相关文章

  1. 【iOS】FMDB/SQLCipher数据库加解密,迁移

    2016-04-19更新:本文代码可能有些问题,请移步 http://zhengbomo.github.io/2016-04-18/sqlcipher-start/ 查看 sqlite应用几乎在所有的 ...

  2. IOS 使用wxsqlite3为sqlite3数据库加密

    1,下载wxsqlite3 地址http://jaist.dl.sourceforge.net/project/wxcode/Components/wxSQLite3/wxsqlite3-3.1.1. ...

  3. iOS中 FMDB第三方SQLite数据库 UI_20

    1.什么是FMDB? FMDB是iOS平台下SQLite数据库,只不过它是OC方式封装了C语言的SQLite语句,使用起来更加面向对象 2.FMDB的优点:1.使用起来更加面向对象; 2.对比苹果自带 ...

  4. IOS使用FMDB封装的数据库增删改查操作

    // //  DBHelper.h //  LessonStoryBoard // //  Created by 袁冬冬 on 15/10/29. //  Copyright (c) 2015年 袁冬 ...

  5. IOS 使用FMDB多线程访问数据库 及databaseislocked的问题

    原理:文件数据库sqlite,同一时刻允许多个进程/线程读,但同一时刻只允许一个线程写.在操行写操作时,数据库文件被琐定,此时任何其他读/写操作都被阻塞,如果阻塞超过5秒钟(默认是5秒,能过重新编译s ...

  6. ios开发FMDB导入SQLCipher加密数据库

    转:http://www.2cto.com/kf/201407/315727.html [iOS]FMDB/SQLCipher数据库加解密,迁移

  7. Android数据库加密之sqlciher方案

    版权声明:本文为博主原创文章,未经博主允许不得转载. 转载请表明出处:http://www.cnblogs.com/cavalier-/p/6241964.html 前言 大家好,我是Cavalier ...

  8. iOS Sqlite加密(FMDB/SQLCipher)

    /** * 对数据库加密 * * @param path path description * * @return return value description */ + (BOOL)encryp ...

  9. Android数据存储之SQLCipher数据库加密

    前言: 最近研究了Android Sqlite数据库(文章地址:Android数据存储之Sqlite的介绍及使用)以及ContentProvider程序间数据共享(Android探索之ContentP ...

随机推荐

  1. class_create()

    #define class_create(owner, name)               \({                                              \   ...

  2. 双方都在线,qq总是离线发文件

    这是qq支持多地登录后出现的问题. 原因:1.当您传文件给对方,对方是多终端登录(或者开通移动在线功能)的情况下,为了保证对方一定能收到该文件,我们会智能的为用户切换到离线文件,对方会相应在所在的终端 ...

  3. HDU 4927 大数运算

    模板很重要 #include <cstdio> #include <cstring> #include <cstdlib> #include <iostrea ...

  4. 函数buf_page_get_gen

    /********************************************************************//** This is the general functi ...

  5. ASP.NET MVC 传值方法ViewData与ViewBag的区别

    一.介绍 在Asp.net MVC 3 web应用程序中,我们会用到ViewData与ViewBag,对比一下: ViewData ViewBag 它是Key/Value字典集合 它是dynamic类 ...

  6. Ajax、Comet与Websocket

    从 http 协议说起 1996年IETF  HTTP工作组发布了HTTP协议的1.0版本 ,到现在普遍使用的版本1.1,HTTP协议经历了17 年的发展.这种分布式.无状态.基于TCP的请求/响应式 ...

  7. websocket webworker

    对我来说最快的学习途径是实践,所以找两个东西来练手.一个是websocket一个是webwoker,今天先说第一个. 要理解socket就要先理解http和tcp的区别,简单说就是一个是短链,一个是长 ...

  8. 【COCOS2DX-LUA 脚本开发之十二】Hybrid模式-利用AssetsManager实现在线更新脚本文件lua、js、图片等资源(免去平台审核周期)

    本站文章均为李华明Himi原创,转载务必在明显处注明:(作者新浪微博:@李华明Himi) 转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/iphone-c ...

  9. zend studio安装xdebug调试工具

    1. 软件准备 登录xdebug 版本检测地址 http://xdebug.org/wizard.php  :将phpinfo产生的数据页面复制到其文本框内,显示类似如下内容: 二.将下载的xdebu ...

  10. TCP/IP详解学习笔记(8)-DNS域名系统

    前面已经提到了访问一台机器要靠IP地址和MAC地址,其中,MAC地址可以通过ARP协议得到,所以这对用户是透明的,但是IP地址就不行,无论如何用户都需要用一个指定的IP来访问一台计算机,而IP地址又非 ...