草庐IT

qt - 如何使用 Windows/MinGW 平台为带有 SQLCipher 扩展的 SQLite-DB 构建 Qt-SQL-driver-plugin 'QSQLCIPHER'?

coder 2023-07-21 原文

这通常不是在哪里可以找到分步指南的问题,而是指南本身的问题。
我写这篇文章的目的是给其他人一个提示,他们在编译驱动程序插件时遇到了和我最近一样的问题。

如何使用 Windows/MinGW 平台使用 SQLCipher-extension 为 SQLite-DB 构建 Qt-SQL-driver-plugin 'QSQLCIPHER'?

最佳答案

如何使用 Windows/MinGW 平台为带有 SQLCipher 扩展的 SQLite-DB 构建 Qt-SQL-driver-plugin 'QSQLCIPHER':

  • 适用于 Windows/MinGW 的 Qt 5.4.0
  • 下载Qt
  • 安装包括源,例如到 C:\Qt\Qt5.4.0
  • 适用于 Windows 的 OpenSSL
  • 下载 Win32 OpenSSL v1.0.2a
  • 下载 Visual C++ 2008 Redistributable
  • 通过执行“vcredist_x86.exe”安装 Visual C++ 2008 Redistributable
  • 通过执行“Win32OpenSSL-1_0_2.exe”安装 OpenSSL v1.0.2a
  • 目标目录,例如C:\OpenSSL-Win32
  • 在安装过程中,选择将库安装到 Windows 系统目录 ( C:\Windows\SysWOW64 )
  • 的选项
  • MinGW - 适用于 Windows 的极简主义 GNU
  • 下载并安装“mingw-get-setup.exe”
  • 启动 MinGW 安装程序
  • MSYS基础系统的安装
  • 选择:所有包 -> MSYS -> MSYS 基础系统
  • 选择 msys-base (Class 'bin') 进行安装
  • 菜单:安装 -> 应用更改
  • 默认安装文件到目录C:\MinGW
  • Tcl/Tk 的安装
  • 选择:所有包 -> MinGW -> MinGW 贡献
  • 选择“mingw32-tcl”和“mingw32-tk”(类“bin”)进行安装
  • 菜单:安装 -> 应用更改
  • 默认安装文件到目录C:\MinGW
  • 复制C:\MinGW的内容到 Qt-MinGW 目录 C:\Qt\Qt5.4.0\Tools\mingw491_32
  • C:\Qt\Qt5.4.0\Tools\mingw491_32\msys\1.0\etc 中创建文件“fstab”
  • 插入内容如下:
    #Win32_Path                        Mount_Point
    C:/Qt/Qt5.4.0/Tools/mingw491_32    /mingw
    C:/Qt/Qt5.4.0/5.4                  /qt
    C:/                                /c
    
  • zlib-库
  • 下载 zlib-dll-二进制文件
  • 将文件“zlib1.dll”提取并复制到 Qt-MinGW 目录 C:\Qt\Qt5.4.0\Tools\mingw491_32\msys\1.0\bin
  • SQL密码
  • 下载 SQLCipher 压缩文件
  • 提取 zip 文件,例如至 C:\temp\sqlcipher-master
  • 复制 OpenSSL-Win32-libraries
  • 复制 C:\OpenSSL-Win32\bin\libeay32.dllC:\temp\sqlcipher-master
  • 复制 C:\OpenSSL-Win32\lib\libeay32.libC:\temp\sqlcipher-master
  • 构建SQLCipher.exe
  • 执行 MSYS:C:\Qt\Qt5.4.0\Tools\mingw491_32\msys\1.0\msys.bat
    $ cd /c/temp/sqlcipher-master
    $ ./configure --prefix=$(pwd)/dist --with-crypto-lib=none --disable-tcl CFLAGS="-DSQLITE_HAS_CODEC -DSQLCIPHER_CRYPTO_OPENSSL -I/c/openssl-win32/include /c/temp/sqlcipher-master/libeay32.dll -L/c/temp/sqlcipher-master/ -static-libgcc" LDFLAGS="-leay32"
    $ make clean
    $ make sqlite3.c
    $ make
    $ make dll
    $ make install
    
  • 保存可执行的 SQLite/SQLCipher 数据库,例如至 C:\sqlcipher
  • 复制 C:\temp\sqlcipher-master\dist\bin\sqlcipher.exeC:\sqlcipher .
    文件“sqlcipher.exe”是与非加密原始命令行界面“sqlite3.exe”等价的加密文件。
  • 复制 C:\temp\sqlcipher-master\sqlite3.dllC:\sqlcipher .
    该文件是加密扩展的 SQLite 库。
  • 带有 SQLCipher-extension 的 SQLite 数据库现在可以工作了。
  • 构建 Qt-QSQLCIPHER-driver-plugin
  • 创建目录:C:\Qt\Qt5.4.0\5.4\Src\qtbase\src\plugins\sqldrivers\sqlcipher
  • 在新目录中创建以下三个文件:
  • 文件 1:smain.cpp:
    #include <qsqldriverplugin.h>
    #include <qstringlist.h>
    #include "../../../../src/sql/drivers/sqlite/qsql_sqlite_p.h" // There was a missing " at the end of this line
    QT_BEGIN_NAMESPACE
    class QSQLcipherDriverPlugin : public QSqlDriverPlugin
    {
        Q_OBJECT
        Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QSqlDriverFactoryInterface" FILE "sqlcipher.json")
    public:
        QSQLcipherDriverPlugin();
    
        QSqlDriver* create(const QString &);
    };
    QSQLcipherDriverPlugin::QSQLcipherDriverPlugin()
        : QSqlDriverPlugin()
    {
    }
    QSqlDriver* QSQLcipherDriverPlugin::create(const QString &name)
    {
        if (name == QLatin1String("QSQLCIPHER")) {
            QSQLiteDriver* driver = new QSQLiteDriver();
            return driver;
        }
        return 0;
    }
    QT_END_NAMESPACE
    #include "smain.moc"
    
  • 文件 2:sqlcipher.pro
    TARGET = qsqlcipher
    SOURCES = smain.cpp
    OTHER_FILES += sqlcipher.json
    include(../../../sql/drivers/sqlcipher/qsql_sqlite.pri)
    wince*: DEFINES += HAVE_LOCALTIME_S=0
    PLUGIN_CLASS_NAME = QSQLcipherDriverPlugin
    include(../qsqldriverbase.pri)
    
  • 文件 3:sqlcipher.json
    {
        "Keys": [ "QSQLCIPHER" ]
    }
    
  • 复制目录 C:\Qt\Qt5.4.0\5.4\Src\qtbase\src\sql\drivers\sqliteC:\Qt\Qt5.4.0\5.4\Src\qtbase\src\sql\drivers\sqlcipher
  • 自定义文件 C:\Qt\Qt5.4.0\5.4\Src\qtbase\src\sql\drivers\sqlcipher\qsql_sqlite.pri该文件的内容应如下所示:
    HEADERS += $$PWD/qsql_sqlite_p.h
    SOURCES += $$PWD/qsql_sqlite.cpp
    !system-sqlite:!contains(LIBS, .*sqlite3.*) {
        include($$PWD/../../../3rdparty/sqlcipher.pri)     #<-- change path of sqlite.pri to sqlcipher.pri here !
    } else {
        LIBS += $$QT_LFLAGS_SQLITE
        QMAKE_CXXFLAGS *= $$QT_CFLAGS_SQLITE
    }
    
  • 此目录中的其余两个文件无需更改。
  • 在目录 C:\Qt\Qt5.4.0\5.4\Src\qtbase\src\3rdparty 中创建文件 'sqlcipher.pri'具有以下内容:
    CONFIG(release, debug|release):DEFINES *= NDEBUG
    DEFINES += SQLITE_OMIT_LOAD_EXTENSION SQLITE_OMIT_COMPLETE SQLITE_ENABLE_FTS3 SQLITE_ENABLE_FTS3_PARENTHESIS SQLITE_ENABLE_RTREE SQLITE_HAS_CODEC
    !contains(CONFIG, largefile):DEFINES += SQLITE_DISABLE_LFS
    contains(QT_CONFIG, posix_fallocate):DEFINES += HAVE_POSIX_FALLOCATE=1
    winrt: DEFINES += SQLITE_OS_WINRT
    winphone: DEFINES += SQLITE_WIN32_FILEMAPPING_API=1
    qnx: DEFINES += _QNX_SOURCE
    INCLUDEPATH +=  $$PWD/sqlcipher c:/openssl-win32/include
    SOURCES +=      $$PWD/sqlcipher/sqlite3.c
    LIBS += -L$$PWD/sqlcipher/lib -lsqlcipher -leay32 -lsqlite3
    TR_EXCLUDE += $$PWD/*
    
  • 创建和填充 C:\Qt\Qt5.4.0\5.4\Src\qtbase\src\3rdparty\sqlcipher
  • 创建两个目录:
    C:\Qt\Qt5.4.0\5.4\Src\qtbase\src\3rdparty\sqlcipher
    C:\Qt\Qt5.4.0\5.4\Src\qtbase\src\3rdparty\sqlcipher\lib
    
  • 将以下文件复制到 C:\Qt\Qt5.4.0\5.4\Src\qtbase\src\3rdparty\sqlcipher :
    C:\temp\sqlcipher-master\shell.c
    C:\temp\sqlcipher-master\sqlite3.c
    C:\temp\sqlcipher-master\sqlite3.h
    C:\temp\sqlcipher-master\sqlite3ext.h
    
  • 将以下文件/目录复制到 C:\Qt\Qt5.4.0\5.4\Src\qtbase\src\3rdparty\sqlcipher\lib :
    C:\temp\sqlcipher-master\dist\lib
    C:\temp\sqlcipher-master\sqlite3.dll
    C:\OpenSSL-Win32\bin\libeay32.dll
    
  • 该目录现在包含以下文件和目录:
    C:\QT\QT5.4.0\5.4\SRC\QTBASE\SRC\3RDPARTY\SQLCIPHER
    |   shell.c
    |   sqlite3.c
    |   sqlite3.h
    |   sqlite3ext.h
    |
    \---lib
        |   libeay32.dll
        |   libsqlcipher.a
        |   libsqlcipher.la
        |   sqlite3.dll
        |
        \---pkgconfig
                sqlcipher.pc
    
  • 为 Qt 编译 QSQLCIPHER-driver-plugin:
  • 打开 Qt 命令行 C:\Windows\System32\cmd.exe /A /Q /K C:\Qt\Qt5.4.0\5.4\mingw491_32\bin\qtenv2.bat
  • 执行以下命令:
    cd C:\Qt\Qt5.4.0\5.4\Src\qtbase\src\pluins\sqldrivers\sqlcipher
    qmake
    mingw32-make
    
  • 这将在以下目录中构建 QSQLCIPHER-driver-plugin:
    C:\QT\QT5.4.0\5.4\SRC\QTBASE\PLUGINS\SQLDRIVERS
        libqsqlcipher.a
        libqsqlcipherd.a
        qsqlcipher.dll
        qsqlcipherd.dll
    
  • 将“qsqlcipher.dll”和“qsqlcipherd.dll”复制到SQL-driver-plugin-directory C:\Qt\Qt5.4.0\5.4\mingw491_32\plugins\sqldrivers .
  • 创建一个新的加密 SQLite/SQLCipher 数据库
  • 使用测试表和一些测试数据创建新的 SQLite-Plaintext-database 'plaintext.db'
  • 将目录更改为 C:\sqlcipher ,其中包含“sqlcipher.exe”和“sqlite3.dll”(见上文)。
    C:\sqlcipher>sqlcpher.exe plaintext.db
      SQLCipher version 3.8.6 2014-08-15 11:46:33
      Enter ".help" for instructions
      Enter SQL statements terminated with a ";"
      sqlite> create table testtable (id integer, name text);
      sqlite> insert into testtable (id,name) values(1,'Bob');
      sqlite> insert into testtable (id,name) values(2,'Charlie');
      sqlite> insert into testtable (id,name) values(3,'Daphne');
      sqlite> select * from testtable;
      1|Bob
      2|Charlie
      3|Daphne
      sqlite> .exit
    
  • 开通 C:\sqlcipher\plaintext.db使用标准文本编辑器:
    可以明文读取数据库方案和测试数据。
  • 加密明文数据库
    这将创建数据库 C:\sqlcipher\encrypted.db使用 key “testkey”。
    C:\sqlcipher>sqlcipher.exe plaintext.db
        SQLCipher version 3.8.6 2014-08-15 11:46:33
        Enter ".help" for instructions
        Enter SQL statements terminated with a ";"
        sqlite> ATTACH DATABASE 'encrypted.db' AS encrypted KEY 'testkey';
        sqlite> SELECT sqlcipher_export('encrypted');
        sqlite> DETACH DATABASE encrypted;
        sqlite> .exit
    
  • 开通 C:\sqlcipher\encrypted.db使用标准文本编辑器:
    数据现在已加密。
  • 更多有用信息请访问:
    https://www.zetetic.net/sqlcipher/sqlcipher-api/
  • 将 SQLite 数据库与 SQLCipher 扩展一起使用并通过 Qt 访问
  • 创建一个新的 Qt 命令行项目,例如'qsqlcipher'
  • 项目文件
    QT       += core sql
    QT       -= gui
    TARGET = qsqlcipher
    CONFIG   += console
    CONFIG   -= app_bundle
    TEMPLATE = app
    SOURCES += main.cpp
    
  • 测试程序'main.cpp'
    #include <QCoreApplication>
    #include <QSqlDatabase>
    #include <QSqlQuery>
    #include <QDebug>
    #include <QString>
    int main(int argc, char *argv[]) {
        QCoreApplication a(argc, argv);
        qDebug() << QSqlDatabase::drivers();
        QSqlDatabase db = QSqlDatabase::addDatabase("QSQLCIPHER");
        db.setDatabaseName("C:/sqlcipher/encrypted.db");
        db.open();
        QSqlQuery q;
        q.exec("PRAGMA key = 'testkey';");
        q.exec("insert into testtable (id,name) values(4,'dummy')");
        q.exec("SELECT id,name anz FROM testtable");
        while (q.next()) {
            QString id = q.value(0).toString();
            QString name = q.value(1).toString();
            qDebug() << "id=" << id << ",  name=" << name;
        }
        db.close();
        return 0;
    }
    
  • 编译并执行
    ("QSQLCIPHER", "QSQLITE", "QMYSQL", "QMYSQL3", "QODBC", "QODBC3", "QPSQL", "QPSQL7")
    id= "1" ,  name= "Bob"
    id= "2" ,  name= "Charlie"
    id= "3" ,  name= "Daphne"
    id= "4" ,  name= "dummy"
    
  • 交付 Qt 程序时,不要忘记 Qt 库、平台库、SQL 驱动程序插件“qsqlcipher.dll”和 OpenSSL 库“libeay32.dll”。
    上面测试程序的例子:
    C:\TEMP\QSQLCIPHER-TEST
    |   icudt53.dll
    |   icuin53.dll
    |   icuuc53.dll
    |   libeay32.dll
    |   libgcc_s_dw2-1.dll
    |   libstdc++-6.dll
    |   libwinpthread-1.dll
    |   qsqlcipher.exe
    |   Qt5Core.dll
    |   Qt5Sql.dll
    |
    +---platforms
    |       qminimal.dll
    |       qoffscreen.dll
    |       qwindows.dll
    |
    \---sqldrivers
            qsqlcipher.dll
    
  • 注意:测试程序包含 key :
    ...
    q.exec("PRAGMA key = 'testkey';");
    ...
    

    测试程序的二进制文件中的这个关键字符串可以使用十六进制编辑器轻松读取,在我看来,它缺乏安全性:
    ...
    00002C90  70 68 65 72 2F 65 6E 63 72 79 70 74 65 64 2E 64  pher/encrypted.d
    00002CA0  62 00 50 52 41 47 4D 41 20 6B 65 79 20 3D 20 27  b.PRAGMA key = '
    00002CB0  74 65 73 74 6B 65 79 27 3B 00 00 00 69 6E 73 65  testkey';...inse
    00002CC0  72 74 20 69 6E 74 6F 20 74 65 73 74 74 61 62 6C  rt into testtabl
    ...
    

    有关如何解决此问题的方法,请询问您自己选择的搜索引擎。 ;-)
    例如。搜索:在可执行文件中隐藏字符串
  • 关于qt - 如何使用 Windows/MinGW 平台为带有 SQLCipher 扩展的 SQLite-DB 构建 Qt-SQL-driver-plugin 'QSQLCIPHER'?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29196087/

    有关qt - 如何使用 Windows/MinGW 平台为带有 SQLCipher 扩展的 SQLite-DB 构建 Qt-SQL-driver-plugin 'QSQLCIPHER'?的更多相关文章

    1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

      我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

    2. ruby - 使用 RubyZip 生成 ZIP 文件时设置压缩级别 - 2

      我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看ruby​​zip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d

    3. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

      类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

    4. ruby-on-rails - 使用 Ruby on Rails 进行自动化测试 - 最佳实践 - 2

      很好奇,就使用ruby​​onrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提

    5. ruby - 在 Ruby 中使用匿名模块 - 2

      假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于

    6. ruby - 使用 ruby​​ 和 savon 的 SOAP 服务 - 2

      我正在尝试使用ruby​​和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我

    7. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

      关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

    8. ruby-on-rails - rails : "missing partial" when calling 'render' in RSpec test - 2

      我正在尝试测试是否存在表单。我是Rails新手。我的new.html.erb_spec.rb文件的内容是:require'spec_helper'describe"messages/new.html.erb"doit"shouldrendertheform"dorender'/messages/new.html.erb'reponse.shouldhave_form_putting_to(@message)with_submit_buttonendendView本身,new.html.erb,有代码:当我运行rspec时,它失败了:1)messages/new.html.erbshou

    9. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

      我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

    10. ruby - 使用 ruby​​ 将 HTML 转换为纯文本并维护结构/格式 - 2

      我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h

    随机推荐