From c0a16c609ff8e639a9477ee08693c3478933e7fe Mon Sep 17 00:00:00 2001 From: Konstantinos Sideris <sideris.konstantin@gmail.com> Date: Tue, 22 May 2018 21:32:26 +0300 Subject: [PATCH] Add tests for megolm sessions locally --- examples/crypto_bot.cpp | 2 + include/mtxclient/crypto/client.hpp | 3 ++ lib/crypto/client.cpp | 6 +++ tests/e2ee.cpp | 80 +++++++++++++++++++++++++++++ 4 files changed, 91 insertions(+) diff --git a/examples/crypto_bot.cpp b/examples/crypto_bot.cpp index ea57c7c46..8ba2573e6 100644 --- a/examples/crypto_bot.cpp +++ b/examples/crypto_bot.cpp @@ -475,6 +475,7 @@ keys_uploaded_cb(const mtx::responses::UploadKeys &, RequestErr err) return; } + olm_client->mark_keys_as_published(); console->info("keys uploaded"); } @@ -852,6 +853,7 @@ login_cb(const mtx::responses::Login &, RequestErr err) return; } + olm_client->mark_keys_as_published(); console->info("keys uploaded"); console->debug("starting initial sync"); diff --git a/include/mtxclient/crypto/client.hpp b/include/mtxclient/crypto/client.hpp index b9dbd91a5..ad97eeb1f 100644 --- a/include/mtxclient/crypto/client.hpp +++ b/include/mtxclient/crypto/client.hpp @@ -180,6 +180,9 @@ public: //! Generate the json structure for the signed one time key. json signed_one_time_key_json(const std::string &key, const std::string &signature); + //! Marks the current set of one time keys as being published. + void mark_keys_as_published(); + //! Prepare request for the /keys/upload endpoint by signing identity & one time keys. mtx::requests::UploadKeys create_upload_keys_request(const OneTimeKeys &keys); mtx::requests::UploadKeys create_upload_keys_request(); diff --git a/lib/crypto/client.cpp b/lib/crypto/client.cpp index ec7c2b372..d63e542dc 100644 --- a/lib/crypto/client.cpp +++ b/lib/crypto/client.cpp @@ -142,6 +142,12 @@ OlmClient::signed_one_time_key_json(const std::string &key, const std::string &s {"signatures", {{user_id_, {{"ed25519:" + device_id_, signature}}}}}}; } +void +OlmClient::mark_keys_as_published() +{ + olm_account_mark_keys_as_published(account_.get()); +} + mtx::requests::UploadKeys OlmClient::create_upload_keys_request() { diff --git a/tests/e2ee.cpp b/tests/e2ee.cpp index 24b608468..1ff78d88c 100644 --- a/tests/e2ee.cpp +++ b/tests/e2ee.cpp @@ -559,3 +559,83 @@ TEST(Encryption, OlmSessions) auto body_str = std::string((char *)decrypted.data(), decrypted.size()); ASSERT_EQ(body_str, plaintext); } + +TEST(Encryption, MegolmSessions) +{ + auto alice = std::make_shared<OlmClient>(); + alice->create_new_account(); + alice->generate_one_time_keys(1); + + auto bob = std::make_shared<OlmClient>(); + bob->create_new_account(); + bob->generate_one_time_keys(1); + + // Alice wants to send an encrypted megolm message to Bob. + const std::string secret_message = "Hey, Bob!"; + + // Alice creates an outbound megolm session that will be used by both parties. + auto outbound_megolm_session = alice->init_outbound_group_session(); + auto msg_index = olm_outbound_group_session_message_index(outbound_megolm_session.get()); + ASSERT_EQ(msg_index, 0); + + // Alice extracts the session id & session key so she can share them with Bob. + const auto session_id = mtx::crypto::session_id(outbound_megolm_session.get()); + const auto session_key = mtx::crypto::session_key(outbound_megolm_session.get()); + + // Encrypt the message using megolm. + auto encrypted_secret_message = + alice->encrypt_group_message(outbound_megolm_session.get(), secret_message); + + msg_index = olm_outbound_group_session_message_index(outbound_megolm_session.get()); + ASSERT_EQ(msg_index, 1); + + // First she will create an outbound olm session so she can share the session data. + // Alice will need Bob's curve25519 key and one claimed one time key. + auto outbound_olm_session = alice->create_outbound_session( + bob->identity_keys().curve25519, bob->one_time_keys().curve25519.begin()->second); + const auto msg_type = olm_encrypt_message_type(outbound_olm_session.get()); + + // Plaintext version of the session data to be shared. + const auto session_data = json{{"session_id", session_id}, {"session_key", session_key}}; + + // Alice encrypts the session data using olm. + const auto encrypted_session_data = + alice->encrypt_message(outbound_olm_session.get(), session_data.dump()); + const auto encrypted_session_data_str = + std::string((char *)encrypted_session_data.data(), encrypted_session_data.size()); + + // + // Alice sends the olm & megolm messages to Bob ... + // + + // Bob creates an inbound olm session to receive the session data. + auto inbound_olm_session = bob->create_inbound_session(encrypted_session_data); + + // and validates that the message was indeed from Alice. + ASSERT_EQ(1, + matches_inbound_session_from(inbound_olm_session.get(), + alice->identity_keys().curve25519, + encrypted_session_data_str)); + + // Bob decrypts the encrypted olm message. + auto plaintext_session_data = + bob->decrypt_message(inbound_olm_session.get(), msg_type, encrypted_session_data_str); + auto session_str_data = json::parse( + std::string((char *)plaintext_session_data.data(), plaintext_session_data.size())); + + // Validate that the output matches the input. + ASSERT_EQ(session_id, session_str_data.at("session_id").get<std::string>()); + ASSERT_EQ(session_key, session_str_data.at("session_key").get<std::string>()); + + // Bob will use the session_key to create an inbound megolm session. + // The session_id will be used to map future messages to this session. + auto inbound_megolm_session = bob->init_inbound_group_session(session_key); + + // Bob can finally decrypt Alice's original message. + auto ciphertext = + std::string((char *)encrypted_secret_message.data(), encrypted_secret_message.size()); + auto bob_plaintext = bob->decrypt_group_message(inbound_megolm_session.get(), ciphertext); + + auto output_str = std::string((char *)bob_plaintext.data.data(), bob_plaintext.data.size()); + ASSERT_EQ(output_str, secret_message); +} -- GitLab