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

2021-12-08 00:00:00 qt encryption mingw sqlite sqlcipher

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

This is not typically a question where to find a step-by-step guide, but rather the guide itself.
My intention with this post is to give others a hint, who have the same problems in compiling the driver-plugin as I just had recently.

推荐答案

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

  1. 适用于 Windows/MinGW 的 Qt 5.4.0

  1. Qt 5.4.0 for Windows/MinGW

  • 下载 Qt
  • 安装包括源代码,例如C:QtQt5.4.0

Windows 版 OpenSSL

OpenSSL for Windows

  • 下载 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:WindowsSysWOW64) 的选项

    MinGW - 适用于 Windows 的极简主义 GNU

    MinGW - Minimalist GNU for Windows

    • 下载并安装mingw-get-setup.exe"
    • MinGW 安装程序的启动
      • 安装MSYS基础系统
        • 选择:所有包 -> MSYS -> MSYS 基础系统
        • 选择 msys-base (Class 'bin') 进行安装
        • 菜单:安装 -> 应用更改
        • 默认安装文件到目录C:MinGW
        • 选择:所有包 -> MinGW -> MinGW 贡献
        • 选择mingw32-tcl"和mingw32-tk"(类bin")进行安装
        • 菜单:安装 -> 应用更改
        • 默认安装文件到目录C:MinGW

        C:QtQt5.4.0Toolsmingw491_32msys1.0etc

        • 插入内容如下:

        • Insert content as follows:

        #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:QtQt5.4.0Toolsmingw491_32msys1.0in

        SQLCipher

        • 下载 SQLCipher 压缩文件
        • 提取 zip 文件,例如C: empsqlcipher-master
        • 复制 OpenSSL-Win32-libraries
          • C:OpenSSL-Win32inlibeay32.dll复制到C: empsqlcipher-master
          • C:OpenSSL-Win32liblibeay32.lib复制到C: empsqlcipher-master
          • Download the SQLCipher-zip-file
          • Extract the zip-file e.g. to C: empsqlcipher-master
          • Copy OpenSSL-Win32-libraries
            • Copy C:OpenSSL-Win32inlibeay32.dll to C: empsqlcipher-master
            • Copy C:OpenSSL-Win32liblibeay32.lib to C: empsqlcipher-master

            构建 SQLCipher.exe

            Build SQLCipher.exe

            • 执行 MSYS:C:QtQt5.4.0Toolsmingw491_32msys1.0msys.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

            Save the executable SQLite/SQLCipher-database e.g. to C:sqlcipher

            • C: empsqlcipher-masterdistinsqlcipher.exe复制到C:sqlcipher.
              文件sqlcipher.exe"是与非加密原始命令行界面sqlite3.exe"的加密等效项.
            • C: empsqlcipher-mastersqlite3.dll复制到C:sqlcipher.
              该文件是加密扩展的 SQLite 库.

            构建 Qt-QSQLCIPHER-driver-plugin

            Build Qt-QSQLCIPHER-driver-plugin

            • 创建目录:
              C:QtQt5.4.05.4Srcqtbasesrcpluginssqldriverssqlcipher
            • 在新目录中创建以下三个文件:

            • Create directory:
              C:QtQt5.4.05.4Srcqtbasesrcpluginssqldriverssqlcipher
            • Create the following three files within the new directory:

            • 文件 1:smain.cpp:

            • File 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

          • File 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

          • File 3: sqlcipher.json

            {
                "Keys": [ "QSQLCIPHER" ]
            }
            

          • 自定义文件C:QtQt5.4.05.4Srcqtbasesrcsqldriverssqlcipherqsql_sqlite.pri
            文件内容如下:

            Customize file C:QtQt5.4.05.4Srcqtbasesrcsqldriverssqlcipherqsql_sqlite.pri
            The content of the file shall be like:

            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:QtQt5.4.05.4Srcqtbasesrc3rdparty中创建文件'sqlcipher.pri',内容如下:

          • The remaining two files in this directory need not to be changed.
          • Create file 'sqlcipher.pri' in directory C:QtQt5.4.05.4Srcqtbasesrc3rdparty with following content:

            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:QtQt5.4.05.4Srcqtbasesrc3rdpartysqlcipher

            • 创建两个目录:

            • Create the two directories:

            C:QtQt5.4.05.4Srcqtbasesrc3rdpartysqlcipher
            C:QtQt5.4.05.4Srcqtbasesrc3rdpartysqlcipherlib
            

          • 将以下文件复制到C:QtQt5.4.05.4Srcqtbasesrc3rdpartysqlcipher:

            C:	empsqlcipher-mastershell.c
            C:	empsqlcipher-mastersqlite3.c
            C:	empsqlcipher-mastersqlite3.h
            C:	empsqlcipher-mastersqlite3ext.h
            

          • 将以下文件/目录复制到C:QtQt5.4.05.4Srcqtbasesrc3rdpartysqlcipherlib:

            C:	empsqlcipher-masterdistlib
            C:	empsqlcipher-mastersqlite3.dll
            C:OpenSSL-Win32inlibeay32.dll
            

          • 该目录现在包含以下文件和目录:

          • The directory now consists of the following files and directories:

            C:QTQT5.4.05.4SRCQTBASESRC3RDPARTYSQLCIPHER
            |   shell.c
            |   sqlite3.c
            |   sqlite3.h
            |   sqlite3ext.h
            |
            ---lib
                |   libeay32.dll
                |   libsqlcipher.a
                |   libsqlcipher.la
                |   sqlite3.dll
                |
                ---pkgconfig
                        sqlcipher.pc
            

          • 为 Qt 编译 QSQLCIPHER-driver-plugin:

            Compile the QSQLCIPHER-driver-plugin for Qt:

            • 打开Qt命令行C:WindowsSystem32cmd.exe/A/Q/KC:QtQt5.4.05.4mingw491_32inqtenv2.bat
            • 执行以下命令:

            • Open Qt-command line C:WindowsSystem32cmd.exe /A /Q /K C:QtQt5.4.05.4mingw491_32inqtenv2.bat
            • Execute the following commands:

            cd C:QtQt5.4.05.4Srcqtbasesrcpluinssqldriverssqlcipher
            qmake
            mingw32-make
            

          • 这会在以下目录中构建 QSQLCIPHER-driver-plugin:

          • This builds the QSQLCIPHER-driver-plugin within the following directory:

            C:QTQT5.4.05.4SRCQTBASEPLUGINSSQLDRIVERS
                libqsqlcipher.a
                libqsqlcipherd.a
                qsqlcipher.dll
                qsqlcipherd.dll
            

          • 将qsqlcipher.dll"和qsqlcipherd.dll"复制到SQL-driver-plugin-directory C:QtQt5.4.05.4mingw491_32pluginssqldrivers.莉>

            创建一个新的加密 SQLite/SQLCipher 数据库

            Create a new encrypted SQLite/SQLCipher-database

            • 使用测试表和一些测试数据创建新的 SQLite-Plaintext-database 'plaintext.db'

            • Create new SQLite-Plaintext-database 'plaintext.db' with a test table and some test data

            • 将目录更改为 C:sqlcipher,其中包含sqlcipher.exe"和sqlite3.dll"(见上文).

            • Change directory to C:sqlcipher, which contains 'sqlcipher.exe' and 'sqlite3.dll' (see above).

            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
            

          • 加密明文数据库
            这将使用密钥testkey"创建数据库 C:sqlcipherencrypted.db.

            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:sqlcipherencrypted.db:
            数据现已加密.
          • 有关更多有用信息,请访问:
            https://www.zetetic.net/sqlcipher/sqlcipher-api/莉>

            使用 SQLite 数据库和 SQLCipher 扩展并通过 Qt 访问

            Usage of the SQLite-database with SQLCipher-extension and access via Qt

            • 创建一个新的 Qt 命令行项目,例如'qsqlcipher'
            • 项目文件

            • Create a new Qt-command-line-project e.g. 'qsqlcipher'
            • Project file

            QT       += core sql
            QT       -= gui
            TARGET = qsqlcipher
            CONFIG   += console
            CONFIG   -= app_bundle
            TEMPLATE = app
            SOURCES += main.cpp
            

          • 测试程序'main.cpp'

          • Test-program '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;
            }
            

          • 编译执行

          • Compile and execute

            ("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".
            上面测试程序的例子:

          • When delivering a Qt-program do not forget the Qt-libraries, the platforms-libraries, SQL-driver-plugin 'qsqlcipher.dll' and the OpenSSL-library 'libeay32.dll'.
            Example for the test program above:

            C:TEMPQSQLCIPHER-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
            

          • 注意:测试程序包含密钥:

          • Caution: The test program contains the key:

            ...
            q.exec("PRAGMA key = 'testkey';");
            ...
            

            测试程序的二进制文件中的这个关键字符串可以使用十六进制编辑器轻松读取,在我看来,这缺乏安全性:

            This key string in the binary file of the test program can easiliy be read using a hex-editor, which is, to my opinion, a lack in security:

            ...
            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
            ...
            

            有关如何解决此问题的方法,请咨询您自己选择的搜索引擎.;-)
            例如.搜索:在可执行文件中隐藏字符串

            For approaches how to solve this problem, ask the search engine of your own choice. ;-)
            E.g. search for: hide string in executable

相关文章