Page MenuHomePhorge

D26.1732558651.diff
No OneTemporary

Size
6 KB
Referenced Files
None
Subscribers
None

D26.1732558651.diff

diff --git a/src/client/client-model.hpp b/src/client/client-model.hpp
--- a/src/client/client-model.hpp
+++ b/src/client/client-model.hpp
@@ -97,8 +97,13 @@
std::pair<Event, std::optional<std::string> /* sessionKey */>
megOlmEncrypt(Event e, std::string roomId, Timestamp timeMs, RandomData random);
/// precondition: the one-time keys for those devices must already be claimed
+ [[deprecated("Use olmEncryptSplit instead")]]
Event olmEncrypt(Event e, immer::map<std::string, immer::flex_vector<std::string>> userIdToDeviceIdMap, RandomData random);
+ /// precondition: the one-time keys for those devices must already be claimed
+ /// @return A map from user id to device id to encrypted event for that device
+ immer::map<std::string, immer::map<std::string, Event>> olmEncryptSplit(Event e, immer::map<std::string, immer::flex_vector<std::string>> userIdToDeviceIdMap, RandomData random);
+
/// @return number of one-time keys we need to generate
std::size_t numOneTimeKeysNeeded() const;
diff --git a/src/client/client-model.cpp b/src/client/client-model.cpp
--- a/src/client/client-model.cpp
+++ b/src/client/client-model.cpp
@@ -225,6 +225,62 @@
return Event(JsonWrap(encJson));
}
+ immer::map<std::string, immer::map<std::string, Event>> ClientModel::olmEncryptSplit(
+ Event e,
+ immer::map<std::string, immer::flex_vector<std::string>> userIdToDeviceIdMap, RandomData random)
+ {
+ using ResT = immer::map<std::string, immer::map<std::string, Event>>;
+ if (!crypto) {
+ kzo.client.dbg() << "We do not have e2ee, so do not encrypt events" << std::endl;
+ return ResT{};
+ }
+
+ if (e.encrypted()) {
+ kzo.client.dbg() << "The event is already encrypted. Ignoring it." << std::endl;
+ return ResT{};
+ }
+
+ auto origJson = e.originalJson().get();
+
+ auto encJson = json::object();
+ encJson["content"] = json{
+ {"algorithm", CryptoConstants::olmAlgo},
+ {"ciphertext", json::object()},
+ {"sender_key", constCrypto().curve25519IdentityKey()},
+ };
+
+ encJson["type"] = "m.room.encrypted";
+
+ ResT messages;
+
+ for (auto [userId, devices] : userIdToDeviceIdMap) {
+ messages = std::move(messages).set(userId, immer::map<std::string, Event>());
+ for (auto dev : devices) {
+ auto devInfoOpt = deviceLists.get(userId, dev);
+ if (! devInfoOpt) {
+ continue;
+ }
+ auto devInfo = devInfoOpt.value();
+ auto jsonForThisDevice = origJson;
+ jsonForThisDevice["sender"] = this->userId;
+ jsonForThisDevice["recipient"] = userId;
+ jsonForThisDevice["recipient_keys"] = json{
+ {CryptoConstants::ed25519, devInfo.ed25519Key}
+ };
+ jsonForThisDevice["keys"] = json{
+ {CryptoConstants::ed25519, constCrypto().ed25519IdentityKey()}
+ };
+ auto thisEventJson = encJson;
+ thisEventJson["content"]["ciphertext"]
+ .merge_patch(withCrypto([&](auto &c) { return c.encryptOlmWithRandom(random, jsonForThisDevice, devInfo.curve25519Key); }));
+ random.erase(0, Crypto::encryptOlmMaxRandomSize());
+ messages = setIn(std::move(messages), Event(thisEventJson), userId, dev);
+ }
+ }
+
+ return messages;
+ }
+
immer::flex_vector<std::string /* deviceId */> ClientModel::devicesToSendKeys(std::string userId) const
{
auto trustLevelNeeded = this->trustLevelNeededToSendKeys;
diff --git a/src/tests/client/encryption-test.cpp b/src/tests/client/encryption-test.cpp
--- a/src/tests/client/encryption-test.cpp
+++ b/src/tests/client/encryption-test.cpp
@@ -7,6 +7,7 @@
#include <libkazv-config.hpp>
#include <catch2/catch_all.hpp>
+#include <client/actions/encryption.hpp>
#include <client-model.hpp>
#include "client-test-util.hpp"
@@ -91,3 +92,51 @@
REQUIRE(!encryptedEvent.originalJson().get()["content"].contains("m.relates_to"));
}
+
+TEST_CASE("ClientModel::olmEncryptSplit()", "[client][encryption]")
+{
+ auto makeDeviceInfo = [](const Crypto &crypto, std::string userId, std::string deviceId) {
+ auto client = makeClient(withCrypto(crypto));
+ client.userId = userId;
+ client.deviceId = deviceId;
+ auto [next, _] = updateClient(client, UploadIdentityKeysAction{});
+ return json::parse(std::get<Bytes>(next.nextJobs[0].requestBody()))["device_keys"];
+ };
+
+ auto receiver1 = makeCrypto();
+ receiver1.genOneTimeKeysWithRandom(genRandomData(Crypto::genOneTimeKeysRandomSize(1)), 1);
+ auto receiver2 = makeCrypto();
+ receiver2.genOneTimeKeysWithRandom(genRandomData(Crypto::genOneTimeKeysRandomSize(1)), 1);
+
+ auto oneTimeKeys1 = receiver1.unpublishedOneTimeKeys();
+ auto cv25519Key1 = oneTimeKeys1["curve25519"].items().begin().value().template get<std::string>();
+ auto oneTimeKeys2 = receiver2.unpublishedOneTimeKeys();
+ auto cv25519Key2 = oneTimeKeys2["curve25519"].items().begin().value().template get<std::string>();
+
+ auto queryKeysRespJson = json{
+ {"device_keys", {{"@receiver:example.com", {
+ {"device1", makeDeviceInfo(receiver1, "@receiver:example.com", "device1")},
+ {"device2", makeDeviceInfo(receiver2, "@receiver:example.com", "device2")},
+ }}}},
+ };
+
+ // Query keys
+ auto client = makeClient(withCrypto(makeCrypto()));
+ std::tie(client, std::ignore) = processResponse(client, QueryKeysResponse(
+ makeResponse("QueryKeys", withResponseJsonBody(queryKeysRespJson))
+ ));
+
+ // Claim keys
+ client.withCrypto([&](auto &c) { c.createOutboundSessionWithRandom(genRandomData(Crypto::createOutboundSessionRandomSize()), receiver1.curve25519IdentityKey(), cv25519Key1); });
+ client.withCrypto([&](auto &c) { c.createOutboundSessionWithRandom(genRandomData(Crypto::createOutboundSessionRandomSize()), receiver2.curve25519IdentityKey(), cv25519Key2); });
+
+ // encrypt
+ auto res = client.olmEncryptSplit(Event(json::object()),
+ {{"@receiver:example.com", {"device1", "device2"}}},
+ genRandomData(Crypto::encryptOlmMaxRandomSize() * 2));
+
+ REQUIRE(res["@receiver:example.com"]["device1"].originalJson().get().at("content").at("ciphertext").size() == 1);
+ REQUIRE(res["@receiver:example.com"]["device1"].originalJson().get().at("content").at("ciphertext").contains(receiver1.curve25519IdentityKey()));
+ REQUIRE(res["@receiver:example.com"]["device2"].originalJson().get().at("content").at("ciphertext").size() == 1);
+ REQUIRE(res["@receiver:example.com"]["device2"].originalJson().get().at("content").at("ciphertext").contains(receiver2.curve25519IdentityKey()));
+}

File Metadata

Mime Type
text/plain
Expires
Mon, Nov 25, 10:17 AM (11 h, 55 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
39862
Default Alt Text
D26.1732558651.diff (6 KB)

Event Timeline