Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F115713
D159.1732754769.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Size
12 KB
Referenced Files
None
Subscribers
None
D159.1732754769.diff
View Options
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
Details
Attached
Mime Type
text/plain
Expires
Wed, Nov 27, 4:46 PM (16 h, 19 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
41035
Default Alt Text
D159.1732754769.diff (12 KB)
Attached To
Mode
D159: Port InboundGroupSession to vodozemac
Attached
Detach File
Event Timeline
Log In to Comment