针对 qt的sqlite加密数据库sqlitecipher插件QtCipherSqlitePlugin

💂 个人主页:pp不会算法^ v ^
🤟 版权: 本文由【pp不会算法v】原创、在CSDN首发、需要转载请联系博主
💬 如果文章对你有帮助、欢迎关注、点赞、收藏(一键三连)和订阅专栏哦

文章目录

  • 简介
  • 编译安装
  • 使用
  • 可视化工具查看
  • 完结

简介

在客户端存储数据的时候很多情况都会使用sqlite,像微信这种主流软件在客户端储存数据也用到了sqlite,
但是普通的sqlite是没有加密的也就是说别人可以直接打开那个.db文件查看存储的内容,

针对数据安全,有两种方案:
一种就是将写入的数据加密,这样就算别人打开也是加密后的内容
另一种就是对数据库本身加密,sqlite官方提供也一个加密版本但是那是商业收费的
但是还是有两款开源的基于sqlite的加密数据库sqlitecipher和wxsqlite
wxsqlite3是基于sqlitecipher的,

我下面介绍的这个qt插件就是基于wxsqlite的
在这里插入图片描述

编译安装

github链接:https://github.com/devbean/QtCipherSqlitePlugin.git
不要用gitee上那个镜像,那个稍微有点问题(别问为什么我用过出了问题)

把代码拉取下来之后直接打开pro文件用mingw编译,编译完之后在生成目录下的
plugins/sqldrivers/这个目录下生成如下图的三个库文件
在这里插入图片描述
然后将下面这两个文件复制导对对应编译器的:D:\ITSoftWare\QT5.15.2\Qtbase\5.15.2\mingw81_64\plugins\sqldrivers(以我的为例我是用mingw81_64编译的,release和debug模式编译的都一样)中
在这里插入图片描述
然后把下面这个.a文件放到对应编译器目录的lib目录下:D:\ITSoftWare\QT5.15.2\Qtbase\5.15.2\mingw81_64\lib(以我的为例)
在这里插入图片描述

使用

输出QSqlDatabase::drivers()看一看时候包含了 SQLITECIPHER,如果包含了那么证明安装成功了
使用和qt的sqlite模块基本一致,
只要在初始化数据库的时候添加一下密码就行了,
db_ = QSqlDatabase::addDatabase(“SQLITECIPHER”, connectionName_);
db_.setPassword(“123698745”);

示例代码:

