Skip to content

Qt插件——使用 QtCipherSqlitePlugin 对数据库进行加密 #127

@holdyounger

Description

@holdyounger

Qt插件——使用 QtCipherSqlitePlugin 对数据库进行加密

开源库介绍

devbean/QtCipherSqlitePlugin: A Qt plugin for cipher SQLite. (github.com)

该加密库是基于 SQLite 和 wxSQLite3 源代码开发的的一个加密 SQLite 的Qt插件。总结就是,可以使用该插件对 SQLite 的数据库进行加密。

开始

  1. 在开始之前,可以去仓库的 wiki 界面找到相应的开始教程,以下操作参考 wiki 。

> 1. 拉取该库到本地后,打开 QtCipherSqlitePlugin.pro,就能看到如下图所示的工程结构。
>
> image-20220508222820701
>
> 1. demo 目录是一个如何使用该加密插件的工程,涉及数据库的加密、打开、创建等
> 2. sqlitecipher是我们编译 dll 的工程文件
> 3. 为 Qt 的插件测试工程,里边有关于该加密库的详细使用方式介绍。
>
> 2. 不论是使用上述测试工程中的哪个,我们第一步都需要编译插件的动态库出来使用。
>
> 1. 单独sqlitecipher.pro
> 2. 为 sqlitecipher.pro 调整 Qt kits ,笔者的环境为 MSVC 2015 32 bit, Release模式
> 3. 右击项目文件,点击部署即可
> 4. 到工程所在的文件夹,就能看到 build-sqlitecipher-Desktop_Qt_5_9_9_MSVC2015_32bit-Release 的文件夹,在 .\plugins\sqldrivers下就能看到生成的动态库文件,动态库 sqlitecipher.dll
> 5. 拷贝该文件到你的 Qt 目录下 kits 对应的文件夹当中。如笔者的为 $Qt安装目录$\5.9.9\msvc2015\plugins\sqldrivers

使用

到这一步,我们就需要查看一下动态库是否可用了。使用 Qt#include <QSqlDatabase>中的方法即可:

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

执行上述代码,如果加载成功的话,我们会在 qDebug() 的输出中看到相应的数据库名。

("QSQLITE", "QMYSQL", "QMYSQL3", "QODBC", "QODBC3", "QPSQL", "QPSQL7", "SQLITECIPHER")

以上代码,在 demo 所在工程中都能找到对应的代码,不用读者编写。

> 另外,使用 SQLITECIPHER 数据库也可以打开普通未加密的 QSQLITE 创建的数据库。

加密

加密数据库的使用也简单,区别于普通数据库的方式是需要设置连接属性。以该开源库为例,其主要通过三个连接属性去决定是否设置密码。主要涉及到的关键字为以下三个:

  • Added by QtCipherSqlitePlugin
    • QSQLITE_CREATE_KEY
    • QSQLITE_UPDATE_KEY
    • QSQLITE_REMOVE_KEY

还有其他几个继承自 SqlitePlugin 的关键字,用法与 SqlitePlugin 打开数据库设置一致。

  • Provided by Qt SqlitePlugin
    • QSQLITE_BUSY_TIMEOUT
    • QSQLITE_OPEN_READONLY
    • QSQLITE_OPEN_URI
    • QSQLITE_ENABLE_SHARED_CACHE

以下代码演示三种关键字的用法。

创建数据库密码 QSQLITE_CREATE_KEY

如果输出中有 SQLITECIPHER 的名字,那么恭喜你,插件没有问题!
为没有加密的数据库增加密码
Qt 默认提供的 SQLite 插件是没有加密功能的。新版本的 QtCipherSqlitePlugin 支持为原本没有加密的数据库增加密码,使用方法如下:
C++

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 将使用改密码为这个数据库进行加密。

删除数据库密码 QSQLITE_REMOVE_KEY

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);
}

更新数据库密码 QSQLITE_UPDATE_KEY

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= ,则作用等同于删除密码。同样的,设置 setConnectOptions("") 也相当于清除设置的属性。

补充

以下代码是我个人想写一个通用的设置属性的接口,后来思考一番不太现实以示众多读者,不要重蹈覆辙。

bool setDBConfig(QSqlDatabase* dbconn, QMap<ENUM_SQLKEY, QString> qMapCfg)
{
	for (auto it : qMapCfg.toStdMap())
	{
		if (it.first <= QSQLITE_REMOVE_KEY)
		{
			dbconn->setPassword(it.second);
			dbconn->setConnectOptions(GETOBJNAME(it.first));
		}
		else if (it.first == QSQLITE_UPDATE_KEY)
		{
			dbconn->setPassword(it.second);
			dbconn->setConnectOptions(QString("%1=%2").arg().arg());
		}
		
	}
}

blog link Qt插件——使用 QtCipherSqlitePlugin 对数据库进行加密

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions