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

8

这通常不是一个寻找一步一步指南的问题,而是指南本身。

我写这篇文章的目的是为了给其他人提供一些提示,他们在编译驱动程序插件时遇到与我类似的问题。

如何在Windows/MinGW平台上构建Qt-SQL-driver-plugin“QSQLCIPHER”以使用带有SQLCipher扩展的SQLite-DB?


4
必须遵循StackOverflow的问题和回答格式。建议您将答案发布为实际答案,放在您的问题下面,并将问题简化为一个实际问题(您需要稍等一会儿)。最好在问题中添加一些您遇到的问题,以便清楚地表明您已经尝试解决问题(我知道您已经解决了问题,但问题必须独立存在,不能依赖于可能的答案,即使您已经有了一个答案)。请参阅:http://meta.stackexchange.com/questions/17463 - Artjom B.
如果在第5步中遇到gawk抱怨“反斜杠不是行上的最后一个字符”的问题,则请转到两个makeopcode?.awk文件中修复您的行结束符为Unix格式。 - André
教程非常有用,但是在按照您设置的所有步骤后,我停在了这里:D:\Qt\5.5.1\5.5\src\qtbase\src\plugins\sqldrivers\sqlcipher>mingw32-make mingw32-make -f Makefile.Release all mingw32-make[1]: 进入目录 'D:/Qt/5.5.1/5.5/src/qtbase/src/plugins/sqldrivers/sqlcipher' mingw32-make[1]: *** 没有指定规则来制作目标“release/smain.moc”,需要“release/smain.o”。 停止。 mingw32-make[1]: 离开目录 'D:/Qt/5.5.1/5.5/src/qtbase/src/plugins/sqldrivers/sqlcipher' makefile:38: 目标“release-all”的规则失败 mingw32-make: *** [release-all] 错误 2 - H Aßdøµ
该驱动程序是在Windows 7下构建的,并且在Windows 8.1下也可以运行。但我对其他Windows版本没有经验。@rrrfusco:或者您是否在询问其他操作系统,如Linux?这是不可行的。 - Woodpecker
@rrrfusco:抱歉,我无法直接回答您的问题。我已在Windows 7(64位)上构建了驱动程序,并且该驱动程序也可以在Windows 8.1(64位)上运行。但是我没有在32位Windows上的经验。您的XP和Win8系统是否为32位?我将尝试获取一个32位系统来测试我的驱动程序并给出答案。 - Woodpecker
1个回答

12
如何使用Windows/MinGW平台构建带有SQLCipher扩展的SQLite数据库的Qt-SQL-driver插件“QSQLCIPHER”:
  1. 下载Qt 5.4.0 for Windows/MinGW,并安装包括源代码,例如到 C:\Qt\Qt5.4.0

  2. 下载OpenSSL for Windows,并安装Visual C++ 2008 Redistributable, 执行 'vcredist_x86.exe' 安装

    • 下载Win32 OpenSSL v1.0.2a
    • 执行 'Win32OpenSSL-1_0_2.exe' 安装
      • 目标目录例如: C:\OpenSSL-Win32
      • 在安装过程中选择将库安装到Windows系统目录( C:\Windows\SysWOW64
  3. 下载并安装Minimalist GNU for Windows(MinGW)的'mingw-get-setup.exe'

    • 启动MinGW Installer
      • 安装MSYS Base System
        • 选择:All Packages -> MSYS -> MSYS Base System
        • 选择msys-base (Class 'bin')进行安装
        • 菜单:installation -> apply changes
        • 文件默认安装到目录C:\MinGW
      • 安装Tcl/Tk
        • 选择:All Packages -> MinGW -> MinGW Contributed
        • 选择 'mingw32-tcl' 和 'mingw32-tk' (Class 'bin') 进行安装
        • 菜单:installation -> apply changes
        • 文件默认安装到目录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-Library

        • 下载 zlib-dll 二进制文件
        • 解压缩并将文件 'zlib1.dll' 复制到 Qt-MinGW 目录 C:\Qt\Qt5.4.0\Tools\mingw491_32\msys\1.0\bin
      • SQLCipher

        • 下载 SQLCipher 压缩文件
        • 将压缩文件解压缩,例如解压到 C:\temp\sqlcipher-master
        • 复制 OpenSSL Win32 库
          • C:\OpenSSL-Win32\bin\libeay32.dll 复制到 C:\temp\sqlcipher-master
          • C:\OpenSSL-Win32\lib\libeay32.lib 复制到 C:\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.exe复制到C:\sqlcipher
            文件'sqlcipher.exe'是非加密原始命令行界面'sqlite3.exe'的加密等效物。
          • C:\temp\sqlcipher-master\sqlite3.dll复制到C:\sqlcipher
            此文件是通过加密扩展的SQLite库。
        • 具有SQLCipher扩展名的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\sqlite复制到C:\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驱动程序插件:

          • 打开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驱动程序插件:
          C:\QT\QT5.4.0\5.4\SRC\QTBASE\PLUGINS\SQLDRIVERS
              libqsqlcipher.a
              libqsqlcipherd.a
              qsqlcipher.dll
              qsqlcipherd.dll
          
        • 将 'qsqlcipher.dll' 和 'qsqlcipherd.dll' 复制到 SQL 驱动插件目录 C:\Qt\Qt5.4.0\5.4\mingw491_32\plugins\sqldrivers
      • 创建一个新的加密 SQLite/SQLCipher 数据库

        • 创建新的 SQLite 明文数据库 'plaintext.db' 并添加测试表和测试数据

          • 更改目录为包含 'sqlcipher.exe' 和 'sqlite3.dll' 的目录 C:\sqlcipher (参见上文)。

    • 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
      
  4. 使用标准文本编辑器打开C:\sqlcipher\plaintext.db
    数据库结构和测试数据可以以明文形式读取。
  5. 加密明文数据库
    这将使用密钥'testkey'创建数据库C:\sqlcipher\encrypted.db

  6. 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
    
  7. 使用标准文本编辑器打开C:\sqlcipher\encrypted.db
  8. 数据现在已加密。
  9. 获取更多有用信息请访问:https://www.zetetic.net/sqlcipher/sqlcipher-api/
  10. 使用带有SQLCipher扩展和通过Qt访问的SQLite数据库

    • 创建一个新的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
      
      注意:测试程序包含密钥:
      ...
      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
      ...
      

      要解决这个问题,可以询问你自己选择的搜索引擎的方法。;-)
      例如,搜索以下内容:在可执行文件中隐藏字符串


很棒!顺便说一下:不要在代码中硬编码密钥,动态生成它。 - Fan Yang
你好, 我想在Qt 5.9及以上版本中完成这项工作。我该怎么做呢?因为Qt的新版本中结构已经发生了变化。非常感谢任何帮助。 - Ahmad
@Ahmad,你是否成功构建了qsqlcipher.dll?能否提供一下步骤? - Veera
@Veera,是的,最终我成功地构建了它,并构建了Qt插件以在QT中使用它。我怎样才能将一些信息发送给你? - Ahmad

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接