首页 Qt 带有加密功能的 SQLite Qt 插件(v0.5)

带有加密功能的 SQLite Qt 插件(v0.5)

47 4.9K

QtCipherSqlitePlugin 是一个能够加密 SQLite 数据的 Qt 插件,经过之前几个版本的更新,现在已经有不少使用。

但是,由于之前的版本与 Qt 私有类紧密耦合,导致插件的代码会随着 Qt 的更新出现无法编译的情况。解决方案之一是添加对 Qt 版本的判断,但是终究无法解决后续 Qt 版本的升级所带来的阵痛。于是,这一次大刀阔斧的进行调整,将 Qt 的某些私有类直接添加到插件中,除去 Qt 私有类的依赖。针对以后 Qt 的更新,插件只会选择对性能有影响的部分进行跟进,至于 Qt 内部架构的调整,则不在插件代码更新范围内。

经过这一次的调整,编译插件变得非常简单:只需要使用 QtCreator 打开插件中 sqlitecipher 文件夹下的 sqlitecipher.pro 进行编译即可。编译后,需要将生成的 sqlitecipher.dll 复制到 Qt 的 plugins/sqldrivers 文件夹下。本次更新。豆子使用 Qt 5.5 和 Qt 5.7 进行了测试,如果有其它版本的 Qt 不能正常使用,请及时联系豆子。

当然,本次更新我们还是使用了 SQLITECIPHER 作为插件的名字。如果需要修改这个名字,Qt4 需要修改 smain.cpp 中的 DriverName 定义,Qt5 需要修改 SqliteCipherDriverPlugin.json 中的 SQLITECIPHER 一行。

出去上述调整,更为重要的是,本次更新增加了很多新功能,包括为原来没有密码的 SQLite 数据库添加密码,修改数据库密码以及删除密码。下面我们将着重介绍这些功能的使用。

检查 QtCipherSqlitePlugin 是否成功加载

我们可以使用下面的代码检查 QtCipherSqlitePlugin 是否成功加载:

qDebug() << QSqlDatabase::drivers();

如果输出中有 SQLITECIPHER 的名字,那么恭喜你,插件没有问题!

为没有加密的数据库增加密码

Qt 默认提供的 SQLite 插件是没有加密功能的。新版本的 QtCipherSqlitePlugin 支持为原本没有加密的数据库增加密码,使用方法如下:

QSqlDatabase dbconn = QSqlDatabase::addDatabase("SQLITECIPHER");
dbconn.setDatabaseName("test.db");
dbconn.setPassword("test");
dbconn.setConnectOptions("QSQLITE_CREATE_KEY");

if (!dbconn.open()) {
    qDebug() << "Can not open connection: " << dbconn.lastError().driverText();
    exit(CONNECTION_FAILED);
}

上面的代码,我们使用 test.db 数据库,将密码设置为 test,同时指定连接选项为QSQLITE_CREATE_KEY。此时,调用open()函数之后,QtCipherSqlitePlugin 将使用改密码为这个数据库进行加密。

删除数据库密码

QtCipherSqlitePlugin 可以删除数据库密码,此时需要提供原密码,并使用连接选项QSQLITE_REMOVE_KEY,如下:

QSqlDatabase dbconn = QSqlDatabase::addDatabase("SQLITECIPHER");
dbconn.setDatabaseName("test.db");
dbconn.setPassword("test");
dbconn.setConnectOptions("QSQLITE_REMOVE_KEY");

if (!dbconn.open()) {
    qDebug() << "Can not open connection: " << dbconn.lastError().driverText();
    exit(CONNECTION_FAILED);
}

更新数据库密码

QtCipherSqlitePlugin 可以更新数据库原有密码,需要设置原密码,并且使用连接选项QSQLITE_UPDATE_KEY设置新密码,具体代码如下:

QSqlDatabase dbconn = QSqlDatabase::addDatabase("SQLITECIPHER");
dbconn.setDatabaseName("test.db");
dbconn.setPassword("test");
dbconn.setConnectOptions("QSQLITE_UPDATE_KEY=newtest");

