Page MenuHomePhorge

D159.1726887000.diff
No OneTemporary

D159.1726887000.diff

diff --git a/src/base/maybe.hpp b/src/base/maybe.hpp
--- a/src/base/maybe.hpp
+++ b/src/base/maybe.hpp
@@ -26,7 +26,7 @@
std::string m_reason;
using BaseT = std::optional<T>;
public:
- Maybe(T x) : BaseT(x) {}
+ Maybe(T x) : BaseT(std::move(x)) {}
Maybe(NotBut r) : BaseT(), m_reason(r.reason()) {}
std::string reason() const { return m_reason; }
diff --git a/src/crypto/CMakeLists.txt b/src/crypto/CMakeLists.txt
--- a/src/crypto/CMakeLists.txt
+++ b/src/crypto/CMakeLists.txt
@@ -14,6 +14,7 @@
set_target_properties(kazvcrypto PROPERTIES VERSION ${libkazv_VERSION_STRING} SOVERSION ${libkazv_SOVERSION})
target_link_libraries(kazvcrypto PUBLIC kazvbase Olm::Olm ${CRYPTOPP_TARGET_NAME})
+target_link_libraries(kazvcrypto PRIVATE vodozemac::vodozemac)
target_include_directories(kazvcrypto PRIVATE .)
diff --git a/src/crypto/crypto-util-p.hpp b/src/crypto/crypto-util-p.hpp
new file mode 100644
--- /dev/null
+++ b/src/crypto/crypto-util-p.hpp
@@ -0,0 +1,28 @@
+/*
+ * This file is part of libkazv.
+ * SPDX-FileCopyrightText: 2024 tusooa <tusooa@kazv.moe>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#pragma once
+#include <libkazv-config.hpp>
+#include <array>
+#include <vector>
+#include <cstdint>
+#include <maybe.hpp>
+
+namespace Kazv
+{
+ static const std::array<std::uint8_t, 32> VODOZEMAC_PICKLE_KEY = {};
+ static const std::vector<std::uint8_t> OLM_PICKLE_KEY = {'x', 'x', 'x'};
+
+ template<class Func>
+ static auto checkVodozemacError(Func &&func) -> Maybe<std::invoke_result_t<Func>>
+ {
+ try {
+ return std::forward<Func>(func)();
+ } catch (const std::exception &e) {
+ return NotBut(e.what());
+ }
+ }
+}
diff --git a/src/crypto/inbound-group-session-p.hpp b/src/crypto/inbound-group-session-p.hpp
--- a/src/crypto/inbound-group-session-p.hpp
+++ b/src/crypto/inbound-group-session-p.hpp
@@ -9,7 +9,7 @@
#include "inbound-group-session.hpp"
-#include <olm/olm.h>
+#include <vodozemac.h>
#include <immer/map.hpp>
@@ -52,8 +52,7 @@
InboundGroupSessionPrivate(const InboundGroupSessionPrivate &that);
~InboundGroupSessionPrivate() = default;
- ByteArray sessionData;
- OlmInboundGroupSession *session;
+ std::optional<rust::Box<vodozemac::megolm::InboundGroupSession>> session;
std::string ed25519Key;
@@ -66,6 +65,7 @@
std::string pickle() const;
bool unpickle(std::string pickleData);
+ bool unpickleFromLibolm(std::string pickleData);
};
}
diff --git a/src/crypto/inbound-group-session.cpp b/src/crypto/inbound-group-session.cpp
--- a/src/crypto/inbound-group-session.cpp
+++ b/src/crypto/inbound-group-session.cpp
@@ -1,13 +1,13 @@
/*
* This file is part of libkazv.
- * SPDX-FileCopyrightText: 2021 Tusooa Zhu <tusooa@kazv.moe>
+ * SPDX-FileCopyrightText: 2021-2024 tusooa <tusooa@kazv.moe>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
#include <libkazv-config.hpp>
-
#include "inbound-group-session-p.hpp"
+#include "crypto-util-p.hpp"
#include <types.hpp>
@@ -15,36 +15,24 @@
namespace Kazv
{
- std::size_t InboundGroupSessionPrivate::checkError(std::size_t code) const
- {
- if (code == olm_error()) {
- kzo.crypto.warn() << "Olm inbound group session error: "
- << olm_inbound_group_session_last_error(session) << std::endl;
- }
- return code;
- }
-
- std::string InboundGroupSessionPrivate::error() const
- {
- return olm_inbound_group_session_last_error(session);
- }
-
-
InboundGroupSessionPrivate::InboundGroupSessionPrivate()
- : sessionData(olm_inbound_group_session_size(), '\0')
- , session(olm_inbound_group_session(sessionData.data()))
+ : session(std::nullopt)
{
}
InboundGroupSessionPrivate::InboundGroupSessionPrivate(std::string sessionKey, std::string ed25519Key)
: InboundGroupSessionPrivate()
{
+ valid = false;
this->ed25519Key = ed25519Key;
- auto keyBuf = ByteArray(sessionKey.begin(), sessionKey.end());
+ auto keyRust = checkVodozemacError([&]() { return vodozemac::megolm::session_key_from_base64(rust::Str(sessionKey)); });
+ if (!keyRust) {
+ return;
+ }
- auto res = checkError(olm_init_inbound_group_session(session, keyBuf.data(), keyBuf.size()));
- if (res != olm_error()) {
+ this->session = checkVodozemacError([&]() { return vodozemac::megolm::new_inbound_group_session(*(keyRust.value())); });
+ if (this->session.has_value()) {
valid = true;
}
}
@@ -59,25 +47,26 @@
std::string InboundGroupSessionPrivate::pickle() const
{
- auto pickleData = std::string(olm_pickle_inbound_group_session_length(session), '\0');
- auto key = ByteArray(3, 'x');
- checkError(olm_pickle_inbound_group_session(session,
- key.data(), key.size(),
- pickleData.data(), pickleData.size()));
- return pickleData;
+ auto pickleData = this->session.value()->pickle(
+ VODOZEMAC_PICKLE_KEY);
+ return static_cast<std::string>(pickleData);
}
bool InboundGroupSessionPrivate::unpickle(std::string pickleData)
{
- auto key = ByteArray(3, 'x');
- auto res = checkError(olm_unpickle_inbound_group_session(
- session,
- key.data(), key.size(),
- pickleData.data(), pickleData.size()));
-
- return res != olm_error();
+ this->session = checkVodozemacError([&]() {
+ return vodozemac::megolm::inbound_group_session_from_pickle(pickleData, VODOZEMAC_PICKLE_KEY);
+ });
+ return this->session.has_value();
}
+ bool InboundGroupSessionPrivate::unpickleFromLibolm(std::string pickleData)
+ {
+ this->session = checkVodozemacError([&]() {
+ return vodozemac::megolm::inbound_group_session_from_libolm_pickle(pickleData, rust::Slice<const unsigned char>(OLM_PICKLE_KEY.data(), OLM_PICKLE_KEY.size()));
+ });
+ return this->session.has_value();
+ }
InboundGroupSession::InboundGroupSession()
: m_d(new InboundGroupSessionPrivate)
@@ -120,29 +109,18 @@
MaybeString InboundGroupSession::decrypt(std::string message, std::string eventId, std::int_fast64_t originServerTs)
{
- ByteArray msgBuffer(message.begin(), message.end());
- ByteArray msgBuffer2 = msgBuffer;
-
- auto size = m_d->checkError(olm_group_decrypt_max_plaintext_length(
- m_d->session,
- msgBuffer.data(), msgBuffer.size()));
- if (size == olm_error()) {
- return NotBut(m_d->error());
+ auto messageRust = checkVodozemacError([&]() { return vodozemac::megolm::megolm_message_from_base64(rust::Str(message)); });
+ if (!messageRust.has_value()) {
+ return NotBut(messageRust.reason());
}
+ auto decrypted = checkVodozemacError([&]() { return m_d->session.value()->decrypt(*(messageRust.value())); });
- auto plainText = ByteArray(size, '\0');
- std::uint32_t messageIndex;
-
- auto actualSize = m_d->checkError(olm_group_decrypt(
- m_d->session,
- msgBuffer2.data(), msgBuffer2.size(),
- plainText.data(), plainText.size(),
- &messageIndex));
-
- if (actualSize == olm_error()) {
- return NotBut(m_d->error());
+ if (!decrypted.has_value()) {
+ return NotBut(decrypted.reason());
}
+ auto [plainText, messageIndex] = *decrypted;
+
// Check for possible replay attack
auto keyForThisMsg = KeyOfDecryptedEvent{eventId, originServerTs};
@@ -156,7 +134,7 @@
}
}
- return std::string(plainText.begin(), plainText.begin() + actualSize);
+ return std::string(plainText.begin(), plainText.end());
}
std::string InboundGroupSession::ed25519Key() const
@@ -167,6 +145,7 @@
void to_json(nlohmann::json &j, const InboundGroupSession &s)
{
j = nlohmann::json::object();
+ j["version"] = 1;
j["ed25519Key"] = s.m_d->ed25519Key;
j["valid"] = s.m_d->valid;
j["decryptedEvents"] = s.m_d->decryptedEvents;
@@ -181,7 +160,11 @@
s.m_d->valid = j.at("valid");
s.m_d->decryptedEvents = j.at("decryptedEvents");
if (s.m_d->valid) {
- s.m_d->valid = s.m_d->unpickle(j.at("session"));
+ if (j.contains("version") && j["version"] == 1) { // vodozemac format
+ s.m_d->valid = s.m_d->unpickle(j.at("session"));
+ } else { // libolm format
+ s.m_d->valid = s.m_d->unpickleFromLibolm(j.at("session"));
+ }
}
}
}
diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt
--- a/src/tests/CMakeLists.txt
+++ b/src/tests/CMakeLists.txt
@@ -109,6 +109,7 @@
libkazv_add_tests(
crypto-test.cpp
crypto/deterministic-test.cpp
+ crypto/inbound-group-session-test.cpp
EXTRA_LINK_LIBRARIES kazvcrypto
)
diff --git a/src/tests/crypto/crypto-test-resource.hpp b/src/tests/crypto/crypto-test-resource.hpp
new file mode 100644
--- /dev/null
+++ b/src/tests/crypto/crypto-test-resource.hpp
@@ -0,0 +1,28 @@
+/*
+ * This file is part of libkazv.
+ * SPDX-FileCopyrightText: 2024 tusooa <tusooa@kazv.moe>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#pragma once
+#include <libkazv-config.hpp>
+#include <fstream>
+#include <streambuf>
+#include <nlohmann/json.hpp>
+#include "kazvtest-respath.hpp"
+
+inline const std::string cryptoDumpPath = resPath + "/libolm-crypto-dump";
+
+inline nlohmann::json getCryptoDumpResource()
+{
+ std::ifstream s(cryptoDumpPath);
+ std::string str((std::istreambuf_iterator<char>(s)),
+ std::istreambuf_iterator<char>());
+ return nlohmann::json::parse(str);
+}
+
+inline nlohmann::json cryptoDumpResource()
+{
+ static nlohmann::json res = getCryptoDumpResource();
+ return res;
+};
diff --git a/src/tests/crypto/inbound-group-session-test.cpp b/src/tests/crypto/inbound-group-session-test.cpp
new file mode 100644
--- /dev/null
+++ b/src/tests/crypto/inbound-group-session-test.cpp
@@ -0,0 +1,76 @@
+/*
+ * This file is part of libkazv.
+ * SPDX-FileCopyrightText: 2024 tusooa <tusooa@kazv.moe>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#include <libkazv-config.hpp>
+#include <catch2/catch_test_macros.hpp>
+#include <inbound-group-session.hpp>
+#include <outbound-group-session.hpp>
+#include <crypto.hpp>
+#include "crypto-test-resource.hpp"
+
+using namespace Kazv;
+
+static const auto resource = cryptoDumpResource();
+
+TEST_CASE("InboundGroupSession conversion from libolm to vodozemac")
+{
+ auto sessionJson = resource["a"]["inboundGroupSessions"][0][1];
+ auto session = sessionJson.template get<InboundGroupSession>();
+ REQUIRE(session.valid());
+ REQUIRE(session.ed25519Key() == sessionJson["ed25519Key"]);
+ auto encrypted = resource["megolmEncrypted"];
+ auto plainText = resource["megolmPlainText"];
+ auto a = Crypto();
+ a.loadJson(resource["a"]);
+ auto decrypted = a.decrypt(encrypted);
+ REQUIRE(decrypted.has_value());
+ auto decryptedJson = json::parse(decrypted.value());
+ REQUIRE(decryptedJson == plainText);
+}
+
+TEST_CASE("InboundGroupSession::from_json error handling")
+{
+ auto sessionJson = resource["a"]["inboundGroupSessions"][0][1];
+ sessionJson["session"] = "AAAAAAAAAA";
+ auto session = sessionJson.template get<InboundGroupSession>();
+ REQUIRE(!session.valid());
+}
+
+TEST_CASE("InboundGroupSession::decrypt error handling")
+{
+ auto sessionJson = resource["a"]["inboundGroupSessions"][0][1];
+ auto session = sessionJson.template get<InboundGroupSession>();
+ WHEN("message not decryptable") {
+ auto res = session.decrypt("AAAAAA", "$1", 1234);
+ REQUIRE(!res);
+ }
+
+ WHEN("message is not valid base64") {
+ auto res = session.decrypt("喵喵喵", "$1", 1234);
+ REQUIRE(!res);
+ }
+
+ WHEN("message is before the index") {
+ auto ogs = OutboundGroupSession(RandomTag{}, genRandomData(OutboundGroupSession::constructRandomSize()), 0);
+ auto encrypted1 = ogs.encrypt("text");
+ auto igs = InboundGroupSession(ogs.sessionKey(), "placeholder");
+ auto res = igs.decrypt(encrypted1, "$1", 1234);
+ REQUIRE(!res.has_value());
+ }
+}
+
+TEST_CASE("InboundGroupSession constructor error handling")
+{
+ WHEN("key not valid") {
+ auto session = InboundGroupSession("AAAAAA", "ed25519Key");
+ REQUIRE(!session.valid());
+ }
+
+ WHEN("key is not valid base64") {
+ auto session = InboundGroupSession("喵喵喵", "ed25519Key");
+ REQUIRE(!session.valid());
+ }
+}

File Metadata

Mime Type
text/plain
Expires
Fri, Sep 20, 7:50 PM (22 h, 32 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
16778
Default Alt Text
D159.1726887000.diff (12 KB)

Event Timeline