- PVSM.RU - https://www.pvsm.ru -

Простая реализация шифрования и расшифровывания файлов в Qt

Приветствую, почтенное читатели.

Недавно столкнулся с необходимостью шифровать и расшифровывать файлы в Qt проекте. Основное условие – простота и прозрачность, так как, по сути, нужно заменить работу с файлами через QFile [1] на что-то, что может писать данные в зашифрованном виде и читать их из зашифрованного файла. В итоге родился небольшой класс. Затем появилось желание поделиться с общественностью им, может кому-то пригодится и сэкономит время, а может кто-то доработает его и изменит жизнь к лучшему.

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

Тот, кто уже знаком с Qt, и в частности с QIODevice [2], знает, какой это мощный инструмент для работы с устройствами ввода-вывода. Поэтому, практически сразу было принято решение взять этот класс за основу и отнаследоваться от него. Не буду подробно останавливаться на этом моменте, только отмечу, что основная «магия» заключается в переопределении методов

qint64 QIODevice::writeData(const char *data, qint64 len)

и

qint64 QIODevice::readData(char *data, qint64 len)

соответственно для записи данных и их чтения.

Чтобы указать, с каким файлом работать, у пользователя класса есть несколько способов:
1) Передать путь к файлу
2) Передать указатель на объект QFileDevice.

Если вам интересно, почему QFileDevice, а не QFile, то ответ прост. Чтобы можно было передавать такой полезный класс как QSaveFile [3].

После этого стал актуальным вопрос, какой инструмент использовать непосредственно для шифрования и расшифровывания данных? После недолгого исследования было принято решение остановиться на библиотеке OpenSSL потому что, во-первых, это один из лидеров в мире шифрования данных, во-вторых, наш проект уже использовал эту библиотеку для других задач.

Поэтому при выборе алгоритма шифрования было решено использовать симметричный алгоритм, т.к. он позволяет быстро шифровать данные блоками. Важным требованием к реализуемому классу было возможность писать в файл с любого места. В этой связи пришлось иметь в виду, чтобы зашифрованные данные не зависели от предыдущих или последующих данных. В свете всех ограничений, было решено выбрать алгоритм AES с режимом ECB [4]. Такой режим позволяет получить независимость конкретного блока данных от остальных, однако, уровень защищенности конечно падает. Пришлось смириться с этим. Стоит отметить, что сейчас пользователь может выбрать битность ключа 128, 192 или 256 бит (чем меньше битность, тем быстрее работает алгоритм, но становится при этом менее защищенным). Для шифрования с помощью OpenSSL использовались высокоуровневые EVP методы шифрования [5].

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

Из интересных моментов еще стоит отметить то, что класс может работать и с обычными файлами. Если не указать пароль, то с файлом будем работать также, как будто работаем с обычным QFile.

Для понимания работы с классом, я сделал два тестовых проекта.
Первый проект содержит выполнение основных операций с файлами. Для сравнения используется объект класс QFile, результаты которого проверяются с разработанным классом.
Второй проект показывает, как можно полезно организовать работы с зашифрованными файлами для конечного пользователя. В проекте реализовано шифрование выбранной пользователем картинки и последующее отображение ее в QWebView – файл зашифрован, но пользователь видит исходное изображение.

Использовать класс очень просто – копируете 2 файла (cryptfiledevice.cpp и cryptfiledevice.h) в ваш проект и можете уже работать с ним.

Зависимости на данный момент:
1) Qt >= 5.1.0 (так как для хеша пароля и соли используется SHA3)
2) Компилятор, поддерживающий c++11

Класс и тестовые проекты тестировались на Windows 7 (x86, x64), Ubuntu (x64) и MacOS X Mavericks.

Есть еще некоторые мысли, которые хотелось бы реализовать в будущем. Это реализация методов remove, rename, exists по аналогии с QFile, чтобы не подключать QFile, если нет в нем необходимости. Также, хотелось бы добавить метод, который позволит пользователю определить, является этот файл зашифрованным или нет. Надеюсь, что в скором будущем руки дойдут, и я добавлю этот функционал.
Плюс ко всему, можно будет подумать насчет работы с другими алгоритмами.

Исходники выложил в открытом доступе на GitHub под лицензией MIT. Берите, пользуйтесь, совершенствуйте на здоровье. Все предложения и пожелания можете отправлять на email или писать в issue tracker (вся информация есть в README на GitHub).

Ссылка на GitHub: CryptFileDevice [6]

Автор: tywonka

Источник [7]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/qt-2/71385

Ссылки в тексте:

[1] QFile: http://qt-project.org/doc/qt-5/qfile.html

[2] QIODevice: http://qt-project.org/doc/qt-5/qiodevice.html

[3] QSaveFile: http://qt-project.org/doc/qt-5/qsavefile.html

[4] ECB: http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation

[5] EVP методы шифрования: https://www.openssl.org/docs/crypto/evp.html

[6] CryptFileDevice: https://github.com/alexeylysenko/CryptFileDevice

[7] Источник: http://habrahabr.ru/post/240051/