使用SQLCipher加密数据库

  Xcode中集成了免费的sqlite,但是不提供加密的模块,突然有一天,蛋疼的客户要求把数据进行加密,于是乎就寻找使用简单并且可以把数据迁移过度到加密数据库的框架。

  SQLCipher是第三方的开源框架,实现对sqlite的加密,官网链接:http://sqlcipher.net。下面开始下载并导入框架。(使用命令行下载)

一、使用SQLCipher需要3个文件:sqlcipher,openssl-xcode,openssl-1.0.0e

  下载 openssl-xcode

  

cd ~/Documents/code/SQLCipherApp
git clone https://github.com/sqlcipher/openssl-xcode.git

  下载 sqlcipher

cd ~/Documents/code/SQLCipherApp
git clone https://github.com/sqlcipher/sqlcipher.git

  下载 openssl-1.0.0e

curl -o openssl-1.0.0e.tar.gz http://www.openssl.org/source/openssl-1.0.0e.tar.gz
//解压
tar xzf openssl-1.0.0e.tar.gz

   把这三个目录拷贝到工程目录中

二.配置Xcode

  1、打开Xcode 的设置页,进入locations ->source trees  ,点击+号添加项目 ,settingname 和 display name 均设为  “OPENSSL_SRC”  path设置为你工程目录下openssl-1.0.0e的所在路径。比如我的路径是:/Users/henry/Documents/工程公用/SQLCipherApp/openssl-1.0.0e

  

2、添加项目的引用 ,将文件里的openssl.xcodeproj 和sqlcipher.xcodeproj (分别在openssl-xcode文件和sqlcipher文件下)添加到你的主工程下,建立引用

3、配置编译库,进入项目的工程TARGETS,进入build phases ->target dependencies,添加图中的两个项目

  

link binary with libraries添加这两个库

三、下面举个使用的例子

首先需要引入头文件 import<sqlite3.h>

