Add FileEncryptJob and FileDecryptJob

This handles encryption and decryption of files.
Just create the job and start off.

Signed-off-by: Roeland Jago Douma <roeland@famdouma.nl>
This commit is contained in:
Roeland Jago Douma 2017-12-14 16:54:56 +01:00
parent 82c07236c1
commit be3afd1291
No known key found for this signature in database
GPG key ID: F941078878347C0C
2 changed files with 223 additions and 0 deletions

View file

@ -26,6 +26,7 @@
#include <QStack>
#include <QInputDialog>
#include <QLineEdit>
#include <QIODevice>
#include <keychain.h>
@ -1291,4 +1292,188 @@ bool ClientSideEncryption::isFolderEncrypted(const QString& path) {
return (*it);
}
FileEncryptionJob::FileEncryptionJob(QByteArray &key, QByteArray &iv, QFile *input, QFile *output, QObject *parent)
: QObject(parent),
_key(key),
_iv(iv),
_input(input),
_output(output)
{
}
void FileEncryptionJob::start()
{
_input->open(QIODevice::ReadOnly);
_output->open(QIODevice::WriteOnly);
// Init
EVP_CIPHER_CTX *ctx;
/* Create and initialise the context */
if(!(ctx = EVP_CIPHER_CTX_new())) {
qCInfo(lcCse()) << "Could not create context";
exit(-1);
}
/* Initialise the decryption operation. */
if(!EVP_EncryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL)) {
qCInfo(lcCse()) << "Could not init cipher";
exit(-1);
}
EVP_CIPHER_CTX_set_padding(ctx, 0);
/* Set IV length. */
if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, _iv.size(), NULL)) {
qCInfo(lcCse()) << "Could not set iv length";
exit(-1);
}
/* Initialise key and IV */
if(!EVP_EncryptInit_ex(ctx, NULL, NULL, (const unsigned char *)_key.constData(), (const unsigned char *)_iv.constData())) {
qCInfo(lcCse()) << "Could not set key and iv";
exit(-1);
}
unsigned char *out = (unsigned char *)malloc(sizeof(unsigned char) * (1024 + 16 -1));
int len = 0;
int total_len = 0;
while(!_input->atEnd()) {
QByteArray data = _input->read(1024);
if (data.size() == 0) {
qCInfo(lcCse()) << "Could not read data from file";
exit(-1);
}
if(!EVP_EncryptUpdate(ctx, out, &len, (unsigned char *)data.constData(), data.size())) {
qCInfo(lcCse()) << "Could not encrypt";
exit(-1);
}
_output->write((char *)out, len);
total_len += len;
}
if(1 != EVP_EncryptFinal_ex(ctx, out, &len)) {
qCInfo(lcCse()) << "Could finalize encryption";
exit(-1);
}
_output->write((char *)out, len);
total_len += len;
/* Get the tag */
unsigned char *tag = (unsigned char *)malloc(sizeof(unsigned char) * 16);
if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag)) {
qCInfo(lcCse()) << "Could not get tag";
exit(-1);
}
_output->write((char *)tag, 16);
free(out);
free(tag);
EVP_CIPHER_CTX_free(ctx);
_input->close();
_output->close();
emit finished(_output);
}
FileDecryptionJob::FileDecryptionJob(QByteArray &key, QByteArray &iv, QFile *input, QFile *output, QObject *parent)
: QObject(parent),
_key(key),
_iv(iv),
_input(input),
_output(output)
{
}
void FileDecryptionJob::start()
{
_input->open(QIODevice::ReadOnly);
_output->open(QIODevice::WriteOnly);
// Init
EVP_CIPHER_CTX *ctx;
/* Create and initialise the context */
if(!(ctx = EVP_CIPHER_CTX_new())) {
qCInfo(lcCse()) << "Could not create context";
exit(-1);
}
/* Initialise the decryption operation. */
if(!EVP_DecryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL)) {
qCInfo(lcCse()) << "Could not init cipher";
exit(-1);
}
EVP_CIPHER_CTX_set_padding(ctx, 0);
/* Set IV length. */
if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, _iv.size(), NULL)) {
qCInfo(lcCse()) << "Could not set iv length";
exit(-1);
}
/* Initialise key and IV */
if(!EVP_DecryptInit_ex(ctx, NULL, NULL, (const unsigned char *)_key.constData(), (const unsigned char *)_iv.constData())) {
qCInfo(lcCse()) << "Could not set key and iv";
exit(-1);
}
qint64 size = _input->size() - 16;
unsigned char *out = (unsigned char *)malloc(sizeof(unsigned char) * (1024 + 16 -1));
int len = 0;
while(_input->pos() < size) {
int toRead = size - _input->pos();
if (toRead > 1024) {
toRead = 1024;
}
QByteArray data = _input->read(toRead);
if (data.size() == 0) {
qCInfo(lcCse()) << "Could not read data from file";
exit(-1);
}
if(!EVP_DecryptUpdate(ctx, out, &len, (unsigned char *)data.constData(), data.size())) {
qCInfo(lcCse()) << "Could not decrypt";
exit(-1);
}
_output->write((char *)out, len);
}
QByteArray tag = _input->read(16);
/* Set expected tag value. Works in OpenSSL 1.0.1d and later */
if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, tag.size(), (unsigned char *)tag.constData())) {
qCInfo(lcCse()) << "Could not set expected tag";
exit(-1);
}
if(1 != EVP_DecryptFinal_ex(ctx, out, &len)) {
qCInfo(lcCse()) << "Could finalize decryption";
exit(-1);
}
_output->write((char *)out, len);
free(out);
EVP_CIPHER_CTX_free(ctx);
_input->close();
_output->close();
emit finished(_output);
}
}

View file

@ -6,6 +6,7 @@
#include <QJsonDocument>
#include <QSslCertificate>
#include <QSslKey>
#include <QFile>
#include <openssl/rsa.h>
#include <openssl/evp.h>
@ -123,6 +124,43 @@ private:
QByteArray _metadata;
};
class FileEncryptionJob : public QObject
{
Q_OBJECT
public:
FileEncryptionJob(QByteArray &key, QByteArray &iv, QFile *input, QFile *output, QObject *parent = 0);
public slots:
void start();
signals:
void finished(QFile *output);
private:
QByteArray _key;
QByteArray _iv;
QPointer<QFile> _input;
QPointer<QFile> _output;
};
class FileDecryptionJob : public QObject
{
Q_OBJECT
public:
FileDecryptionJob(QByteArray &key, QByteArray &iv, QFile *input, QFile *output, QObject *parent = 0);
public slots:
void start();
signals:
void finished(QFile *output);
private:
QByteArray _key;
QByteArray _iv;
QPointer<QFile> _input;
QPointer<QFile> _output;
};
} // namespace OCC