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

Woo*_*ker 5 sqlite encryption qt mingw sqlcipher

这通常不是一个问题,在哪里可以找到分步指南,而是指导本身.
我对这篇文章的意图是给别人一个提示,他在编译驱动程序插件方面遇到的问题和我最近的问题一样.

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

Éti*_*nne 5

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

  1. 适用于Windows / MinGW的Qt 5.4.0

    • 下载Qt
    • 安装包括源,例如 C:\Qt\Qt5.4.0
  2. 适用于Windows的OpenSSL

    • 下载Win32 OpenSSL v1.0.2a
    • 下载Visual C ++ 2008可再发行组件
    • 通过执行'vcredist_x86.exe'安装Visual C ++ 2008可再发行组件
    • 通过执行'Win32OpenSSL-1_0_2.exe'安装OpenSSL v1.0.2a
      • 目标目录,例如 C:\OpenSSL-Win32
      • 在安装过程中,选择将库安装到Windows系统目录的选项(C:\Windows\SysWOW64
  3. MinGW-Windows的极简GNU

    • 下载并安装“ mingw-get-setup.exe”
    • MinGW安装程序的启动
      • 安装MSYS基本系统
        • 选择:所有软件包-> MSYS-> MSYS基本系统
        • 选择基于msys的库(“ 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
    • 在以下位置创建文件“ fstab” C:\Qt\Qt5.4.0\Tools\mingw491_32\msys\1.0\etc

  4. zlib-库

    • 下载zlib-dll-二进制文件
    • 提取文件“ zlib1.dll”并将其复制到Qt-MinGW目录 C:\Qt\Qt5.4.0\Tools\mingw491_32\msys\1.0\bin
  5. SQL密码

    • 下载SQLCipher-zip文件
    • 提取压缩文件,例如 C:\temp\sqlcipher-master
    • 复制OpenSSL-Win32库
      • 复制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
        
        Run Code Online (Sandbox Code Playgroud)
    • 保存可执行的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数据库现在可以工作了。
  6. 构建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"
        
        Run Code Online (Sandbox Code Playgroud)
      • 文件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)
        
        Run Code Online (Sandbox Code Playgroud)
      • 文件3:sqlcipher.json

        {
            "Keys": [ "QSQLCIPHER" ]
        }
        
        Run Code Online (Sandbox Code Playgroud)
    • 复制目录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
      }
      
      Run Code Online (Sandbox Code Playgroud)
    • 此目录中的其余两个文件无需更改。
    • 在目录中创建文件“ sqlcipher.pri”,C:\Qt\Qt5.4.0\5.4\Src\qtbase\src\3rdparty其内容如下:

      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/*
      
      Run Code Online (Sandbox Code Playgroud)
    • 创建并填写 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
        
        Run Code Online (Sandbox Code Playgroud)
      • 将以下文件复制到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
        
        Run Code Online (Sandbox Code Playgroud)
      • 将以下文件/目录复制到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
        
        Run Code Online (Sandbox Code Playgroud)
      • 该目录现在包含以下文件和目录:

        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
        
        Run Code Online (Sandbox Code Playgroud)
    • 为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
        
        Run Code Online (Sandbox Code Playgroud)
      • 这将在以下目录中构建QSQLCIPHER-driver-plugin:

        C:\QT\QT5.4.0\5.4\SRC\QTBASE\PLUGINS\SQLDRIVERS
            libqsqlcipher.a
            libqsqlcipherd.a
            qsqlcipher.dll
            qsqlcipherd.dll
        
        Run Code Online (Sandbox Code Playgroud)
      • 将“ qsqlcipher.dll”和“ qsqlcipherd.dll”复制到SQL-driver-plugin-directory C:\Qt\Qt5.4.0\5.4\mingw491_32\plugins\sqldrivers
  7. 创建一个新的加密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
        
        Run Code Online (Sandbox Code Playgroud)
    • C:\sqlcipher\plaintext.db使用标准的文本编辑器打开:
      数据库方案和测试数据可以以纯文本格式读取。
    • 加密明文数据库
      这将C:\sqlcipher\encrypted.db使用密钥“ 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
      
      Run Code Online (Sandbox Code Playgroud)
    • C:\sqlcipher\encrypted.db使用标准的文本编辑器打开:
      数据现已加密。
    • 有关更多有用的信息,请访问:https :
      //www.zetetic.net/sqlcipher/sqlcipher-api/
  8. 结合使用SQLite数据库和SQLCipher-extension和通过Qt访问

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

      QT       += core sql
      QT       -= gui
      TARGET = qsqlcipher
      CONFIG   += console
      CONFIG   -= app_bundle
      TEMPLATE = app
      SOURCES += main.cpp
      
      Run Code Online (Sandbox Code Playgroud)
    • 测试程序“ 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;
      }
      
      Run Code Online (Sandbox Code Playgroud)
    • 编译并执行

      ("QSQLCIPHER", "QSQLITE", "QMYSQL", "QMYSQL3", "QODBC", "QODBC3", "QPSQL", "QPSQL7")
      id= "1" ,  name= "Bob"
      id= "2" ,  name= "Charlie"
      id= "3" ,  name= "Daphne"
      id= "4" ,  name= "dummy"
      
      Run Code Online (Sandbox Code Playgroud)
    • 提供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
      
      Run Code Online (Sandbox Code Playgroud)
    • 警告:测试程序包含以下密钥:

      ...
      q.exec("PRAGMA key = 'testkey';");
      ...
      
      Run Code Online (Sandbox Code Playgroud)

      可以使用十六进制编辑器轻松读取测试程序的二进制文件中的此密钥字符串,我认为这是缺乏安全性的:

      ...
      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
      ...
      
      Run Code Online (Sandbox Code Playgroud)

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