SQLITE3添加加密功能SqlCipher的编译和使用
作为懒人的我尽力写的详细了,如有错误之处还望大家指正。
懒人专用链接:(包含了所有环境和源码,以及编译好的源码)
https://download.csdn.net/download/qq_36626674/88357196
本文环境介绍:
Win32 OpenSSL v1.1.1、VS2013、ActiveTcl-8.6
一、环境搭建,安装openssl和tcl;
- openssl下载安装;
Openssl下载网站地址(这里是安装包):
https://slproweb.com/products/Win32OpenSSL.html
需要注意:请下载1.x的版本(原因:试了一下Win32 OpenSSL v3.0.10,编译完了发现sqlite3使用的是老版本接口,在3.0版本中已经废弃了),本文测试时使用版本为Win32 OpenSSL v1.1.1;安装步骤就不说了吧,下一步,下一步就行了。
我当时的下载地址(使用迅雷下载吧,浏览器下载不动!):
https://slproweb.com/download/Win32OpenSSL-1_1_1v.exe
当然你也可以去官网下载源码自己编译,我没编译,所以只有自行百度了。
官网地址:https://www.openssl.org/source/
- Tcl下载;
官网地址:https://platform.activestate.com/
进入官网后,点击左上角“sign up”注册并登录,登录后点击到“project”界面,然后点击安装ActiveTcl-8.6(本文使用版本),如下图所示。
我当时的下载地址(使用迅雷下载吧,浏览器下载不动!):
https://camel-builds.s3.amazonaws.com/ActiveTcl/MSWin32-x64/20230607T174924Z/ActiveTcl-8.6.13.0000-MSWin32-x64-559160e0.msi?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAQ5FYQM547I2EFPRW%2F20230918%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20230918T085152Z&X-Amz-Expires=21600&X-Amz-SignedHeaders=host&X-Amz-Signature=8d3dbee28c33c0e380851005dd89ce4112048582f5fea3f64d3f30e8602195bb
- SqlCipher源码下载、编译
- 下载源码
官网地址(当然了,我反正是进不去哈哈):
https://github.com/sqlcipher/sqlcipher
我是去这个地址下载的(本文使用版本为3.4.2):
sqlcipher: Mirror of https://github.com/sqlcipher/sqlcipher.git - Gitee.com
- 编译源码
下载好的源码解压后,进入源码目录,右键编辑“ Makefile.msc”文件,搜索“DSQLITE_TEMP_STORE”,
修改:
TCC = $(TCC) -DSQLITE_TEMP_STORE=1
RCC = $(RCC) -DSQLITE_TEMP_STORE=1
为:
TCC = $(TCC) -DSQLITE_TEMP_STORE=2
RCC = $(RCC) -DSQLITE_TEMP_STORE=2
然后在这个下面添加:
TCC = $(TCC) -DSQLITE_HAS_CODEC
RCC = $(RCC) -DSQLITE_HAS_CODEC
TCC = $(TCC) -DSQLITE_ENABLE_FTS4
RCC = $(RCC) -DSQLITE_ENABLE_FTS4
TCC = $(TCC) -DSQLITE_ENABLE_JSON1
RCC = $(RCC) -DSQLITE_ENABLE_JSON1
TCC = $(TCC) -DSQLITE_ENABLE_FTS3
RCC = $(RCC) -DSQLITE_ENABLE_FTS3
TCC = $(TCC) -DSQLITE_ENABLE_FTS3_PARENTHESIS
RCC = $(RCC) -DSQLITE_ENABLE_FTS3_PARENTHESIS
TCC = $(TCC) -DSQLITE_ENABLE_FTS5
RCC = $(RCC) -DSQLITE_ENABLE_FTS5
TCC = $(TCC) -DNOCRYPT
RCC = $(RCC) -DNOCRYPT
TCC = $(TCC) -DSQLCIPHER_CRYPTO_OPENSSL
RCC = $(RCC) -DSQLCIPHER_CRYPTO_OPENSSL
然后把openssl头文件和库文件路径包含进来,因为我的openssl安装在“C:\Program Files (x86)\OpenSSL-Win32”,所以我填写的是:
TCC = $(TCC) -IC:\Program Files (x86)\OpenSSL-Win32\include
RCC = $(RCC) -IC:\Program Files (x86)\OpenSSL-Win32\include
LTLIBPATHS=$(LTLIBPATHS)/LIBPATH:C:\Program Files (x86)\OpenSSL-Win32\lib
LTLIBS = $(LTLIBS) libcrypto.lib libssl.lib
打开vs的命令行工具“VS2013 开发人员命令提示”,因为我用的VS2013所以是这个,注意不要使用“VS2013 x86 本机工具命令提示”,后面这个可能编译不过。
切换到“ Makefile.msc”文件所在目录,执行(使用源码的话就执行第一个生成sqlite3.c、sqlite3.h、sqlite3ext.h就行了):
nmake /f Makefile.msc sqlite3.c
主要生成sqlite3.c、sqlite3.h、shell.c、sqlite3ext.h等。
执行:
nmake /f Makefile.msc
主要生成sqlite3.exe、sqlite3.dll、sqlite3.lib、libsqlite3.lib等。
到此生成完成了。
- 测试是否可用
新建控制台程序,将sqlite3.c、sqlite3.h、sqlite3ext.h三个文件拷贝到控制台项目目录,然后添加这三个到项目中,
1、“项目属性->VC++目录->包含目录”添加openssl头文件路径:
C:\Program Files (x86)\OpenSSL-Win32\include
2、“项目属性->VC++目录->库目录”添加openssl库文件路径:
C:\Program Files (x86)\OpenSSL-Win32\lib
3、“项目属性->C/C++->预处理器”添加
_CRT_SECURE_NO_WARNINGS
4、“项目属性->C/C++->预编译头”选择不使用预编译头,因为sqlite.c是c语言的,没法使用预编译。
5、在sqlite3.h添加:
#ifndef SQLITE_HAS_CODEC
#define SQLITE_HAS_CODEC 1 //这条不添加,sqlite3_key等函数找不到
#endif
//包含openssl库
#pragma comment(lib,"libcrypto.lib")
#pragma comment(lib,"libssl.lib")
如下所示是项目文件构成
然后编译项目,好的大坑来了!!!几千个错误,什么未定义呀,什么的,然后根据内容添加了头文件,好了没有未定义了,提示什么winbase.h啥的文件内部有莫名错误,我人都蒙了,最后把sqlite3.c也加上了
#ifndef SQLITE_HAS_CODEC
#define SQLITE_HAS_CODEC 1 //这条不添加,sqlite3_key等函数找不到
#endif
一下就好了,咱就说包含了sqlite3.h的不应该宏定义也会包含嘛!有懂得讲讲嘛,啥原理啊?
- 测试代码
在ConsoleApplication2.cpp添加
#include "sqlite3.h"
#include <Windows.h>
然后main函数添加下面的测试代码:
sqlite3 * sqlite3_db_ = nullptr;
int re;
char dbPath[] = "G:\\VS_Project_Temp\\ConsoleApplication2\\ConsoleApplication2\\test.db";//这个路径自己改一下
DeleteFileA(dbPath);//删除已存在文件
//新数据库无密码测试
#if 1
re = sqlite3_open(dbPath, &sqlite3_db_);
re = sqlite3_exec(sqlite3_db_, "CREATE TABLE IF NOT EXISTS AAA (ID INTEGER,Data INTEGER);", 0, 0, 0);//返回SQLITE_NOTADB 26 表示密码不对,返回SQLITE_OK 0表示操作成功;
re = sqlite3_close(sqlite3_db_);
#endif
//测试数据库是否有密码
#if 1
re = sqlite3_open(dbPath, &sqlite3_db_);
re = sqlite3_key(sqlite3_db_, "1234", 4);//本来没有密码,但是这里输入了密码,所以也算密码错误;
re = sqlite3_exec(sqlite3_db_, "INSERT INTO AAA (ID,Data)VALUES(3,3);", 0, 0, 0);//(应该返回26)返回SQLITE_NOTADB 26 表示密码不对,返回SQLITE_OK 0表示操作成功;
re = sqlite3_close(sqlite3_db_);
#endif
DeleteFileA(dbPath);//删除已存在文件
//新数据库添加密码测试
#if 1
re = sqlite3_open(dbPath, &sqlite3_db_);
re = sqlite3_key(sqlite3_db_,"123",3);//设置密码
re = sqlite3_exec(sqlite3_db_, "CREATE TABLE IF NOT EXISTS AAA (ID INTEGER,Data INTEGER);",0,0,0);//(应该返回0)
re = sqlite3_close(sqlite3_db_);
#endif
//测试数据库是否有密码
#if 1
re = sqlite3_open(dbPath, &sqlite3_db_);
re = sqlite3_key(sqlite3_db_, "123", 3);//正确的密码
re = sqlite3_exec(sqlite3_db_, "INSERT INTO AAA (ID,Data)VALUES(3,3);", 0, 0, 0);//(应该返回0)返回SQLITE_NOTADB 26 表示密码不对,返回SQLITE_OK 0表示操作成功;
re = sqlite3_close(sqlite3_db_);
#endif
//修改密码测试
#if 1
re = sqlite3_open(dbPath, &sqlite3_db_);
re = sqlite3_key(sqlite3_db_, "123", 3);
re = sqlite3_rekey(sqlite3_db_, "1234", 4);
re = sqlite3_close(sqlite3_db_);
#endif
//测试数据库是否修改正确密码
#if 1
re = sqlite3_open(dbPath, &sqlite3_db_);
re = sqlite3_key(sqlite3_db_,"123",3);//错误的密码
re = sqlite3_exec(sqlite3_db_, "INSERT INTO AAA (ID,Data)VALUES(3,3);", 0, 0, 0);//(应该返回26)返回SQLITE_NOTADB 26 表示密码不对,返回SQLITE_OK 0表示操作成功;
re = sqlite3_close(sqlite3_db_);
#endif
//测试数据库是否修改正确密码
#if 1
re = sqlite3_open(dbPath, &sqlite3_db_);
re = sqlite3_key(sqlite3_db_, "1234", 4);//正确的密码
re = sqlite3_exec(sqlite3_db_, "INSERT INTO AAA (ID,Data)VALUES(3,3);", 0, 0, 0);//(应该返回0)返回SQLITE_NOTADB 26 表示密码不对,返回SQLITE_OK 0表示操作成功;
re = sqlite3_close(sqlite3_db_);
#endif
DeleteFileA(dbPath);//删除已存在文件