#include <QtSql>
#include <QCoreApplication>
#include <QTemporaryDir>#ifndef QT_DEBUG
#error Must be built in debug mode!
#endif#ifdef Q_OS_IOS
#  include <QtPlugin>Q_IMPORT_PLUGIN(SqliteCipherDriverPlugin)
#endif#define CONNECTION_FAILED -1int main(int argc, char *argv[])
{QCoreApplication app(argc, argv);Q_UNUSED(app)qDebug() << QSqlDatabase::drivers();Q_ASSERT(QSqlDatabase::isDriverAvailable("QSQLITE")); // from QtQ_ASSERT(QSqlDatabase::isDriverAvailable("SQLITECIPHER")); // from our pluginQTemporaryDir tmp;Q_ASSERT(tmp.isValid());auto withDB = [&](const char *driver, auto fn) {QString path = QDir(tmp.path()).absoluteFilePath(QString(driver) + ".db");{QSqlDatabase db = QSqlDatabase::addDatabase(driver, "db");db.setDatabaseName(path);Q_ASSERT(db.open());fn(db);}QSqlDatabase::removeDatabase("db");};//    // QSQLITE
//    {
//        // Create a SQLite db
//        withDB("QSQLITE", [](auto db) {
//            db.exec("create table foo (bar integer)");
//            db.exec("insert into foo values (42)");
//        });//        // Check that we can read from the SQLite db
//        withDB("QSQLITE", [](auto db) {
//            QSqlQuery q = db.exec("select bar from foo");
//            Q_ASSERT(q.next());
//            Q_ASSERT(q.value(0).toInt() == 42);
//        });//        // Check that SQLite is not SQLCipher
//        withDB("QSQLITE", [](auto db) {
//            QSqlQuery q = db.exec("select sqlcipher_export()");
//            QString errmsg = q.lastError().databaseText();
//            Q_ASSERT(errmsg.startsWith("no such function"));
//        });
//    }//    // SQLITECIPHER
//    {
//        // Check that SQLiteCipher is not SQLite
//        withDB("SQLITECIPHER", [](auto db) {
//            QSqlQuery q = db.exec("select sqlcipher_export()");
//            QString errmsg = q.lastError().databaseText();
//            qDebug() << errmsg;
//            Q_ASSERT(errmsg.startsWith("wrong number of arguments"));
//        });//        // Create a SQLiteCipher db with a passphrase
//        withDB("SQLITECIPHER", [](auto db) {
//            db.exec("pragma key='foobar'");
//            db.exec("create table foo (bar integer)");
//            db.exec("insert into foo values (42)");
//        });//        // Check that we can't read from the SQLiteCipher db without the passphrase
//        withDB("SQLITECIPHER", [](auto db) {
//            QSqlQuery q = db.exec("select bar from foo");
//            Q_ASSERT(!q.next());
//        });//        // Check that we can read from the SQLiteCipher db with the passphrase
//        withDB("SQLITECIPHER", [](auto db) {
//            db.exec("pragma key='foobar'");
//            QSqlQuery q = db.exec("select bar from foo");
//            Q_ASSERT(q.next());
//            Q_ASSERT(q.value(0).toInt() == 42);
//        });
//    }QString dir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
//    QString DB_FILE_PATH = dir + "/test_chacha20.db";QString DB_FILE_PATH = dir + "/local.db";qDebug() << "DB File Path is:" << DB_FILE_PATH;QSqlDatabase dbconn = QSqlDatabase::addDatabase("SQLITECIPHER");dbconn.setDatabaseName(DB_FILE_PATH); //localDB.db is already existing before running the applicationdbconn.setPassword("pass");dbconn.setConnectOptions("QSQLITE_USE_CIPHER=sqlcipher; SQLCIPHER_LEGACY=1; SQLCIPHER_LEGACY_PAGE_SIZE=4096; QSQLITE_CREATE_KEY");bool open = dbconn.open();qDebug() << "open: " << open;qDebug() << "isOpen(): " << dbconn.isOpen() << dbconn.isOpenError();qDebug() << "create_key: " << dbconn.lastError();if (!dbconn.isOpen()){qDebug() << "Connection failed: " << dbconn.lastError().driverText();exit(CONNECTION_FAILED);}QSqlQuery query;
//    query.exec("create table test (id int, name varchar)");
//    query.exec("insert into test values (1, 'AAA')");
//    query.exec("insert into test values (2, 'BBB')");
//    query.exec("insert into test values (3, 'CCC')");
//    query.exec("insert into test values (4, 'DDD')");
//    query.exec("insert into test values (5, 'EEE')");
//    query.exec("insert into test values (6, 'FFF')");
//    query.exec("insert into test values (7, 'GGG')");
//    query.exec("select * from test where name regexp '(a|A)$'");
//    if (query.next()) {
//        qDebug() << "Regexp result: " << query.value(0).toInt() << ": " << query.value(1).toString();
//    } else {
//        qDebug() << "This plugin does not support regexp.";
//    }
//    qDebug() << "----------" << endl;query.exec("select id, name from test");while (query.next()) {qDebug() << query.value(0).toInt() << ": " << query.value(1).toString();}
//    qDebug() << "----------" << endl;
//    query.exec("update mapping set name='ZZZ' where id=1");
//    query.exec("select id, name from mapping");
//    while (query.next()) {
//        qDebug() << query.value(0).toInt() << ": " << query.value(1).toString();
//    }
//    qDebug() << "----------" << endl;
//    query.exec("delete from mapping where id=4");
//    query.exec("select id, name from mapping");
//    while (query.next()) {
//        qDebug() << query.value(0).toInt() << ": " << query.value(1).toString();
//    }
//    query.exec("drop table mapping");dbconn.close();return 0;
}

