diff options
author | Alexey Andreyev <aa13q@ya.ru> | 2021-01-28 23:51:56 +0300 |
---|---|---|
committer | Tobias Fella <fella@posteo.de> | 2021-12-01 21:34:52 +0100 |
commit | d72f220e3e3a3b243fdafd93d1405f8207dc516a (patch) | |
tree | f4306b6397e39d6842a29f9a31fe5c858be8a4af /lib/crypto | |
parent | 9f71b2a79fba7c5d5ce09ebfdd482c8c470203d9 (diff) | |
download | libquotient-d72f220e3e3a3b243fdafd93d1405f8207dc516a.tar.gz libquotient-d72f220e3e3a3b243fdafd93d1405f8207dc516a.zip |
E2EE: initial port to internal olm wrapper
Remove qtolm git module. Update CMakeLists.txt.
Rename olm to crypto subdir to prevent disambiguation. Rename internal
files accordingly. Comment out not ported E2EE API usage.
Diffstat (limited to 'lib/crypto')
-rw-r--r-- | lib/crypto/e2ee.h | 7 | ||||
-rw-r--r-- | lib/crypto/qolmaccount.cpp | 23 | ||||
-rw-r--r-- | lib/crypto/qolmaccount.h | 15 | ||||
-rw-r--r-- | lib/crypto/qolmerrors.cpp (renamed from lib/crypto/errors.cpp) | 16 | ||||
-rw-r--r-- | lib/crypto/qolmerrors.h (renamed from lib/crypto/errors.h) | 4 | ||||
-rw-r--r-- | lib/crypto/qolminboundsession.cpp | 8 | ||||
-rw-r--r-- | lib/crypto/qolminboundsession.h | 8 | ||||
-rw-r--r-- | lib/crypto/qolmmessage.cpp (renamed from lib/crypto/message.cpp) | 14 | ||||
-rw-r--r-- | lib/crypto/qolmmessage.h (renamed from lib/crypto/message.h) | 10 | ||||
-rw-r--r-- | lib/crypto/qolmoutboundsession.cpp | 14 | ||||
-rw-r--r-- | lib/crypto/qolmoutboundsession.h | 12 | ||||
-rw-r--r-- | lib/crypto/qolmsession.cpp | 246 | ||||
-rw-r--r-- | lib/crypto/qolmsession.cpp.back | 29 | ||||
-rw-r--r-- | lib/crypto/qolmsession.h | 92 | ||||
-rw-r--r-- | lib/crypto/qolmsession.h.back | 49 | ||||
-rw-r--r-- | lib/crypto/qolmutils.cpp (renamed from lib/crypto/utils.cpp) | 2 | ||||
-rw-r--r-- | lib/crypto/qolmutils.h (renamed from lib/crypto/utils.h) | 2 | ||||
-rw-r--r-- | lib/crypto/session.cpp | 242 | ||||
-rw-r--r-- | lib/crypto/session.h | 77 |
19 files changed, 440 insertions, 430 deletions
diff --git a/lib/crypto/e2ee.h b/lib/crypto/e2ee.h index 74f876e4..73dd7f65 100644 --- a/lib/crypto/e2ee.h +++ b/lib/crypto/e2ee.h @@ -5,15 +5,17 @@ #pragma once -#include "util.h" #include <optional> #include <string> #include <variant> -#include <QMap> +#include <QMap> #include <QStringList> +#include "util.h" + namespace Quotient { + inline const auto CiphertextKeyL = "ciphertext"_ls; inline const auto SenderKeyKeyL = "sender_key"_ls; inline const auto DeviceIdKeyL = "device_id"_ls; @@ -37,7 +39,6 @@ inline const auto MegolmV1AesSha2AlgoKey = QStringLiteral("m.megolm.v1.aes-sha2"); inline const QStringList SupportedAlgorithms = { OlmV1Curve25519AesSha2AlgoKey, MegolmV1AesSha2AlgoKey }; - struct Unencrypted {}; struct Encrypted { QByteArray key; diff --git a/lib/crypto/qolmaccount.cpp b/lib/crypto/qolmaccount.cpp index 8824e7ef..fc0fc1cf 100644 --- a/lib/crypto/qolmaccount.cpp +++ b/lib/crypto/qolmaccount.cpp @@ -3,8 +3,8 @@ // SPDX-License-Identifier: LGPL-2.1-or-later #ifdef Quotient_E2EE_ENABLED -#include "crypto/qolmaccount.h" -#include "crypto/utils.h" +#include "qolmaccount.h" +#include "crypto/qolmutils.h" #include <QJsonObject> #include <QJsonDocument> #include <QDebug> @@ -31,7 +31,7 @@ bool operator==(const IdentityKeys& lhs, const IdentityKeys& rhs) } // Convert olm error to enum -OlmError lastError(OlmAccount *account) { +QOlmError lastError(OlmAccount *account) { const std::string error_raw = olm_account_last_error(account); return fromString(error_raw); @@ -77,7 +77,7 @@ void QOlmAccount::unpickle(QByteArray &pickled, const PicklingMode &mode) } } -std::variant<QByteArray, OlmError> QOlmAccount::pickle(const PicklingMode &mode) +std::variant<QByteArray, QOlmError> QOlmAccount::pickle(const PicklingMode &mode) { const QByteArray key = toKey(mode); const size_t pickleLength = olm_pickle_account_length(m_account); @@ -118,6 +118,11 @@ QByteArray QOlmAccount::sign(const QByteArray &message) const return signatureBuffer; } +QByteArray QOlmAccount::sign(const QJsonObject &message) const +{ + return sign(QJsonDocument(message).toJson(QJsonDocument::Compact)); +} + QByteArray QOlmAccount::signIdentityKeys() const { const auto keys = identityKeys(); @@ -197,19 +202,19 @@ OlmAccount *Quotient::QOlmAccount::data() return m_account; } -std::variant<std::unique_ptr<QOlmSession>, OlmError> QOlmAccount::createInboundSession(const Message &preKeyMessage) +std::variant<std::unique_ptr<QOlmSession>, QOlmError> QOlmAccount::createInboundSession(const QOlmMessage &preKeyMessage) { - Q_ASSERT(preKeyMessage.type() == Message::PreKey); + Q_ASSERT(preKeyMessage.type() == QOlmMessage::PreKey); return QOlmSession::createInboundSession(this, preKeyMessage); } -std::variant<std::unique_ptr<QOlmSession>, OlmError> QOlmAccount::createInboundSessionFrom(const QByteArray &theirIdentityKey, const Message &preKeyMessage) +std::variant<std::unique_ptr<QOlmSession>, QOlmError> QOlmAccount::createInboundSessionFrom(const QByteArray &theirIdentityKey, const QOlmMessage &preKeyMessage) { - Q_ASSERT(preKeyMessage.type() == Message::PreKey); + Q_ASSERT(preKeyMessage.type() == QOlmMessage::PreKey); return QOlmSession::createInboundSessionFrom(this, theirIdentityKey, preKeyMessage); } -std::variant<std::unique_ptr<QOlmSession>, OlmError> QOlmAccount::createOutboundSession(const QByteArray &theirIdentityKey, const QByteArray &theirOneTimeKey) +std::variant<std::unique_ptr<QOlmSession>, QOlmError> QOlmAccount::createOutboundSession(const QByteArray &theirIdentityKey, const QByteArray &theirOneTimeKey) { return QOlmSession::createOutboundSession(this, theirIdentityKey, theirOneTimeKey); } diff --git a/lib/crypto/qolmaccount.h b/lib/crypto/qolmaccount.h index f98d78ba..b33e3768 100644 --- a/lib/crypto/qolmaccount.h +++ b/lib/crypto/qolmaccount.h @@ -5,9 +5,9 @@ #ifdef Quotient_E2EE_ENABLED #include "crypto/e2ee.h" -#include "crypto/errors.h" -#include "crypto/session.h" -#include <olm/olm.h> +#include "crypto/qolmerrors.h" +#include "crypto/qolmmessage.h" +#include "crypto/qolmsession.h" #include <QObject> struct OlmAccount; @@ -38,13 +38,14 @@ public: void unpickle(QByteArray &picked, const PicklingMode &mode); //! Serialises an OlmAccount to encrypted Base64. - std::variant<QByteArray, OlmError> pickle(const PicklingMode &mode); + std::variant<QByteArray, QOlmError> pickle(const PicklingMode &mode); //! Returns the account's public identity keys already formatted as JSON IdentityKeys identityKeys() const; //! Returns the signature of the supplied message. QByteArray sign(const QByteArray &message) const; + QByteArray sign(const QJsonObject& message) const; //! Sign identity keys. QByteArray signIdentityKeys() const; @@ -70,17 +71,17 @@ public: //! Creates an inbound session for sending/receiving messages from a received 'prekey' message. //! //! \param message An Olm pre-key message that was encrypted for this account. - std::variant<std::unique_ptr<QOlmSession>, OlmError> createInboundSession(const Message &preKeyMessage); + std::variant<std::unique_ptr<QOlmSession>, QOlmError> createInboundSession(const QOlmMessage &preKeyMessage); //! Creates an inbound session for sending/receiving messages from a received 'prekey' message. //! //! \param theirIdentityKey - The identity key of an Olm account that //! encrypted this Olm message. - std::variant<std::unique_ptr<QOlmSession>, OlmError> createInboundSessionFrom(const QByteArray &theirIdentityKey, const Message &preKeyMessage); + std::variant<std::unique_ptr<QOlmSession>, QOlmError> createInboundSessionFrom(const QByteArray &theirIdentityKey, const QOlmMessage &preKeyMessage); //! Creates an outbound session for sending messages to a specific /// identity and one time key. - std::variant<std::unique_ptr<QOlmSession>, OlmError> createOutboundSession(const QByteArray &theirIdentityKey, const QByteArray &theirOneTimeKey); + std::variant<std::unique_ptr<QOlmSession>, QOlmError> createOutboundSession(const QByteArray &theirIdentityKey, const QByteArray &theirOneTimeKey); // HACK do not use directly QOlmAccount(OlmAccount *account); diff --git a/lib/crypto/errors.cpp b/lib/crypto/qolmerrors.cpp index 00ff962d..f407383e 100644 --- a/lib/crypto/errors.cpp +++ b/lib/crypto/qolmerrors.cpp @@ -1,21 +1,21 @@ // SPDX-FileCopyrightText: 2021 Carl Schwan <carlschwan@kde.org> // SPDX-License-Identifier: LGPL-2.1-or-later #ifdef Quotient_E2EE_ENABLED -#include "crypto/errors.h" +#include "qolmerrors.h" -Quotient::OlmError Quotient::fromString(const std::string &error_raw) { +Quotient::QOlmError Quotient::fromString(const std::string &error_raw) { if (error_raw.compare("BAD_ACCOUNT_KEY")) { - return OlmError::BadAccountKey; + return QOlmError::BadAccountKey; } else if (error_raw.compare("BAD_MESSAGE_KEY_ID")) { - return OlmError::BadMessageKeyId; + return QOlmError::BadMessageKeyId; } else if (error_raw.compare("INVALID_BASE64")) { - return OlmError::InvalidBase64; + return QOlmError::InvalidBase64; } else if (error_raw.compare("NOT_ENOUGH_RANDOM")) { - return OlmError::NotEnoughRandom; + return QOlmError::NotEnoughRandom; } else if (error_raw.compare("OUTPUT_BUFFER_TOO_SMALL")) { - return OlmError::OutputBufferTooSmall; + return QOlmError::OutputBufferTooSmall; } else { - return OlmError::Unknown; + return QOlmError::Unknown; } } #endif diff --git a/lib/crypto/errors.h b/lib/crypto/qolmerrors.h index 09d2a989..400573c6 100644 --- a/lib/crypto/errors.h +++ b/lib/crypto/qolmerrors.h @@ -10,7 +10,7 @@ namespace Quotient { //! All errors that could be caused by an operation regarding Olm //! Errors are named exactly like the ones in libolm. -enum OlmError +enum QOlmError { BadAccountKey, BadMessageFormat, @@ -24,7 +24,7 @@ enum OlmError Unknown, }; -OlmError fromString(const std::string &error_raw); +QOlmError fromString(const std::string &error_raw); } //namespace Quotient diff --git a/lib/crypto/qolminboundsession.cpp b/lib/crypto/qolminboundsession.cpp index 539fdc51..8f5056d8 100644 --- a/lib/crypto/qolminboundsession.cpp +++ b/lib/crypto/qolminboundsession.cpp @@ -8,7 +8,7 @@ #include <cstring> using namespace Quotient; -OlmError lastError(OlmInboundGroupSession *session) { +QOlmError lastError(OlmInboundGroupSession *session) { const std::string error_raw = olm_inbound_group_session_last_error(session); std::cout << error_raw; @@ -75,7 +75,7 @@ QByteArray QOlmInboundGroupSession::pickle(const PicklingMode &mode) const return pickledBuf; } -std::variant<std::unique_ptr<QOlmInboundGroupSession>, OlmError> QOlmInboundGroupSession::unpickle(QByteArray &pickled, const PicklingMode &mode) +std::variant<std::unique_ptr<QOlmInboundGroupSession>, QOlmError> QOlmInboundGroupSession::unpickle(QByteArray &pickled, const PicklingMode &mode) { QByteArray pickledBuf = pickled; const auto groupSession = olm_inbound_group_session(new uint8_t[olm_inbound_group_session_size()]); @@ -90,7 +90,7 @@ std::variant<std::unique_ptr<QOlmInboundGroupSession>, OlmError> QOlmInboundGrou return std::make_unique<QOlmInboundGroupSession>(groupSession); } -std::variant<std::pair<QString, uint32_t>, OlmError> QOlmInboundGroupSession::decrypt(const QByteArray &message) +std::variant<std::pair<QString, uint32_t>, QOlmError> QOlmInboundGroupSession::decrypt(const QByteArray &message) { // This is for capturing the output of olm_group_decrypt uint32_t messageIndex = 0; @@ -122,7 +122,7 @@ std::variant<std::pair<QString, uint32_t>, OlmError> QOlmInboundGroupSession::de return std::make_pair<QString, qint32>(QString(output), messageIndex); } -std::variant<QByteArray, OlmError> QOlmInboundGroupSession::exportSession(uint32_t messageIndex) +std::variant<QByteArray, QOlmError> QOlmInboundGroupSession::exportSession(uint32_t messageIndex) { const auto keyLen = olm_export_inbound_group_session_length(m_groupSession); QByteArray keyBuf(keyLen, '0'); diff --git a/lib/crypto/qolminboundsession.h b/lib/crypto/qolminboundsession.h index a58fbbbc..6af71cbd 100644 --- a/lib/crypto/qolminboundsession.h +++ b/lib/crypto/qolminboundsession.h @@ -10,7 +10,7 @@ #include <variant> #include <memory> #include "olm/olm.h" -#include "crypto/errors.h" +#include "crypto/qolmerrors.h" #include "crypto/e2ee.h" namespace Quotient { @@ -29,12 +29,12 @@ public: QByteArray pickle(const PicklingMode &mode) const; //! Deserialises from encrypted Base64 that was previously obtained by pickling //! an `OlmInboundGroupSession`. - static std::variant<std::unique_ptr<QOlmInboundGroupSession>, OlmError> unpickle(QByteArray &picked, const PicklingMode &mode); + static std::variant<std::unique_ptr<QOlmInboundGroupSession>, QOlmError> unpickle(QByteArray &picked, const PicklingMode &mode); //! Decrypts ciphertext received for this group session. - std::variant<std::pair<QString, uint32_t>, OlmError> decrypt(const QByteArray &message); + std::variant<std::pair<QString, uint32_t>, QOlmError> decrypt(const QByteArray &message); //! Export the base64-encoded ratchet key for this session, at the given index, //! in a format which can be used by import. - std::variant<QByteArray, OlmError> exportSession(uint32_t messageIndex); + std::variant<QByteArray, QOlmError> exportSession(uint32_t messageIndex); //! Get the first message index we know how to decrypt. uint32_t firstKnownIndex() const; //! Get a base64-encoded identifier for this session. diff --git a/lib/crypto/message.cpp b/lib/crypto/qolmmessage.cpp index 830633bf..ae98d52f 100644 --- a/lib/crypto/message.cpp +++ b/lib/crypto/qolmmessage.cpp @@ -3,36 +3,36 @@ // SPDX-License-Identifier: LGPL-2.1-or-later #ifdef Quotient_E2EE_ENABLED -#include "crypto/message.h" +#include "qolmmessage.h" using namespace Quotient; -Message::Message(const QByteArray &ciphertext, Message::Type type) +QOlmMessage::QOlmMessage(const QByteArray &ciphertext, QOlmMessage::Type type) : QByteArray(std::move(ciphertext)) , m_messageType(type) { Q_ASSERT_X(!ciphertext.isEmpty(), "olm message", "Ciphertext is empty"); } -Message::Message(const Message &message) +QOlmMessage::QOlmMessage(const QOlmMessage &message) : QByteArray(message) , m_messageType(message.type()) { } -Message::Type Message::type() const +QOlmMessage::Type QOlmMessage::type() const { return m_messageType; } -QByteArray Message::toCiphertext() const +QByteArray QOlmMessage::toCiphertext() const { return QByteArray(*this); } -Message Message::fromCiphertext(const QByteArray &ciphertext) +QOlmMessage QOlmMessage::fromCiphertext(const QByteArray &ciphertext) { - return Message(ciphertext, Message::General); + return QOlmMessage(ciphertext, QOlmMessage::General); } diff --git a/lib/crypto/message.h b/lib/crypto/qolmmessage.h index 1ae19ba8..d203364d 100644 --- a/lib/crypto/message.h +++ b/lib/crypto/qolmmessage.h @@ -18,7 +18,7 @@ namespace Quotient { * * The class provides functions to get a type and the ciphertext. */ -class Message : public QByteArray { +class QOlmMessage : public QByteArray { Q_GADGET public: enum Type { @@ -27,11 +27,11 @@ public: }; Q_ENUM(Type) - Message() = default; - explicit Message(const QByteArray &ciphertext, Type type = General); - explicit Message(const Message &message); + QOlmMessage() = default; + explicit QOlmMessage(const QByteArray &ciphertext, Type type = General); + explicit QOlmMessage(const QOlmMessage &message); - static Message fromCiphertext(const QByteArray &ciphertext); + static QOlmMessage fromCiphertext(const QByteArray &ciphertext); Q_INVOKABLE Type type() const; Q_INVOKABLE QByteArray toCiphertext() const; diff --git a/lib/crypto/qolmoutboundsession.cpp b/lib/crypto/qolmoutboundsession.cpp index 3bfb0187..14b7368e 100644 --- a/lib/crypto/qolmoutboundsession.cpp +++ b/lib/crypto/qolmoutboundsession.cpp @@ -3,12 +3,12 @@ // SPDX-License-Identifier: LGPL-2.1-or-later #ifdef Quotient_E2EE_ENABLED -#include "crypto/qolmoutboundsession.h" -#include "crypto/utils.h" +#include "qolmoutboundsession.h" +#include "crypto/qolmutils.h" using namespace Quotient; -OlmError lastError(OlmOutboundGroupSession *session) { +QOlmError lastError(OlmOutboundGroupSession *session) { const std::string error_raw = olm_outbound_group_session_last_error(session); return fromString(error_raw); @@ -48,7 +48,7 @@ std::unique_ptr<QOlmOutboundGroupSession> QOlmOutboundGroupSession::create() return std::make_unique<QOlmOutboundGroupSession>(olmOutboundGroupSession); } -std::variant<QByteArray, OlmError> QOlmOutboundGroupSession::pickle(const PicklingMode &mode) +std::variant<QByteArray, QOlmError> QOlmOutboundGroupSession::pickle(const PicklingMode &mode) { QByteArray pickledBuf(olm_pickle_outbound_group_session_length(m_groupSession), '0'); QByteArray key = toKey(mode); @@ -65,7 +65,7 @@ std::variant<QByteArray, OlmError> QOlmOutboundGroupSession::pickle(const Pickli } -std::variant<std::unique_ptr<QOlmOutboundGroupSession>, OlmError> QOlmOutboundGroupSession::unpickle(QByteArray &pickled, const PicklingMode &mode) +std::variant<std::unique_ptr<QOlmOutboundGroupSession>, QOlmError> QOlmOutboundGroupSession::unpickle(QByteArray &pickled, const PicklingMode &mode) { QByteArray pickledBuf = pickled; auto *olmOutboundGroupSession = olm_outbound_group_session(new uint8_t[olm_outbound_group_session_size()]); @@ -84,7 +84,7 @@ std::variant<std::unique_ptr<QOlmOutboundGroupSession>, OlmError> QOlmOutboundGr return std::make_unique<QOlmOutboundGroupSession>(olmOutboundGroupSession); } -std::variant<QByteArray, OlmError> QOlmOutboundGroupSession::encrypt(const QString &plaintext) +std::variant<QByteArray, QOlmError> QOlmOutboundGroupSession::encrypt(const QString &plaintext) { QByteArray plaintextBuf = plaintext.toUtf8(); const auto messageMaxLen = olm_group_encrypt_message_length(m_groupSession, plaintextBuf.length()); @@ -116,7 +116,7 @@ QByteArray QOlmOutboundGroupSession::sessionId() const return idBuffer; } -std::variant<QByteArray, OlmError> QOlmOutboundGroupSession::sessionKey() const +std::variant<QByteArray, QOlmError> QOlmOutboundGroupSession::sessionKey() const { const auto keyMaxLength = olm_outbound_group_session_key_length(m_groupSession); QByteArray keyBuffer(keyMaxLength, '0'); diff --git a/lib/crypto/qolmoutboundsession.h b/lib/crypto/qolmoutboundsession.h index 6c6c635c..6b4fd30b 100644 --- a/lib/crypto/qolmoutboundsession.h +++ b/lib/crypto/qolmoutboundsession.h @@ -4,8 +4,8 @@ #pragma once #ifdef Quotient_E2EE_ENABLED -#include "olm/olm.h" // from Olm -#include "crypto/errors.h" +#include "olm/olm.h" +#include "crypto/qolmerrors.h" #include "crypto/e2ee.h" #include <memory> @@ -22,12 +22,12 @@ public: //! Throw OlmError on errors static std::unique_ptr<QOlmOutboundGroupSession> create(); //! Serialises an `QOlmOutboundGroupSession` to encrypted Base64. - std::variant<QByteArray, OlmError> pickle(const PicklingMode &mode); + std::variant<QByteArray, QOlmError> pickle(const PicklingMode &mode); //! Deserialises from encrypted Base64 that was previously obtained by //! pickling a `QOlmOutboundGroupSession`. - static std::variant<std::unique_ptr<QOlmOutboundGroupSession>, OlmError> unpickle(QByteArray &pickled, const PicklingMode &mode); + static std::variant<std::unique_ptr<QOlmOutboundGroupSession>, QOlmError> unpickle(QByteArray &pickled, const PicklingMode &mode); //! Encrypts a plaintext message using the session. - std::variant<QByteArray, OlmError> encrypt(const QString &plaintext); + std::variant<QByteArray, QOlmError> encrypt(const QString &plaintext); //! Get the current message index for this session. //! @@ -42,7 +42,7 @@ public: //! //! Each message is sent with a different ratchet key. This function returns the //! ratchet key that will be used for the next message. - std::variant<QByteArray, OlmError> sessionKey() const; + std::variant<QByteArray, QOlmError> sessionKey() const; QOlmOutboundGroupSession(OlmOutboundGroupSession *groupSession); private: OlmOutboundGroupSession *m_groupSession; diff --git a/lib/crypto/qolmsession.cpp b/lib/crypto/qolmsession.cpp index afa42728..cfe21650 100644 --- a/lib/crypto/qolmsession.cpp +++ b/lib/crypto/qolmsession.cpp @@ -1,29 +1,243 @@ -// SPDX-FileCopyrightText: 2021 Carl Schwan <carlschwan@kde.org> +// SPDX-FileCopyrightText: 2021 Alexey Andreyev <aa13q@ya.ru> // // SPDX-License-Identifier: LGPL-2.1-or-later -#include "crypto/qolmsession.h" +#ifdef Quotient_E2EE_ENABLED +#include "qolmsession.h" +#include "crypto/qolmutils.h" +#include "logging.h" +#include <cstring> +#include <QDebug> using namespace Quotient; -std::optional<OlmMessage> fromTypeAndCipthertext(size_t messageType, const QByteArray &ciphertext) +QOlmError lastError(OlmSession* session) { + const std::string error_raw = olm_session_last_error(session); + + return fromString(error_raw); +} + +Quotient::QOlmSession::~QOlmSession() +{ + olm_clear_session(m_session); + delete[](reinterpret_cast<uint8_t *>(m_session)); +} + +OlmSession* QOlmSession::create() { - if (messageType == OLM_MESSAGE_TYPE_PRE_KEY) { - return PreKeyMessage { ciphertext }; - } else if (messageType == OLM_MESSAGE_TYPE_MESSAGE) { - return Message { ciphertext }; + return olm_session(new uint8_t[olm_session_size()]); +} + +std::variant<std::unique_ptr<QOlmSession>, QOlmError> QOlmSession::createInbound(QOlmAccount *account, const QOlmMessage &preKeyMessage, bool from, const QString &theirIdentityKey) +{ + if (preKeyMessage.type() != QOlmMessage::PreKey) { + qCDebug(E2EE) << "The message is not a pre-key"; + throw BadMessageFormat; } - return std::nullopt; + + const auto olmSession = create(); + + QByteArray oneTimeKeyMessageBuf = preKeyMessage.toCiphertext(); + QByteArray theirIdentityKeyBuf = theirIdentityKey.toUtf8(); + size_t error = 0; + if (from) { + error = olm_create_inbound_session_from(olmSession, account->data(), theirIdentityKeyBuf.data(), theirIdentityKeyBuf.length(), oneTimeKeyMessageBuf.data(), oneTimeKeyMessageBuf.length()); + } else { + error = olm_create_inbound_session(olmSession, account->data(), oneTimeKeyMessageBuf.data(), oneTimeKeyMessageBuf.length()); + } + + if (error == olm_error()) { + const auto lastErr = lastError(olmSession); + if (lastErr == QOlmError::NotEnoughRandom) { + throw lastErr; + } + return lastErr; + } + + return std::make_unique<QOlmSession>(olmSession); } -std::pair<OlmMessageType, QByteArray> toPair(const OlmMessage &message) +std::variant<std::unique_ptr<QOlmSession>, QOlmError> QOlmSession::createInboundSession(QOlmAccount *account, const QOlmMessage &preKeyMessage) { - return std::visit([](auto &arg) { - using T = std::decay_t<decltype(arg)>; - if constexpr (std::is_same_v<T, Message>) { - return std::make_pair<OlmMessageType, QByteArray>(MessageType, QByteArray(arg.message)); - } else if constexpr (std::is_same_v<T, PreKeyMessage>) { - return std::make_pair<OlmMessageType, QByteArray>(PreKeyType, QByteArray(arg.message)); + return createInbound(account, preKeyMessage); +} + +std::variant<std::unique_ptr<QOlmSession>, QOlmError> QOlmSession::createInboundSessionFrom(QOlmAccount *account, const QString &theirIdentityKey, const QOlmMessage &preKeyMessage) +{ + return createInbound(account, preKeyMessage, true, theirIdentityKey); +} + +std::variant<std::unique_ptr<QOlmSession>, QOlmError> QOlmSession::createOutboundSession(QOlmAccount *account, const QString &theirIdentityKey, const QString &theirOneTimeKey) +{ + auto *olmOutboundSession = create(); + const auto randomLen = olm_create_outbound_session_random_length(olmOutboundSession); + QByteArray randomBuf = getRandom(randomLen); + + QByteArray theirIdentityKeyBuf = theirIdentityKey.toUtf8(); + QByteArray theirOneTimeKeyBuf = theirOneTimeKey.toUtf8(); + const auto error = olm_create_outbound_session(olmOutboundSession, + account->data(), + reinterpret_cast<uint8_t *>(theirIdentityKeyBuf.data()), theirIdentityKeyBuf.length(), + reinterpret_cast<uint8_t *>(theirOneTimeKeyBuf.data()), theirOneTimeKeyBuf.length(), + reinterpret_cast<uint8_t *>(randomBuf.data()), randomBuf.length()); + + if (error == olm_error()) { + const auto lastErr = lastError(olmOutboundSession); + if (lastErr == QOlmError::NotEnoughRandom) { + throw lastErr; } - }, message); + return lastErr; + } + + randomBuf.clear(); + return std::make_unique<QOlmSession>(olmOutboundSession); +} + +std::variant<QByteArray, QOlmError> QOlmSession::pickle(const PicklingMode &mode) +{ + QByteArray pickledBuf(olm_pickle_session_length(m_session), '0'); + QByteArray key = toKey(mode); + const auto error = olm_pickle_session(m_session, key.data(), key.length(), + pickledBuf.data(), pickledBuf.length()); + + if (error == olm_error()) { + return lastError(m_session); + } + + key.clear(); + + return pickledBuf; +} + +std::variant<std::unique_ptr<QOlmSession>, QOlmError> QOlmSession::unpickle(const QByteArray &pickled, const PicklingMode &mode) +{ + QByteArray pickledBuf = pickled; + auto *olmSession = create(); + QByteArray key = toKey(mode); + const auto error = olm_unpickle_session(olmSession, key.data(), key.length(), + pickledBuf.data(), pickledBuf.length()); + if (error == olm_error()) { + return lastError(olmSession); + } + + key.clear(); + return std::make_unique<QOlmSession>(olmSession); } + +QOlmMessage QOlmSession::encrypt(const QString &plaintext) +{ + QByteArray plaintextBuf = plaintext.toUtf8(); + const auto messageMaxLen = olm_encrypt_message_length(m_session, plaintextBuf.length()); + QByteArray messageBuf(messageMaxLen, '0'); + const auto messageType = encryptMessageType(); + const auto randomLen = olm_encrypt_random_length(m_session); + QByteArray randomBuf = getRandom(randomLen); + const auto error = olm_encrypt(m_session, + reinterpret_cast<uint8_t *>(plaintextBuf.data()), plaintextBuf.length(), + reinterpret_cast<uint8_t *>(randomBuf.data()), randomBuf.length(), + reinterpret_cast<uint8_t *>(messageBuf.data()), messageBuf.length()); + + if (error == olm_error()) { + throw lastError(m_session); + } + + return QOlmMessage(messageBuf, messageType); +} + +std::variant<QString, QOlmError> QOlmSession::decrypt(const QOlmMessage &message) const +{ + const auto messageType = message.type(); + const auto ciphertext = message.toCiphertext(); + const auto messageTypeValue = messageType == QOlmMessage::Type::General + ? OLM_MESSAGE_TYPE_MESSAGE : OLM_MESSAGE_TYPE_PRE_KEY; + + // We need to clone the message because + // olm_decrypt_max_plaintext_length destroys the input buffer + QByteArray messageBuf(ciphertext.length(), '0'); + std::copy(message.begin(), message.end(), messageBuf.begin()); + + const auto plaintextMaxLen = olm_decrypt_max_plaintext_length(m_session, messageTypeValue, + reinterpret_cast<uint8_t *>(messageBuf.data()), messageBuf.length()); + + if (plaintextMaxLen == olm_error()) { + return lastError(m_session); + } + + QByteArray plaintextBuf(plaintextMaxLen, '0'); + QByteArray messageBuf2(ciphertext.length(), '0'); + std::copy(message.begin(), message.end(), messageBuf2.begin()); + + const auto plaintextResultLen = olm_decrypt(m_session, messageTypeValue, + reinterpret_cast<uint8_t *>(messageBuf2.data()), messageBuf2.length(), + reinterpret_cast<uint8_t *>(plaintextBuf.data()), plaintextMaxLen); + + if (plaintextResultLen == olm_error()) { + const auto lastErr = lastError(m_session); + if (lastErr == QOlmError::OutputBufferTooSmall) { + throw lastErr; + } + return lastErr; + } + QByteArray output(plaintextResultLen, '0'); + std::memcpy(output.data(), plaintextBuf.data(), plaintextResultLen); + plaintextBuf.clear(); + return output; +} + +QOlmMessage::Type QOlmSession::encryptMessageType() +{ + const auto messageTypeResult = olm_encrypt_message_type(m_session); + if (messageTypeResult == olm_error()) { + throw lastError(m_session); + } + if (messageTypeResult == OLM_MESSAGE_TYPE_PRE_KEY) { + return QOlmMessage::PreKey; + } + return QOlmMessage::General; +} + +QByteArray QOlmSession::sessionId() const +{ + const auto idMaxLength = olm_session_id_length(m_session); + QByteArray idBuffer(idMaxLength, '0'); + const auto error = olm_session_id(m_session, reinterpret_cast<uint8_t *>(idBuffer.data()), + idBuffer.length()); + if (error == olm_error()) { + throw lastError(m_session); + } + return idBuffer; +} + +bool QOlmSession::hasReceivedMessage() const +{ + return olm_session_has_received_message(m_session); +} + +std::variant<bool, QOlmError> QOlmSession::matchesInboundSession(QOlmMessage &preKeyMessage) +{ + Q_ASSERT(preKeyMessage.type() == QOlmMessage::Type::PreKey); + QByteArray oneTimeKeyBuf(preKeyMessage.data()); + const auto matchesResult = olm_matches_inbound_session(m_session, oneTimeKeyBuf.data(), oneTimeKeyBuf.length()); + + if (matchesResult == olm_error()) { + return lastError(m_session); + } + switch (matchesResult) { + case 0: + return false; + case 1: + return true; + default: + return QOlmError::Unknown; + } +} + +QOlmSession::QOlmSession(OlmSession *session) + : m_session(session) +{ +} + +#endif // Quotient_E2EE_ENABLED + + + diff --git a/lib/crypto/qolmsession.cpp.back b/lib/crypto/qolmsession.cpp.back new file mode 100644 index 00000000..ee8b2a7f --- /dev/null +++ b/lib/crypto/qolmsession.cpp.back @@ -0,0 +1,29 @@ +// SPDX-FileCopyrightText: 2021 Carl Schwan <carlschwan@kde.org> +// +// SPDX-License-Identifier: LGPL-2.1-or-later + +#include "olm/qolmsession.h" + +using namespace Quotient; + +std::optional<OlmMessage> fromTypeAndCipthertext(size_t messageType, const QByteArray &ciphertext) +{ + if (messageType == OLM_MESSAGE_TYPE_PRE_KEY) { + return PreKeyMessage { ciphertext }; + } else if (messageType == OLM_MESSAGE_TYPE_MESSAGE) { + return QOlmMessage { ciphertext }; + } + return std::nullopt; +} + +std::pair<OlmMessageType, QByteArray> toPair(const OlmMessage &message) +{ + return std::visit([](auto &arg) { + using T = std::decay_t<decltype(arg)>; + if constexpr (std::is_same_v<T, QOlmMessage>) { + return std::make_pair<OlmMessageType, QByteArray>(MessageType, QByteArray(arg.message)); + } else if constexpr (std::is_same_v<T, PreKeyMessage>) { + return std::make_pair<OlmMessageType, QByteArray>(PreKeyType, QByteArray(arg.message)); + } + }, message); +} diff --git a/lib/crypto/qolmsession.h b/lib/crypto/qolmsession.h index 3be3c7fc..6e13801e 100644 --- a/lib/crypto/qolmsession.h +++ b/lib/crypto/qolmsession.h @@ -1,49 +1,77 @@ -// SPDX-FileCopyrightText: 2021 Carl Schwan <carlschwan@kde.org> +// SPDX-FileCopyrightText: 2021 Alexey Andreyev <aa13q@ya.ru> // // SPDX-License-Identifier: LGPL-2.1-or-later #pragma once -#include <variant> -#include <olm/olm.h> +#ifdef Quotient_E2EE_ENABLED + +#include <QDebug> +#include <olm/olm.h> // FIXME: OlmSession #include "crypto/e2ee.h" -#include "crypto/errors.h" +#include "crypto/qolmmessage.h" +#include "crypto/qolmerrors.h" +#include "crypto/qolmaccount.h" namespace Quotient { -//! An encrypted Olm message. -struct Message { - QByteArray message; -}; +class QOlmAccount; +class QOlmSession; -//! A encrypted Olm pre-key message. -//! -//! This message, unlike a normal Message, can be used to create new Olm sessions. -struct PreKeyMessage -{ - QByteArray message; -}; -enum OlmMessageType +//! Either an outbound or inbound session for secure communication. +class QOlmSession { - PreKeyType, - MessageType, -}; +public: + ~QOlmSession(); + //! Creates an inbound session for sending/receiving messages from a received 'prekey' message. + static std::variant<std::unique_ptr<QOlmSession>, QOlmError> createInboundSession(QOlmAccount *account, const QOlmMessage &preKeyMessage); + static std::variant<std::unique_ptr<QOlmSession>, QOlmError> createInboundSessionFrom(QOlmAccount *account, const QString &theirIdentityKey, const QOlmMessage &preKeyMessage); + static std::variant<std::unique_ptr<QOlmSession>, QOlmError> createOutboundSession(QOlmAccount *account, const QString &theirIdentityKey, const QString &theirOneTimeKey); + //! Serialises an `QOlmSession` to encrypted Base64. + std::variant<QByteArray, QOlmError> pickle(const PicklingMode &mode); + //! Deserialises from encrypted Base64 that was previously obtained by pickling a `QOlmSession`. + static std::variant<std::unique_ptr<QOlmSession>, QOlmError> unpickle(const QByteArray &pickled, const PicklingMode &mode); + //! Encrypts a plaintext message using the session. + QOlmMessage encrypt(const QString &plaintext); -using OlmMessage = std::variant<Message, PreKeyMessage>; + //! Decrypts a message using this session. Decoding is lossy, meaing if + //! the decrypted plaintext contains invalid UTF-8 symbols, they will + //! be returned as `U+FFFD` (�). + std::variant<QString, QOlmError> decrypt(const QOlmMessage &message) const; -std::optional<OlmMessage> fromTypeAndCipthertext(size_t messageType, const QByteArray &ciphertext); + //! Get a base64-encoded identifier for this session. + QByteArray sessionId() const; -std::pair<OlmMessageType, QByteArray> toPair(const OlmMessage &message); + //! The type of the next message that will be returned from encryption. + QOlmMessage::Type encryptMessageType(); -//class QOlmSession -//{ -// /// Creates an inbound session for sending/receiving messages from a received 'prekey' message. -// static std::variant<std::unique_ptr<QOlmSession>, OlmError> createInboundSession(const QOlmAccount &account, -// PreKeyMessage &message); -// -////private: -// //static std::variant<std::unique_ptr<QOlmSession>, OlmError> createSessionWith(std::function<std::variant<size_t(OlmSession *)>> func); -//} + //! Checker for any received messages for this session. + bool hasReceivedMessage() const; + + //! Checks if the 'prekey' message is for this in-bound session. + std::variant<bool, QOlmError> matchesInboundSession(QOlmMessage &preKeyMessage); + + friend bool operator<(const QOlmSession& lhs, const QOlmSession& rhs) + { + return lhs.sessionId() < rhs.sessionId(); + } + + friend bool operator<(const std::unique_ptr<QOlmSession> &lhs, const std::unique_ptr<QOlmSession> &rhs) { + return *lhs < *rhs; + } + + QOlmSession(OlmSession* session); +private: + //! Helper function for creating new sessions and handling errors. + static OlmSession* create(); + static std::variant<std::unique_ptr<QOlmSession>, QOlmError> createInbound(QOlmAccount *account, const QOlmMessage& preKeyMessage, bool from = false, const QString& theirIdentityKey = ""); + OlmSession* m_session; +}; + + +//using QOlmSessionPtr = std::unique_ptr<QOlmSession>; + +} //namespace Quotient -} +#endif // Quotient_E2EE_ENABLED diff --git a/lib/crypto/qolmsession.h.back b/lib/crypto/qolmsession.h.back new file mode 100644 index 00000000..cbba5cef --- /dev/null +++ b/lib/crypto/qolmsession.h.back @@ -0,0 +1,49 @@ +// SPDX-FileCopyrightText: 2021 Carl Schwan <carlschwan@kde.org> +// +// SPDX-License-Identifier: LGPL-2.1-or-later + +#pragma once + +#include "olm/e2ee.h" +#include "olm/olm.h" +#include "olm/errors.h" +#include <variant> + +namespace Quotient { + +//! An encrypted Olm message. +struct QOlmMessage { + QByteArray message; +}; + +//! A encrypted Olm pre-key message. +//! +//! This message, unlike a normal Message, can be used to create new Olm sessions. +struct PreKeyMessage +{ + QByteArray message; +}; + +enum OlmMessageType +{ + PreKeyType, + MessageType, +}; + +using OlmMessage = std::variant<QOlmMessage, PreKeyMessage>; + +std::optional<OlmMessage> fromTypeAndCipthertext(size_t messageType, const QByteArray &ciphertext); + +std::pair<OlmMessageType, QByteArray> toPair(const OlmMessage &message); + +//class QOlmSession +//{ +// /// Creates an inbound session for sending/receiving messages from a received 'prekey' message. +// static std::variant<std::unique_ptr<QOlmSession>, OlmError> createInboundSession(const QOlmAccount &account, +// PreKeyMessage &message); +// +////private: +// //static std::variant<std::unique_ptr<QOlmSession>, OlmError> createSessionWith(std::function<std::variant<size_t(OlmSession *)>> func); +//} + +} diff --git a/lib/crypto/utils.cpp b/lib/crypto/qolmutils.cpp index cb20abf8..a486ea0f 100644 --- a/lib/crypto/utils.cpp +++ b/lib/crypto/qolmutils.cpp @@ -3,7 +3,7 @@ // SPDX-License-Identifier: LGPL-2.1-or-later #ifdef Quotient_E2EE_ENABLED -#include "crypto/utils.h" +#include "crypto/qolmutils.h" #include <QDebug> #include <openssl/rand.h> diff --git a/lib/crypto/utils.h b/lib/crypto/qolmutils.h index cea87144..11e9f3cc 100644 --- a/lib/crypto/utils.h +++ b/lib/crypto/qolmutils.h @@ -5,6 +5,8 @@ #pragma once #ifdef Quotient_E2EE_ENABLED +#include <QByteArray> + #include "crypto/e2ee.h" namespace Quotient { diff --git a/lib/crypto/session.cpp b/lib/crypto/session.cpp deleted file mode 100644 index 8b2cb022..00000000 --- a/lib/crypto/session.cpp +++ /dev/null @@ -1,242 +0,0 @@ -// SPDX-FileCopyrightText: 2021 Alexey Andreyev <aa13q@ya.ru> -// -// SPDX-License-Identifier: LGPL-2.1-or-later - -#ifdef Quotient_E2EE_ENABLED -#include "crypto/session.h" -#include "crypto/utils.h" -#include "logging.h" -#include <cstring> - -using namespace Quotient; - -OlmError lastError(OlmSession* session) { - const std::string error_raw = olm_session_last_error(session); - - return fromString(error_raw); -} - -Quotient::QOlmSession::~QOlmSession() -{ - olm_clear_session(m_session); - delete[](reinterpret_cast<uint8_t *>(m_session)); -} - -OlmSession* QOlmSession::create() -{ - return olm_session(new uint8_t[olm_session_size()]); -} - -std::variant<std::unique_ptr<QOlmSession>, OlmError> QOlmSession::createInbound(QOlmAccount *account, const Message &preKeyMessage, bool from, const QString &theirIdentityKey) -{ - if (preKeyMessage.type() != Message::PreKey) { - qCDebug(E2EE) << "The message is not a pre-key"; - throw BadMessageFormat; - } - - const auto olmSession = create(); - - QByteArray oneTimeKeyMessageBuf = preKeyMessage.toCiphertext(); - QByteArray theirIdentityKeyBuf = theirIdentityKey.toUtf8(); - size_t error = 0; - if (from) { - error = olm_create_inbound_session_from(olmSession, account->data(), theirIdentityKeyBuf.data(), theirIdentityKeyBuf.length(), oneTimeKeyMessageBuf.data(), oneTimeKeyMessageBuf.length()); - } else { - error = olm_create_inbound_session(olmSession, account->data(), oneTimeKeyMessageBuf.data(), oneTimeKeyMessageBuf.length()); - } - - if (error == olm_error()) { - const auto lastErr = lastError(olmSession); - if (lastErr == OlmError::NotEnoughRandom) { - throw lastErr; - } - return lastErr; - } - - return std::make_unique<QOlmSession>(olmSession); -} - -std::variant<std::unique_ptr<QOlmSession>, OlmError> QOlmSession::createInboundSession(QOlmAccount *account, const Message &preKeyMessage) -{ - return createInbound(account, preKeyMessage); -} - -std::variant<std::unique_ptr<QOlmSession>, OlmError> QOlmSession::createInboundSessionFrom(QOlmAccount *account, const QString &theirIdentityKey, const Message &preKeyMessage) -{ - return createInbound(account, preKeyMessage, true, theirIdentityKey); -} - -std::variant<std::unique_ptr<QOlmSession>, OlmError> QOlmSession::createOutboundSession(QOlmAccount *account, const QString &theirIdentityKey, const QString &theirOneTimeKey) -{ - auto *olmOutboundSession = create(); - const auto randomLen = olm_create_outbound_session_random_length(olmOutboundSession); - QByteArray randomBuf = getRandom(randomLen); - - QByteArray theirIdentityKeyBuf = theirIdentityKey.toUtf8(); - QByteArray theirOneTimeKeyBuf = theirOneTimeKey.toUtf8(); - const auto error = olm_create_outbound_session(olmOutboundSession, - account->data(), - reinterpret_cast<uint8_t *>(theirIdentityKeyBuf.data()), theirIdentityKeyBuf.length(), - reinterpret_cast<uint8_t *>(theirOneTimeKeyBuf.data()), theirOneTimeKeyBuf.length(), - reinterpret_cast<uint8_t *>(randomBuf.data()), randomBuf.length()); - - if (error == olm_error()) { - const auto lastErr = lastError(olmOutboundSession); - if (lastErr == OlmError::NotEnoughRandom) { - throw lastErr; - } - return lastErr; - } - - randomBuf.clear(); - return std::make_unique<QOlmSession>(olmOutboundSession); -} - -std::variant<QByteArray, OlmError> QOlmSession::pickle(const PicklingMode &mode) -{ - QByteArray pickledBuf(olm_pickle_session_length(m_session), '0'); - QByteArray key = toKey(mode); - const auto error = olm_pickle_session(m_session, key.data(), key.length(), - pickledBuf.data(), pickledBuf.length()); - - if (error == olm_error()) { - return lastError(m_session); - } - - key.clear(); - - return pickledBuf; -} - -std::variant<std::unique_ptr<QOlmSession>, OlmError> QOlmSession::unpickle(const QByteArray &pickled, const PicklingMode &mode) -{ - QByteArray pickledBuf = pickled; - auto *olmSession = create(); - QByteArray key = toKey(mode); - const auto error = olm_unpickle_session(olmSession, key.data(), key.length(), - pickledBuf.data(), pickledBuf.length()); - if (error == olm_error()) { - return lastError(olmSession); - } - - key.clear(); - return std::make_unique<QOlmSession>(olmSession); -} - -Message QOlmSession::encrypt(const QString &plaintext) -{ - QByteArray plaintextBuf = plaintext.toUtf8(); - const auto messageMaxLen = olm_encrypt_message_length(m_session, plaintextBuf.length()); - QByteArray messageBuf(messageMaxLen, '0'); - const auto messageType = encryptMessageType(); - const auto randomLen = olm_encrypt_random_length(m_session); - QByteArray randomBuf = getRandom(randomLen); - const auto error = olm_encrypt(m_session, - reinterpret_cast<uint8_t *>(plaintextBuf.data()), plaintextBuf.length(), - reinterpret_cast<uint8_t *>(randomBuf.data()), randomBuf.length(), - reinterpret_cast<uint8_t *>(messageBuf.data()), messageBuf.length()); - - if (error == olm_error()) { - throw lastError(m_session); - } - - return Message(messageBuf, messageType); -} - -std::variant<QString, OlmError> QOlmSession::decrypt(const Message &message) const -{ - const auto messageType = message.type(); - const auto ciphertext = message.toCiphertext(); - const auto messageTypeValue = messageType == Message::Type::General - ? OLM_MESSAGE_TYPE_MESSAGE : OLM_MESSAGE_TYPE_PRE_KEY; - - // We need to clone the message because - // olm_decrypt_max_plaintext_length destroys the input buffer - QByteArray messageBuf(ciphertext.length(), '0'); - std::copy(message.begin(), message.end(), messageBuf.begin()); - - const auto plaintextMaxLen = olm_decrypt_max_plaintext_length(m_session, messageTypeValue, - reinterpret_cast<uint8_t *>(messageBuf.data()), messageBuf.length()); - - if (plaintextMaxLen == olm_error()) { - return lastError(m_session); - } - - QByteArray plaintextBuf(plaintextMaxLen, '0'); - QByteArray messageBuf2(ciphertext.length(), '0'); - std::copy(message.begin(), message.end(), messageBuf2.begin()); - - const auto plaintextResultLen = olm_decrypt(m_session, messageTypeValue, - reinterpret_cast<uint8_t *>(messageBuf2.data()), messageBuf2.length(), - reinterpret_cast<uint8_t *>(plaintextBuf.data()), plaintextMaxLen); - - if (plaintextResultLen == olm_error()) { - const auto lastErr = lastError(m_session); - if (lastErr == OlmError::OutputBufferTooSmall) { - throw lastErr; - } - return lastErr; - } - QByteArray output(plaintextResultLen, '0'); - std::memcpy(output.data(), plaintextBuf.data(), plaintextResultLen); - plaintextBuf.clear(); - return output; -} - -Message::Type QOlmSession::encryptMessageType() -{ - const auto messageTypeResult = olm_encrypt_message_type(m_session); - if (messageTypeResult == olm_error()) { - throw lastError(m_session); - } - if (messageTypeResult == OLM_MESSAGE_TYPE_PRE_KEY) { - return Message::PreKey; - } - return Message::General; -} - -QByteArray QOlmSession::sessionId() const -{ - const auto idMaxLength = olm_session_id_length(m_session); - QByteArray idBuffer(idMaxLength, '0'); - const auto error = olm_session_id(m_session, reinterpret_cast<uint8_t *>(idBuffer.data()), - idBuffer.length()); - if (error == olm_error()) { - throw lastError(m_session); - } - return idBuffer; -} - -bool QOlmSession::hasReceivedMessage() const -{ - return olm_session_has_received_message(m_session); -} - -std::variant<bool, OlmError> QOlmSession::matchesInboundSession(Message &preKeyMessage) -{ - Q_ASSERT(preKeyMessage.type() == Message::Type::PreKey); - QByteArray oneTimeKeyBuf(preKeyMessage.data()); - const auto matchesResult = olm_matches_inbound_session(m_session, oneTimeKeyBuf.data(), oneTimeKeyBuf.length()); - - if (matchesResult == olm_error()) { - return lastError(m_session); - } - switch (matchesResult) { - case 0: - return false; - case 1: - return true; - default: - return OlmError::Unknown; - } -} - -QOlmSession::QOlmSession(OlmSession *session) - : m_session(session) -{ -} - -#endif // Quotient_E2EE_ENABLED - - - diff --git a/lib/crypto/session.h b/lib/crypto/session.h deleted file mode 100644 index 24702564..00000000 --- a/lib/crypto/session.h +++ /dev/null @@ -1,77 +0,0 @@ -// SPDX-FileCopyrightText: 2021 Alexey Andreyev <aa13q@ya.ru> -// -// SPDX-License-Identifier: LGPL-2.1-or-later - -#pragma once - -#ifdef Quotient_E2EE_ENABLED - -#include <QDebug> -#include <olm/olm.h> -#include "crypto/e2ee.h" -#include "crypto/message.h" -#include "crypto/errors.h" -#include "crypto/qolmaccount.h" - -namespace Quotient { - -class QOlmAccount; -class QOlmSession; - - -//! Either an outbound or inbound session for secure communication. -class QOlmSession -{ -public: - ~QOlmSession(); - //! Creates an inbound session for sending/receiving messages from a received 'prekey' message. - static std::variant<std::unique_ptr<QOlmSession>, OlmError> createInboundSession(QOlmAccount *account, const Message &preKeyMessage); - static std::variant<std::unique_ptr<QOlmSession>, OlmError> createInboundSessionFrom(QOlmAccount *account, const QString &theirIdentityKey, const Message &preKeyMessage); - static std::variant<std::unique_ptr<QOlmSession>, OlmError> createOutboundSession(QOlmAccount *account, const QString &theirIdentityKey, const QString &theirOneTimeKey); - //! Serialises an `QOlmSession` to encrypted Base64. - std::variant<QByteArray, OlmError> pickle(const PicklingMode &mode); - //! Deserialises from encrypted Base64 that was previously obtained by pickling a `QOlmSession`. - static std::variant<std::unique_ptr<QOlmSession>, OlmError> unpickle(const QByteArray &pickled, const PicklingMode &mode); - //! Encrypts a plaintext message using the session. - Message encrypt(const QString &plaintext); - - //! Decrypts a message using this session. Decoding is lossy, meaing if - //! the decrypted plaintext contains invalid UTF-8 symbols, they will - //! be returned as `U+FFFD` (�). - std::variant<QString, OlmError> decrypt(const Message &message) const; - - //! Get a base64-encoded identifier for this session. - QByteArray sessionId() const; - - //! The type of the next message that will be returned from encryption. - Message::Type encryptMessageType(); - - //! Checker for any received messages for this session. - bool hasReceivedMessage() const; - - //! Checks if the 'prekey' message is for this in-bound session. - std::variant<bool, OlmError> matchesInboundSession(Message &preKeyMessage); - - friend bool operator<(const QOlmSession& lhs, const QOlmSession& rhs) - { - return lhs.sessionId() < rhs.sessionId(); - } - - friend bool operator<(const std::unique_ptr<QOlmSession> &lhs, const std::unique_ptr<QOlmSession> &rhs) { - return *lhs < *rhs; - } - - QOlmSession(OlmSession* session); -private: - //! Helper function for creating new sessions and handling errors. - static OlmSession* create(); - static std::variant<std::unique_ptr<QOlmSession>, OlmError> createInbound(QOlmAccount *account, const Message& preKeyMessage, bool from = false, const QString& theirIdentityKey = ""); - OlmSession* m_session; -}; - - -//using QOlmSessionPtr = std::unique_ptr<QOlmSession>; - -} //namespace Quotient - -#endif // Quotient_E2EE_ENABLED |