Привязка SQLCipher к Qt
Материал из Wiki.crossplatform.ru
Содержание |
Краткое описание 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
Настройка MSYS
После инсталляции необходимо отредактировать файл fstab. Он находится в папке еtс (т.е. C:\msys\1.0\etc). Убедитесь, что определены следующие точки монтирования (они отображают каталоги MS Windows на точки монтирования в стиле Unix) :
c:/Qt/2010.05/mingw /mingw c:/Qt/2010.05/qt /qt c:/ /c
Конфигурирование и компиляция 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';"); то при запуске приложения мы получим сообщение об ошибке.