mirror of
https://invent.kde.org/network/falkon.git
synced 2024-12-20 18:56:34 +01:00
Added AES encryption/decryption ability (version 1)
-AesInterface is a Qt interface for AES encryption/decryption that uses AES 256 CBC mode.
This commit is contained in:
parent
50a4d78026
commit
6342884e86
@ -243,7 +243,9 @@ SOURCES += \
|
|||||||
tools/delayedfilewatcher.cpp \
|
tools/delayedfilewatcher.cpp \
|
||||||
autofill/passwordmanager.cpp \
|
autofill/passwordmanager.cpp \
|
||||||
autofill/passwordbackends/databasepasswordbackend.cpp \
|
autofill/passwordbackends/databasepasswordbackend.cpp \
|
||||||
autofill/passwordbackends/passwordbackend.cpp
|
autofill/passwordbackends/passwordbackend.cpp \
|
||||||
|
tools/aesinterface.cpp
|
||||||
|
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
webview/tabpreview.h \
|
webview/tabpreview.h \
|
||||||
@ -422,7 +424,8 @@ HEADERS += \
|
|||||||
tools/delayedfilewatcher.h \
|
tools/delayedfilewatcher.h \
|
||||||
autofill/passwordmanager.h \
|
autofill/passwordmanager.h \
|
||||||
autofill/passwordbackends/passwordbackend.h \
|
autofill/passwordbackends/passwordbackend.h \
|
||||||
autofill/passwordbackends/databasepasswordbackend.h
|
autofill/passwordbackends/databasepasswordbackend.h \
|
||||||
|
tools/aesinterface.h
|
||||||
|
|
||||||
FORMS += \
|
FORMS += \
|
||||||
preferences/autofillmanager.ui \
|
preferences/autofillmanager.ui \
|
||||||
@ -510,6 +513,8 @@ mac {
|
|||||||
LIBS += -framework CoreServices
|
LIBS += -framework CoreServices
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LIBS += -llibeay32
|
||||||
|
|
||||||
message(===========================================)
|
message(===========================================)
|
||||||
message( Using following defines:)
|
message( Using following defines:)
|
||||||
message( $$DEFINES)
|
message( $$DEFINES)
|
||||||
|
203
src/lib/tools/aesinterface.cpp
Normal file
203
src/lib/tools/aesinterface.cpp
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
/* ============================================================
|
||||||
|
* QupZilla - WebKit based browser
|
||||||
|
* Copyright (C) 2013 S. Razi Alavizadeh <s.r.alavizadeh@gmail.com>
|
||||||
|
* Copyright (C) 2013 David Rosca <nowrep@gmail.com>
|
||||||
|
*
|
||||||
|
* This is based on a work by Saju Pillai <saju.pillai@gmail.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* ============================================================ */
|
||||||
|
|
||||||
|
#include "aesinterface.h"
|
||||||
|
|
||||||
|
#include <openssl/aes.h>
|
||||||
|
#include <openssl/rand.h>
|
||||||
|
#include <openssl/sha.h>
|
||||||
|
|
||||||
|
#include <QCryptographicHash>
|
||||||
|
#include <QByteArray>
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
//////////////////////////////////////////////
|
||||||
|
/// Version 1:
|
||||||
|
/// init(): n=5, EVP_CIPHER=EVP_aes_256_cbc(), EVP_MD=EVP_sha256(), Random IV
|
||||||
|
/// Encrypted data structure: Version$InitializationVector_base64$EncryptedData_base64
|
||||||
|
const int AesInterface::VERSION = 1;
|
||||||
|
|
||||||
|
AesInterface::AesInterface(QObject* parent)
|
||||||
|
: QObject(parent)
|
||||||
|
, m_ok(false)
|
||||||
|
{
|
||||||
|
EVP_CIPHER_CTX_init(&m_encodeCTX);
|
||||||
|
EVP_CIPHER_CTX_init(&m_decodeCTX);
|
||||||
|
}
|
||||||
|
|
||||||
|
AesInterface::~AesInterface()
|
||||||
|
{
|
||||||
|
EVP_CIPHER_CTX_cleanup(&m_encodeCTX);
|
||||||
|
EVP_CIPHER_CTX_cleanup(&m_decodeCTX);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create an 256 bit 'key' using the supplied password, and creates a random 'iv'.
|
||||||
|
// saltArray is an array of 8 bytes can be added for taste.
|
||||||
|
// Fills in the encryption and decryption ctx objects and returns true on success
|
||||||
|
bool AesInterface::init(int evpMode, const QByteArray &password, const QByteArray &iVector)
|
||||||
|
{
|
||||||
|
m_iVector.clear();
|
||||||
|
|
||||||
|
int i;
|
||||||
|
const int nrounds = 5;
|
||||||
|
uchar key[EVP_MAX_KEY_LENGTH];
|
||||||
|
|
||||||
|
// Gen "key" for AES 256 CBC mode. A SHA1 digest is used to hash the supplied
|
||||||
|
// key material. nrounds is the number of times that we hash the material.
|
||||||
|
// More rounds are more secure but slower.
|
||||||
|
i = EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha256(), 0, (uchar*)password.data(), password.size(), nrounds, key, 0);
|
||||||
|
|
||||||
|
if (i != 32) {
|
||||||
|
qWarning("Key size is %d bits - should be 256 bits", i * 8);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int result;
|
||||||
|
if (evpMode == EVP_PKEY_MO_ENCRYPT) {
|
||||||
|
m_iVector = createRandomData(EVP_MAX_IV_LENGTH);
|
||||||
|
result = EVP_EncryptInit_ex(&m_encodeCTX, EVP_aes_256_cbc(), NULL, key, (uchar*)m_iVector.constData());
|
||||||
|
}
|
||||||
|
else if (evpMode == EVP_PKEY_MO_DECRYPT) {
|
||||||
|
result = EVP_DecryptInit_ex(&m_decodeCTX, EVP_aes_256_cbc(), NULL, key, (uchar*)iVector.constData());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result == 0) {
|
||||||
|
qWarning("EVP is not initialized!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray AesInterface::encrypt(const QByteArray &plainData, const QByteArray &password)
|
||||||
|
{
|
||||||
|
if (!init(EVP_PKEY_MO_ENCRYPT, password)) {
|
||||||
|
m_ok = false;
|
||||||
|
return plainData;
|
||||||
|
}
|
||||||
|
|
||||||
|
// max ciphertext len for a n bytes of plaintext is n + AES_BLOCK_SIZE -1 bytes
|
||||||
|
int dataLength = plainData.size();
|
||||||
|
int cipherlength = dataLength + AES_BLOCK_SIZE;
|
||||||
|
int finalLength = 0;
|
||||||
|
uchar* ciphertext = (uchar*)malloc(cipherlength);
|
||||||
|
|
||||||
|
// allows reusing of 'm_encodeCTX' for multiple encryption cycles
|
||||||
|
EVP_EncryptInit_ex(&m_encodeCTX, NULL, NULL, NULL, NULL);
|
||||||
|
|
||||||
|
// update ciphertext, c_len is filled with the length of ciphertext generated,
|
||||||
|
// dataLength is the size of plaintext in bytes
|
||||||
|
EVP_EncryptUpdate(&m_encodeCTX, ciphertext, &cipherlength, (uchar*)plainData.data(), dataLength);
|
||||||
|
|
||||||
|
// update ciphertext with the final remaining bytes
|
||||||
|
EVP_EncryptFinal_ex(&m_encodeCTX, ciphertext + cipherlength, &finalLength);
|
||||||
|
|
||||||
|
dataLength = cipherlength + finalLength;
|
||||||
|
QByteArray out((char*)ciphertext, dataLength);
|
||||||
|
out = QByteArray::number(AesInterface::VERSION) + '$' + m_iVector.toBase64() + '$' + out.toBase64();
|
||||||
|
free(ciphertext);
|
||||||
|
|
||||||
|
m_ok = true;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray AesInterface::decrypt(const QByteArray &cipherData, const QByteArray &password)
|
||||||
|
{
|
||||||
|
m_ok = false;
|
||||||
|
|
||||||
|
if (cipherData.isEmpty()) {
|
||||||
|
m_ok = true;
|
||||||
|
return QByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QByteArray> cipherSections(cipherData.split('$'));
|
||||||
|
if (cipherSections.size() != 3) {
|
||||||
|
qWarning() << "Decrypt error: It seems data is corrupted";
|
||||||
|
return QByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cipherSections.at(0).toInt() > AesInterface::VERSION) {
|
||||||
|
QMessageBox::information(0, tr("Warning!"), tr("Data has been encrypted with a newer version of QupZilla."
|
||||||
|
"\nPlease install latest version of QupZilla."));
|
||||||
|
return QByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cipherSections.at(0).toInt() != 1) {
|
||||||
|
qWarning() << Q_FUNC_INFO << "There is just version 1 of decoder, yet ;-)";
|
||||||
|
return QByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!init(EVP_PKEY_MO_DECRYPT, password, QByteArray::fromBase64(cipherSections.at(1)))) {
|
||||||
|
return QByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray cipherArray = QByteArray::fromBase64(cipherSections.at(2));
|
||||||
|
int cipherLength = cipherArray.size();
|
||||||
|
int plainTextLength = cipherLength;
|
||||||
|
int finalLength = 0;
|
||||||
|
|
||||||
|
uchar* cipherText = (uchar*)cipherArray.data();
|
||||||
|
// because we have padding ON, we must allocate an extra cipher block size of memory
|
||||||
|
uchar* plainText = (uchar*)malloc(plainTextLength + AES_BLOCK_SIZE);
|
||||||
|
|
||||||
|
EVP_DecryptInit_ex(&m_decodeCTX, NULL, NULL, NULL, NULL);
|
||||||
|
EVP_DecryptUpdate(&m_decodeCTX, plainText, &plainTextLength, cipherText, cipherLength);
|
||||||
|
int success = EVP_DecryptFinal_ex(&m_decodeCTX, plainText + plainTextLength, &finalLength);
|
||||||
|
|
||||||
|
cipherLength = plainTextLength + finalLength;
|
||||||
|
|
||||||
|
QByteArray result((char*)plainText, cipherLength);
|
||||||
|
free(plainText);
|
||||||
|
|
||||||
|
if (success != 1) {
|
||||||
|
return QByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_ok = true;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray AesInterface::passwordToHash(const QString &masterPassword)
|
||||||
|
{
|
||||||
|
if (!masterPassword.isEmpty()) {
|
||||||
|
QByteArray result = masterPassword.toUtf8();
|
||||||
|
result = QCryptographicHash::hash(result, QCryptographicHash::Sha1) + result;
|
||||||
|
result = QCryptographicHash::hash(result, QCryptographicHash::Sha1);
|
||||||
|
return result.toBase64();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return QByteArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray AesInterface::createRandomData(int length)
|
||||||
|
{
|
||||||
|
uchar* randomData = (uchar*)malloc(length);
|
||||||
|
|
||||||
|
if (RAND_bytes(randomData, length) != 1) {
|
||||||
|
RAND_pseudo_bytes(randomData, length);
|
||||||
|
}
|
||||||
|
QByteArray data((char*)randomData, length);
|
||||||
|
free(randomData);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
58
src/lib/tools/aesinterface.h
Normal file
58
src/lib/tools/aesinterface.h
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
/* ============================================================
|
||||||
|
* QupZilla - WebKit based browser
|
||||||
|
* Copyright (C) 2013 S. Razi Alavizadeh <s.r.alavizadeh@gmail.com>
|
||||||
|
* Copyright (C) 2013 David Rosca <nowrep@gmail.com>
|
||||||
|
*
|
||||||
|
* This is based on a work by Saju Pillai <saju.pillai@gmail.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* ============================================================ */
|
||||||
|
#ifndef AESINTERFACE_H
|
||||||
|
#define AESINTERFACE_H
|
||||||
|
|
||||||
|
#include "qz_namespace.h"
|
||||||
|
|
||||||
|
#include <openssl/evp.h>
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
#include <QHash>
|
||||||
|
#include <QList>
|
||||||
|
class QT_QUPZILLA_EXPORT AesInterface : public QObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static const int VERSION;
|
||||||
|
|
||||||
|
explicit AesInterface(QObject* parent = 0);
|
||||||
|
~AesInterface();
|
||||||
|
|
||||||
|
inline bool isOk() { return m_ok; }
|
||||||
|
|
||||||
|
QByteArray encrypt(const QByteArray &plainData, const QByteArray &password);
|
||||||
|
QByteArray decrypt(const QByteArray &cipherData, const QByteArray &password);
|
||||||
|
|
||||||
|
static void encryptSomeData(const QByteArray &pass = QByteArray());
|
||||||
|
static QByteArray passwordToHash(const QString &masterPassword);
|
||||||
|
|
||||||
|
static QByteArray createRandomData(int length);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool init(int evpMode, const QByteArray &password, const QByteArray &iVector = QByteArray());
|
||||||
|
|
||||||
|
EVP_CIPHER_CTX m_encodeCTX;
|
||||||
|
EVP_CIPHER_CTX m_decodeCTX;
|
||||||
|
|
||||||
|
bool m_ok;
|
||||||
|
QByteArray m_iVector;
|
||||||
|
};
|
||||||
|
#endif //AESINTERFACE_H
|
Loading…
Reference in New Issue
Block a user