if (!dbconn.open()) {
    qDebug() << "Can not open connection: " << dbconn.lastError().driverText();
    exit(CONNECTION_FAILED);
}

如果原密码不正确,QtCipherSqlitePlugin 会直接返回错误。

如果新密码设置为空,例如QSQLITE_UPDATE_KEY=,则作用等同于删除密码。

如果需要,可以到 github 上面获取 git 库,checkout 代码的 0.5 标签即可。

47 评论

喻纹东 2016年5月27日 - 10:36

我用的是Qt5.6为什么我没有找到sqlitecipher 文件夹?

回复
喻纹东 2016年5月27日 - 10:39

你能不能出一个Qt给sqlite数据库加密的详细教程啊? 不要一句话概括安装步骤,新手真的很难懂的

回复
豆子 2016年5月27日 - 14:48

插件没有安装步骤,只需要把编译出来的 dll 复制到 Qt 安装目录下的 plugins/sqldrivers 文件夹就可以了。使用的话和普通 sqlite 使用一样,只不过需要提供密码。

回复
喻纹东 2016年5月27日 - 14:58

经过这一次的调整,编译插件变得非常简单:只需要使用 QtCreator 打开插件中 sqlitecipher 文件夹下的 sqlitecipher.pro 进行编译即可。编译后,需要将生成的 sqlitecipher.dll 复制到 Qt 的 plugins/sqldrivers 文件夹下。本次更新。豆子使用 Qt 5.5 和 Qt 5.7 进行了测试,如果有其它版本的 Qt 不能正常使用,请及时联系豆子。
------------------------------------------------------------------------------------
我安装的Qt5.6中没有sqlitecipher 文件夹啊

回复
喻纹东 2016年5月27日 - 15:02

你能把这个sqlitecipher 这个文件夹的具体路径发过来吗?

回复
豆子 2016年6月3日 - 12:39

在 github clone 下来的项目中就有这个目录的

回复
QT菜鸟 2016年6月9日 - 09:24

博主,能不能写一个简单的使用插件对数据库进行加密和打开数据库的例子,谢谢,我现在按你教程能创建加密数据库了,但是二次连接时总是无法打开数据库,应该是open时有问题(使用db.open(db_name,db_passwd)除了第一次返回true,之后都是false),还想请你能帮忙给个建议。谢谢

回复
喻纹东 2016年5月27日 - 10:40

我最常用的是Qt4.7.2版本, 最好能出一个4.7.2版本的给sqlite加密的教程,谢谢!

回复
豆子 2016年5月27日 - 14:46

Qt 4.7.2 没有测试,可能这套代码不能通过编译,需要自己按照 Qt 提供的 sqlite 插件的代码修改下。

回复
QT菜鸟 2016年6月8日 - 01:24

博主你好,我用你提供的为QT 默认的sqlite原本没有加密的数据库增加密码的代码进行测试只能在第一次编译时数据库能打得开,第二次编译(未修改任何代码)后数据库就打不开了,提示“”QSqlQuery::exec: database not open"",这是为什么呢?是因为需要用到那个函数才能重新开启吗?谢谢

QSqlDatabase dbconn = QSqlDatabase::addDatabase("SQLITECIPHER");
dbconn.setDatabaseName("test.db");
dbconn.setPassword("test");
dbconn.setConnectOptions("QSQLITE_CREATE_KEY");

if (!dbconn.open()) {
qDebug() << "Can not open connection: " << dbconn.lastError().driverText();
//exit(CONNECTION_FAILED);
}

回复
豆子 2016年6月14日 - 21:56

如果是相同的代码,因为你用了 QSQLITE_CREATE_KEY,这个参数是创建密码。第一次运行时,因为原数据库没有密码,所以创建了密码;第二次运行时,由于原数据库已经有密码了,就不能重复创建了(否则你就可以随意修改任意 sqlite 数据库密码了,这是不安全的),所以无法打开。

回复
vintx 2016年6月25日 - 07:04

那么有没有相应的函数判断,该数据库是否加过密的?

回复
豆子 2016年6月25日 - 17:44

目前 sqlite 没有提供类似的函数,所以只能试错了

回复
顾育豪 2016年7月26日 - 19:43

博主你好,我用了你提供的插件,数据库加解密都没有问题。但是在读写数据库的过程中,即通过setPassword的方法后打开数据库,发现数据库的读写速度很慢。请问这是什么原因?

回复
豆子 2016年7月29日 - 11:25

这个我不大清楚,你的数据量是多少?写入频率是多少?最好能提供一下相应的测试代码

回复
青山 2016年8月23日 - 15:43

"编译后,需要将生成的 sqlitecipher.dll 复制到 Qt 的 plugins/sqldrivers 文件夹下"
-------------------
是下面这个文件吗? 文件名差了一个字母
sqlitecipherd.dll

回复
青山 2016年8月23日 - 16:43

在豆子老师的另外一篇文章中找到了答案,顺便贴上来。
https://www.devbean.net/2013/06/qt-study-road-2-database/ 评论
带有 d 的是 debug 版本,大概因为你的 pro 文件中没有添加 DEBUG 之类的宏。至于这个宏这么写,就要去看看文档了。没有 debug 版本其实也没有关系,只是不能调试。

回复
大鹏 2016年8月26日 - 12:00

豆子,你好,我这边存在一个问题就是当密码设置为空时,后面就再也不能更新密码了?请问是否存在这个bug?

回复
豆子 2016年8月26日 - 17:46

当密码被设置为空时,相当于删除密码,之后应该重新添加密码而不是更新,试试重新添加可不可以

回复
stlcours 2016年8月27日 - 05:10

请问豆子,你这个插件可以静态编译吗?因为我的整个项目是静态编译的,单独设置一个多级目录实在是怪怪的。感谢回答!

回复
豆子 2016年8月27日 - 08:42

这个插件就是从官方的插件修改而来的,应该是支持的。按照文档的要求需要在编译 Qt 静态库时添加-qt-sql-<driver>参数,你可以看看文档 SQL Database Drivers

回复
ZCShou 2016年10月25日 - 22:12

就是不知道该怎么进行静态的编译啊,豆子哥哥能不能教一下怎么静态编译啊!!

回复
xh 2017年2月21日 - 16:30

在树莓派上用Qt5.3.2 编译出来的 so文件。
qDebug() << QSqlDatabase::drivers(); 可以打印出 SQLITECIPHER。
但是在 db.open() 是提示 段错误

回复
豆子 2017年2月21日 - 21:29

你的编译器是什么版本的呢?

回复
2017年3月9日 - 10:21

4.8.7编译不过

回复
2017年3月9日 - 10:25

我想编译成vs2010和Qt公用的加密数据库,但是用qt加密后vs不能用,反过来也不能用,弄了好几天,请问豆子我在编译时应该注意什么?谢谢了~

回复
2017年3月9日 - 16:20

抱歉豆子,是我的疏忽,编译的时候CODEC_TYPE=CODEC_TYPEAES256,Qt写成256,vs里面的写的是128,导致的错误!

回复
零口酥 2018年3月19日 - 15:13

qt 5.10.1 驱动能用 但是无法添加密码

回复
零口酥 2018年3月19日 - 15:24

不好意思,经过检查是关键字打错了

回复
zhai kang 2018年6月12日 - 15:47

你好 我这运行qDebug() << QSqlDatabase::drivers();显示SQLITECIPHER,但是整个程序运行显示SQLITECIPHER无法加载,是因为我生成.dll的时候出错了的原因吗

回复
豆子 2018年6月14日 - 13:28

可能是编译的问题,也可能是版本问题,这个要看具体细节的了

回复
yoer 2018年7月13日 - 17:55

1. qt版本为 5.7
2. qDebug() << QSqlDatabase::drivers(); 输出了SQLITECIPHER;
3. 已经 setConnectOptions("QSQLITE_CREATE_KEY");

