From d72f220e3e3a3b243fdafd93d1405f8207dc516a Mon Sep 17 00:00:00 2001 From: Alexey Andreyev Date: Thu, 28 Jan 2021 23:51:56 +0300 Subject: E2EE: initial port to internal olm wrapper Remove qtolm git module. Update CMakeLists.txt. Rename olm to crypto subdir to prevent disambiguation. Rename internal files accordingly. Comment out not ported E2EE API usage. --- lib/encryptionmanager.h | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'lib/encryptionmanager.h') diff --git a/lib/encryptionmanager.h b/lib/encryptionmanager.h index 714f95fd..9d2c8138 100644 --- a/lib/encryptionmanager.h +++ b/lib/encryptionmanager.h @@ -9,12 +9,9 @@ #include #include -namespace QtOlm { -class Account; -} - namespace Quotient { class Connection; +class QOlmAccount; class EncryptionManager : public QObject { Q_OBJECT @@ -39,7 +36,7 @@ public: const QByteArray& senderKey); QByteArray olmAccountPickle(); - QtOlm::Account* account() const; + QOlmAccount* account() const; private: class Private; -- cgit v1.2.3 From 40d6616ef0c4a9be20d5fe5e50f4b9959d0ab3d1 Mon Sep 17 00:00:00 2001 From: Tobias Fella Date: Fri, 11 Jun 2021 18:37:58 +0200 Subject: Cleanup and Refactor EncryptionManager --- lib/connection.cpp | 45 +++--- lib/encryptionmanager.cpp | 352 +++++++--------------------------------------- lib/encryptionmanager.h | 20 +-- 3 files changed, 69 insertions(+), 348 deletions(-) (limited to 'lib/encryptionmanager.h') diff --git a/lib/connection.cpp b/lib/connection.cpp index 10256d9c..2d040e8a 100644 --- a/lib/connection.cpp +++ b/lib/connection.cpp @@ -118,7 +118,7 @@ public: #ifdef Quotient_E2EE_ENABLED std::unique_ptr olmAccount; bool isUploadingKeys = false; - QScopedPointer encryptionManager; + EncryptionManager *encryptionManager; #endif // Quotient_E2EE_ENABLED QPointer resolverJob = nullptr; @@ -194,17 +194,14 @@ public: EventPtr sessionDecryptMessage(const EncryptedEvent& encryptedEvent) { - qCWarning(E2EE) << "End-to-end encryption (E2EE) support is turned off."; - return {}; #ifndef Quotient_E2EE_ENABLED qCWarning(E2EE) << "End-to-end encryption (E2EE) support is turned off."; return {}; -#else // Quotient_E2EE_ENABLED +#else if (encryptedEvent.algorithm() != OlmV1Curve25519AesSha2AlgoKey) return {}; - const auto identityKey = - encryptionManager->account()->identityKeys().curve25519; + const auto identityKey = olmAccount->identityKeys().curve25519; const auto personalCipherObject = encryptedEvent.ciphertext(identityKey); if (personalCipherObject.isEmpty()) { @@ -212,11 +209,11 @@ public: return {}; } const auto decrypted = encryptionManager->sessionDecryptMessage( - personalCipherObject, encryptedEvent.senderKey().toLatin1()); + personalCipherObject, encryptedEvent.senderKey().toLatin1(), olmAccount); if (decrypted.isEmpty()) { qCDebug(E2EE) << "Problem with new session from senderKey:" << encryptedEvent.senderKey() - << encryptionManager->account()->oneTimeKeys().keys; + << olmAccount->oneTimeKeys().keys; return {}; } @@ -233,22 +230,18 @@ public: // TODO: keys to constants const auto decryptedEventObject = decryptedEvent->fullJson(); - const auto recipient = - decryptedEventObject.value("recipient"_ls).toString(); + const auto recipient = decryptedEventObject.value("recipient"_ls).toString(); if (recipient != data->userId()) { qCDebug(E2EE) << "Found user" << recipient << "instead of us" << data->userId() << "in Olm plaintext"; return {}; } - const auto ourKey = - decryptedEventObject.value("recipient_keys"_ls).toObject() - .value(Ed25519Key).toString(); - if (ourKey - != QString::fromUtf8( - encryptionManager->account()->identityKeys().ed25519)) { + const auto ourKey = decryptedEventObject.value("recipient_keys"_ls).toObject() + .value(Ed25519Key).toString(); + if (ourKey != QString::fromUtf8(olmAccount->identityKeys().ed25519)) { qCDebug(E2EE) << "Found key" << ourKey << "instead of ours own ed25519 key" - << encryptionManager->account()->identityKeys().ed25519 + << olmAccount->identityKeys().ed25519 << "in Olm plaintext"; return {}; } @@ -266,6 +259,7 @@ public: Connection::Connection(const QUrl& server, QObject* parent) : QObject(parent), d(new Private(std::make_unique(server))) { + d->encryptionManager = new EncryptionManager(this); d->q = this; // All d initialization should occur before this line } @@ -791,21 +785,20 @@ void Connection::Private::consumePresenceData(Events&& presenceData) void Connection::Private::consumeToDeviceEvents(Events&& toDeviceEvents) { #ifdef Quotient_E2EE_ENABLED - // handling m.room_key to-device encrypted event - visitEach(toDeviceEvents, [this](const EncryptedEvent& ee) { - if (ee.algorithm() != OlmV1Curve25519AesSha2AlgoKey) { - qCDebug(E2EE) << "Encrypted event" << ee.id() << "algorithm" - << ee.algorithm() << "is not supported"; + qWarning() << "Consuming to device events" << toDeviceEvents.size(); + if(toDeviceEvents.size() > 0) + visitEach(toDeviceEvents, [this](const EncryptedEvent& event) { + if (event.algorithm() != OlmV1Curve25519AesSha2AlgoKey) { + qCDebug(E2EE) << "Unsupported algorithm" << event.id() << "for event" << event.algorithm(); return; } - visit(*sessionDecryptMessage(ee), - [this, senderKey = ee.senderKey()](const RoomKeyEvent& roomKeyEvent) { + visit(*sessionDecryptMessage(event), + [this, senderKey = event.senderKey()](const RoomKeyEvent& roomKeyEvent) { if (auto* detectedRoom = q->room(roomKeyEvent.roomId())) { detectedRoom->handleRoomKeyEvent(roomKeyEvent, senderKey); } else { - qCDebug(E2EE) - << "Encrypted event room id" << roomKeyEvent.roomId() + qCDebug(E2EE) << "Encrypted event room id" << roomKeyEvent.roomId() << "is not found at the connection" << q->objectName(); } }, diff --git a/lib/encryptionmanager.cpp b/lib/encryptionmanager.cpp index 53890fdb..b9bd6646 100644 --- a/lib/encryptionmanager.cpp +++ b/lib/encryptionmanager.cpp @@ -26,69 +26,16 @@ using std::move; class EncryptionManager::Private { public: - explicit Private(const QByteArray& encryptionAccountPickle, - float signedKeysProportion, float oneTimeKeyThreshold) + explicit Private() : q(nullptr) - , signedKeysProportion(move(signedKeysProportion)) - , oneTimeKeyThreshold(move(oneTimeKeyThreshold)) { - Q_ASSERT((0 <= signedKeysProportion) && (signedKeysProportion <= 1)); - Q_ASSERT((0 <= oneTimeKeyThreshold) && (oneTimeKeyThreshold <= 1)); - if (encryptionAccountPickle.isEmpty()) { - // new e2ee TODO: olmAccount.reset(new QOlmAccount()); - } else { - // new e2ee TODO: olmAccount.reset(new QOlmAccount(encryptionAccountPickle)); // TODO: passphrase even with qtkeychain? - } - /* - * Note about targetKeysNumber: - * - * From: https://github.com/Zil0/matrix-python-sdk/ - * File: matrix_client/crypto/olm_device.py - * - * Try to maintain half the number of one-time keys libolm can hold - * uploaded on the HS. This is because some keys will be claimed by - * peers but not used instantly, and we want them to stay in libolm, - * until the limit is reached and it starts discarding keys, starting by - * the oldest. - */ - targetKeysNumber = olmAccount->maxNumberOfOneTimeKeys() / 2; - targetOneTimeKeyCounts = { - { SignedCurve25519Key, - qRound(signedKeysProportion * targetKeysNumber) }, - { Curve25519Key, - qRound((1 - signedKeysProportion) * targetKeysNumber) } - }; - updateKeysToUpload(); } ~Private() = default; EncryptionManager* q; - UploadKeysJob* uploadIdentityKeysJob = nullptr; - UploadKeysJob* uploadOneTimeKeysInitJob = nullptr; - UploadKeysJob* uploadOneTimeKeysJob = nullptr; - QueryKeysJob* queryKeysJob = nullptr; - - std::unique_ptr olmAccount; - - float signedKeysProportion; - float oneTimeKeyThreshold; - int targetKeysNumber; - - void updateKeysToUpload(); - bool oneTimeKeyShouldUpload(); - - QHash oneTimeKeyCounts; - void setOneTimeKeyCounts(const QHash oneTimeKeyCountsNewValue) - { - oneTimeKeyCounts = oneTimeKeyCountsNewValue; - updateKeysToUpload(); - } - QHash oneTimeKeysToUploadCounts; - QHash targetOneTimeKeyCounts; - // A map from senderKey to InboundSession - QMap> sessions; // TODO: cache + std::map> sessions; // TODO: cache void updateDeviceKeys( const QHash>& deviceKeys) @@ -100,279 +47,76 @@ public: } } } - QString sessionDecrypt(const QOlmMessage& message, const QString& senderKey) + QString sessionDecryptPrekey(const QOlmMessage& message, const QString &senderKey, std::unique_ptr& olmAccount) { - // Try to decrypt message body using one of the known sessions for that - // device - /*bool sessionsPassed = false; - // new e2ee TODO: - for (auto &senderSession : sessions) { - if (senderSession == sessions.last()) { - sessionsPassed = true; - } - - const auto decryptedResult = senderSession->decrypt(message); - if (std::holds_alternative(decryptedResult)) { - qCDebug(E2EE) - << "Success decrypting Olm event using existing session" - << senderSession->sessionId(); - return std::get(decryptedResult); - } else { - const auto error = std::get(decryptedResult); - if (message.type() == QOlmMessage::PreKey) { - const auto matches = senderSession->matchesInboundSessionFrom(senderKey, message); - if (auto hasMatch = std::get_if(&matches)) { - if (hasMatch) { - // We had a matching session for a pre-key message, but - // it didn't work. This means something is wrong, so we - // fail now. - qCDebug(E2EE) - << "Error decrypting pre-key message with existing " - "Olm session" - << senderSession->sessionId() << "reason:" << error; - return QString(); - } - } + Q_ASSERT(message.type() == QOlmMessage::PreKey); + for(auto& session : sessions) { + const auto matches = session.second->matchesInboundSessionFrom(senderKey, message); + if(std::holds_alternative(matches) && std::get(matches)) { + qCDebug(E2EE) << "Found inbound session"; + const auto result = session.second->decrypt(message); + if(std::holds_alternative(result)) { + return std::get(result); + } else { + qCDebug(E2EE) << "Failed to decrypt prekey message"; + return {}; } - // Simply keep trying otherwise } } - if (sessionsPassed || sessions.empty()) { - if (message.type() != QOlmMessage::PreKey) { - // Not a pre-key message, we should have had a matching session - if (!sessions.empty()) { - qCDebug(E2EE) << "Error decrypting with existing sessions"; - return QString(); - } - qCDebug(E2EE) << "No existing sessions"; - return QString(); - } - // We have a pre-key message without any matching session, in this - // case we should try to create one. - qCDebug(E2EE) << "try to establish new InboundSession with" << senderKey; - QOlmMessage preKeyMessage = QOlmMessage(message.toCiphertext(), QOlmMessage::PreKey); - // new e2ee TODO: - //const auto sessionResult = olmAccount->createInboundSessionFrom(senderKey.toUtf8(), preKeyMessage); - - if (const auto error = std::get_if(&sessionResult)) { - qCDebug(E2EE) << "Error decrypting pre-key message when trying " - "to establish a new session:" - << error; - return QString(); - } - - const auto newSession = std::get>(olmAccount->createInboundSessionFrom(senderKey.toUtf8(), preKeyMessage)); - - qCDebug(E2EE) << "Created new Olm session" << newSession->sessionId(); - - const auto decryptedResult = newSession->decrypt(message); - if (const auto error = std::get_if(&decryptedResult)) { - qCDebug(E2EE) - << "Error decrypting pre-key message with new session" - << error; - return QString(); - } - - if (auto error = olmAccount->removeOneTimeKeys(newSession)) { - qCDebug(E2EE) - << "Error removing one time keys" - << error.value(); + qCDebug(E2EE) << "Creating new inbound session"; + auto newSessionResult = olmAccount->createInboundSessionFrom(senderKey.toUtf8(), message); + if(std::holds_alternative(newSessionResult)) { + qCWarning(E2EE) << "Failed to create inbound session for" << senderKey; + return {}; + } + std::unique_ptr newSession = std::move(std::get>(newSessionResult)); + // TODO Error handling? + olmAccount->removeOneTimeKeys(newSession); + const auto result = newSession->decrypt(message); + sessions[senderKey] = std::move(newSession); + if(std::holds_alternative(result)) { + return std::get(result); + } else { + qCDebug(E2EE) << "Failed to decrypt prekey message with new session"; + return {}; + } + } + QString sessionDecryptGeneral(const QOlmMessage& message, const QString &senderKey) + { + Q_ASSERT(message.type() == QOlmMessage::General); + for(auto& session : sessions) { + const auto result = session.second->decrypt(message); + if(std::holds_alternative(result)) { + return std::get(result); } - //sessions.insert(senderKey, std::move(newSession)); TODO - //return std::get(decryptedResult); - }*/ - return QString(); + } + qCWarning(E2EE) << "Failed to decrypt message"; + return {}; } }; -EncryptionManager::EncryptionManager(const QByteArray& encryptionAccountPickle, - float signedKeysProportion, - float oneTimeKeyThreshold, QObject* parent) +EncryptionManager::EncryptionManager(QObject* parent) : QObject(parent) - , d(std::make_unique(std::move(encryptionAccountPickle), - std::move(signedKeysProportion), - std::move(oneTimeKeyThreshold))) + , d(std::make_unique()) { d->q = this; } EncryptionManager::~EncryptionManager() = default; -void EncryptionManager::uploadIdentityKeys(Connection* connection) -{ - // https://matrix.org/docs/spec/client_server/latest#post-matrix-client-r0-keys-upload - DeviceKeys deviceKeys { - /* - * The ID of the user the device belongs to. Must match the user ID used - * when logging in. The ID of the device these keys belong to. Must - * match the device ID used when logging in. The encryption algorithms - * supported by this device. - */ - connection->userId(), - connection->deviceId(), - SupportedAlgorithms, - /* - * Public identity keys. The names of the properties should be in the - * format :. The keys themselves should be encoded - * as specified by the key algorithm. - */ - { { Curve25519Key + QStringLiteral(":") + connection->deviceId(), - d->olmAccount->identityKeys().curve25519 }, - { Ed25519Key + QStringLiteral(":") + connection->deviceId(), - d->olmAccount->identityKeys().curve25519 } }, - /* signatures should be provided after the unsigned deviceKeys - generation */ - {} - }; - - QJsonObject deviceKeysJsonObject = toJson(deviceKeys); - /* additionally removing signatures key, - * since we could not initialize deviceKeys - * without an empty signatures value: - */ - deviceKeysJsonObject.remove(QStringLiteral("signatures")); - /* - * Signatures for the device key object. - * A map from user ID, to a map from : to the - * signature. The signature is calculated using the process called Signing - * JSON. - */ - deviceKeys.signatures = { - { connection->userId(), - { { Ed25519Key + QStringLiteral(":") + connection->deviceId(), - d->olmAccount->sign(deviceKeysJsonObject) } } } - }; - - d->uploadIdentityKeysJob = connection->callApi(deviceKeys); - connect(d->uploadIdentityKeysJob, &BaseJob::success, this, [this] { - d->setOneTimeKeyCounts(d->uploadIdentityKeysJob->oneTimeKeyCounts()); - }); -} - -void EncryptionManager::uploadOneTimeKeys(Connection* connection, - bool forceUpdate) -{ - if (forceUpdate || d->oneTimeKeyCounts.isEmpty()) { - d->uploadOneTimeKeysInitJob = connection->callApi(); - connect(d->uploadOneTimeKeysInitJob, &BaseJob::success, this, [this] { - d->setOneTimeKeyCounts(d->uploadOneTimeKeysInitJob->oneTimeKeyCounts()); - }); - } - - int signedKeysToUploadCount = - d->oneTimeKeysToUploadCounts.value(SignedCurve25519Key, 0); - int unsignedKeysToUploadCount = - d->oneTimeKeysToUploadCounts.value(Curve25519Key, 0); - - d->olmAccount->generateOneTimeKeys(signedKeysToUploadCount - + unsignedKeysToUploadCount); - - QHash oneTimeKeys = {}; - const auto& olmAccountCurve25519OneTimeKeys = d->olmAccount->oneTimeKeys().curve25519(); - - int oneTimeKeysCounter = 0; - for (auto it = olmAccountCurve25519OneTimeKeys.cbegin(); - it != olmAccountCurve25519OneTimeKeys.cend(); ++it) { - QString keyId = it.key(); - QString keyType; - QVariant key; - if (oneTimeKeysCounter < signedKeysToUploadCount) { - QJsonObject message { { QStringLiteral("key"), - it.value() } }; - - QByteArray signedMessage = d->olmAccount->sign(message); - QJsonObject signatures { - { connection->userId(), - QJsonObject { { Ed25519Key + QStringLiteral(":") - + connection->deviceId(), - QString::fromUtf8(signedMessage) } } } - }; - message.insert(QStringLiteral("signatures"), signatures); - key = message; - keyType = SignedCurve25519Key; - } else { - key = it.value(); - keyType = Curve25519Key; - } - ++oneTimeKeysCounter; - oneTimeKeys.insert(QString("%1:%2").arg(keyType).arg(keyId), key); - } - d->uploadOneTimeKeysJob = - connection->callApi(none, oneTimeKeys); - connect(d->uploadOneTimeKeysJob, &BaseJob::success, this, [this] { - d->setOneTimeKeyCounts(d->uploadOneTimeKeysJob->oneTimeKeyCounts()); - }); - // new e2ee TODO: d->olmAccount->markKeysAsPublished(); - qCDebug(E2EE) << QString("Uploaded new one-time keys: %1 signed, %2 unsigned.") - .arg(signedKeysToUploadCount) - .arg(unsignedKeysToUploadCount); -} - -void EncryptionManager::updateOneTimeKeyCounts( - Connection* connection, const QHash& deviceOneTimeKeysCount) -{ - d->oneTimeKeyCounts = deviceOneTimeKeysCount; - if (d->oneTimeKeyShouldUpload()) { - qCDebug(E2EE) << "Uploading new one-time keys."; - uploadOneTimeKeys(connection); - } -} - -void Quotient::EncryptionManager::updateDeviceKeys( - Connection* connection, const QHash& deviceKeys) -{ - d->queryKeysJob = connection->callApi(deviceKeys); - connect(d->queryKeysJob, &BaseJob::success, this, - [this] { d->updateDeviceKeys(d->queryKeysJob->deviceKeys()); }); -} - QString EncryptionManager::sessionDecryptMessage( - const QJsonObject& personalCipherObject, const QByteArray& senderKey) + const QJsonObject& personalCipherObject, const QByteArray& senderKey, std::unique_ptr& account) { QString decrypted; int type = personalCipherObject.value(TypeKeyL).toInt(-1); QByteArray body = personalCipherObject.value(BodyKeyL).toString().toLatin1(); if (type == 0) { QOlmMessage preKeyMessage(body, QOlmMessage::PreKey); - decrypted = d->sessionDecrypt(preKeyMessage, senderKey); + decrypted = d->sessionDecryptPrekey(preKeyMessage, senderKey, account); } else if (type == 1) { - QOlmMessage message(body, QOlmMessage::PreKey); - decrypted = d->sessionDecrypt(message, senderKey); + QOlmMessage message(body, QOlmMessage::General); + decrypted = d->sessionDecryptGeneral(message, senderKey); } return decrypted; } - -QByteArray EncryptionManager::olmAccountPickle() -{ - // new e2ee TODO: return d->olmAccount->pickle(); // TODO: passphrase even with qtkeychain? - return {}; -} - -QOlmAccount *EncryptionManager::account() const -{ - return d->olmAccount.get(); -} - -void EncryptionManager::Private::updateKeysToUpload() -{ - for (auto it = targetOneTimeKeyCounts.cbegin(); - it != targetOneTimeKeyCounts.cend(); ++it) { - int numKeys = oneTimeKeyCounts.value(it.key(), 0); - int numToCreate = qMax(it.value() - numKeys, 0); - oneTimeKeysToUploadCounts.insert(it.key(), numToCreate); - } -} - -bool EncryptionManager::Private::oneTimeKeyShouldUpload() -{ - if (oneTimeKeyCounts.empty()) - return true; - for (auto it = targetOneTimeKeyCounts.cbegin(); - it != targetOneTimeKeyCounts.cend(); ++it) { - if (oneTimeKeyCounts.value(it.key(), 0) - < it.value() * oneTimeKeyThreshold) - return true; - } - return false; -} #endif // Quotient_E2EE_ENABLED diff --git a/lib/encryptionmanager.h b/lib/encryptionmanager.h index 9d2c8138..17f4f853 100644 --- a/lib/encryptionmanager.h +++ b/lib/encryptionmanager.h @@ -17,26 +17,10 @@ class EncryptionManager : public QObject { Q_OBJECT public: - // TODO: store constats separately? - // TODO: 0.5 oneTimeKeyThreshold instead of 0.1? - explicit EncryptionManager( - const QByteArray& encryptionAccountPickle = QByteArray(), - float signedKeysProportion = 1, float oneTimeKeyThreshold = float(0.1), - QObject* parent = nullptr); + explicit EncryptionManager(QObject* parent = nullptr); ~EncryptionManager(); - - void uploadIdentityKeys(Connection* connection); - void uploadOneTimeKeys(Connection* connection, bool forceUpdate = false); - void - updateOneTimeKeyCounts(Connection* connection, - const QHash& deviceOneTimeKeysCount); - void updateDeviceKeys(Connection* connection, - const QHash& deviceKeys); QString sessionDecryptMessage(const QJsonObject& personalCipherObject, - const QByteArray& senderKey); - QByteArray olmAccountPickle(); - - QOlmAccount* account() const; + const QByteArray& senderKey, std::unique_ptr& account); private: class Private; -- cgit v1.2.3 From 3e51359d1b7891b9a6e4611662c753653c3618bf Mon Sep 17 00:00:00 2001 From: Tobias Fella Date: Wed, 2 Jun 2021 19:39:34 +0200 Subject: Things --- lib/connection.cpp | 1 + lib/encryptionmanager.h | 1 + 2 files changed, 2 insertions(+) (limited to 'lib/encryptionmanager.h') diff --git a/lib/connection.cpp b/lib/connection.cpp index 2d040e8a..494db170 100644 --- a/lib/connection.cpp +++ b/lib/connection.cpp @@ -796,6 +796,7 @@ void Connection::Private::consumeToDeviceEvents(Events&& toDeviceEvents) visit(*sessionDecryptMessage(event), [this, senderKey = event.senderKey()](const RoomKeyEvent& roomKeyEvent) { if (auto* detectedRoom = q->room(roomKeyEvent.roomId())) { + qWarning() << "IT'S A ROOMKEY EVENT, RUUUUUUUUUUUUUUUUUN"; detectedRoom->handleRoomKeyEvent(roomKeyEvent, senderKey); } else { qCDebug(E2EE) << "Encrypted event room id" << roomKeyEvent.roomId() diff --git a/lib/encryptionmanager.h b/lib/encryptionmanager.h index 17f4f853..db9bff07 100644 --- a/lib/encryptionmanager.h +++ b/lib/encryptionmanager.h @@ -19,6 +19,7 @@ class EncryptionManager : public QObject { public: explicit EncryptionManager(QObject* parent = nullptr); ~EncryptionManager(); + QString sessionDecryptMessage(const QJsonObject& personalCipherObject, const QByteArray& senderKey, std::unique_ptr& account); -- cgit v1.2.3 From f89c05408bc9a4bf59366f92c50f055d527b9a28 Mon Sep 17 00:00:00 2001 From: Tobias Fella Date: Sat, 12 Jun 2021 18:58:54 +0200 Subject: Remove unrelated changes --- lib/connection.cpp | 7 +++---- lib/encryptionmanager.h | 1 - 2 files changed, 3 insertions(+), 5 deletions(-) (limited to 'lib/encryptionmanager.h') diff --git a/lib/connection.cpp b/lib/connection.cpp index d7115885..ab5e030b 100644 --- a/lib/connection.cpp +++ b/lib/connection.cpp @@ -797,13 +797,12 @@ void Connection::Private::consumeToDeviceEvents(Events&& toDeviceEvents) return; } - visit(*sessionDecryptMessage(ee), - [this, senderKey = ee.senderKey()](const RoomKeyEvent& roomKeyEvent) { + visit(*sessionDecryptMessage(event), + [this, senderKey = event.senderKey()](const RoomKeyEvent& roomKeyEvent) { if (auto* detectedRoom = q->room(roomKeyEvent.roomId())) { detectedRoom->handleRoomKeyEvent(roomKeyEvent, senderKey); } else { - qCDebug(E2EE) - << "Encrypted event room id" << roomKeyEvent.roomId() + qCDebug(E2EE) << "Encrypted event room id" << roomKeyEvent.roomId() << "is not found at the connection" << q->objectName(); } }, diff --git a/lib/encryptionmanager.h b/lib/encryptionmanager.h index db9bff07..17f4f853 100644 --- a/lib/encryptionmanager.h +++ b/lib/encryptionmanager.h @@ -19,7 +19,6 @@ class EncryptionManager : public QObject { public: explicit EncryptionManager(QObject* parent = nullptr); ~EncryptionManager(); - QString sessionDecryptMessage(const QJsonObject& personalCipherObject, const QByteArray& senderKey, std::unique_ptr& account); -- cgit v1.2.3 From 9f08e5d865a5500d2926f10de85da2d5dcd063f7 Mon Sep 17 00:00:00 2001 From: Tobias Fella Date: Wed, 8 Sep 2021 16:07:45 +0200 Subject: Add a function for decrypting E2EE files/images --- lib/encryptionmanager.cpp | 24 ++++++++++++++++++++++++ lib/encryptionmanager.h | 2 ++ 2 files changed, 26 insertions(+) (limited to 'lib/encryptionmanager.h') diff --git a/lib/encryptionmanager.cpp b/lib/encryptionmanager.cpp index b9bd6646..48e6701c 100644 --- a/lib/encryptionmanager.cpp +++ b/lib/encryptionmanager.cpp @@ -7,11 +7,13 @@ #include "connection.h" #include "crypto/e2ee.h" +#include "events/encryptedfile.h" #include "csapi/keys.h" #include #include +#include #include "crypto/qolmaccount.h" #include "crypto/qolmsession.h" @@ -21,6 +23,8 @@ #include #include +#include + using namespace Quotient; using std::move; @@ -119,4 +123,24 @@ QString EncryptionManager::sessionDecryptMessage( } return decrypted; } + +QByteArray EncryptionManager::decryptFile(const QByteArray &ciphertext, EncryptedFile* file) +{ + const auto key = QByteArray::fromBase64(file->key.k.replace(QLatin1Char('_'), QLatin1Char('/')).replace(QLatin1Char('-'), QLatin1Char('+')).toLatin1()); + const auto iv = QByteArray::fromBase64(file->iv.toLatin1()); + const auto sha256 = QByteArray::fromBase64(file->hashes["sha256"].toLatin1()); + if(sha256 != QCryptographicHash::hash(ciphertext, QCryptographicHash::Sha256)) { + qCWarning(E2EE) << "Hash verification failed for file"; + return QByteArray(); + } + QByteArray plaintext(ciphertext.size(), 0); + EVP_CIPHER_CTX *ctx; + int length; + ctx = EVP_CIPHER_CTX_new(); + EVP_DecryptInit_ex(ctx, EVP_aes_256_ctr(), NULL, (const unsigned char *)key.data(), (const unsigned char *)iv.data()); + EVP_DecryptUpdate(ctx, (unsigned char *)plaintext.data(), &length, (const unsigned char *)ciphertext.data(), ciphertext.size()); + EVP_DecryptFinal_ex(ctx, (unsigned char *)plaintext.data() + length, &length); + EVP_CIPHER_CTX_free(ctx); + return plaintext; +} #endif // Quotient_E2EE_ENABLED diff --git a/lib/encryptionmanager.h b/lib/encryptionmanager.h index 17f4f853..96569980 100644 --- a/lib/encryptionmanager.h +++ b/lib/encryptionmanager.h @@ -12,6 +12,7 @@ namespace Quotient { class Connection; class QOlmAccount; +struct EncryptedFile; class EncryptionManager : public QObject { Q_OBJECT @@ -21,6 +22,7 @@ public: ~EncryptionManager(); QString sessionDecryptMessage(const QJsonObject& personalCipherObject, const QByteArray& senderKey, std::unique_ptr& account); + static QByteArray decryptFile(const QByteArray &ciphertext, EncryptedFile* encryptedFile); private: class Private; -- cgit v1.2.3 From 7b5edb737522b03d4f697e0e09f1771ad5edef89 Mon Sep 17 00:00:00 2001 From: Tobias Fella Date: Mon, 7 Feb 2022 21:48:07 +0100 Subject: Remove encryptionmanager and various fixes --- CMakeLists.txt | 2 +- autotests/testolmaccount.cpp | 2 +- lib/connection.cpp | 108 ++++++++++++++++++++++++----- lib/connection.h | 2 - lib/e2ee/qolminboundsession.cpp | 2 + lib/encryptionmanager.cpp | 149 ---------------------------------------- lib/encryptionmanager.h | 33 --------- lib/events/encryptedfile.cpp | 27 ++++++++ lib/events/encryptedfile.h | 6 ++ lib/jobs/downloadfilejob.cpp | 5 +- lib/mxcreply.cpp | 3 +- 11 files changed, 130 insertions(+), 209 deletions(-) delete mode 100644 lib/encryptionmanager.cpp delete mode 100644 lib/encryptionmanager.h create mode 100644 lib/events/encryptedfile.cpp (limited to 'lib/encryptionmanager.h') diff --git a/CMakeLists.txt b/CMakeLists.txt index 9ef3477e..69ac7e20 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -156,6 +156,7 @@ list(APPEND lib_SRCS lib/events/roomkeyevent.cpp lib/events/stickerevent.cpp lib/events/keyverificationevent.cpp + lib/events/encryptedfile.cpp lib/jobs/requestdata.cpp lib/jobs/basejob.cpp lib/jobs/syncjob.cpp @@ -174,7 +175,6 @@ if (${PROJECT_NAME}_ENABLE_E2EE) lib/e2ee/qolmerrors.cpp lib/e2ee/qolmsession.cpp lib/e2ee/qolmmessage.cpp - lib/encryptionmanager.cpp ) endif() diff --git a/autotests/testolmaccount.cpp b/autotests/testolmaccount.cpp index 45d158eb..62b786d0 100644 --- a/autotests/testolmaccount.cpp +++ b/autotests/testolmaccount.cpp @@ -537,7 +537,7 @@ void TestOlmAccount::enableEncryption() QString joinedRoom; auto job = alice->createRoom(Connection::PublishRoom, QString(), QString(), QString(), {"@bob:localhost"}); - connect(alice.get(), &Connection::newRoom, this, [alice, bob, joinedRoom, this] (Quotient::Room *room) { + connect(alice.get(), &Connection::newRoom, this, [alice, bob, &joinedRoom, this] (Quotient::Room *room) { room->activateEncryption(); QSignalSpy spy(room, &Room::encryption); diff --git a/lib/connection.cpp b/lib/connection.cpp index 58e3a9f8..1a1b284d 100644 --- a/lib/connection.cpp +++ b/lib/connection.cpp @@ -37,7 +37,6 @@ #ifdef Quotient_E2EE_ENABLED # include "e2ee/qolmaccount.h" # include "e2ee/qolmutils.h" -# include "encryptionmanager.h" # include "database.h" #if QT_VERSION_MAJOR >= 6 @@ -117,6 +116,10 @@ public: bool encryptionUpdateRequired = false; PicklingMode picklingMode = Unencrypted {}; Database *database = nullptr; + + // A map from SenderKey to vector of InboundSession + UnorderedMap> olmSessions; + #endif GetCapabilitiesJob* capabilitiesJob = nullptr; @@ -127,7 +130,6 @@ public: #ifdef Quotient_E2EE_ENABLED std::unique_ptr olmAccount; bool isUploadingKeys = false; - EncryptionManager *encryptionManager; #endif // Quotient_E2EE_ENABLED QPointer resolverJob = nullptr; @@ -201,6 +203,85 @@ public: return q->stateCacheDir().filePath("state.json"); } +#ifdef Quotient_E2EE_ENABLED + void loadSessions() { + olmSessions = q->database()->loadOlmSessions(q->picklingMode()); + } + void saveSession(QOlmSessionPtr& session, const QString &senderKey) { + auto pickleResult = session->pickle(q->picklingMode()); + if (std::holds_alternative(pickleResult)) { + qCWarning(E2EE) << "Failed to pickle olm session. Error" << std::get(pickleResult); + return; + } + q->database()->saveOlmSession(senderKey, session->sessionId(), std::get(pickleResult)); + } + QString sessionDecryptPrekey(const QOlmMessage& message, const QString &senderKey, std::unique_ptr& olmAccount) + { + Q_ASSERT(message.type() == QOlmMessage::PreKey); + for(auto& session : olmSessions[senderKey]) { + const auto matches = session->matchesInboundSessionFrom(senderKey, message); + if(std::holds_alternative(matches) && std::get(matches)) { + qCDebug(E2EE) << "Found inbound session"; + const auto result = session->decrypt(message); + if(std::holds_alternative(result)) { + return std::get(result); + } else { + qCDebug(E2EE) << "Failed to decrypt prekey message"; + return {}; + } + } + } + qCDebug(E2EE) << "Creating new inbound session"; + auto newSessionResult = olmAccount->createInboundSessionFrom(senderKey.toUtf8(), message); + if(std::holds_alternative(newSessionResult)) { + qCWarning(E2EE) << "Failed to create inbound session for" << senderKey << std::get(newSessionResult); + return {}; + } + auto newSession = std::move(std::get(newSessionResult)); + auto error = olmAccount->removeOneTimeKeys(newSession); + if (error) { + qWarning(E2EE) << "Failed to remove one time key for session" << newSession->sessionId(); + } + const auto result = newSession->decrypt(message); + saveSession(newSession, senderKey); + olmSessions[senderKey].push_back(std::move(newSession)); + if(std::holds_alternative(result)) { + return std::get(result); + } else { + qCDebug(E2EE) << "Failed to decrypt prekey message with new session"; + return {}; + } + } + QString sessionDecryptGeneral(const QOlmMessage& message, const QString &senderKey) + { + Q_ASSERT(message.type() == QOlmMessage::General); + for(auto& session : olmSessions[senderKey]) { + const auto result = session->decrypt(message); + if(std::holds_alternative(result)) { + return std::get(result); + } + } + qCWarning(E2EE) << "Failed to decrypt message"; + return {}; + } + + QString sessionDecryptMessage( + const QJsonObject& personalCipherObject, const QByteArray& senderKey, std::unique_ptr& account) + { + QString decrypted; + int type = personalCipherObject.value(TypeKeyL).toInt(-1); + QByteArray body = personalCipherObject.value(BodyKeyL).toString().toLatin1(); + if (type == 0) { + QOlmMessage preKeyMessage(body, QOlmMessage::PreKey); + decrypted = sessionDecryptPrekey(preKeyMessage, senderKey, account); + } else if (type == 1) { + QOlmMessage message(body, QOlmMessage::General); + decrypted = sessionDecryptGeneral(message, senderKey); + } + return decrypted; + } +#endif + EventPtr sessionDecryptMessage(const EncryptedEvent& encryptedEvent) { #ifndef Quotient_E2EE_ENABLED @@ -217,7 +298,7 @@ public: qCDebug(E2EE) << "Encrypted event is not for the current device"; return {}; } - const auto decrypted = encryptionManager->sessionDecryptMessage( + const auto decrypted = sessionDecryptMessage( personalCipherObject, encryptedEvent.senderKey().toLatin1(), olmAccount); if (decrypted.isEmpty()) { qCDebug(E2EE) << "Problem with new session from senderKey:" @@ -443,6 +524,7 @@ void Connection::Private::loginToServer(LoginArgTs&&... loginArgs) #ifndef Quotient_E2EE_ENABLED qCWarning(E2EE) << "End-to-end encryption (E2EE) support is turned off."; #endif // Quotient_E2EE_ENABLED + database->clear(); }); connect(loginJob, &BaseJob::failure, q, [this, loginJob] { emit q->loginError(loginJob->errorString(), loginJob->rawDataSample()); @@ -493,13 +575,15 @@ void Connection::Private::completeSetup(const QString& mxId) picklingMode = Encrypted { job.binaryData() }; } + database = new Database(data->userId(), q); + // init olmAccount olmAccount = std::make_unique(data->userId(), data->deviceId(), q); connect(olmAccount.get(), &QOlmAccount::needsSave, q, &Connection::saveOlmAccount); - database = new Database(data->userId(), q); - - encryptionManager = new EncryptionManager(q); +#ifdef Quotient_E2EE_ENABLED + loadSessions(); +#endif if (database->accountPickle().isEmpty()) { // create new account and save unpickle data @@ -2019,18 +2103,6 @@ void Connection::saveOlmAccount() #endif } -QString Connection::e2eeDataDir() const -{ - auto safeUserId = userId(); - safeUserId.replace(':', '_'); - const QString path = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) % '/' - % safeUserId % '/'; - QDir dir; - if (!dir.exists(path)) - dir.mkpath(path); - return path; -} - #ifdef Quotient_E2EE_ENABLED QJsonObject Connection::decryptNotification(const QJsonObject ¬ification) { diff --git a/lib/connection.h b/lib/connection.h index 93ee496e..8dec2a0c 100644 --- a/lib/connection.h +++ b/lib/connection.h @@ -401,8 +401,6 @@ public: bool lazyLoading() const; void setLazyLoading(bool newValue); - QString e2eeDataDir() const; - /*! Start a pre-created job object on this connection */ Q_INVOKABLE BaseJob* run(BaseJob* job, RunningPolicy runningPolicy = ForegroundRequest); diff --git a/lib/e2ee/qolminboundsession.cpp b/lib/e2ee/qolminboundsession.cpp index 9bc80eef..2e9cc716 100644 --- a/lib/e2ee/qolminboundsession.cpp +++ b/lib/e2ee/qolminboundsession.cpp @@ -4,6 +4,8 @@ #include "e2ee/qolminboundsession.h" #include +#include + using namespace Quotient; QOlmError lastError(OlmInboundGroupSession *session) { diff --git a/lib/encryptionmanager.cpp b/lib/encryptionmanager.cpp deleted file mode 100644 index abdcdcee..00000000 --- a/lib/encryptionmanager.cpp +++ /dev/null @@ -1,149 +0,0 @@ -// SPDX-FileCopyrightText: 2019 Alexey Andreyev -// SPDX-FileCopyrightText: 2019 Kitsune Ral -// SPDX-License-Identifier: LGPL-2.1-or-later - -#ifdef Quotient_E2EE_ENABLED -#include "encryptionmanager.h" - -#include "connection.h" -#include "events/encryptedfile.h" -#include "database.h" - -#include "csapi/keys.h" - -#include -#include -#include - -#include "e2ee/e2ee.h" -#include "e2ee/qolmaccount.h" -#include "e2ee/qolmsession.h" -#include "e2ee/qolmmessage.h" -#include "e2ee/qolmerrors.h" -#include "e2ee/qolmutils.h" -#include -#include - -#include - -using namespace Quotient; -using std::move; - -class EncryptionManager::Private { -public: - EncryptionManager* q; - - Connection* connection; - - // A map from SenderKey to vector of InboundSession - UnorderedMap> sessions; - - void loadSessions() { - sessions = connection->database()->loadOlmSessions(connection->picklingMode()); - } - void saveSession(QOlmSessionPtr& session, const QString &senderKey) { - auto pickleResult = session->pickle(connection->picklingMode()); - if (std::holds_alternative(pickleResult)) { - qCWarning(E2EE) << "Failed to pickle olm session. Error" << std::get(pickleResult); - return; - } - connection->database()->saveOlmSession(senderKey, session->sessionId(), std::get(pickleResult)); - } - QString sessionDecryptPrekey(const QOlmMessage& message, const QString &senderKey, std::unique_ptr& olmAccount) - { - Q_ASSERT(message.type() == QOlmMessage::PreKey); - for(auto& session : sessions[senderKey]) { - const auto matches = session->matchesInboundSessionFrom(senderKey, message); - if(std::holds_alternative(matches) && std::get(matches)) { - qCDebug(E2EE) << "Found inbound session"; - const auto result = session->decrypt(message); - if(std::holds_alternative(result)) { - return std::get(result); - } else { - qCDebug(E2EE) << "Failed to decrypt prekey message"; - return {}; - } - } - } - qCDebug(E2EE) << "Creating new inbound session"; - auto newSessionResult = olmAccount->createInboundSessionFrom(senderKey.toUtf8(), message); - if(std::holds_alternative(newSessionResult)) { - qCWarning(E2EE) << "Failed to create inbound session for" << senderKey << std::get(newSessionResult); - return {}; - } - auto newSession = std::move(std::get(newSessionResult)); - auto error = olmAccount->removeOneTimeKeys(newSession); - if (error) { - qWarning(E2EE) << "Failed to remove one time key for session" << newSession->sessionId(); - } - const auto result = newSession->decrypt(message); - saveSession(newSession, senderKey); - sessions[senderKey].push_back(std::move(newSession)); - if(std::holds_alternative(result)) { - return std::get(result); - } else { - qCDebug(E2EE) << "Failed to decrypt prekey message with new session"; - return {}; - } - } - QString sessionDecryptGeneral(const QOlmMessage& message, const QString &senderKey) - { - Q_ASSERT(message.type() == QOlmMessage::General); - for(auto& session : sessions[senderKey]) { - const auto result = session->decrypt(message); - if(std::holds_alternative(result)) { - return std::get(result); - } - } - qCWarning(E2EE) << "Failed to decrypt message"; - return {}; - } -}; - -EncryptionManager::EncryptionManager(QObject* parent) - : QObject(parent) - , d(std::make_unique()) -{ - d->q = this; - d->connection = static_cast(parent); - d->loadSessions(); -} - -EncryptionManager::~EncryptionManager() = default; - -QString EncryptionManager::sessionDecryptMessage( - const QJsonObject& personalCipherObject, const QByteArray& senderKey, std::unique_ptr& account) -{ - QString decrypted; - int type = personalCipherObject.value(TypeKeyL).toInt(-1); - QByteArray body = personalCipherObject.value(BodyKeyL).toString().toLatin1(); - if (type == 0) { - QOlmMessage preKeyMessage(body, QOlmMessage::PreKey); - decrypted = d->sessionDecryptPrekey(preKeyMessage, senderKey, account); - } else if (type == 1) { - QOlmMessage message(body, QOlmMessage::General); - decrypted = d->sessionDecryptGeneral(message, senderKey); - } - return decrypted; -} - -QByteArray EncryptionManager::decryptFile(const QByteArray &ciphertext, EncryptedFile* file) -{ - const auto key = QByteArray::fromBase64(file->key.k.replace(QLatin1Char('_'), QLatin1Char('/')).replace(QLatin1Char('-'), QLatin1Char('+')).toLatin1()); - const auto iv = QByteArray::fromBase64(file->iv.toLatin1()); - const auto sha256 = QByteArray::fromBase64(file->hashes["sha256"].toLatin1()); - if(sha256 != QCryptographicHash::hash(ciphertext, QCryptographicHash::Sha256)) { - qCWarning(E2EE) << "Hash verification failed for file"; - return QByteArray(); - } - QByteArray plaintext(ciphertext.size(), 0); - EVP_CIPHER_CTX *ctx; - int length; - ctx = EVP_CIPHER_CTX_new(); - EVP_DecryptInit_ex(ctx, EVP_aes_256_ctr(), NULL, (const unsigned char *)key.data(), (const unsigned char *)iv.data()); - EVP_DecryptUpdate(ctx, (unsigned char *)plaintext.data(), &length, (const unsigned char *)ciphertext.data(), ciphertext.size()); - EVP_DecryptFinal_ex(ctx, (unsigned char *)plaintext.data() + length, &length); - EVP_CIPHER_CTX_free(ctx); - return plaintext; -} -#endif // Quotient_E2EE_ENABLED diff --git a/lib/encryptionmanager.h b/lib/encryptionmanager.h deleted file mode 100644 index 96569980..00000000 --- a/lib/encryptionmanager.h +++ /dev/null @@ -1,33 +0,0 @@ -// SPDX-FileCopyrightText: 2019 Alexey Andreyev -// SPDX-License-Identifier: LGPL-2.1-or-later - -#ifdef Quotient_E2EE_ENABLED -#pragma once - -#include - -#include -#include - -namespace Quotient { -class Connection; -class QOlmAccount; -struct EncryptedFile; - -class EncryptionManager : public QObject { - Q_OBJECT - -public: - explicit EncryptionManager(QObject* parent = nullptr); - ~EncryptionManager(); - QString sessionDecryptMessage(const QJsonObject& personalCipherObject, - const QByteArray& senderKey, std::unique_ptr& account); - static QByteArray decryptFile(const QByteArray &ciphertext, EncryptedFile* encryptedFile); - -private: - class Private; - std::unique_ptr d; -}; - -} // namespace Quotient -#endif // Quotient_E2EE_ENABLED diff --git a/lib/events/encryptedfile.cpp b/lib/events/encryptedfile.cpp new file mode 100644 index 00000000..5ec344bb --- /dev/null +++ b/lib/events/encryptedfile.cpp @@ -0,0 +1,27 @@ +// SPDX-FileCopyrightText: 2021 Carl Schwan +// +// SPDX-License-Identifier: LGPL-2.1-or-later + +#include "encryptedfile.h" + +using namespace Quotient; + +QByteArray EncryptedFile::decryptFile(const QByteArray &ciphertext) const +{ + QString _key = key.k; + _key = QByteArray::fromBase64(_key.replace(QLatin1Char('_'), QLatin1Char('/')).replace(QLatin1Char('-'), QLatin1Char('+')).toLatin1()); + const auto sha256 = QByteArray::fromBase64(hashes["sha256"].toLatin1()); + if(sha256 != QCryptographicHash::hash(ciphertext, QCryptographicHash::Sha256)) { + qCWarning(E2EE) << "Hash verification failed for file"; + return QByteArray(); + } + QByteArray plaintext(ciphertext.size(), 0); + EVP_CIPHER_CTX *ctx; + int length; + ctx = EVP_CIPHER_CTX_new(); + EVP_DecryptInit_ex(ctx, EVP_aes_256_ctr(), NULL, (const unsigned char *)_key.data(), (const unsigned char *)iv.toLatin1().data()); + EVP_DecryptUpdate(ctx, (unsigned char *)plaintext.data(), &length, (const unsigned char *)ciphertext.data(), ciphertext.size()); + EVP_DecryptFinal_ex(ctx, (unsigned char *)plaintext.data() + length, &length); + EVP_CIPHER_CTX_free(ctx); + return plaintext; +} diff --git a/lib/events/encryptedfile.h b/lib/events/encryptedfile.h index 24ac9de1..f271d345 100644 --- a/lib/events/encryptedfile.h +++ b/lib/events/encryptedfile.h @@ -5,6 +5,10 @@ #pragma once #include "converters.h" +#include "logging.h" + +#include +#include namespace Quotient { /** @@ -44,6 +48,8 @@ public: QString iv; QHash hashes; QString v; + + QByteArray decryptFile(const QByteArray &ciphertext) const; }; template <> diff --git a/lib/jobs/downloadfilejob.cpp b/lib/jobs/downloadfilejob.cpp index 2eea9d59..c5280770 100644 --- a/lib/jobs/downloadfilejob.cpp +++ b/lib/jobs/downloadfilejob.cpp @@ -9,7 +9,6 @@ #ifdef Quotient_E2EE_ENABLED # include -# include "encryptionmanager.h" # include "events/encryptedfile.h" #endif @@ -126,7 +125,7 @@ BaseJob::Status DownloadFileJob::prepareResult() QByteArray encrypted = d->tempFile->readAll(); EncryptedFile file = *d->encryptedFile; - auto decrypted = EncryptionManager::decryptFile(encrypted, &file); + auto decrypted = file.decryptFile(encrypted); d->targetFile->write(decrypted); d->tempFile->remove(); } else { @@ -151,7 +150,7 @@ BaseJob::Status DownloadFileJob::prepareResult() auto encrypted = d->tempFile->readAll(); EncryptedFile file = *d->encryptedFile; - auto decrypted = EncryptionManager::decryptFile(encrypted, &file); + auto decrypted = file.decryptFile(encrypted); d->tempFile->write(decrypted); } else { #endif diff --git a/lib/mxcreply.cpp b/lib/mxcreply.cpp index c7f27b0c..c666cce3 100644 --- a/lib/mxcreply.cpp +++ b/lib/mxcreply.cpp @@ -9,7 +9,6 @@ #include "room.h" #ifdef Quotient_E2EE_ENABLED -#include "encryptionmanager.h" #include "events/encryptedfile.h" #endif @@ -51,7 +50,7 @@ MxcReply::MxcReply(QNetworkReply* reply, Room* room, const QString &eventId) } else { EncryptedFile file = *d->m_encryptedFile; auto buffer = new QBuffer(this); - buffer->setData(EncryptionManager::decryptFile(d->m_reply->readAll(), &file)); + buffer->setData(file.decryptFile(d->m_reply->readAll())); buffer->open(ReadOnly); d->m_device = buffer; } -- cgit v1.2.3