可视化工具查看

由于数据库被加密了使用一般的数据库可视化工具例如Navicat查看不了,这里我们可以下载sqlitestudio这款工具,也是qt写的,安装好了之打开上述示例代码创建的数据库
在这里插入图片描述

完结

如果你觉得对你有帮助,那麻烦三连一下吧

qt/c++技术交流q群:287590944

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/786005.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

太绝了!34张思维导图搞定Web安全知识架构

推荐关注 越来越多的朋友开始了解网络安全&#xff0c;但是不知道从哪里下手&#xff0c;网上的资源也很散乱&#xff0c;没有头绪&#xff0c;经常做无用功。 今天给大家分享几份网络安全思维导图&#xff0c;非常适合零基础入门或想进一步学习的小伙伴。 注&#xff1a;文…

leetcode 不同路径

62. 不同路径 问题描述 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在下图中标记为 “Finish” &#xff09;。 问总共有多少条不同的…

【数据处理包Pandas】DataFrame数据选择的基本方法

目录 一、选择行/列&#xff08;一&#xff09;读取文件&#xff08;二&#xff09;选择行&#xff08;三&#xff09;选择列&#xff08;四&#xff09;选择多行多列 二、带条件筛选&#xff08;一&#xff09;startswith()方法&#xff08;二&#xff09;mean()方法&#xff…

本地运行github上下载的项目--接Git入门篇

1.了解项目 这是一个基于Spring Boot 和 Mybatis Plus 构建的Java项目&#xff0c;很经典的外卖项目&#xff0c;参考b站的黑马瑞吉外卖。 2.构建项目 SpringBoot项目&#xff0c;首先下载一些常见的项目要求的组件。然后配置如下&#xff1a; 看README&#xff0c;在阅读该…

如何查找局域网内连接设备的IP地址?

如何查找局域网内连接设备的IP地址? 第一种方法:通过CMD指令 在电脑开始菜单中找到运行,点击打开,输入CMD,然后回车,如下图所示, 如下图所示,输入ipconfig/all,然后回车, 如下图所示,此时会扫描出所有的连接设备的IP地址、MAC地址以及网关等信息, 这时候在cmd命令窗…

设置浏览器声音外放,其他声音耳机里放

需求描述&#xff1a; 我想在耳机里听歌&#xff0c;浏览器里的声音外放 找到这个面板 让浏览器的声音输出设为&#xff0c;扬声器

超图打开不同格式的dem文件

dem&#xff0c;数字高程模型&#xff1b; dem文件的后缀是什么? 有*.dem格式的&#xff0c;也有Raster&#xff0c;ASCII和Tiff类型的。Raster类型的是一个raster文件夹里面有很多不同格式的文件共同组成了DEM文件的内容。ASCII类型的是个txt文件。Tiff类型的也是一个文件夹…

Learning Discriminative Representations for Skeleton Based Action Recognition

标题&#xff1a;基于骨架的动作识别的学习判别性表示 原文链接&#xff1a;Learning Discriminative Representations for Skeleton Based Action Recognition (thecvf.com) 源码链接&#xff1a;https://github.com/zhysora/FR-Head 发表&#xff1a;CVPR 摘要 最近&…

面试题:MySQL 优化篇

定位慢查询 &#x1f496; 开源工具 调试工具&#xff1a;Arthas&#xff08;阿尔萨斯&#xff09;运维工具&#xff1a;Prometheus&#xff08;普罗米修斯&#xff09;、Skywalking &#x1f496; MySQL 慢查询日志 # 开启 MySQL 慢查询日志开关 slow_query_log1 # 设置慢…

k8s入门到实战(七)—— 回顾:使用yaml文件配置pv、pvc、configmap部署mysql服务

实战&#xff1a;部署 mysql 服务 回顾加深 pv、pvc、configmap 删除所有 deployment、pv、pvc、configmap、StorageClass创建一个 nsf 挂载目录给 mysql mkdir -p /nfs/data/mysql创建 yaml 文件mysql-server.yaml # 创建pv apiVersion: v1 kind: PersistentVolume metadat…

