aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexey Andreyev <aa13q@ya.ru>2019-08-23 17:14:09 +0300
committerAlexey Andreev <aa13q@ya.ru>2020-02-25 17:57:32 +0300
commit715a0c0aa094eedbe24516e19a7b37dde71ba994 (patch)
tree332f95145eaf3a1ae9315a72ad62e9986bf4d676
parent3c293b287466e8de188fc62e73efc4730ab4dd31 (diff)
downloadlibquotient-715a0c0aa094eedbe24516e19a7b37dde71ba994.tar.gz
libquotient-715a0c0aa094eedbe24516e19a7b37dde71ba994.zip
E2EE: add connection session decrypt, handle to-device and device_one_time_keys_count
Signed-off-by: Alexey Andreev <aa13q@ya.ru>
-rw-r--r--lib/connection.cpp112
-rw-r--r--lib/room.cpp5
-rw-r--r--lib/room.h2
3 files changed, 119 insertions, 0 deletions
diff --git a/lib/connection.cpp b/lib/connection.cpp
index 75c459d5..98c8a4bc 100644
--- a/lib/connection.cpp
+++ b/lib/connection.cpp
@@ -43,6 +43,8 @@
#include "jobs/mediathumbnailjob.h"
#include "jobs/syncjob.h"
+#include "account.h" // QtOlm
+
#include <QtCore/QCoreApplication>
#include <QtCore/QDir>
#include <QtCore/QElapsedTimer>
@@ -148,6 +150,65 @@ public:
{
return q->stateCacheDir().filePath("state.json");
}
+
+ RoomEventPtr sessionDecryptMessage(const EncryptedEvent& encryptedEvent)
+ {
+ if (encryptedEvent.algorithm() != OlmV1Curve25519AesSha2AlgoKey)
+ {
+ return {};
+ }
+ QString identityKey =
+ encryptionManager->account()->curve25519IdentityKey();
+ QJsonObject personalCipherObject =
+ encryptedEvent.ciphertext(identityKey);
+ if (personalCipherObject.isEmpty()) {
+ qCDebug(E2EE) << "Encrypted event is not for the current device";
+ return {};
+ }
+ QString decrypted = encryptionManager->sessionDecryptMessage(
+ personalCipherObject, encryptedEvent.senderKey().toLatin1());
+ if (decrypted.isEmpty()) {
+ qCDebug(E2EE) << "Problem with new session from senderKey:"
+ << encryptedEvent.senderKey()
+ << encryptionManager->account()->oneTimeKeys();
+ return {};
+ }
+
+ RoomEventPtr decryptedEvent = makeEvent<RoomMessageEvent>(
+ QJsonDocument::fromJson(decrypted.toUtf8()).object());
+
+ if (decryptedEvent->senderId() != encryptedEvent.senderId()) {
+ qCDebug(E2EE) << "Found user" << decryptedEvent->senderId()
+ << "instead of sender" << encryptedEvent.senderId()
+ << "in Olm plaintext";
+ return {};
+ }
+
+ // TODO: keys to constants
+ QJsonObject decryptedEventObject = decryptedEvent->fullJson();
+ QString recipient =
+ decryptedEventObject.value("recipient"_ls).toString();
+ if (recipient != data->userId()) {
+ qCDebug(E2EE) << "Found user" << recipient << "instead of us"
+ << data->userId() << "in Olm plaintext";
+ return {};
+ }
+ QString ourKey = decryptedEventObject.value("recipient_keys"_ls)
+ .toObject()
+ .value(Ed25519Key)
+ .toString();
+ if (ourKey
+ != QString::fromUtf8(
+ encryptionManager->account()->ed25519IdentityKey())) {
+ qCDebug(E2EE) << "Found key" << ourKey
+ << "instead of ours own ed25519 key"
+ << encryptionManager->account()->ed25519IdentityKey()
+ << "in Olm plaintext";
+ return {};
+ }
+
+ return decryptedEvent;
+ }
};
Connection::Connection(const QUrl& server, QObject* parent)
@@ -533,6 +594,57 @@ void Connection::onSyncSuccess(SyncData&& data, bool fromCache)
d->dcLocalAdditions.clear();
d->dcLocalRemovals.clear();
}
+ // handling m.room_key to-device encrypted event
+ for (auto&& toDeviceEvent : data.takeToDeviceEvents()) {
+ if (toDeviceEvent->type() == EncryptedEvent::typeId()) {
+ event_ptr_tt<EncryptedEvent> encryptedEvent =
+ makeEvent<EncryptedEvent>(toDeviceEvent->fullJson());
+ if (encryptedEvent->algorithm() != OlmV1Curve25519AesSha2AlgoKey) {
+ qCDebug(E2EE)
+ << "Encrypted event" << encryptedEvent->id() << "algorithm"
+ << encryptedEvent->algorithm() << "is not supported";
+ return;
+ }
+
+ // TODO: full maintaining of the device keys
+ // with device_lists sync extention and /keys/query
+ qCDebug(E2EE) << "Getting device keys for the m.room_key sender:"
+ << encryptedEvent->senderId();
+ // d->encryptionManager->updateDeviceKeys();
+
+ RoomEventPtr decryptedEvent =
+ d->sessionDecryptMessage(*encryptedEvent.get());
+ // since we are waiting for the RoomKeyEvent:
+ event_ptr_tt<RoomKeyEvent> roomKeyEvent =
+ makeEvent<RoomKeyEvent>(decryptedEvent->fullJson());
+ if (!roomKeyEvent) {
+ qCDebug(E2EE) << "Failed to decrypt olm event from user"
+ << encryptedEvent->senderId();
+ return;
+ }
+ Room* detectedRoom = room(roomKeyEvent->roomId());
+ if (!detectedRoom) {
+ qCDebug(E2EE)
+ << "Encrypted event room id" << encryptedEvent->roomId()
+ << "is not found at the connection";
+ return;
+ }
+ detectedRoom->handleRoomKeyEvent(roomKeyEvent.get(),
+ encryptedEvent->senderKey());
+ }
+ }
+ // handling device_one_time_keys_count
+ auto deviceOneTimeKeysCount = data.deviceOneTimeKeysCount();
+ if (!d->encryptionManager)
+ {
+ qCDebug(E2EE) << "Encryption manager is not there yet";
+ return;
+ }
+ if (!deviceOneTimeKeysCount.isEmpty())
+ {
+ d->encryptionManager->updateOneTimeKeyCounts(this,
+ deviceOneTimeKeysCount);
+ }
}
void Connection::stopSync()
diff --git a/lib/room.cpp b/lib/room.cpp
index b29f6f48..45c1be8b 100644
--- a/lib/room.cpp
+++ b/lib/room.cpp
@@ -1233,6 +1233,11 @@ QString Room::decryptMessage(QByteArray cipher, const QString& senderKey,
return decrypted;
}
+void Room::handleRoomKeyEvent(RoomKeyEvent *roomKeyEvent, QString senderKey)
+{
+ // TODO
+}
+
int Room::joinedCount() const
{
return d->summary.joinedMemberCount.value_or(d->membersMap.size());
diff --git a/lib/room.h b/lib/room.h
index ad19792e..2243ec6b 100644
--- a/lib/room.h
+++ b/lib/room.h
@@ -26,6 +26,7 @@
#include "events/accountdataevents.h"
#include "events/encryptedevent.h"
+#include "events/roomkeyevent.h"
#include "events/roommessageevent.h"
#include "events/roomcreateevent.h"
#include "events/roomtombstoneevent.h"
@@ -215,6 +216,7 @@ public:
const QString& sessionId) const;
QString decryptMessage(QByteArray cipher, const QString& senderKey,
const QString& deviceId, const QString& sessionId);
+ void handleRoomKeyEvent(RoomKeyEvent* roomKeyEvent, QString senderKey);
int joinedCount() const;
int invitedCount() const;
int totalMemberCount() const;