//打开数据库的函数
  +(BOOL) OpenDB {
    NSArray *pathArr = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *docPaths = [pathArr objectAtIndex:0];
    NSString *dbPath = [docPaths stringByAppendingFormat:@"/myDB.db"];
    int status = sqlite3_open([dbPath UTF8String], &GB_DB);

    if (status != SQLITE_OK)
    {
        LOG_CINFO(@"打开数据库出错!");
        DB_Opened = NO;
        return DB_Opened;
    }
    DB_Opened = YES;
sqlite3_stmt *statement;
#if UseASE
    //验证sql语句是否成功
    const char *key = [[GlobalData GetInstance].GB_DBKey UTF8String];
    sqlite3_key(GB_DB, key, strlen(key));
#endif
    if(sqlite3_prepare_v2(GB_DB, [sql UTF8String], -1, &statement, nil) != SQLITE_OK)
    {
        LOG_CINFO(@"创建表格失败!");
        return  NO;
    }

    int success = sqlite3_step(statement);
    sqlite3_finalize(statement);
    //[MyDataBase CloseDB];
    if (success != SQLITE_DONE)
    {
        LOG_CINFO(@"在创建表格的过程中出错,创建没有进行完!");
        return NO;
    }
        return YES;
}
//创建需要的数据表
+ (void)CreateNeedTable {
    @autoreleasepool {

        //插入用户信息表
        LocalDataBase *userTb = [LocalDataBase GetTableWithType:@"user" HasUser:NO];
            //先创建
               [userTb CreateTableWithKeys:[NSArray arrayWithObjects:@"userid", nil] OtherNeeds:[NSArray arrayWithObjects:@"siteid",@"username",@"password",@"mobilePhone",@"name", nil] Data:nil];
}
//根据参数创建表,keys是主键,needs是那些非主键,但是必须需要的,如需要用它来排序,搜索的字段,data为数据项的整个data形式,用data是为了减少字段数
-(BOOL) CreateTableWithKeys:(NSArray *)keys OtherNeeds:(NSArray *)needs Data:(NSString *)data {
    //如果有信息,说明注册成功了已经
    if(self.myTableInfo)
    {
        return YES;
    }

    //首先确保数据库是打开的
    if (![LocalDataBase OpenDB])
    {
        return NO;
    }

    //把所有非数据的字段写到一个数组中

    NSMutableArray *allArr = [NSMutableArray arrayWithCapacity:10];
    if ([keys count] > 0)
    {
        [allArr addObjectsFromArray:keys];
    }

    if ([needs count] > 0)
    {
        [allArr addObjectsFromArray:needs];
    }

    if (self.hasUser)
    {
        [allArr insertObject:@"userName" atIndex:0];
    }

    int keysCount = [allArr count];

    if (self.myTableInfo == nil)
    {
        self.myTableInfo = [NSMutableArray arrayWithCapacity:keysCount+1];
    }
    //插入数据
    for(int i = 0; i < keysCount;++i)
    {
        NSString *key = [allArr objectAtIndex:i];
        [self.myTableInfo addObject:[NSDictionary dictionaryWithObjectsAndKeys:@"text",@"type", key,@"key", nil]];
    }

    //创建sql语句
    NSMutableString *cSql = [NSMutableString stringWithFormat:@"create table if not exists %@ (",self.myTableName];

    //把非数据类型的字段加入sql语句
    for(NSString *key in allArr)
    {
        [cSql appendFormat:@"%@ text,",key];
    }

    //把数据类型的字段加入Sql语句
    if (data != nil)
    {
        [cSql appendFormat:@"%@ blob,",data];
        [self.myTableInfo addObject:[NSDictionary dictionaryWithObjectsAndKeys:@"blob",@"type", data,@"key", nil]];
    }

    //添加主键
    [cSql appendString:@"primary key("];

    int keyCount = [keys count];
    if (keyCount > 0)//有多个主键的情况
    {
        for(int i = 0; i < keyCount - 1; ++i)
        {
            NSString *key = [keys objectAtIndex:i];
             [cSql appendFormat:@"%@,",key];
        }

        if(self.hasUser)
        {
            [cSql appendString:@"userName,"];
        }
        [cSql appendFormat:@"%@)",[keys objectAtIndex:keyCount - 1]];
    }
    else
    {
//        if (keyCount == 1)//只有一个主键的情况
//        {
//            [cSql appendFormat:@"%@)",[keys objectAtIndex:0]];
//        }
//        else
        {
            if(self.hasUser)
            {
                [cSql appendString:@"userName)"];
            }
        }
    }

    [cSql appendString:@")"];

    LOG_CINFO(@"========sql 语句 创建表=========");
    LOG_CINFO(cSql);

    {
        NSMutableDictionary *dic = (NSMutableDictionary *)[GlobalFunc ParseDicFromFile:@"dbInfo.plist"];
        if (dic == nil)
        {
            dic = [NSMutableDictionary dictionaryWithCapacity:1];
        }
        [dic setObject:self.myTableInfo forKey:self.myTableName];
        [GlobalFunc WriteDicToFile:dic FileName:@"dbInfo.plist"];
    }

    return [LocalDataBase CreateTableWithSql:cSql];
}
//向表中插入数据
-(BOOL) InsertDataWithDic:(NSDictionary *)dic Replace:(BOOL) replace {
    // 打开数据库
    if (!DB_Opened)
    {
        if(![LocalDataBase OpenDB])
        {
            LOG_CINFO(@"插入数据失败,打开数据库出错!");
            return NO;
        }
    }

    NSMutableDictionary *tmpDic = [NSMutableDictionary dictionaryWithDictionary:dic];
    if (self.hasUser)
    {
        [tmpDic setObject:[GlobalData GetInstance].GB_UserName forKey:@"userName"];
    }

    NSMutableArray *allKeys = [NSMutableArray arrayWithArray:[tmpDic allKeys]];

    NSMutableString *cSql = nil;
    //生成插入语句
    if (replace)
    {
        cSql = [NSMutableString stringWithFormat:@"insert or REPLACE into %@(",self.myTableName];
    }
    else
    {
        cSql = [NSMutableString stringWithFormat:@"insert into %@(",self.myTableName];
    }

    int keysCount = [allKeys count];

    if (keysCount > 0)
    {
        for(int i = 0; i < keysCount-1;++i)
        {
            [cSql appendFormat:@"%@,",[allKeys objectAtIndex:i]];
        }

        [cSql appendFormat:@"%@)",[allKeys objectAtIndex:keysCount -1]];
    }
    else
    {
        return NO;
    }

    [cSql appendString:@" values("];

    for(int i = 0; i<keysCount -1; ++i)
    {
        [cSql appendString:@"?,"];
    }
    [cSql appendString:@"?)"];

    LOG_CINFO(@"========sql 语句 插入表=========");
    LOG_CINFO(cSql);

    //测试sql 语句是否正确
    sqlite3_stmt *statement;

    const char *insertStatement = [cSql UTF8String];
#if UseASE
    //验证sql语句是否成功
    const char *key = [[GlobalData GetInstance].GB_DBKey UTF8String];
    sqlite3_key(GB_DB, key, strlen(key));
#endif
    if(sqlite3_prepare_v2(GB_DB, insertStatement, -1, &statement, NULL) != SQLITE_OK)
    {
        LOG_CINFO(@"向表格中插入数据失败,可能Sql语句不正确!");
        [GlobalFunc ShowNormalAlert:[NSString stringWithFormat:@"向表格中插入数据失败,可能Sql语句不正确,表名为%@",self.myTableName]];
        return  NO;
    }

    for(int i = 0; i < keysCount;++i)
    {
        NSString *key = [allKeys objectAtIndex:i];

        id value = [tmpDic objectForKey:key];

        //如果是Data类型
        if ([value isKindOfClass:[NSData class]])
        {
            sqlite3_bind_blob(statement,  i+1, [value bytes], [value length], NULL);
        }
        else//是字符串类型
        {
            sqlite3_bind_text(statement, i+1, [value UTF8String], -1, NULL);
        }
    }

    int success = sqlite3_step(statement);
    // 释放资源
    sqlite3_finalize(statement);

    if (success == SQLITE_ERROR)
    {
        LOG_CINFO(@"向表格中插入数据失败,未知原因提前结束!");
        [GlobalFunc ShowNormalAlert:[NSString stringWithFormat:@"向表格中插入数据失败,未知原因提前结束,表名为%@",self.myTableName]];
        return NO;
    }
    LOG_CINFO(@"向表格中插入数据成功!");
    return YES;

}
//更新表字段,key是要更新的字段名称,newValue是更新后要设计的值,where是条件(sql语句中的),condition是满足更新的条件,use是否使用用户名为条件
-(BOOL) UpdateRecordWithKey:(NSString *)key Value:(NSString *)newValue Where:(NSString *)where Condition:(NSString *)condition UseUser:(BOOL)use {
    if(![LocalDataBase OpenDB])
    {
        return NO;
    }
    @try
    {
        NSString *tmpUpdateSql = nil;

        if (use && self.hasUser)
        {
            tmpUpdateSql =  [NSString stringWithFormat:@"UPDATE %@ SET %@ = ? where %@ = ? and userName = ?",self.myTableName,key,where];
        }
        else
        {
            tmpUpdateSql = [NSString stringWithFormat:@"UPDATE %@ SET %@ = ? where %@ = ?",self.myTableName,key,where];//@"UPDATE tb_bulletlist SET has_read = ? where bulletin_code = ? and user_name=?";
        }
        sqlite3_stmt *statement;

        LOG_CINFO(@"========sql 语句 更新表=========");
        LOG_CINFO(tmpUpdateSql);
#if UseASE
        //验证sql语句是否成功
        const char *key = [[GlobalData GetInstance].GB_DBKey UTF8String];
        sqlite3_key(GB_DB, key, strlen(key));
#endif
        if(sqlite3_prepare_v2(GB_DB, [tmpUpdateSql UTF8String], -1, &statement, nil) != SQLITE_OK)
        {
            LOG_CINFO(@"更新数据失败!");
             [GlobalFunc ShowNormalAlert:[NSString stringWithFormat:@"更新数据失败,表名为%@",self.myTableName]];
            return  NO;
        }

        sqlite3_bind_text(statement, 1, [newValue UTF8String], -1, NULL);
        sqlite3_bind_text(statement, 2, [condition UTF8String], -1, NULL);

        if (use && self.hasUser)
        {
            sqlite3_bind_text(statement, 3, [[GlobalData GetInstance].GB_UserName UTF8String], -1, NULL);
        }
        int success = sqlite3_step(statement);

        sqlite3_finalize(statement);
        //[MyDataBase CloseDB];
        if (success != SQLITE_DONE)
        {
            LOG_CINFO(@"更新数据失败,未知原因提前结束!");
             [GlobalFunc ShowNormalAlert:[NSString stringWithFormat:@"更新数据失败,未知原因提前结束,表名为%@",self.myTableName]];
            return NO;
        }

    }
    @catch (NSException *e)
    {
       // LOG_CERR(e);
    }

    return YES;
}
//根据传入的关键字和关键字的值,得到一条记录,如果不存在这条记录,返回为nil,估也可用来判断是否存在某条记录,use是否使用用户名为条件
-(NSMutableDictionary *) GetOneRecordWithKeys:(NSArray *)keys Values:(NSArray *)values UseUser:(BOOL)use {
    if ([keys count] != [values count])
    {
//        [GlobalFunc ShowNormalAlert:[NSString stringWithFormat:@"GetOneRecordWithKeys 数据查询参数keys与values个数不一致,表名为%@",self.myTableName]];

        return nil;
    }

    // 打开数据库
    if (!DB_Opened)
    {
        if(![LocalDataBase OpenDB])
        {
            LOG_CINFO(@"查询数据失败,打开数据库出错!");
            return nil;
        }
    }

    NSMutableString *cSql = [NSMutableString stringWithFormat:@"select * from %@ where ",self.myTableName];
    if (use && self.hasUser)
    {
        [cSql appendFormat:@"userName = ‘%@‘ and ",[GlobalData GetInstance].GB_UserName];
    }

    int keyCount = [keys count];
    for (int i = 0; i < keyCount; ++i)
    {
        if (i == 0)
        {
            [cSql appendFormat:@"%@ = ‘%@‘",[keys objectAtIndex:i],[values objectAtIndex:i]];
        }
        else
        {
            [cSql appendFormat:@" and %@ = ‘%@‘",[keys objectAtIndex:i],[values objectAtIndex:i]];
        }

    }

    NSArray *tmpArr = [self GetDataArrWithSql:cSql];

    if ([tmpArr count] == 0)
    {
        return nil;
    }
    else
    {
        return [tmpArr objectAtIndex:0];
    }
}

  如果在编译时提示:No architectures to compile for (ARCHS=armv6,armv7, VALID_ARCHS=armv7 armv7s则将在Bulid Settings选项下面的Architectures和Valid Architectures里面都改成一样(例如:都填写 armv6 armv7),问题解决。 对于警告 :warning: implicit declaration of function ‘sqlite3_key‘ is invalid in C99 只需要将Bulid Settings选项下的C Language Dialect 改为:C89[-std-c89] 就可以,即使用c89标准

或者去掉项目中的arm64

以上只是贴出代码的一部分,可能看起来有些吃力,稍后会把一个完整的使用数据库的类整理出来。

本文参考:http://blog.csdn.net/kuai0705/article/details/8931996

时间: 2024-10-04 11:22:09

使用SQLCipher加密数据库的相关文章

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

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

iOS 使用FMDB SQLCipher给数据库加密

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

直接利用Android手机破解微信加密数据库EnMicroMsg.db

※首先,简单介绍一下微信加密数据库EnMicroMsg.db的破解方法: 要先批评一下微信,居然用开源的数据库加密方式,这不是一破解一个准吗... 如果你的模拟器或者真机已经获得了root权限,就可以直接将记录聊天记录的数据库文件拷贝出来,数据库文件具体存放位置如下: 在/data/data/中: (题外话:android原生的模拟器root起来很复杂,推荐一款第三方模拟器:genymotion,很方便) ※我们拿到EnMicroMsg.db后,用常用的数据库管理软件打开,发现EnMicroMs

在asp.net中使用加密数据库联接字符串

在我们发布网站时,加密web.config,这样可以有效保证数据库用户和密码安全,其步骤如下: 1.添加密钥 执行:C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\aspnet_regiis -pc "hnlaw" -exp 其中"hnlaw"为密钥名称 2.添加web.config节点 在web.config的<configuration></configuration>之间添加: <con

app逆向——安卓备份文件以及sqliteCipher加密数据库

分析 题目是XCTF app3,下载得到一个ab后缀的文件 .ab后缀名的文件是Android系统的备份文件格式,它分为加密和未加密两种类型 ab文件的前24个字节是类似文件头的东西,如果是加密的,在前24个字节中会有AES-256的标志,如果未加密,则在前24个字节中会有none的标志 载入winHex,发现ANDROID BACKUP 2 1 none,nono代表没有加密 将ab文件转成zip文件 github上有个开源项目Android backup extractor可以将.ab文件转

代码实现sqlite的解密(sqlcipher 微信数据库)

最近在研究解密微信APP的数据库, 1.通过Android手机内置备份功能,可以获取到微信的数据库文件,再通过adb传到电脑上. 2.获取微信EnMicroMsg.db库的密码,方法见网页:http://www.wjdiankong.cn/android%E9%80%86%E5%90%91%E4%B9%8B%E6%97%85-android%E4%B8%AD%E5%A6%82%E4%BD%95%E8%8E%B7%E5%8F%96%E5%9C%A8%E9%9D%9Eroot%E8%AE%BE%E5

找回MD5加密的密码及MD5加密数据库中数据

有时,在开发过程中,如果不小心更改掉了项目管理员帐号的密码而又忘了,存在数据库里的密码又是MD5加密后的,这时候怎么办?最为菜鸟的我,刚开始也很迷茫,不过向前辈们请教了请教,自己也查了查资料,特意整理记录一下,并分享给大家. 前提是你知道这个密码存在在哪个表的哪个字段,只不过是加密了,如果是oracle数据库的话,可以用DBMS_OBFUSCATION_TOOLKIT.MD5 ( input => utl_raw.cast_to_raw('预置密码'))来得到一个MD5加密后的密码, 所以我们可

Java加密数据库

一.背景 数据库配置以明文方式展示如图,会造成安全隐患,如果有黑客入侵会造成密码泄露,信息窃取和破坏等. 二.加密步骤 1.对数据库信息加密: 对数据库中的账号和密码信息进行加密(选择一种算法)然后替换掉原来的明文数据库配置信息. 2.解密: 在Spring读取使用配置文件时进行解密成明文. 三.编码实现 1.加密类实现:(采用DES算法) 1.1DES算法介绍: DES是一种对称算法,即加密和解密使用的是相同的算法. 详细介绍:https://blog.csdn.net/qq_27570955

【Druid】-Druid数据源加密数据库密码配置

1.数据库配置文件添加配置 <property name="filter" value="config"> <property name="connectionProperties" value="config.decrypt=true"/> 2.使用druid.jar 命令生成密码加密串 Java -cp druid.jar com.alibaba.druid.filter.config.Config