黑马鸿蒙笔记 3

目录 11.ArkUI组件-Column和Row 12.ArkUI组件-循环控制 13.ArkUI组件-List 14.ArkUI组件-自定义组件 15.ArkUI组件-状态管理State装饰器 16.ArkUI组件-状态管理-任务统计案例 17.ArkUI组件-状态管理-PropLinkProvideConsume 11.ArkUI组件-Column和Row Colum和Row的交叉…

QT-飞机水平仪图标

QT-飞机水平仪图标 一、演示效果二、关键程序三、下载链接 一、演示效果 二、关键程序 #include <stdio.h> #include <stdlib.h> #include <string.h>#include <QtCore> #include <QtGui> #include <QDebug> #include <QTableWidget&g…

Oracle Solaris 11.3开工失败问题处理记录

1、故障现像 起初是我这有套RAC有点问题&#xff0c;我想重启1个节点&#xff0c;结果发现重启后该节点的IP能PING通&#xff0c;但SSH连不上去&#xff0c;对应的RAC服务也没有自动启动。 操作系统是solaris 11.3。由于该IP对应的主机是LDOM&#xff0c;于是我去主域上telnet…

【BlossomRPC】接入注册中心

文章目录 NacosZookeeper自研配置中心 RPC项目 配置中心项目 网关项目 这是BlossomRPC项目的最后一篇文章了&#xff0c;接入完毕注册中心&#xff0c;一个完整的RPC框架就设计完成了。 对于项目对注册中心的整合&#xff0c;其实我们只需要再服务启动的时候将ip/port/servic…

Qt6.6添加多媒体模块Multimedia报错问题

问题 QT包含多媒体模块Multimedia时提示未知的模块&#xff1a; error: Project ERROR: Unknown module(s) in QT: multimedia 在帮助文档中只可以找到QMediaPlayer类&#xff0c;但是点进去是空的&#xff0c;这是因为没有安装多媒体模块及对应的帮助文档。 解决 使用在线…

● 435. 无重叠区间 ● 763.划分字母区间 ● 56. 合并区间

● 435. 无重叠区间 class Solution:def eraseOverlapIntervals(self, intervals: List[List[int]]) -> int:if len(intervals)1:return 0intervalssorted(intervals,keylambda x:(x[0],x[1]))res0for i in range(1,len(intervals)):if intervals[i][0]<intervals[i-1][…

代码随想录算法训练营第41天|343. 整数拆分 |96.不同的二叉搜索树

代码随想录算法训练营第41天|343. 整数拆分 |96.不同的二叉搜索树 详细布置 今天两题都挺有难度&#xff0c;建议大家思考一下没思路&#xff0c;直接看题解&#xff0c;第一次做&#xff0c;硬想很难想出来。 343. 整数拆分 https://programmercarl.com/0343.%E6%95%B4%E6%…

【Go】十三、面向对象:方法

文章目录 1、面向对象2、结构体实例的创建3、结构体之间的转换4、方法5、结构体值拷贝6、方法的注意点7、方法和函数的区别8、跨包创建结构体实例 1、面向对象 Go的结构体struct ⇒ Java的Class类Go基于struct来实现OOP相比Java&#xff0c;Go去掉了方法重载、构造函数和析构函…

css- 4

1.浮动 1. 浮动最初用于实现文字环绕效果 2. 现在&#xff0c;浮动是主流的布局方式之一 1.1元素浮动之后的特点 元素浮动之后&#xff0c;称为浮动元素&#xff0c;具有如下特点&#xff1a; 1. 浮动元素脱离文档流 2. 多个浮动的元素会水平排列&#xff0c;一行放不下自动换…

Redis高级面试题-2024

说说你对Redis的理解 Redis是一个基于Key-Value存储结构的开源内存数据库&#xff0c;也是一种NoSQL数据库。 它支持多种数据类型&#xff0c;包括String、Map、Set、ZSet和List&#xff0c;以满足不同应用场景的需求。 Redis以内存存储和优化的数据结构为基础&#xff0c;提…