Привязка SQLCipher к Qt

Материал из Wiki.crossplatform.ru

(Различия между версиями)
Перейти к: навигация, поиск
(Установка и сборка SqlCipher.)
Строка 12: Строка 12:
<source lang="bash">
<source lang="bash">
-
#Создаём копию плагина sqlite с именем sqlcipher
+
    #Создаём копию плагина sqlite с именем sqlcipher
-
$ cd QTDIR/src/plugins/sqldrivers
+
    $ cd QTDIR/src/plugins/sqldrivers
-
$ cp -rf sqlite sqlcipher
+
    $ cp -rf sqlite sqlcipher
</source>
</source>
Строка 24: Строка 24:
Клонируем из репозитория исходники '''S'''ql'''C'''ipher. Для этого в Вашей системе должен быть установлен [http://git-scm.com/ git]. Клонирование производится в любое удобное место.
Клонируем из репозитория исходники '''S'''ql'''C'''ipher. Для этого в Вашей системе должен быть установлен [http://git-scm.com/ git]. Клонирование производится в любое удобное место.
<source lang="bash">
<source lang="bash">
-
$ git clone git://github.com/sjlombardo/sqlcipher.git
+
    $ git clone git://github.com/sjlombardo/sqlcipher.git
</source>
</source>
Далее, нам необходимо собрать '''S'''ql'''C'''ipher. Для этого выполняем следующие действия (не забываем изменить путь в --prefix)
Далее, нам необходимо собрать '''S'''ql'''C'''ipher. Для этого выполняем следующие действия (не забываем изменить путь в --prefix)
<source lang="bash">
<source lang="bash">
-
$ ./configure --prefix=/home/user/qtsdk/qt/src/plugins/sqldrivers/sqlcipher CFLAGS="-DSQLITE_HAS_CODEC" LDFLAGS="-lcrypto"
+
    $ ./configure --prefix=/home/user/qtsdk/qt/src/plugins/sqldrivers/sqlcipher CFLAGS="-DSQLITE_HAS_CODEC" LDFLAGS="-lcrypto"
-
$ make
+
    $ make
-
$ make install
+
    $ make install
</source>
</source>
Теперь в ''~/qtsdk/qt/src/plugins/sqldrivers'' у нас появилось структура каталогов '''bin''', '''include''', '''lib''' - которые необходимы нам для сборки нового sql плагина для '''Q'''t.
Теперь в ''~/qtsdk/qt/src/plugins/sqldrivers'' у нас появилось структура каталогов '''bin''', '''include''', '''lib''' - которые необходимы нам для сборки нового sql плагина для '''Q'''t.
-
 
=== Установка и сборка SqlCipher (Windows). ===
=== Установка и сборка SqlCipher (Windows). ===
-
 
==== Установка дополнительного ПО. ====
==== Установка дополнительного ПО. ====
Строка 44: Строка 42:
Скачиваем и устанавливаем [http://www.slproweb.com/download/Win32OpenSSL-0_9_8m.exe Win32 OpenSSL v0.9.8m]. Во время установки не менять место размещения dll-файлов.
Скачиваем и устанавливаем [http://www.slproweb.com/download/Win32OpenSSL-0_9_8m.exe Win32 OpenSSL v0.9.8m]. Во время установки не менять место размещения dll-файлов.
-
Так же нам потребуется [http://downloads.sourceforge.net/mingw/tcltk-8.4.1-1.exe TclTk] (специальная сборка для '''M'''in'''G'''W). Скачиваем, устанавливаем. Во время установки указываем путь до '''M'''in'''G'''W.
+
Так же нам потребуется [http://downloads.sourceforge.net/mingw/tcltk-8.4.1-1.exe TclTk] (специальная сборка для MinGW). Скачиваем, устанавливаем. Во время установки указываем путь до MinGW.
Находим файл MINGWPATH/bin/'''tclsh84.exe''' и переименивываем его в '''tclsh.exe'''
Находим файл MINGWPATH/bin/'''tclsh84.exe''' и переименивываем его в '''tclsh.exe'''
====Конфигурирование и компиляция sqlcipher====
====Конфигурирование и компиляция sqlcipher====
 +
Для сборки sqlcipher, запускаем MSYS и выполняем следущие действия (обязательно учитываем регистр при написании)
Для сборки sqlcipher, запускаем MSYS и выполняем следущие действия (обязательно учитываем регистр при написании)
<source lang="bash">
<source lang="bash">
-
$ cd sqlcipher
+
    $ cd sqlcipher
-
$ ./configure --prefix=/QTPATH/src/plugins/sqldrivers/sqlcipher --disable-tcl --disable-amalgamation
+
    $ ./configure --prefix=/QTPATH/src/plugins/sqldrivers/sqlcipher --disable-tcl --disable-amalgamation
-
CFLAGS="-DSQLITE_HAS_CODEC -I../OpenSSL/include /c/Windows/System32/libeay32.dll"
+
    CFLAGS="-DSQLITE_HAS_CODEC -I../OpenSSL/include /c/Windows/System32/libeay32.dll"
-
$ make
+
    $ make
-
$ make dll
+
    $ make dll
-
$ make install  
+
    $ make install  
-
$ cp /OPENSSLPATH/lib/MinGW/libeay32.a /QTPATH/src/plugins/sqldrivers/sqlcipher/lib
+
    $ cp /OPENSSLPATH/lib/MinGW/libeay32.a /QTPATH/src/plugins/sqldrivers/sqlcipher/lib
</source>
</source>
 +
 +
 +
==Создание нового sql плагина для Qt==
 +
 +
Переходим в заранее подготовленную директорию для создания нового sql плагина для Qt
 +
<source lang="bash">
 +
    $ cd ~/qtsdk/qt/src/plugins/sqlcipher
 +
</source>
 +
 +
Переименовываем файл проекта
 +
<source lang="bash">
 +
    $ mv sqlite.pro sqlcipher.pro
 +
</source>
 +
 +
Открываем в любом текстовом редакторе файл ''sqlcipher.pro''. Модифицируем его следующим образом
 +
<source lang="make">
 +
    TARGET = qsqlcipher
 +
 +
    HEADERS = ../../../sql/drivers/sqlite/qsql_sqlite.h
 +
    SOURCES = smain.cpp \
 +
    ../../../sql/drivers/sqlite/qsql_sqlite.cpp
 +
 +
    !system-sqlite:!contains( LIBS, .*sqlite.* ) {
 +
        CONFIG(release, debug|release):DEFINES *= NDEBUG
 +
        DEFINES += SQLITE_OMIT_LOAD_EXTENSION SQLITE_OMIT_COMPLETE
 +
 +
        INCLUDEPATH += include
 +
 +
        win32 {   
 +
            LIBS += ./lib/libsqlite3.a ./lib/libeay32.a   
 +
        }
 +
        unix {
 +
            QMAKE_RPATHDIR += lib
 +
            LIBS += -Llib -lsqlite3
 +
        }
 +
    } else {
 +
        LIBS *= $$QT_LFLAGS_SQLITE
 +
        QMAKE_CXXFLAGS *= $$QT_CFLAGS_SQLITE
 +
    }
 +
 +
    include(../qsqldriverbase.pri)
 +
</source>
 +
 +
 +
модифицируем файл ''smain.cpp''
 +
<source lang="cpp-qt">
 +
    #include <qsqldriverplugin.h>
 +
    #include <qstringlist.h>
 +
    #include "../../../../src/sql/drivers/sqlite/qsql_sqlite.h"
 +
 +
    QT_BEGIN_NAMESPACE
 +
 +
    class QSqlCipherDriverPlugin : public QSqlDriverPlugin
 +
    {
 +
    public:
 +
        QSqlCipherDriverPlugin();
 +
 +
        QSqlDriver* create(const QString &);
 +
        QStringList keys() const;
 +
    };
 +
 +
    QSqlCipherDriverPlugin::QSqlCipherDriverPlugin()
 +
        : QSqlDriverPlugin()
 +
    {
 +
    }
 +
 +
    QSqlDriver* QSqlCipherDriverPlugin::create(const QString &name)
 +
    {
 +
        if (name == QLatin1String("QSQLCIPHER")) {
 +
            QSQLiteDriver* driver = new QSQLiteDriver();
 +
            return driver;
 +
        }
 +
        return 0;
 +
    }
 +
 +
    QStringList QSqlCipherDriverPlugin::keys() const
 +
    {
 +
        QStringList l;
 +
        l  << QLatin1String("QSQLCIPHER");
 +
        return l;
 +
    }
 +
 +
    Q_EXPORT_STATIC_PLUGIN(QSQLiteDriverPlugin)
 +
    Q_EXPORT_PLUGIN2(qsqlcipher, QSqlCipherDriverPlugin)
 +
 +
    QT_END_NAMESPACE
 +
</source>
 +
 +
 +
Компилируем плагин
 +
<source lang="bash">
 +
    $ ~/qtsdk/qt/bin/qmake
 +
    $ make
 +
    $ make install
 +
</source>
 +
 +
В каталоге ''~/qtsdk/qt/plugins/sqldrivers'' у Вас должен появиться файл '''libqsqlcipher.so'''
 +
 +
==Создание тестового приложения==
 +
 +
<source lang="bash">
 +
    $ cd /home/user/qtsdk/qt/examples/sql/sqlwidgetmapper
 +
</source>
 +
 +
В качестве тестого приложения нам подойдет стандартный пример из поставки '''Q'''t ''sqlwidgetmapper''. Необходимо только немного модифицировать в файле ''window.cpp'' метод '''setupModel'''
 +
<source lang="cpp-qt">
 +
    void Window::setupModel()
 +
    {
 +
        QSqlDatabase db = QSqlDatabase::addDatabase("QSQLCIPHER");
 +
 +
        if (!QFile::exists("test.db")) {
 +
            db.setDatabaseName("test.db");
 +
            if (!db.open()) {
 +
                QMessageBox::critical(0, tr("Cannot open database"),
 +
                    tr("Unable to establish a database connection.\n"
 +
                      "This example needs SQLCipher support."),
 +
                        QMessageBox::Cancel);
 +
                return;
 +
            }
 +
 +
            QSqlQuery query;
 +
            query.exec("pragma key = '12345';");
 +
            query.exec("create table person (id int primary key, "
 +
                      "name varchar(20), address varchar(200), typeid int)");
 +
            query.exec("insert into person values(1, 'Alice', "
 +
                      "'<qt>123 Main Street<br/>Market Town</qt>', 101)");
 +
            query.exec("insert into person values(2, 'Bob', "
 +
                      "'<qt>PO Box 32<br/>Mail Handling Service"
 +
                      "<br/>Service City</qt>', 102)");
 +
            query.exec("insert into person values(3, 'Carol', "
 +
                      "'<qt>The Lighthouse<br/>Remote Island</qt>', 103)");
 +
            query.exec("insert into person values(4, 'Donald', "
 +
                      "'<qt>47338 Park Avenue<br/>Big City</qt>', 101)");
 +
            query.exec("insert into person values(5, 'Emma', "
 +
                      "'<qt>Research Station<br/>Base Camp<br/>"
 +
                      "Big Mountain</qt>', 103)");
 +
        //! [Set up the main table]
 +
 +
        //! [Set up the address type table]
 +
            query.exec("create table addresstype (id int, description varchar(20))");
 +
            query.exec("insert into addresstype values(101, 'Home')");
 +
            query.exec("insert into addresstype values(102, 'Work')");
 +
            query.exec("insert into addresstype values(103, 'Other')");
 +
        } else {
 +
            db.setDatabaseName("test.db");
 +
            if (!db.open()) {
 +
                QMessageBox::critical(0, tr("Cannot open database"),
 +
                    tr("Unable to establish a database connection.\n"
 +
                      "This example needs SQLCipher support."),
 +
                        QMessageBox::Cancel);
 +
                return;
 +
            }
 +
 +
            QSqlQuery query;
 +
            query.exec("pragma key = '12345';");
 +
 +
            {//===-Test-===
 +
                query.exec("select * from addresstype;");
 +
                if (query.lastError().type() != QSqlError::NoError) {
 +
                    QMessageBox::critical(0, tr("Cannot open database"),
 +
                        tr("%1").arg(query.lastError().text()), QMessageBox::Cancel);
 +
                    return;
 +
                }
 +
            }
 +
        }
 +
 +
        model = new QSqlRelationalTableModel(this);
 +
        model->setTable("person");
 +
        model->setEditStrategy(QSqlTableModel::OnManualSubmit);
 +
 +
        typeIndex = model->fieldIndex("typeid");
 +
 +
        model->setRelation(typeIndex,
 +
              QSqlRelation("addresstype", "id", "description"));
 +
        model->select();
 +
    }
 +
</source>
 +
 +
<source lang="bash">
 +
    $ ~/soft/qtsdk-2010.02/qt/bin/qmake
 +
    $ make
 +
 +
    $ ./sqlwidgetmapper
 +
</source>
 +
 +
После закрытия программы, открываем файл '''test.db''' и видим что все данные у нас зашифрованы. При повторном запуске программы БД так же доступна. А вот если закомментировать '''''query.exec("pragma key = '12345';");''''' то при запуске приложения мы получим сообщение об ошибке.
 +
 +
 +
== Обсуждение ==
 +
[http://www.forum.crossplatform.ru/index.php?showtopic=4577&hl=sqlcipher Обсудить на форуме...]
 +
[[Категория:Qt FAQ]]

Версия 20:27, 23 апреля 2010

Содержание

Краткое описание SQLCipher.

SQLCipher - это кроссплатформенное расширение SQLite, с открытым исходным кодом. Она зашифровывает страницы базы данных прежде чем они записываются для хранения и дешифрует их во время чтения. Т.о. SQLCipher предоставляет полностью зашифрованную SQLite базу данных. При этом, пользователю не требуется обладать специальными знаниями лежащими в основе безопасности баз данных. Приложение будет использовать стандартное API для манипуляции таблицами используя SQL.За кулисами библиотека сама молча управляет аспектами безопасности.

Подробнее о SQLCipher смотрите на сайте разработчика. [1]

Подготовка к интеграции.

Для того что бы получить возможность использовать SQLCipher в своем приложении на Qt, нам потребуется пересобрать существующий qsqlite плагин, внеся в исходный код этого плагина незначительные изменения.

Не смотря на то, что SQLCipher можно использовать без шифрования, т.е. как обычную SQLite базу данных, тем не менее, давайте не будем трогать существующий плагин для SQLite, а сделаем на его основе новый.

    #Создаём копию плагина sqlite с именем sqlcipher
    $ cd QTDIR/src/plugins/sqldrivers
    $ cp -rf sqlite sqlcipher


Установка и сборка SqlCipher.

Установка и сборка SqlCipher (Linux).

Клонируем из репозитория исходники SqlCipher. Для этого в Вашей системе должен быть установлен git. Клонирование производится в любое удобное место.

    $ git clone git://github.com/sjlombardo/sqlcipher.git

Далее, нам необходимо собрать SqlCipher. Для этого выполняем следующие действия (не забываем изменить путь в --prefix)

    $ ./configure --prefix=/home/user/qtsdk/qt/src/plugins/sqldrivers/sqlcipher CFLAGS="-DSQLITE_HAS_CODEC" LDFLAGS="-lcrypto"
    $ make
    $ make install

Теперь в ~/qtsdk/qt/src/plugins/sqldrivers у нас появилось структура каталогов bin, include, lib - которые необходимы нам для сборки нового sql плагина для Qt.

Установка и сборка SqlCipher (Windows).

Установка дополнительного ПО.

Скачиваем и устанавливаем на свой компьютер MSYS. В конце установки будет задано несколько вопросов, соглашаемся с ними и указываем путь до MinGW (входит в поставку Qt).

Скачиваем и устанавливаем Win32 OpenSSL v0.9.8m. Во время установки не менять место размещения dll-файлов.

Так же нам потребуется TclTk (специальная сборка для MinGW). Скачиваем, устанавливаем. Во время установки указываем путь до MinGW. Находим файл MINGWPATH/bin/tclsh84.exe и переименивываем его в tclsh.exe

Конфигурирование и компиляция sqlcipher

Для сборки sqlcipher, запускаем MSYS и выполняем следущие действия (обязательно учитываем регистр при написании)

    $ cd sqlcipher
    $ ./configure --prefix=/QTPATH/src/plugins/sqldrivers/sqlcipher --disable-tcl --disable-amalgamation
    CFLAGS="-DSQLITE_HAS_CODEC -I../OpenSSL/include /c/Windows/System32/libeay32.dll"
    $ make
    $ make dll
    $ make install 
    $ cp /OPENSSLPATH/lib/MinGW/libeay32.a /QTPATH/src/plugins/sqldrivers/sqlcipher/lib


Создание нового sql плагина для Qt

Переходим в заранее подготовленную директорию для создания нового sql плагина для Qt

    $ cd ~/qtsdk/qt/src/plugins/sqlcipher

Переименовываем файл проекта

    $ mv sqlite.pro sqlcipher.pro

Открываем в любом текстовом редакторе файл sqlcipher.pro. Модифицируем его следующим образом

    TARGET = qsqlcipher
 
    HEADERS = ../../../sql/drivers/sqlite/qsql_sqlite.h
    SOURCES = smain.cpp \
    ../../../sql/drivers/sqlite/qsql_sqlite.cpp
 
    !system-sqlite:!contains( LIBS, .*sqlite.* ) {
        CONFIG(release, debug|release):DEFINES *= NDEBUG
        DEFINES += SQLITE_OMIT_LOAD_EXTENSION SQLITE_OMIT_COMPLETE
 
        INCLUDEPATH += include
 
        win32 {    
            LIBS += ./lib/libsqlite3.a ./lib/libeay32.a    
        }
        unix {
            QMAKE_RPATHDIR += lib
            LIBS += -Llib -lsqlite3
        }
    } else {
        LIBS *= $$QT_LFLAGS_SQLITE
        QMAKE_CXXFLAGS *= $$QT_CFLAGS_SQLITE
    }
 
    include(../qsqldriverbase.pri)


модифицируем файл smain.cpp

    #include <qsqldriverplugin.h>
    #include <qstringlist.h>
    #include "../../../../src/sql/drivers/sqlite/qsql_sqlite.h"
 
    QT_BEGIN_NAMESPACE
 
    class QSqlCipherDriverPlugin : public QSqlDriverPlugin
    {
    public:
        QSqlCipherDriverPlugin();
 
        QSqlDriver* create(const QString &);
        QStringList keys() const;
    };
 
    QSqlCipherDriverPlugin::QSqlCipherDriverPlugin()
        : QSqlDriverPlugin()
    {
    }
 
    QSqlDriver* QSqlCipherDriverPlugin::create(const QString &name)
    {
        if (name == QLatin1String("QSQLCIPHER")) {
            QSQLiteDriver* driver = new QSQLiteDriver();
            return driver;
        }
        return 0;
    }
 
    QStringList QSqlCipherDriverPlugin::keys() const
    {
        QStringList l;
        l  << QLatin1String("QSQLCIPHER");
        return l;
    }
 
    Q_EXPORT_STATIC_PLUGIN(QSQLiteDriverPlugin)
    Q_EXPORT_PLUGIN2(qsqlcipher, QSqlCipherDriverPlugin)
 
    QT_END_NAMESPACE


Компилируем плагин

    $ ~/qtsdk/qt/bin/qmake
    $ make
    $ make install

В каталоге ~/qtsdk/qt/plugins/sqldrivers у Вас должен появиться файл libqsqlcipher.so

Создание тестового приложения

    $ cd /home/user/qtsdk/qt/examples/sql/sqlwidgetmapper

В качестве тестого приложения нам подойдет стандартный пример из поставки Qt sqlwidgetmapper. Необходимо только немного модифицировать в файле window.cpp метод setupModel

    void Window::setupModel()
    {
        QSqlDatabase db = QSqlDatabase::addDatabase("QSQLCIPHER");
 
        if (!QFile::exists("test.db")) {
            db.setDatabaseName("test.db");
            if (!db.open()) {
                QMessageBox::critical(0, tr("Cannot open database"),
                    tr("Unable to establish a database connection.\n"
                       "This example needs SQLCipher support."),
                        QMessageBox::Cancel);
                return;
            }
 
            QSqlQuery query;
            query.exec("pragma key = '12345';");
            query.exec("create table person (id int primary key, "
                       "name varchar(20), address varchar(200), typeid int)");
            query.exec("insert into person values(1, 'Alice', "
                       "'<qt>123 Main Street<br/>Market Town</qt>', 101)");
            query.exec("insert into person values(2, 'Bob', "
                       "'<qt>PO Box 32<br/>Mail Handling Service"
                       "<br/>Service City</qt>', 102)");
            query.exec("insert into person values(3, 'Carol', "
                       "'<qt>The Lighthouse<br/>Remote Island</qt>', 103)");
            query.exec("insert into person values(4, 'Donald', "
                       "'<qt>47338 Park Avenue<br/>Big City</qt>', 101)");
            query.exec("insert into person values(5, 'Emma', "
                       "'<qt>Research Station<br/>Base Camp<br/>"
                       "Big Mountain</qt>', 103)");
        //! [Set up the main table]
 
        //! [Set up the address type table]
            query.exec("create table addresstype (id int, description varchar(20))");
            query.exec("insert into addresstype values(101, 'Home')");
            query.exec("insert into addresstype values(102, 'Work')");
            query.exec("insert into addresstype values(103, 'Other')");
        } else {
            db.setDatabaseName("test.db");
            if (!db.open()) {
                QMessageBox::critical(0, tr("Cannot open database"),
                    tr("Unable to establish a database connection.\n"
                       "This example needs SQLCipher support."),
                        QMessageBox::Cancel);
                return;
            }
 
            QSqlQuery query;
            query.exec("pragma key = '12345';");
 
            {//===-Test-===
                query.exec("select * from addresstype;");
                if (query.lastError().type() != QSqlError::NoError) {
                    QMessageBox::critical(0, tr("Cannot open database"),
                        tr("%1").arg(query.lastError().text()), QMessageBox::Cancel);
                    return;
                }
            }
        }
 
        model = new QSqlRelationalTableModel(this);
        model->setTable("person");
        model->setEditStrategy(QSqlTableModel::OnManualSubmit);
 
        typeIndex = model->fieldIndex("typeid");
 
        model->setRelation(typeIndex,
               QSqlRelation("addresstype", "id", "description"));
        model->select();
    }
    $ ~/soft/qtsdk-2010.02/qt/bin/qmake
    $ make
 
    $ ./sqlwidgetmapper

После закрытия программы, открываем файл test.db и видим что все данные у нас зашифрованы. При повторном запуске программы БД так же доступна. А вот если закомментировать query.exec("pragma key = '12345';"); то при запуске приложения мы получим сообщение об ошибке.


Обсуждение

Обсудить на форуме...