A simple implementation of encryption and decryption files in Qt
-
Hi, Qt community.
Recently faced with the need to encrypt and decrypt files in Qt project. The main condition - simplicity and transparency, as, in fact, need to replace work with files via "QFile":http://qt-project.org/doc/qt-5/qfile.html to something that can write the encrypted data and read from the encrypted file. In the end, was born a small class. Then I desire to share it with the community, maybe it can someone come in handy and save time, and maybe someone will improve it and change lives for the better.
The main point, as I have already said, was simple and transparent work with the class. I.e. the class should be able to write encrypted data, and to read the original data from the encrypted file.
One who is already familiar with Qt and in particular with "QIODevice":http://qt-project.org/doc/qt-5/qiodevice.html knows that it’s a powerful tool for working with input/output devices. Therefore, almost immediately it was decided to take this class as a basic and inherited from QIODevice. I’m not going to dwell on this moment, just note that the main "magic" is in the overriding methods
@qint64 QIODevice::writeData(const char *data, qint64 len);
qint64 QIODevice::readData(char *data, qint64 len);@respectively for writing and reading data.
To specify which file to work, the user class has a few methods:
- set path to the file
- set the pointer to the QFileDevice object.
If you're wondering why I use QFileDevice, not QFile, then the answer is simple. So user can pass such a useful class as "QSaveFile":http://qt-project.org/doc/qt-5/qsavefile.html.
After that was the actual question, what tool can be used directly to encrypt and decrypt data? After some research it was decided to stay on the OpenSSL library because, first, it is one of the leaders in the world of encryption, secondly, our project has already used this library for other tasks.
Therefore, the choice of encryption algorithm, it was decided to use a symmetric algorithm, because it allows you to quickly encrypt data blocks. An important requirement implemented the class was able to write to a file from any location. Consequently, we had to keep in mind that encrypted data is not dependent on previous or subsequent data. Given all the restrictions, it was decided to choose AES algorithm with "CTR mode":http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation. This mode allows you to be independent of the particular data block from the rest data blocks, however, the level of protection of course falls. Had to put up with it. It is worth noting that now the user can select bits key 128, 192 or 256 bits (the lower the better, the faster the algorithm, but is becoming less secure). For encryption using OpenSSL was used a high-level "EVP cipher":https://www.openssl.org/docs/crypto/evp.html and AES_encrypt/AES_decrypt methods.
During the implementation of the class came up with the idea to make a header for the encrypted file, and to store some of the necessary things, for example, the hash from the password and salt to control them correctly when opening the file. Of course, in any case, with an incorrect password and salt the user will not be able to correct read file. But we decided to check it when opening a file in order to the user was sure that if he opened correctly encrypted file, it will work eventually with the correct data source.
One of the interesting points it is worth noting that the class can work with plain files. If you do not specify a password, the file will work as if working with plain QFile.
To understand how class works, I made two test projects.
The first project contains the basic operations with files. For comparison I used the QFile object. All results are checked with QFile object results.
The second project shows how it is useful to organize work with the encrypted files to the end user. In the project I encrypt user-selected images and then display it in QWebView. File is encrypted, but the user sees the original image.To use the class is very simple - just copy 2 files (cryptfiledevice.cpp and cryptfiledevice.h) in your project and can work with him. Current dependencies:
- Qt >= 5.1.0 (because the password hash and salt is used SHA3)
- compiler that supports c++11
The class and test projects was tested on Windows 7 (x86, x64), Ubuntu (x64) and Mac OS X Mavericks.
There are some thoughts that I would like to implement in the future. Implement methods rename, exists by analogy with QFile, not to include QFile, if there is no need for it. Also, I would like to add a method that will allow the user to determine whether the file is encrypted or not. I hope that in the near future reach the hands and I will add this functionality.
Also, I want to think about working with other algorithms.Source posted on GitHub under the MIT license. Take, use, improve health. All suggestions can be sent to email or write to the issue tracker (all information is in the README).
Link to GitHub: "CryptFileDevice":https://github.com/alexeylysenko/CryptFileDevice
This article in "Russian":http://habrahabr.ru/post/240051/p.s. Sorry for my English.
-
Looks amazing, mate, but I am afraid that you posted it in the wrong forum. There is a subforum called "Announcements" and it's more or less related to what you are talking about.
P.S. I tried to move this post, but dunno why, I can't do that now, for some reason :\
-
Hi and welcome to devnet,
Looks nice ! One thing that would be great is to have is the possibility to build it as a library without having to do all the OpenSSL setup for each project.
You could to this by using e.g. the PIMPL paradigm
-
Thanks, SGaist. I will think about this question.
-
@lysenkoalex Thank you for this very useful contribution, I used it in my project.
I have a problem when running the application it also open the command promt window with it. I don't have this problem before using this encryption.
QFile encryptedFile("digiTecData.encrypted"); QFile file(QDir::tempPath() + "memory"); CryptFileDevice cryptFileDevice(&encryptedFile, "01234567890123456789012345678901", "0123456789012345"); cryptFileDevice.open(QIODevice::ReadOnly); file.open(QIODevice::WriteOnly); file.write(cryptFileDevice.readAll()); file.close(); cryptFileDevice.close();
-
Hi, @4j1th
I apologize for not answering your question. I just didn't see it.Let's try to figure out what the problem is. I suggest you always to check result after open any QIODevice object.
So, you should try smth like this:
if (!cryptFileDevice.open(QIODevice::ReadOnly)) { qCritical() << "Cannot open cryptFileDevice"; } if (!file.open(QIODevice::WriteOnly)) { qCritical() << "Cannot open file"; }
Please, try it and write me the result.
Best regards, Aleksey.