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:
parent
f6b1cf9311
commit
7cd800374a
|
@ -192,7 +192,6 @@ set(${PROJECT_NAME}_SOURCES
|
||||||
src/core/coreav.h
|
src/core/coreav.h
|
||||||
src/core/core.cpp
|
src/core/core.cpp
|
||||||
src/core/coredefines.h
|
src/core/coredefines.h
|
||||||
src/core/coreencryption.cpp
|
|
||||||
src/core/corefile.cpp
|
src/core/corefile.cpp
|
||||||
src/core/corefile.h
|
src/core/corefile.h
|
||||||
src/core/core.h
|
src/core/core.h
|
||||||
|
|
1
qtox.pro
1
qtox.pro
|
@ -556,7 +556,6 @@ SOURCES += \
|
||||||
src/chatlog/pixmapcache.cpp \
|
src/chatlog/pixmapcache.cpp \
|
||||||
src/core/core.cpp \
|
src/core/core.cpp \
|
||||||
src/core/coreav.cpp \
|
src/core/coreav.cpp \
|
||||||
src/core/coreencryption.cpp \
|
|
||||||
src/core/corefile.cpp \
|
src/core/corefile.cpp \
|
||||||
src/core/corestructs.cpp \
|
src/core/corestructs.cpp \
|
||||||
src/core/cstring.cpp \
|
src/core/cstring.cpp \
|
||||||
|
|
|
@ -79,12 +79,6 @@ public:
|
||||||
ToxId getSelfId() const;
|
ToxId getSelfId() const;
|
||||||
QPair<QByteArray, QByteArray> getKeypair() 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;
|
bool isReady() const;
|
||||||
|
|
||||||
void sendFile(uint32_t friendId, QString filename, QString filePath, long long filesize);
|
void sendFile(uint32_t friendId, QString filename, QString filePath, long long filesize);
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -53,11 +53,6 @@ Profile::Profile(QString name, const QString& password, bool isNewProfile)
|
||||||
: name{name}, password{password}
|
: name{name}, password{password}
|
||||||
, newProfile{isNewProfile}, isRemoved{false}
|
, newProfile{isNewProfile}, isRemoved{false}
|
||||||
{
|
{
|
||||||
if (!password.isEmpty())
|
|
||||||
{
|
|
||||||
passkey = core->createPasskey(password);
|
|
||||||
}
|
|
||||||
|
|
||||||
Settings& s = Settings::getInstance();
|
Settings& s = Settings::getInstance();
|
||||||
s.setCurrentProfile(name);
|
s.setCurrentProfile(name);
|
||||||
s.saveGlobal();
|
s.saveGlobal();
|
||||||
|
@ -92,6 +87,8 @@ Profile* Profile::loadProfile(QString name, const QString& password)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<ToxEncrypt> tmpKey;
|
||||||
|
|
||||||
// Check password
|
// Check password
|
||||||
{
|
{
|
||||||
QString path = Settings::getInstance().getSettingsDirPath() + name + ".tox";
|
QString path = Settings::getInstance().getSettingsDirPath() + name + ".tox";
|
||||||
|
@ -121,7 +118,7 @@ Profile* Profile::loadProfile(QString name, const QString& password)
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray data = saveFile.readAll();
|
QByteArray data = saveFile.readAll();
|
||||||
if (tox_is_data_encrypted((uint8_t*)data.data()))
|
if (ToxEncrypt::isEncrypted(data))
|
||||||
{
|
{
|
||||||
if (password.isEmpty())
|
if (password.isEmpty())
|
||||||
{
|
{
|
||||||
|
@ -130,11 +127,15 @@ Profile* Profile::loadProfile(QString name, const QString& password)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t salt[TOX_PASS_SALT_LENGTH];
|
tmpKey = ToxEncrypt::makeToxEncrypt(password, data);
|
||||||
tox_get_salt(reinterpret_cast<uint8_t*>(data.data()), salt, nullptr);
|
if (!tmpKey)
|
||||||
auto tmpkey = Core::createPasskey(password, salt);
|
{
|
||||||
|
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())
|
if (data.isEmpty())
|
||||||
{
|
{
|
||||||
qCritical() << "Failed to decrypt the tox save file";
|
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);
|
Profile* p = new Profile(name, password, false);
|
||||||
|
p->passkey = std::move(tmpKey);
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,6 +168,17 @@ Profile* Profile::loadProfile(QString name, const QString& password)
|
||||||
*/
|
*/
|
||||||
Profile* Profile::createProfile(QString name, 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())
|
if (ProfileLocker::hasLock())
|
||||||
{
|
{
|
||||||
qCritical() << "Tried to create profile "<<name<<", but another profile is already locked!";
|
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);
|
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()
|
Profile::~Profile()
|
||||||
|
@ -308,7 +325,7 @@ QByteArray Profile::loadToxSave()
|
||||||
}
|
}
|
||||||
|
|
||||||
data = saveFile.readAll();
|
data = saveFile.readAll();
|
||||||
if (tox_is_data_encrypted((uint8_t*)data.data()))
|
if (ToxEncrypt::isEncrypted(data))
|
||||||
{
|
{
|
||||||
if (password.isEmpty())
|
if (password.isEmpty())
|
||||||
{
|
{
|
||||||
|
@ -317,14 +334,12 @@ QByteArray Profile::loadToxSave()
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t salt[TOX_PASS_SALT_LENGTH];
|
data = passkey->decrypt(data);
|
||||||
tox_get_salt(reinterpret_cast<uint8_t*>(data.data()), salt, nullptr);
|
|
||||||
passkey = core->createPasskey(password, salt);
|
|
||||||
|
|
||||||
data = core->decryptData(data, *passkey);
|
|
||||||
if (data.isEmpty())
|
if (data.isEmpty())
|
||||||
{
|
{
|
||||||
qCritical() << "Failed to decrypt the tox save file";
|
qCritical() << "Failed to decrypt the tox save file";
|
||||||
|
data.clear();
|
||||||
|
goto fail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -374,8 +389,7 @@ void Profile::saveToxSave(QByteArray data)
|
||||||
|
|
||||||
if (!password.isEmpty())
|
if (!password.isEmpty())
|
||||||
{
|
{
|
||||||
passkey = core->createPasskey(password);
|
data = passkey->encrypt(data);
|
||||||
data = core->encryptData(data, *passkey);
|
|
||||||
if (data.isEmpty())
|
if (data.isEmpty())
|
||||||
{
|
{
|
||||||
qCritical() << "Failed to encrypt, can't save!";
|
qCritical() << "Failed to encrypt, can't save!";
|
||||||
|
@ -480,10 +494,8 @@ QByteArray Profile::loadAvatarData(const QString& ownerId, const QString& passwo
|
||||||
QByteArray pic = file.readAll();
|
QByteArray pic = file.readAll();
|
||||||
if (encrypted && !pic.isEmpty())
|
if (encrypted && !pic.isEmpty())
|
||||||
{
|
{
|
||||||
uint8_t salt[TOX_PASS_SALT_LENGTH];
|
// TODO: check if we can use passkey-decrypt(pic) here
|
||||||
tox_get_salt(reinterpret_cast<uint8_t*>(pic.data()), salt, nullptr);
|
pic = ToxEncrypt::decryptPass(password, pic);
|
||||||
auto passkey = core->createPasskey(password, salt);
|
|
||||||
pic = core->decryptData(pic, *passkey);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return pic;
|
return pic;
|
||||||
|
@ -526,7 +538,7 @@ void Profile::saveAvatar(QByteArray pic, const QString& ownerId)
|
||||||
{
|
{
|
||||||
if (!password.isEmpty() && !pic.isEmpty())
|
if (!password.isEmpty() && !pic.isEmpty())
|
||||||
{
|
{
|
||||||
pic = core->encryptData(pic, *passkey);
|
pic = passkey->encrypt(pic);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString path = avatarPath(ownerId);
|
QString path = avatarPath(ownerId);
|
||||||
|
@ -745,7 +757,7 @@ QString Profile::getPassword() const
|
||||||
return password;
|
return password;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Tox_Pass_Key& Profile::getPasskey() const
|
const ToxEncrypt& Profile::getPasskey() const
|
||||||
{
|
{
|
||||||
return *passkey;
|
return *passkey;
|
||||||
}
|
}
|
||||||
|
@ -772,10 +784,19 @@ void Profile::setPassword(const QString& newPassword)
|
||||||
{
|
{
|
||||||
QByteArray avatar = loadAvatarData(core->getSelfId().getPublicKey().toString());
|
QByteArray avatar = loadAvatarData(core->getSelfId().getPublicKey().toString());
|
||||||
QString oldPassword = password;
|
QString oldPassword = password;
|
||||||
|
std::unique_ptr<ToxEncrypt> oldpasskey = std::move(passkey);
|
||||||
password = newPassword;
|
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();
|
saveToxSave();
|
||||||
|
|
||||||
|
// TODO: ensure the database and the tox save file use the same password
|
||||||
if (database)
|
if (database)
|
||||||
{
|
{
|
||||||
database->setPassword(newPassword);
|
database->setPassword(newPassword);
|
||||||
|
|
|
@ -22,8 +22,7 @@
|
||||||
#define PROFILE_H
|
#define PROFILE_H
|
||||||
|
|
||||||
#include "src/core/toxid.h"
|
#include "src/core/toxid.h"
|
||||||
|
#include "src/core/toxencrypt.h"
|
||||||
#include <tox/toxencryptsave.h>
|
|
||||||
|
|
||||||
#include "src/persistence/history.h"
|
#include "src/persistence/history.h"
|
||||||
|
|
||||||
|
@ -56,7 +55,7 @@ public:
|
||||||
bool checkPassword();
|
bool checkPassword();
|
||||||
QString getPassword() const;
|
QString getPassword() const;
|
||||||
void setPassword(const QString& newPassword);
|
void setPassword(const QString& newPassword);
|
||||||
const Tox_Pass_Key& getPasskey() const;
|
const ToxEncrypt& getPasskey() const;
|
||||||
|
|
||||||
QByteArray loadToxSave();
|
QByteArray loadToxSave();
|
||||||
void saveToxSave();
|
void saveToxSave();
|
||||||
|
@ -96,7 +95,7 @@ private:
|
||||||
Core* core;
|
Core* core;
|
||||||
QThread* coreThread;
|
QThread* coreThread;
|
||||||
QString name, password;
|
QString name, password;
|
||||||
std::shared_ptr<Tox_Pass_Key> passkey;
|
std::unique_ptr<ToxEncrypt> passkey;
|
||||||
std::shared_ptr<RawDatabase> database;
|
std::shared_ptr<RawDatabase> database;
|
||||||
std::unique_ptr<History> history;
|
std::unique_ptr<History> history;
|
||||||
bool newProfile;
|
bool newProfile;
|
||||||
|
|
|
@ -19,9 +19,10 @@
|
||||||
|
|
||||||
#include "settingsserializer.h"
|
#include "settingsserializer.h"
|
||||||
#include "serialize.h"
|
#include "serialize.h"
|
||||||
#include "src/nexus.h"
|
|
||||||
|
#include "src/core/toxencrypt.h"
|
||||||
#include "src/persistence/profile.h"
|
#include "src/persistence/profile.h"
|
||||||
#include "src/core/core.h"
|
|
||||||
#include <QSaveFile>
|
#include <QSaveFile>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
@ -328,9 +329,8 @@ void SettingsSerializer::save()
|
||||||
// Encrypt
|
// Encrypt
|
||||||
if (!password.isEmpty())
|
if (!password.isEmpty())
|
||||||
{
|
{
|
||||||
Core* core = Nexus::getCore();
|
// TODO: use passkey
|
||||||
auto passkey = core->createPasskey(password);
|
data = ToxEncrypt::encryptPass(password, data);
|
||||||
data = core->encryptData(data, *passkey);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
f.write(data);
|
f.write(data);
|
||||||
|
@ -367,13 +367,7 @@ void SettingsSerializer::readSerialized()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Core* core = Nexus::getCore();
|
data = ToxEncrypt::decryptPass(password, data);
|
||||||
|
|
||||||
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);
|
|
||||||
if (data.isEmpty())
|
if (data.isEmpty())
|
||||||
{
|
{
|
||||||
qCritical() << "Failed to decrypt the settings file";
|
qCritical() << "Failed to decrypt the settings file";
|
||||||
|
|
Loading…
Reference in New Issue
Block a user