QtCipherSqlitePlugin插件使用(1)
写在前面
注意: 各版本的不同,关注兼容性;
- 本文演示版本: 1.3 ;
- 正考虑为其增加 cmake 脚本, 默认使用 qmake 编译源码;
- 本文演示Qt版本: 5.14
- 本文演示操作系统: windows11
目标
- 本文将介绍 QtCipherSqlitePlugin 的以下三方面
- 构建
- 验证
- 使用
概述
- sqlite默认不支持文件加密, 商业版支持加密。
- QtCipherSqlitePlugin 是一个开源加密sqlite数据库的项目, 可以在 QtCipherSqlitePlugin github 和 QtCipherSqlitePlugin gitee获取源码。
- 基于某些原因,本文不提供源码, 有需要,请联系文末 二维码 或 私信。
以下使用,假定已下载好官方源码
源码下载:
git clone https://github.com/devbean/QtCipherSqlitePlugin.git
构建
官方源码中提供了范例和插件源码。 下文演示为: 构建含演示范例。
步骤
- 1 来到源码解压目录
cd QtCipherSqlitePlugin
- 2 使用QtCreator打开 QtCipherSqlitePlugin目录下的QtCipherSqlitePlugin.pro工程文件
- 3 发现官方默认使用的时VS2015构建套件, 而本机只有Qt5.14, 故而将构建套件改为本机的Qt套件,方法(基于步骤2):
- 5 至于输出输出目录,可自行选择,这里,演示使用默认的shadow build
需要注意: 'sqlitecipher/sqlite3/sqlite3.pri' 中 的CODEC_TYPE保存了加密算法,默认值为:CODEC_TYPE_CHACHA20, 可以改为:
CODEC_TYPE_AES128
、CODEC_TYPE_AES256
、CODEC_TYPE_CHACHA20
和CODEC_TYPE_SQLCIPHER
, 请根据需要修改
- 6 回到 QtCreator中,点击 或者 快捷键: ctrl+b 执行项目构建。构建结束后, 找到输出目录,可见生成成功的动态库、lib和cmake 等一系列文件
- lib 和 动态库位于 path/plugins/sqldrivers
- 插件对应的cmake文件位于: path/lib/cmake/Qt5Sql
下面需要自行对应qt安装目录。
- 7 将生成的动态库(debug和release)拷贝到Qt的安装目录: path/plugins/sqldrivers。 我这里的路径为:
xx/5.14.2/msvc2015_64/plugins/sqldrivers
- 8 将输出目录中,cmake文件拷贝到Qt的安装目录/path/lib/cmake/Qt5Sql,我的路径为:
xxx/5.14.2/msvc2015_64/lib/cmake/Qt5Sql
- 9 将输出的lib文件拷贝到path/lib。 我这里为
xx/5.14.2/msvc2015_64/lib
构建到此结束
验证
- 1 创建测试项目,增加Sql模块, 我这里创建了一个widget的项目(QtVs插件)QtWidgetsApplication1。 QtWidgetsApplication1 的构造函数中增加以下关键代码:
#include <QSqlDatabase>
#include <QDebug>
...
QtWidgetsApplication1::QtWidgetsApplication1(QObject*parent) : QObject(parent)
{
...
qDebug() << "\n\n\n";
qDebug() << QSqlDatabase::drivers();
qDebug() << "\n\n\n";
}
- 2 编译并运行测试项目,如果输出 SQLITECIPHER关键字,则证明可使用 QtCipherSqlitePlugin插件。 否则,请检查构建是否正确。
使用
- QtCipherSqlitePlugin 插件提供了对sqlite数据库文件的加密、更新加密密码、删除密码和的功能。
- 可在运行时指定 CIPHER 详见下面的代码, 自己封装了一个类,包含了加密、删除和更新密钥 以及测试 加密数据库能否打开 4个接口。 copy即可使用
核心代码
...
enum SQLITE_CIPHER
{
SC_aes128cbc = 1,
SC_aes256cbc = 2,
SC_chacha20 = 3,
SC_sqlcipher = 5,
};
class Sqlite : public QObject
{
Q_OBJECT
public:
Sqlite(QObject* parent = nullptr) : QObject(parent)
{
m_cipherHash.insert(SC_aes128cbc, "aes128cbc");
m_cipherHash.insert(SC_aes256cbc, "aes256cbc");
m_cipherHash.insert(SC_chacha20, "chacha20");
m_cipherHash.insert(SC_sqlcipher, "sqlcipher");
}
/// -------------------------------------------------------------------------------
/// @brief: 加密文件
/// @param: const QString & sqlite_file - 哪个文件
/// @param: const QString & password - 密码
/// @param: const QString & codec_type - 加密器
/// @ret: int
/// 0 - 成功
/// 1 - 失败, 参数 sqlite_file 为空 或者 codec_type 为空, 调用errorMsg获取错误详情
/// 2 - 失败,调用 errorMsg 获取错误详情
/// -------------------------------------------------------------------------------
int encodeFile(const QString& sqlite_file, const QString& password, const SQLITE_CIPHER& codec_type)
{
if ((0 == sqlite_file.length()) || (false == m_cipherHash.contains(codec_type)))
{
m_errorStr = tr("the param's length is false, please check or the codec_type is false");
return 1;
}
QSqlDatabase dbconn = QSqlDatabase::addDatabase("SQLITECIPHER");
dbconn.setDatabaseName(sqlite_file);
dbconn.setPassword(password);
const QString conn_str = QString("QSQLITE_USE_CIPHER=%1;QSQLITE_CREATE_KEY").arg(m_cipherHash.value(codec_type));
dbconn.setConnectOptions(conn_str);
if (!dbconn.open())
{
m_errorStr = dbconn.lastError().driverText();
return 2;
}
dbconn.close();
return 0;
}
/// -------------------------------------------------------------------------------
/// @brief: 更新文件密钥
/// @param: const QString & sqlite_file - 哪个文件
/// @param: const QString & old_password - 先前的密钥
/// @param: const QString & new_password - 新的密钥
/// @param: const SQLITE_CIPHER & code_type - 加密器
/// @ret: int
/// 1 - 失败, 参数 sqlite_file 为空 或者 codec_type 为空, 调用errorMsg获取错误详情
/// 2 - 失败,调用 errorMsg 获取错误详情
/// -------------------------------------------------------------------------------
int updateFileKey(const QString& sqlite_file, const QString& old_password, const QString& new_password, const SQLITE_CIPHER& code_type)
{
if ((0 == sqlite_file.length()) || (false == m_cipherHash.contains(codec_type)))
{
m_errorStr = tr("the param's length is false, please check or the codec_type is false");
return 1;
}
QSqlDatabase dbconn = QSqlDatabase::addDatabase("SQLITECIPHER");
dbconn.setDatabaseName(sqlite_file);
dbconn.setPassword(old_password);
const QString conn_str = QString("QSQLITE_USE_CIPHER=%1;QSQLITE_UPDATE_KEY=%2").arg(m_cipherHash.value(codec_type)).arg(new_password);
dbconn.setConnectOptions(conn_str);
if (!dbconn.open())
{
m_errorStr = dbconn.lastError().driverText();
return 2;
}
dbconn.close();
return 0;
}
/// -------------------------------------------------------------------------------
/// @brief: 删除文件
/// @param: const QString & sqlite_file - 数据库文件
/// @param: const QString & password - 密码
/// @param: const SQLITE_CIPHER & codec_type - 加密器
/// @ret: int
/// 1 - 失败, 参数 sqlite_file 为空 或者 codec_type 为空, 调用errorMsg获取错误详情
/// 2 - 失败,调用 errorMsg 获取错误详情
/// -------------------------------------------------------------------------------
int removeFileKey(const QString& sqlite_file, const QString& password, const SQLITE_CIPHER& codec_type)
{
if ((0 == sqlite_file.length()) || (false == m_cipherHash.contains(codec_type)))
{
m_errorStr = tr("the param's length is false, please check or the codec_type is false");
return 1;
}
QSqlDatabase dbconn = QSqlDatabase::addDatabase("SQLITECIPHER");
dbconn.setDatabaseName(sqlite_file);
dbconn.setPassword(password);
const QString conn_str = QString("QSQLITE_USE_CIPHER=%1;QSQLITE_REMOVE_KEY").arg(m_cipherHash.value(codec_type));
dbconn.setConnectOptions(conn_str);
if (!dbconn.open())
{
m_errorStr = dbconn.lastError().driverText();
return 2;
}
dbconn.close();
return 0;
}
/// -------------------------------------------------------------------------------
/// @brief: 测试加密文件是否能打开成功
/// @param: const QString & sqlite_file - 哪个加密文件
/// @param: const QString & password - 加密文件的密码
/// @param: const SQLITE_CIPHER & codec_type - 加密器
/// @ret: int
/// 1 - 失败, 参数 sqlite_file 为空 或者 codec_type 为空, 调用errorMsg获取错误详情
/// 2 - 失败,调用 errorMsg 获取错误详情
/// -------------------------------------------------------------------------------
int testFileKey(const QString& sqlite_file, const QString& password, const SQLITE_CIPHER& codec_type)
{
if ((0 == sqlite_file.length()) || (false == m_cipherHash.contains(codec_type)))
{
m_errorStr = tr("the param's length is false, please check or the codec_type is false");
return 1;
}
QSqlDatabase dbconn = QSqlDatabase::addDatabase("SQLITECIPHER");
dbconn.setDatabaseName(sqlite_file);
dbconn.setPassword(password);
const QString conn_str = QString("QSQLITE_USE_CIPHER=%1").arg(m_cipherHash.value(codec_type));
dbconn.setConnectOptions(conn_str);
if (!dbconn.open())
{
m_errorStr = dbconn.lastError().driverText();
return 2;
}
dbconn.close();
return 0;
}
private:
using HashIntStr = QHash<int, QString>;
HashIntStr m_cipherHash;
}
完。