簡介#
SQLite,是一款輕型的數據庫,是遵守ACID的關系型數據庫管理系統,它包含在一個相對小的C庫中。它是D.RichardHipp建立的公有領域項目。它的設計目標是嵌入式的,而且目前已經在很多嵌入式產品中使用了它,它占用資源非常的低,在嵌入式設備中,可能只需要幾百K的內存就夠了。它能夠支持Windows/Linux/Unix等等主流的操作系統,同時能夠跟很多程序語言相結合,比如 Tcl、C#、PHP、Java等,還有ODBC接口,同樣比起Mysql、PostgreSQL這兩款開源的世界著名數據庫管理系統來講,它的處理速度比他們都快。SQLite第一個Alpha版本誕生於2000年5月。 至2015年已經有15個年頭,SQLite也迎來了一個版本 SQLite 3已經發布。
但是sqlite本身不對數據庫文件進行加密,存儲的文件可以明文查看,存做這一定的安全隱患。還好作者提供了幾個接口可以讓sqlite支持數據加密。比較有名的就是SQLCipher。
SQLCipher是一個開源庫,提供透明,安全的256位AES加密的SQLite數據庫文件。
SQLCipher的社區版的源代碼是一個BSD-風格的開源許可下發布,但是官方提供的二進制庫需要購買。
引用官方的一張圖,加密前和加密后的對比效果:
下載信息#
sqlite官方網站
SQLite3.13.0源碼
SQLite3.def文件
SQLCipher-3.1.0源碼
OpenSSL-1.0.1g
ActivePerl
步驟#
安裝Perl##
從官網上下載ActivePerl並進行安裝,我這里安裝的是x64版本
編譯openssl##
- 解壓Openssl的源碼,例如解壓縮到openssl-1.0.1g目錄下
- 在openssl目錄下新建build.bat批處理文件,內容如下
@echo off
@set OPTS=no-asm
@perl Configure VC-WIN32
@perl util\mkfiles.pl >MINFO
@perl util\mk1mf.pl %OPTS% debug VC-WIN32 >d32.mak
@perl util\mk1mf.pl %OPTS% VC-WIN32 >32.mak
@perl util\mkdef.pl 32 libeay > ms\libeay32.def
@perl util\mkdef.pl 32 ssleay > ms\ssleay32.def
@nmake -f d32.mak
@nmake -f 32.mak
- 打開需要編譯的VC命令行工具進入openssl目錄並運行build.bat開始編譯,編譯成功以后生成libeay32.lib、ssleay32.lib文件。我這里使用的是VS2015的命令行工具Developer Command Prompt for VS2015
編譯sqlite3##
- 用VS2015新建一個空的win32 dll項目,例如我這里取名為sqlite3
- 將下載到的sqlite壓縮包文件解壓縮到sqlite3項目文件夾內
- 修改sqlite3.def文件,在文件的最后添加以下代碼
sqlite3_key
sqlite3_rekey
- 修改sqlite3.c文件,在文件的最開始部分添加以下代碼
/*** START REQUIRED BY SQLCIPHER ***/
#define SQLITE_HAS_CODEC 1
#define SQLITE_ENABLE_RTREE 1
#define SQLITE_ENABLE_COLUMN_METADATA 1
#define SQLITE_TEMP_STORE 2
/*** END REQUIRED BY SQLCIPHER ***/
- 繼續修改sqlite3.c文件,在文件的最后添加以下代碼
#include <sqlcipher/crypto.c> /*** SQLCIPHER ADDITION ***/
#include <sqlcipher/crypto_cc.c> /*** SQLCIPHER ADDITION ***/
#include <sqlcipher/crypto_impl.c> /*** SQLCIPHER ADDITION ***/
#include <sqlcipher/crypto_openssl.c> /*** SQLCIPHER ADDITION ***/
#include <sqlcipher/pager.c> /*** SQLCIPHER ADDITION ***/
- 還是修改sqlite3.c文件,注釋掉不必要的頭文件,新版本好像是注釋掉的
/* #include "sqliteInt.h" */
/* #include "btreeInt.h" */
存放openssl的庫##
將編譯成功的openssl庫文件x86lib,內含libeay32.lib、ssleay32.lib,全部放到sqlite3目錄下,設置工程目錄鏈接這兩個靜態庫
編譯sqlite3##
編譯成功,即可生成對應的sqlite3.dll
使用示例代碼#
不多說了,直接上代碼
#define SQLITE_HAS_CODEC
#include "sqlite3.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef _DEBUG
#pragma comment(lib, "../Debug/sqlite3.lib")
#else
#pragma comment(lib, "../Release/sqlite3.lib")
#endif
#define ERROR(X) /*{printf("[ERROR] iteration %d: ", i); printf X;fflush(stdout);}*/
static int callback(void *NotUsed, int argc, char **argv, char **azColName){
int i;
for(i=0; i<argc; i++){
printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
}
printf("\n");
return 0;
}
int main(int argc, char **argv) {
sqlite3 *db;
const char *file= "sqlcipher.db";
const char *key1 = "test123";
char* key = (char *) key1;
if (sqlite3_open(file, &db) == SQLITE_OK) {
int rc;
if(db == NULL) {
ERROR(("sqlite3_open reported OK, but db is null, retrying open %s\n", sqlite3_errmsg(db)))
}
if(sqlite3_key(db, key, strlen(key)) != SQLITE_OK) {
ERROR(("error setting key %s\n", sqlite3_errmsg(db)))
exit(1);
}
//SQLlite 操作代碼...
char* sqlstatement0 = "create table if not exists test(int id,varchar name);";
char* sqlstatement1 = "insert into test values(1,'hello');";
char* sqlstatement2 = "select * from test;";
char* zErrMsg = NULL;
rc = sqlite3_exec(db, sqlstatement0, callback, 0, &zErrMsg);
if( rc!=SQLITE_OK ){
// printf("%s\n",argv[2]);
fprintf(stderr, "SQL error: %s\n", zErrMsg);
sqlite3_free(zErrMsg);
zErrMsg = NULL;
}
rc = sqlite3_exec(db, sqlstatement1, callback, 0, &zErrMsg);
if( rc!=SQLITE_OK ){
// printf("%s\n",argv[2]);
fprintf(stderr, "SQL error: %s\n", zErrMsg);
sqlite3_free(zErrMsg);
zErrMsg = NULL;
}
rc = sqlite3_exec(db, sqlstatement2, callback, 0, &zErrMsg);
if( rc!=SQLITE_OK ){
// printf("%s\n",argv[2]);
fprintf(stderr, "SQL error: %s\n", zErrMsg);
sqlite3_free(zErrMsg);
zErrMsg = NULL;
}
sqlite3_close(db);
system("pause");
}
}