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

时间:2015-03-22 15:20:15

标签: qt sqlite encryption mingw sqlcipher

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

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

1 个答案:

答案 0 :(得分:4)

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

  1. Qt 5.4.0 for Windows / MinGW

    • 下载Qt
    • 安装包括来源,例如C:\Qt\Qt5.4.0
  2. 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:\Windows\SysWOW64
      • 的选项
  3. MinGW - 适用于Windows的极简GNU

    • 下载并安装' mingw-get-setup.exe'
    • 启动MinGW安装程序
      • 安装MSYS Base System
        • 选择:所有包裹 - > MSYS - > MSYS基础系统
        • 选择msys-base(Class' bin')进行安装
        • 菜单:安装 - >应用更改
        • 默认情况下将文件安装到目录C:\MinGW
      • 安装Tcl / Tk
        • 选择:所有包裹 - > MinGW - > MinGW贡献
        • 选择' mingw32-tcl'和' mingw32-tk' (Class' 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

      • 按如下方式插入内容:

        #Win32_Path                        Mount_Point
        C:/Qt/Qt5.4.0/Tools/mingw491_32    /mingw
        C:/Qt/Qt5.4.0/5.4                  /qt
        C:/                                /c
        
  4. zlib的库

    • 下载zlib-dll-Binaries
    • 提取并复制文件' zlib1.dll'到Qt-MinGW目录C:\Qt\Qt5.4.0\Tools\mingw491_32\msys\1.0\bin
  5. SQLCipher

    • 下载SQLCipher-zip-file
    • 解压缩zip文件,例如到C:\temp\sqlcipher-master
    • 复制OpenSSL-Win32-libraries
      • 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-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"
        
      • 文件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
      }
      
    • 无需更改此目录中的其余两个文件。
    • 创建文件&#39; sqlcipher.pri&#39;目录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/*
      
    • 创建并填写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
        
      • 复制&#39; qsqlcipher.dll&#39;和&#39; qsqlcipherd.dll&#39;到SQL-driver-plugin-directory C:\Qt\Qt5.4.0\5.4\mingw491_32\plugins\sqldrivers
  7. 创建新的加密SQLite / SQLCipher数据库

    • 创建新的SQLite-Plaintext-database&#39; plaintext.db&#39;带有测试表和一些测试数据

      • 将目录更改为C:\sqlcipher,其中包含&#39; sqlcipher.exe&#39;和&#39; sqlite3.dll&#39; (见上文)。

        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
      数据库方案和测试数据可以用明文读取。
    • 加密明文数据库
      这将使用密钥&#39; testkey&#39;来创建数据库C:\sqlcipher\encrypted.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:\sqlcipher\encrypted.db
      数据现已加密。
    • 有关更多有用信息,请访问:
      https://www.zetetic.net/sqlcipher/sqlcipher-api/
  8. 使用带有SQLCipher扩展的SQLite数据库并通过Qt访问

    • 创建一个新的Qt命令行项目,例如&#39; qsqlcipher&#39;
    • 项目文件

      QT       += core sql
      QT       -= gui
      TARGET = qsqlcipher
      CONFIG   += console
      CONFIG   -= app_bundle
      TEMPLATE = app
      SOURCES += main.cpp
      
    • 测试程序&#39; main.cpp&#39;

      #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&#39;和OpenSSL-library&#39; libeay32.dll&#39; 以上测试程序的示例:

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

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