QT 下 SQlite3 資料庫加密及 CppSQLite3 操作資料庫加密
由於最近專案需要考慮本地資料的安全性,避免誰都可以找到資料庫檔案然後右鍵-記事本開啟。。。
所以研究了下SQLite3本地資料庫加密的方法,百度之,有兩種,一是加密資料後存入資料庫,二是整個加密資料庫;
如果選一改地方實在太多,所以一直找直接加密sqlite資料庫的方法;
然後各種搜尋,整合後可行的方式是使用sqlite預留的加密介面,具體編碼是用wxsqlite的加密模組;
1.QT下SQlite3 加密(qt4.8.6)
按照豆子大神的方法,可以成功建立加密資料庫以及以密碼開啟自己建立的資料庫等相關操作,但我的專案特殊需要在qt裡面開啟MFC那邊建立的加密資料庫,總是提示密碼錯誤。。。後來發現豆子這邊是直接使用wxsqlite的原始碼codecext.c中 sqlite3_key 函式加密的,而我那邊MFCCppSQlite3
首先下載豆子大神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); }
由於是使用 lib ,所以在程式碼中沒有用到豆子大神的
enum KEY_OP {
OPEN_WITH_KEY = 0,
CREATE_KEY,
UPDATE_KEY,
REMOVE_KEY
};
如果資料庫已加密必須先執行此函式並輸入正確金鑰才能進行操作,如果資料庫沒有加密,執行此函式後進行資料庫操作反而會出現“此資料庫已加密或不是一個數據庫檔案”的錯誤。經測試,只能在新建資料庫時設定密碼!
改密碼的話先open,再使用舊密碼sqlite3_key ,最後在用新密碼sqlite3_rekey
清空密碼和改密碼一樣,只是最後把新密碼置為空。
2.CppSQLite3 資料庫加密,主要參考這裡
【第一步】先獲得加密的sqlite3.lib
<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即可
【第二步】為CppSQLite3新增加密介面
<1>在CppSQLite3.h的CppSQLite3DB類中新增如下函式宣告:
class CppSQLite3DB
{
public:
CppSQLite3DB();
virtual ~CppSQLite3DB();
void open(const char* szFile);
<span style="color:#ff0000;">void open(const char* szFile, const char* szPass);</span>
<span style="color:#ff0000;">void rekey(const char* szPass);</span>
void close();
//...
}
<2>在CppSQLite3.cpp中新增上述函式的實現:
//原開啟函式
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);
}
<3>.把使用CppSQLite的工程目錄下的 sqlite3.h 和 sqlite3.lib 換成第一步獲得的加密版的sqlite3.lib和sqlite3.h ,另外同樣要加入預定義 SQLITE_HAS_CODEC=1
開啟資料庫可以用:
db.open("資料庫路徑+名稱"); //不帶加密方式開啟資料庫
db.open("資料庫路徑+名稱","密碼"); //帶加密的方式開啟
修改密碼可以用:
db.rekey("密碼"); //修改密碼
由於使用CppSQlite的MFC工程和QT外掛使用的是同一個加密支援庫函式sqlite3.lib,所以兩者生成的加密資料庫可以互相開啟以及相關操作