但是密码却没有加上去

知道什么问题吗?

回复
yoer 2018年7月14日 - 21:35

QSqlDatabase::addDatabase("SQLITECIPHER");
连接数据库时候需要指定插件的driver name

回复
hjz 2018年8月9日 - 09:21

QSqlField fld(q.value(1).toString(), qGetColumnType(typeName), tableName);

回复
yi 2018年9月4日 - 16:03

qt 5.6 SQLITECIPHER驱动没有加载成功啊,怎么回事

回复
豆子 2018年9月8日 - 17:30

这个不是很清楚,有没有将编译出来的 dll 放到 plugins 文件夹中?

回复
WQD 2019年5月24日 - 17:09

大佬您好,我用QT5.12添加您的插件,实现了数据库加密、改密和删除密码。我想咨询下,在实际的数据库操作过程中,比如对表的增删查改操作时候,应该怎么做?是需要先要将密码解除吗?

回复
豆子 2019年5月24日 - 19:53

按照一般的做法,应该是在打开数据库的时候要求用户提供密码,密码通过之后保持数据库的打开,然后进行数据库的各种操作,之后在关闭程序时关闭数据库。

回复
wuxianliang 2019年6月14日 - 16:40

豆子大神你好,我在QT5.12.2window版本使用该插件正常,打算尝试在android上使用,结果编译不过。报错的内容之一是shathree.c文件下“未定义的u64”。令我奇怪的是,当我打开该文件编译window版本的插件时,同样报错但仍然可以生成插件,请问大神知道是什么原因吗?

回复
zheng 2019年9月6日 - 09:21

豆子老师你好,我将你GIT上的代码下载下来,并编译了.pro文件,出现200多个警告,但是最后还是生成了sqlitecipher.dll和sqlitecipherd.dll,我将sqlitecipher.dll放到plugin的sqldriver下,再打印的时候没有显示插件的名字。我的Qt版本是5.9.6.很着急,等回复,谢谢

回复
豆子 2019年9月19日 - 15:30

警告大部分是 sqlite 的,应该不是这个问题。最好把编译出来的所有文件都放过去试试看。

回复
pdz 2020年8月29日 - 15:51

我将sqlitecipher.dll放到plugin的sqldriver下,再打印的时候没有显示插件的名字,但是在你的testApp工程中可以,请问怎么办?

回复
豆子 2020年8月29日 - 20:24

注意下编译版本之类,debug 或者 release?

回复
Josn Josn 2020年10月29日 - 14:28

你好,在Qt5.14.1版本下编译出现以下情况
11:57:20: Starting F:\work\QtCipherSqlitePlugin-master\sqlitecipher\sqlitecipher.cpp ...
11:57:20: 启动程序失败,路径或者权限错误?
11:57:20: F:\work\QtCipherSqlitePlugin-master\sqlitecipher\sqlitecipher.cpp exited with code -1
11:57:20: The process failed to start. Either the invoked program "F:\work\QtCipherSqlitePlugin-master\sqlitecipher\sqlitecipher.cpp" is missing, or you may have insufficient permissions to invoke the program.

回复
Bing 2021年3月25日 - 16:28

请问豆子大佬,加密后的数据库文件如何还原回未加密的状态 或者 使用 sqlite expert、 DB Browser for SQLite等软件打开呢?

回复
Bing 2021年3月25日 - 16:57

找到原因了,因为test代码中有这一句,并没有保存数据,
query.exec("drop table mapping");
其实只要密码设空即可打开。

回复
豆子 2021年4月6日 - 09:14

设置密码为空被定义为删除密码,所以是能打开的。

回复

回复 ZCShou 取消回复

关于我

devbean

devbean

豆子,生于山东,定居南京。毕业于山东大学软件工程专业。软件工程师,主要关注于 Qt、Angular 等界面技术。

主题 Salodad 由 PenciDesign 提供 | 静态文件存储由又拍云存储提供 | 苏ICP备13027999号-2