1
0
mirror of https://github.com/qTox/qTox.git synced 2024-03-22 14:00:36 +08:00

refactor(encryption): move everything to ToxEncrypt

This commit removes coreencryption.cpp and replaces it with ToxEncrypt.
This commit is contained in:
sudden6 2017-02-04 15:30:48 +01:00
parent f6b1cf9311
commit 7cd800374a
No known key found for this signature in database
GPG Key ID: 279509B499E032B9
7 changed files with 56 additions and 175 deletions

View File

@ -192,7 +192,6 @@ set(${PROJECT_NAME}_SOURCES
src/core/coreav.h
src/core/core.cpp
src/core/coredefines.h
src/core/coreencryption.cpp
src/core/corefile.cpp
src/core/corefile.h
src/core/core.h

View File

@ -556,7 +556,6 @@ SOURCES += \
src/chatlog/pixmapcache.cpp \
src/core/core.cpp \
src/core/coreav.cpp \
src/core/coreencryption.cpp \
src/core/corefile.cpp \
src/core/corestructs.cpp \
src/core/cstring.cpp \

View File

@ -79,12 +79,6 @@ public:
ToxId getSelfId() const;
QPair<QByteArray, QByteArray> getKeypair() const;
static std::shared_ptr<Tox_Pass_Key> createPasskey(const QString &password, uint8_t* salt = nullptr);
static QByteArray encryptData(const QByteArray& data, const Tox_Pass_Key& encryptionKey);
static QByteArray encryptData(const QByteArray& data);
static QByteArray decryptData(const QByteArray& data, const Tox_Pass_Key &encryptionKey);
static QByteArray decryptData(const QByteArray& data);
bool isReady() const;
void sendFile(uint32_t friendId, QString filename, QString filePath, long long filesize);

View File

@ -1,125 +0,0 @@
/*
Copyright © 2014-2015 by The qTox Project Contributors
This file is part of qTox, a Qt-based graphical interface for Tox.
qTox is libre 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.
qTox 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 qTox. If not, see <http://www.gnu.org/licenses/>.
*/
/* This file is part of the Core class, but was separated for my sanity */
/* The load function delegates to loadEncrypted here, and the save function */
/* was permanently moved here to handle encryption */
#include "core.h"
#include "src/widget/gui.h"
#include "src/persistence/settings.h"
#include "src/core/cstring.h"
#include "src/nexus.h"
#include "src/persistence/profile.h"
#include <tox/tox.h>
#include <tox/toxencryptsave.h>
#include <QApplication>
#include <QDebug>
#include <QSaveFile>
#include <QFile>
#include <QThread>
#include <algorithm>
#include <cassert>
std::shared_ptr<Tox_Pass_Key> Core::createPasskey(const QString& password, uint8_t* salt)
{
std::shared_ptr<Tox_Pass_Key> encryptionKey(tox_pass_key_new(), tox_pass_key_free);
CString str(password);
if (salt)
tox_pass_key_derive_with_salt(encryptionKey.get(), str.data(), str.size(), salt, nullptr);
else
tox_pass_key_derive(encryptionKey.get(), str.data(), str.size(), nullptr);
return encryptionKey;
}
/**
* @brief Encrypts data.
* @note Uses the default profile's key.
* @param data Data to encrypt.
* @return Encrypted data.
*/
QByteArray Core::encryptData(const QByteArray &data)
{
return encryptData(data, Nexus::getProfile()->getPasskey());
}
QByteArray Core::encryptData(const QByteArray& data, const Tox_Pass_Key& encryptionKey)
{
QByteArray encrypted(data.size() + TOX_PASS_ENCRYPTION_EXTRA_LENGTH, 0x00);
if (!tox_pass_key_encrypt(&encryptionKey, reinterpret_cast<const uint8_t*>(data.data()), data.size(),
(uint8_t*) encrypted.data(), nullptr))
{
qWarning() << "Encryption failed";
return QByteArray();
}
return encrypted;
}
/**
* @brief Decrypts data.
* @note Uses the default profile's key.
* @param data Data to decrypt.
* @return Decrypted data.
*/
QByteArray Core::decryptData(const QByteArray &data)
{
return decryptData(data, Nexus::getProfile()->getPasskey());
}
QByteArray Core::decryptData(const QByteArray& data, const Tox_Pass_Key& encryptionKey)
{
if (data.size() < TOX_PASS_ENCRYPTION_EXTRA_LENGTH)
{
qWarning() << "Not enough data:" << data.size();
return QByteArray();
}
int decryptedSize = data.size() - TOX_PASS_ENCRYPTION_EXTRA_LENGTH;
QByteArray decrypted(decryptedSize, 0x00);
if (!tox_pass_key_decrypt(&encryptionKey, reinterpret_cast<const uint8_t*>(data.data()), data.size(),
(uint8_t*) decrypted.data(), nullptr))
{
qWarning() << "Decryption failed";
return QByteArray();
}
return decrypted;
}
QByteArray Core::getSaltFromFile(QString filename)
{
QFile file(filename);
if (!file.open(QIODevice::ReadOnly))
{
qWarning() << "file" << filename << "doesn't exist";
return QByteArray();
}
QByteArray data = file.read(TOX_PASS_ENCRYPTION_EXTRA_LENGTH);
file.close();
uint8_t salt[TOX_PASS_SALT_LENGTH];
if (!tox_get_salt(reinterpret_cast<uint8_t *>(data.data()), salt, nullptr))
{
qWarning() << "can't get salt from" << filename << "header";
return QByteArray();
}
QByteArray res(reinterpret_cast<const char*>(salt), TOX_PASS_SALT_LENGTH);
return res;
}

View File

@ -53,11 +53,6 @@ Profile::Profile(QString name, const QString& password, bool isNewProfile)
: name{name}, password{password}
, newProfile{isNewProfile}, isRemoved{false}
{
if (!password.isEmpty())
{
passkey = core->createPasskey(password);
}
Settings& s = Settings::getInstance();
s.setCurrentProfile(name);
s.saveGlobal();
@ -92,6 +87,8 @@ Profile* Profile::loadProfile(QString name, const QString& password)
return nullptr;
}
std::unique_ptr<ToxEncrypt> tmpKey;
// Check password
{
QString path = Settings::getInstance().getSettingsDirPath() + name + ".tox";
@ -121,7 +118,7 @@ Profile* Profile::loadProfile(QString name, const QString& password)
}
QByteArray data = saveFile.readAll();
if (tox_is_data_encrypted((uint8_t*)data.data()))
if (ToxEncrypt::isEncrypted(data))
{
if (password.isEmpty())
{
@ -130,11 +127,15 @@ Profile* Profile::loadProfile(QString name, const QString& password)
return nullptr;
}
uint8_t salt[TOX_PASS_SALT_LENGTH];
tox_get_salt(reinterpret_cast<uint8_t*>(data.data()), salt, nullptr);
auto tmpkey = Core::createPasskey(password, salt);
tmpKey = ToxEncrypt::makeToxEncrypt(password, data);
if (!tmpKey)
{
qCritical() << "Failed to derive key of the tox save file";
ProfileLocker::unlock();
return nullptr;
}
data = Core::decryptData(data, *tmpkey);
data = tmpKey->decrypt(data);
if (data.isEmpty())
{
qCritical() << "Failed to decrypt the tox save file";
@ -152,6 +153,8 @@ Profile* Profile::loadProfile(QString name, const QString& password)
}
Profile* p = new Profile(name, password, false);
p->passkey = std::move(tmpKey);
return p;
}
@ -165,6 +168,17 @@ Profile* Profile::loadProfile(QString name, const QString& password)
*/
Profile* Profile::createProfile(QString name, QString password)
{
std::unique_ptr<ToxEncrypt> tmpKey;
if(!password.isEmpty())
{
tmpKey = ToxEncrypt::makeToxEncrypt(password);
if (!tmpKey)
{
qCritical() << "Failed to derive key for the tox save";
return nullptr;
}
}
if (ProfileLocker::hasLock())
{
qCritical() << "Tried to create profile "<<name<<", but another profile is already locked!";
@ -184,7 +198,10 @@ Profile* Profile::createProfile(QString name, QString password)
}
Settings::getInstance().createPersonal(name);
return new Profile(name, password, true);
Profile* p = new Profile(name, password, true);
p->passkey = std::move(tmpKey);
return p;
}
Profile::~Profile()
@ -308,7 +325,7 @@ QByteArray Profile::loadToxSave()
}
data = saveFile.readAll();
if (tox_is_data_encrypted((uint8_t*)data.data()))
if (ToxEncrypt::isEncrypted(data))
{
if (password.isEmpty())
{
@ -317,14 +334,12 @@ QByteArray Profile::loadToxSave()
goto fail;
}
uint8_t salt[TOX_PASS_SALT_LENGTH];
tox_get_salt(reinterpret_cast<uint8_t*>(data.data()), salt, nullptr);
passkey = core->createPasskey(password, salt);
data = core->decryptData(data, *passkey);
data = passkey->decrypt(data);
if (data.isEmpty())
{
qCritical() << "Failed to decrypt the tox save file";
data.clear();
goto fail;
}
}
else
@ -374,8 +389,7 @@ void Profile::saveToxSave(QByteArray data)
if (!password.isEmpty())
{
passkey = core->createPasskey(password);
data = core->encryptData(data, *passkey);
data = passkey->encrypt(data);
if (data.isEmpty())
{
qCritical() << "Failed to encrypt, can't save!";
@ -480,10 +494,8 @@ QByteArray Profile::loadAvatarData(const QString& ownerId, const QString& passwo
QByteArray pic = file.readAll();
if (encrypted && !pic.isEmpty())
{
uint8_t salt[TOX_PASS_SALT_LENGTH];
tox_get_salt(reinterpret_cast<uint8_t*>(pic.data()), salt, nullptr);
auto passkey = core->createPasskey(password, salt);
pic = core->decryptData(pic, *passkey);
// TODO: check if we can use passkey-decrypt(pic) here
pic = ToxEncrypt::decryptPass(password, pic);
}
return pic;
@ -526,7 +538,7 @@ void Profile::saveAvatar(QByteArray pic, const QString& ownerId)
{
if (!password.isEmpty() && !pic.isEmpty())
{
pic = core->encryptData(pic, *passkey);
pic = passkey->encrypt(pic);
}
QString path = avatarPath(ownerId);
@ -745,7 +757,7 @@ QString Profile::getPassword() const
return password;
}
const Tox_Pass_Key& Profile::getPasskey() const
const ToxEncrypt& Profile::getPasskey() const
{
return *passkey;
}
@ -772,10 +784,19 @@ void Profile::setPassword(const QString& newPassword)
{
QByteArray avatar = loadAvatarData(core->getSelfId().getPublicKey().toString());
QString oldPassword = password;
std::unique_ptr<ToxEncrypt> oldpasskey = std::move(passkey);
password = newPassword;
passkey = core->createPasskey(password);
passkey = ToxEncrypt::makeToxEncrypt(password);
if(!passkey)
{
qCritical() << "Failed to derive key from password, the profile won't use the new password";
password = oldPassword;
passkey = std::move(oldpasskey);
return;
}
saveToxSave();
// TODO: ensure the database and the tox save file use the same password
if (database)
{
database->setPassword(newPassword);

View File

@ -22,8 +22,7 @@
#define PROFILE_H
#include "src/core/toxid.h"
#include <tox/toxencryptsave.h>
#include "src/core/toxencrypt.h"
#include "src/persistence/history.h"
@ -56,7 +55,7 @@ public:
bool checkPassword();
QString getPassword() const;
void setPassword(const QString& newPassword);
const Tox_Pass_Key& getPasskey() const;
const ToxEncrypt& getPasskey() const;
QByteArray loadToxSave();
void saveToxSave();
@ -96,7 +95,7 @@ private:
Core* core;
QThread* coreThread;
QString name, password;
std::shared_ptr<Tox_Pass_Key> passkey;
std::unique_ptr<ToxEncrypt> passkey;
std::shared_ptr<RawDatabase> database;
std::unique_ptr<History> history;
bool newProfile;

View File

@ -19,9 +19,10 @@
#include "settingsserializer.h"
#include "serialize.h"
#include "src/nexus.h"
#include "src/core/toxencrypt.h"
#include "src/persistence/profile.h"
#include "src/core/core.h"
#include <QSaveFile>
#include <QFile>
#include <QDebug>
@ -328,9 +329,8 @@ void SettingsSerializer::save()
// Encrypt
if (!password.isEmpty())
{
Core* core = Nexus::getCore();
auto passkey = core->createPasskey(password);
data = core->encryptData(data, *passkey);
// TODO: use passkey
data = ToxEncrypt::encryptPass(password, data);
}
f.write(data);
@ -367,13 +367,7 @@ void SettingsSerializer::readSerialized()
return;
}
Core* core = Nexus::getCore();
uint8_t salt[TOX_PASS_SALT_LENGTH];
tox_get_salt(reinterpret_cast<uint8_t *>(data.data()), salt, nullptr);
auto passkey = core->createPasskey(password, salt);
data = core->decryptData(data, *passkey);
data = ToxEncrypt::decryptPass(password, data);
if (data.isEmpty())
{
qCritical() << "Failed to decrypt the settings file";