由于最近项目需要考虑本地数据的安全性,避免谁都可以找到数据库文件然后右键-记事本打开。。。
所以研究了下SQLite3本地数据库加密的方法,百度之,有两种,一是加密数据后存入数据库,二是整个加密数据库;
如果选一改地方实在太多,所以一直找直接加密sqlite数据库的方法;
然后各种搜索,整合后可行的方式是使用sqlite预留的加密接口,具体编码是用wxsqlite的加密模块;
主要参考[豆子]大神的博客:带有加密功能的 SQLite Qt 插件
按照豆子大神的方法,可以成功创建加密数据库以及以密码打开自己创建的数据库等相关操作,但我的项目特殊需要在qt里面打开MFC那边创建的加密数据库,总是提示密码错误。。。后来发现豆子这边是直接使用wxsqlite的源码codecext.c中 sqlite3_key 函数加密的,而我那边MFCCppSQlite3 中是使用的sqlite3.lib库文件来实现加密的,走的是sqlite3.h中的sqlite3_key 函数。
首先下载豆子大神GitHub打包好的文件,将解压后的sqlitecipher文件夹拷贝到C:\Qt\4.8.6\src\plugins\sqldrivers路径下
然后在VS2008下的QT菜单下打开 sqlitecipher 文件夹内的 sqlitecipher.pro 会生成一个 sqlitecipherd VS工程,在工程属性--Linker--Input--Additional Dependencies 下增加sqlite3.lib(sqlite3.lib的编译获得参考下面CppSQLite3加密方法)
再把sqlite3secure.c从工程中移除,编译。将产生的sqlitecipher.dll 和sqlitecipher.lib 拷贝到C:\Qt\4.8.6\plugins\sqldrivers路径下,至此已经将SQLITECIPHER插件导入到QT下了
使用时,添加一行:QStringList listDriver = QSqlDatabase::drivers(); 从listDriver 中找到SQLITECIPHER的话就表示导入成功了,在代码中使用:
QSqlDatabase dbconn = QSqlDatabase::addDatabase("SQLITECIPHER");
dbconn.setDatabaseName("test.db");
dbconn.setPassword("test");
if (!dbconn.open()) {
qDebug() << "Can not open connection: " << dbconn.lastError().driverText();
exit(CONNECTION_FAILED);
}
enum KEY_OP {
OPEN_WITH_KEY = 0,
CREATE_KEY,
UPDATE_KEY,
REMOVE_KEY
};
如果数据库已加密必须先执行此函数并输入正确密钥才能进行操作,如果数据库没有加密,执行此函数后进行数据库操作反而会出现“此数据库已加密或不是一个数据库文件”的错误。经测试,只能在新建数据库时设置密码!
改密码的话先open,再使用旧密码sqlite3_key ,最后在用新密码sqlite3_rekey
清空密码和改密码一样,只是最后把新密码置为空。
<1>下载最新版wxsqlite(我的版本3-3.3.1)
<2>下载最新版sqlite源码sqlite-amalgamation-xxxxxxx(我的版本3130000)
<3>将sqlite-amalgamation-3130000中的全部文件:shell.c,sqlite3.c,sqlite3.h,sqlite3ext.h
拷贝到\wxsqlite3-3.3.1\sqlite3\secure\src,覆盖原有的。
<4>在VS里新建一个空工程,把\wxsqlite3-3.3.1\sqlite3\secure\src下的所有文件放入工程内,然后把sqlite3secure.c
文件加入到工程
<5>在配置属性中设置配置类型为静态库(.Lib),输出库文件名改为sqlite3.lib,添加预处理:
SQLITE_HAS_CODEC=1
CODEC_TYPE=CODEC_TYPE_AES128
SQLITE_CORE
THREADSAFE
SQLITE_SECURE_DELETE
SQLITE_SOUNDEX
SQLITE_ENABLE_COLUMN_METADATA
<6>编译产生sqlite3.lib即可
<1>在CppSQLite3.h的CppSQLite3DB类中添加如下函数声明:
class CppSQLite3DB
{
public:
CppSQLite3DB();
virtual ~CppSQLite3DB();
void open(const char* szFile);
void open(const char* szFile, const char* szPass);
void rekey(const char* szPass);
void close();
//...
}
//原打开函数
void CppSQLite3DB::open(const char* szFile)
{
int nRet = sqlite3_open(szFile, &mpDB);
if (nRet != SQLITE_OK)
{
const char* szError = sqlite3_errmsg(mpDB);
throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);
}
setBusyTimeout(mnBusyTimeoutMs);
}
//以密码打开或者首次打开创建密码
void CppSQLite3DB::open(const char* szFile,const char* szPass)
{
int nRet = sqlite3_open(szFile, &mpDB);
if (nRet != SQLITE_OK)
{
const char* szError = sqlite3_errmsg(mpDB);
throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);
}
if(szPass != NULL)
{
int nRet = sqlite3_key(mpDB, szPass, strlen(szPass));
if (nRet != SQLITE_OK)
{
const char* szError = sqlite3_errmsg(mpDB);
throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);
}
}
setBusyTimeout(mnBusyTimeoutMs);
}
//修改密码或清空密码
void CppSQLite3DB::rekey(const char* szPass)
{
if(szPass != NULL)
{
int nRet = sqlite3_rekey(mpDB, szPass, strlen(szPass));
if (nRet != SQLITE_OK)
{
const char* szError = sqlite3_errmsg(mpDB);
throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);
}
}
setBusyTimeout(mnBusyTimeoutMs);
}
打开数据库可以用:
db.open("数据库路径+名称"); //不带加密方式打开数据库
db.open("数据库路径+名称","密码"); //带加密的方式打开
修改密码可以用:
db.rekey("密码"); //修改密码
由于使用CppSQlite的MFC工程和QT插件使用的是同一个加密支持库函数sqlite3.lib,所以两者生成的加密数据库可以互相打开以及相关操作