aboutsummaryrefslogtreecommitdiff
path: root/lib/e2ee
diff options
context:
space:
mode:
authorAlexey Rusakov <Kitsune-Ral@users.sf.net>2022-08-24 09:41:51 +0200
committerAlexey Rusakov <Kitsune-Ral@users.sf.net>2022-08-24 09:41:51 +0200
commit82f4efb0227e7e22e831733fae3952818b063ac2 (patch)
tree3b154a16f9d355996a59c611230d0e010edab57f /lib/e2ee
parent16d4f4e48304543a0ab59b235edba07f5f2c2204 (diff)
parent6308bff3336ca7680eee54d9bd125f780fa9f033 (diff)
downloadlibquotient-82f4efb0227e7e22e831733fae3952818b063ac2.tar.gz
libquotient-82f4efb0227e7e22e831733fae3952818b063ac2.zip
Merge branch 'dev' into device-verification
# Conflicts: # autotests/testfilecrypto.cpp # lib/connection.cpp # lib/connection.h # lib/database.cpp # lib/database.h # lib/e2ee/qolmoutboundsession.cpp # lib/e2ee/qolmoutboundsession.h # lib/eventitem.h # lib/events/encryptedevent.cpp # lib/events/encryptedevent.h # lib/events/encryptedfile.cpp # lib/events/encryptedfile.h # lib/events/keyverificationevent.cpp # lib/events/keyverificationevent.h # lib/events/roomkeyevent.h # lib/room.cpp # lib/room.h
Diffstat (limited to 'lib/e2ee')
-rw-r--r--lib/e2ee/e2ee.h82
-rw-r--r--lib/e2ee/qolmaccount.cpp158
-rw-r--r--lib/e2ee/qolmaccount.h44
-rw-r--r--lib/e2ee/qolminboundsession.cpp14
-rw-r--r--lib/e2ee/qolminboundsession.h16
-rw-r--r--lib/e2ee/qolmmessage.cpp4
-rw-r--r--lib/e2ee/qolmoutboundsession.cpp18
-rw-r--r--lib/e2ee/qolmoutboundsession.h20
-rw-r--r--lib/e2ee/qolmsession.cpp73
-rw-r--r--lib/e2ee/qolmsession.h42
-rw-r--r--lib/e2ee/qolmutility.cpp14
-rw-r--r--lib/e2ee/qolmutility.h7
12 files changed, 238 insertions, 254 deletions
diff --git a/lib/e2ee/e2ee.h b/lib/e2ee/e2ee.h
index 268cb525..0772b70a 100644
--- a/lib/e2ee/e2ee.h
+++ b/lib/e2ee/e2ee.h
@@ -6,9 +6,13 @@
#pragma once
#include "converters.h"
-#include "quotient_common.h"
+#include "expected.h"
+#include "qolmerrors.h"
#include <QtCore/QMetaType>
+#include <QtCore/QStringBuilder>
+
+#include <array>
#include <variant>
namespace Quotient {
@@ -33,10 +37,11 @@ constexpr auto SignedCurve25519Key = "signed_curve25519"_ls;
constexpr auto OlmV1Curve25519AesSha2AlgoKey = "m.olm.v1.curve25519-aes-sha2"_ls;
constexpr auto MegolmV1AesSha2AlgoKey = "m.megolm.v1.aes-sha2"_ls;
+constexpr std::array SupportedAlgorithms { OlmV1Curve25519AesSha2AlgoKey,
+ MegolmV1AesSha2AlgoKey };
+
inline bool isSupportedAlgorithm(const QString& algorithm)
{
- static constexpr auto SupportedAlgorithms =
- make_array(OlmV1Curve25519AesSha2AlgoKey, MegolmV1AesSha2AlgoKey);
return std::find(SupportedAlgorithms.cbegin(), SupportedAlgorithms.cend(),
algorithm)
!= SupportedAlgorithms.cend();
@@ -55,6 +60,12 @@ using QOlmSessionPtr = std::unique_ptr<QOlmSession>;
class QOlmInboundGroupSession;
using QOlmInboundGroupSessionPtr = std::unique_ptr<QOlmInboundGroupSession>;
+class QOlmOutboundGroupSession;
+using QOlmOutboundGroupSessionPtr = std::unique_ptr<QOlmOutboundGroupSession>;
+
+template <typename T>
+using QOlmExpected = Expected<T, QOlmError>;
+
struct IdentityKeys
{
QByteArray curve25519;
@@ -62,45 +73,66 @@ struct IdentityKeys
};
//! Struct representing the one-time keys.
-struct QUOTIENT_API OneTimeKeys
+struct UnsignedOneTimeKeys
{
QHash<QString, QHash<QString, QString>> keys;
//! Get the HashMap containing the curve25519 one-time keys.
- QHash<QString, QString> curve25519() const;
-
- //! Get a reference to the hashmap corresponding to given key type.
-// std::optional<QHash<QString, QString>> get(QString keyType) const;
+ QHash<QString, QString> curve25519() const { return keys[Curve25519Key]; }
};
-//! Struct representing the signed one-time keys.
-class SignedOneTimeKey
-{
+class SignedOneTimeKey {
public:
- //! Required. The unpadded Base64-encoded 32-byte Curve25519 public key.
- QString key;
+ explicit SignedOneTimeKey(const QString& unsignedKey, const QString& userId,
+ const QString& deviceId,
+ const QByteArray& signature)
+ : payload { { "key"_ls, unsignedKey },
+ { "signatures"_ls,
+ QJsonObject {
+ { userId, QJsonObject { { "ed25519:"_ls % deviceId,
+ QString(signature) } } } } } }
+ {}
+ explicit SignedOneTimeKey(const QJsonObject& jo = {})
+ : payload(jo)
+ {}
- //! Required. Signatures of the key object.
- //! The signature is calculated using the process described at Signing JSON.
- QHash<QString, QHash<QString, QString>> signatures;
-};
+ //! Unpadded Base64-encoded 32-byte Curve25519 public key
+ QString key() const { return payload["key"_ls].toString(); }
+ //! \brief Signatures of the key object
+ //!
+ //! The signature is calculated using the process described at
+ //! https://spec.matrix.org/v1.3/appendices/#signing-json
+ auto signatures() const
+ {
+ return fromJson<QHash<QString, QHash<QString, QString>>>(
+ payload["signatures"_ls]);
+ }
-template <>
-struct JsonObjectConverter<SignedOneTimeKey> {
- static void fillFrom(const QJsonObject& jo, SignedOneTimeKey& result)
+ QByteArray signature(QStringView userId, QStringView deviceId) const
{
- fromJson(jo.value("key"_ls), result.key);
- fromJson(jo.value("signatures"_ls), result.signatures);
+ return payload["signatures"_ls][userId]["ed25519:"_ls % deviceId]
+ .toString()
+ .toLatin1();
}
- static void dumpTo(QJsonObject &jo, const SignedOneTimeKey &result)
+ //! Whether the key is a fallback key
+ bool isFallback() const { return payload["fallback"_ls].toBool(); }
+ auto toJson() const { return payload; }
+ auto toJsonForVerification() const
{
- addParam<>(jo, QStringLiteral("key"), result.key);
- addParam<>(jo, QStringLiteral("signatures"), result.signatures);
+ auto json = payload;
+ json.remove("signatures"_ls);
+ json.remove("unsigned"_ls);
+ return QJsonDocument(json).toJson(QJsonDocument::Compact);
}
+
+private:
+ QJsonObject payload;
};
+using OneTimeKeys = QHash<QString, std::variant<QString, SignedOneTimeKey>>;
+
template <typename T>
class asKeyValueRange
{
diff --git a/lib/e2ee/qolmaccount.cpp b/lib/e2ee/qolmaccount.cpp
index 476a60bd..ccb191f4 100644
--- a/lib/e2ee/qolmaccount.cpp
+++ b/lib/e2ee/qolmaccount.cpp
@@ -5,6 +5,7 @@
#include "qolmaccount.h"
#include "connection.h"
+#include "e2ee/qolmsession.h"
#include "e2ee/qolmutility.h"
#include "e2ee/qolmutils.h"
@@ -12,20 +13,9 @@
#include <QtCore/QRandomGenerator>
-using namespace Quotient;
-
-QHash<QString, QString> OneTimeKeys::curve25519() const
-{
- return keys[Curve25519Key];
-}
+#include <olm/olm.h>
-//std::optional<QHash<QString, QString>> OneTimeKeys::get(QString keyType) const
-//{
-// if (!keys.contains(keyType)) {
-// return std::nullopt;
-// }
-// return keys[keyType];
-//}
+using namespace Quotient;
// Convert olm error to enum
QOlmError lastError(OlmAccount *account) {
@@ -70,7 +60,7 @@ void QOlmAccount::unpickle(QByteArray &pickled, const PicklingMode &mode)
}
}
-std::variant<QByteArray, QOlmError> QOlmAccount::pickle(const PicklingMode &mode)
+QOlmExpected<QByteArray> QOlmAccount::pickle(const PicklingMode &mode)
{
const QByteArray key = toKey(mode);
const size_t pickleLength = olm_pickle_account_length(m_account);
@@ -119,20 +109,15 @@ QByteArray QOlmAccount::sign(const QJsonObject &message) const
QByteArray QOlmAccount::signIdentityKeys() const
{
const auto keys = identityKeys();
- QJsonObject body
- {
- {"algorithms", QJsonArray{"m.olm.v1.curve25519-aes-sha2", "m.megolm.v1.aes-sha2"}},
- {"user_id", m_userId},
- {"device_id", m_deviceId},
- {"keys",
- QJsonObject{
- {QStringLiteral("curve25519:") + m_deviceId, QString::fromUtf8(keys.curve25519)},
- {QStringLiteral("ed25519:") + m_deviceId, QString::fromUtf8(keys.ed25519)}
- }
- }
- };
- return sign(QJsonDocument(body).toJson(QJsonDocument::Compact));
-
+ return sign(QJsonObject {
+ { "algorithms", QJsonArray { "m.olm.v1.curve25519-aes-sha2",
+ "m.megolm.v1.aes-sha2" } },
+ { "user_id", m_userId },
+ { "device_id", m_deviceId },
+ { "keys", QJsonObject { { QStringLiteral("curve25519:") + m_deviceId,
+ QString::fromUtf8(keys.curve25519) },
+ { QStringLiteral("ed25519:") + m_deviceId,
+ QString::fromUtf8(keys.ed25519) } } } });
}
size_t QOlmAccount::maxNumberOfOneTimeKeys() const
@@ -140,11 +125,15 @@ size_t QOlmAccount::maxNumberOfOneTimeKeys() const
return olm_account_max_number_of_one_time_keys(m_account);
}
-size_t QOlmAccount::generateOneTimeKeys(size_t numberOfKeys) const
+size_t QOlmAccount::generateOneTimeKeys(size_t numberOfKeys)
{
- const size_t randomLength = olm_account_generate_one_time_keys_random_length(m_account, numberOfKeys);
+ const size_t randomLength =
+ olm_account_generate_one_time_keys_random_length(m_account,
+ numberOfKeys);
QByteArray randomBuffer = getRandom(randomLength);
- const auto error = olm_account_generate_one_time_keys(m_account, numberOfKeys, randomBuffer.data(), randomLength);
+ const auto error =
+ olm_account_generate_one_time_keys(m_account, numberOfKeys,
+ randomBuffer.data(), randomLength);
if (error == olm_error()) {
throw lastError(m_account);
@@ -153,49 +142,39 @@ size_t QOlmAccount::generateOneTimeKeys(size_t numberOfKeys) const
return error;
}
-OneTimeKeys QOlmAccount::oneTimeKeys() const
+UnsignedOneTimeKeys QOlmAccount::oneTimeKeys() const
{
const size_t oneTimeKeyLength = olm_account_one_time_keys_length(m_account);
- QByteArray oneTimeKeysBuffer(oneTimeKeyLength, '0');
+ QByteArray oneTimeKeysBuffer(static_cast<int>(oneTimeKeyLength), '0');
- const auto error = olm_account_one_time_keys(m_account, oneTimeKeysBuffer.data(), oneTimeKeyLength);
+ const auto error = olm_account_one_time_keys(m_account,
+ oneTimeKeysBuffer.data(),
+ oneTimeKeyLength);
if (error == olm_error()) {
throw lastError(m_account);
}
const auto json = QJsonDocument::fromJson(oneTimeKeysBuffer).object();
- OneTimeKeys oneTimeKeys;
+ UnsignedOneTimeKeys oneTimeKeys;
fromJson(json, oneTimeKeys.keys);
return oneTimeKeys;
}
-QHash<QString, SignedOneTimeKey> QOlmAccount::signOneTimeKeys(const OneTimeKeys &keys) const
+OneTimeKeys QOlmAccount::signOneTimeKeys(const UnsignedOneTimeKeys &keys) const
{
- QHash<QString, SignedOneTimeKey> signedOneTimeKeys;
- for (const auto &keyid : keys.curve25519().keys()) {
- const auto oneTimeKey = keys.curve25519()[keyid];
- QByteArray sign = signOneTimeKey(oneTimeKey);
- signedOneTimeKeys["signed_curve25519:" + keyid] = signedOneTimeKey(oneTimeKey.toUtf8(), sign);
- }
+ OneTimeKeys signedOneTimeKeys;
+ for (const auto& curveKeys = keys.curve25519();
+ const auto& [keyId, key] : asKeyValueRange(curveKeys))
+ signedOneTimeKeys.insert("signed_curve25519:" % keyId,
+ SignedOneTimeKey {
+ key, m_userId, m_deviceId,
+ sign(QJsonObject { { "key", key } }) });
return signedOneTimeKeys;
}
-SignedOneTimeKey QOlmAccount::signedOneTimeKey(const QByteArray &key, const QString &signature) const
-{
- SignedOneTimeKey sign{};
- sign.key = key;
- sign.signatures = {{m_userId, {{"ed25519:" + m_deviceId, signature}}}};
- return sign;
-}
-
-QByteArray QOlmAccount::signOneTimeKey(const QString &key) const
+std::optional<QOlmError> QOlmAccount::removeOneTimeKeys(
+ const QOlmSession& session)
{
- QJsonDocument j(QJsonObject{{"key", key}});
- return sign(j.toJson(QJsonDocument::Compact));
-}
-
-std::optional<QOlmError> QOlmAccount::removeOneTimeKeys(const QOlmSessionPtr &session) const
-{
- const auto error = olm_remove_one_time_keys(m_account, session->raw());
+ const auto error = olm_remove_one_time_keys(m_account, session.raw());
if (error == olm_error()) {
return lastError(m_account);
@@ -208,54 +187,47 @@ OlmAccount* QOlmAccount::data() { return m_account; }
DeviceKeys QOlmAccount::deviceKeys() const
{
- DeviceKeys deviceKeys;
- deviceKeys.userId = m_userId;
- deviceKeys.deviceId = m_deviceId;
- deviceKeys.algorithms = QStringList {"m.olm.v1.curve25519-aes-sha2", "m.megolm.v1.aes-sha2"};
+ static QStringList Algorithms(SupportedAlgorithms.cbegin(),
+ SupportedAlgorithms.cend());
const auto idKeys = identityKeys();
- deviceKeys.keys["curve25519:" + m_deviceId] = idKeys.curve25519;
- deviceKeys.keys["ed25519:" + m_deviceId] = idKeys.ed25519;
-
- const auto sign = signIdentityKeys();
- deviceKeys.signatures[m_userId]["ed25519:" + m_deviceId] = sign;
-
- return deviceKeys;
+ return DeviceKeys {
+ .userId = m_userId,
+ .deviceId = m_deviceId,
+ .algorithms = Algorithms,
+ .keys { { "curve25519:" + m_deviceId, idKeys.curve25519 },
+ { "ed25519:" + m_deviceId, idKeys.ed25519 } },
+ .signatures {
+ { m_userId, { { "ed25519:" + m_deviceId, signIdentityKeys() } } } }
+ };
}
-UploadKeysJob *QOlmAccount::createUploadKeyRequest(const OneTimeKeys &oneTimeKeys)
+UploadKeysJob* QOlmAccount::createUploadKeyRequest(
+ const UnsignedOneTimeKeys& oneTimeKeys) const
{
- auto keys = deviceKeys();
-
- if (oneTimeKeys.curve25519().isEmpty()) {
- return new UploadKeysJob(keys);
- }
-
- // Sign & append the one time keys.
- auto temp = signOneTimeKeys(oneTimeKeys);
- QHash<QString, QVariant> oneTimeKeysSigned;
- for (const auto &[keyId, key] : asKeyValueRange(temp)) {
- oneTimeKeysSigned[keyId] = QVariant::fromValue(toJson(key));
- }
-
- return new UploadKeysJob(keys, oneTimeKeysSigned);
+ return new UploadKeysJob(deviceKeys(), signOneTimeKeys(oneTimeKeys));
}
-std::variant<QOlmSessionPtr, QOlmError> QOlmAccount::createInboundSession(const QOlmMessage &preKeyMessage)
+QOlmExpected<QOlmSessionPtr> QOlmAccount::createInboundSession(
+ const QOlmMessage& preKeyMessage)
{
Q_ASSERT(preKeyMessage.type() == QOlmMessage::PreKey);
return QOlmSession::createInboundSession(this, preKeyMessage);
}
-std::variant<QOlmSessionPtr, QOlmError> QOlmAccount::createInboundSessionFrom(const QByteArray &theirIdentityKey, const QOlmMessage &preKeyMessage)
+QOlmExpected<QOlmSessionPtr> QOlmAccount::createInboundSessionFrom(
+ const QByteArray& theirIdentityKey, const QOlmMessage& preKeyMessage)
{
Q_ASSERT(preKeyMessage.type() == QOlmMessage::PreKey);
- return QOlmSession::createInboundSessionFrom(this, theirIdentityKey, preKeyMessage);
+ return QOlmSession::createInboundSessionFrom(this, theirIdentityKey,
+ preKeyMessage);
}
-std::variant<QOlmSessionPtr, QOlmError> QOlmAccount::createOutboundSession(const QByteArray &theirIdentityKey, const QByteArray &theirOneTimeKey)
+QOlmExpected<QOlmSessionPtr> QOlmAccount::createOutboundSession(
+ const QByteArray& theirIdentityKey, const QByteArray& theirOneTimeKey)
{
- return QOlmSession::createOutboundSession(this, theirIdentityKey, theirOneTimeKey);
+ return QOlmSession::createOutboundSession(this, theirIdentityKey,
+ theirOneTimeKey);
}
void QOlmAccount::markKeysAsPublished()
@@ -292,10 +264,6 @@ bool Quotient::ed25519VerifySignature(const QString& signingKey,
QByteArray signingKeyBuf = signingKey.toUtf8();
QOlmUtility utility;
auto signatureBuf = signature.toUtf8();
- auto result = utility.ed25519Verify(signingKeyBuf, canonicalJson, signatureBuf);
- if (std::holds_alternative<QOlmError>(result)) {
- return false;
- }
-
- return std::get<bool>(result);
+ return utility.ed25519Verify(signingKeyBuf, canonicalJson, signatureBuf)
+ .value_or(false);
}
diff --git a/lib/e2ee/qolmaccount.h b/lib/e2ee/qolmaccount.h
index 17f43f1a..f2a31314 100644
--- a/lib/e2ee/qolmaccount.h
+++ b/lib/e2ee/qolmaccount.h
@@ -5,21 +5,16 @@
#pragma once
-#include "csapi/keys.h"
#include "e2ee/e2ee.h"
-#include "e2ee/qolmerrors.h"
#include "e2ee/qolmmessage.h"
-#include "e2ee/qolmsession.h"
-#include <QObject>
-struct OlmAccount;
+#include "csapi/keys.h"
-namespace Quotient {
+#include <QtCore/QObject>
-class QOlmSession;
-class Connection;
+struct OlmAccount;
-using QOlmSessionPtr = std::unique_ptr<QOlmSession>;
+namespace Quotient {
//! An olm account manages all cryptographic keys used on a device.
//! \code{.cpp}
@@ -30,7 +25,7 @@ class QUOTIENT_API QOlmAccount : public QObject
Q_OBJECT
public:
QOlmAccount(const QString &userId, const QString &deviceId, QObject *parent = nullptr);
- ~QOlmAccount();
+ ~QOlmAccount() override;
//! Creates a new instance of OlmAccount. During the instantiation
//! the Ed25519 fingerprint key pair and the Curve25519 identity key
@@ -44,7 +39,7 @@ public:
void unpickle(QByteArray &pickled, const PicklingMode &mode);
//! Serialises an OlmAccount to encrypted Base64.
- std::variant<QByteArray, QOlmError> pickle(const PicklingMode &mode);
+ QOlmExpected<QByteArray> pickle(const PicklingMode &mode);
//! Returns the account's public identity keys already formatted as JSON
IdentityKeys identityKeys() const;
@@ -61,40 +56,39 @@ public:
size_t maxNumberOfOneTimeKeys() const;
//! Generates the supplied number of one time keys.
- size_t generateOneTimeKeys(size_t numberOfKeys) const;
+ size_t generateOneTimeKeys(size_t numberOfKeys);
//! Gets the OlmAccount's one time keys formatted as JSON.
- OneTimeKeys oneTimeKeys() const;
+ UnsignedOneTimeKeys oneTimeKeys() const;
//! Sign all one time keys.
- QHash<QString, SignedOneTimeKey> signOneTimeKeys(const OneTimeKeys &keys) const;
-
- //! Sign one time key.
- QByteArray signOneTimeKey(const QString &key) const;
-
- SignedOneTimeKey signedOneTimeKey(const QByteArray &key, const QString &signature) const;
+ OneTimeKeys signOneTimeKeys(const UnsignedOneTimeKeys &keys) const;
- UploadKeysJob *createUploadKeyRequest(const OneTimeKeys &oneTimeKeys);
+ UploadKeysJob* createUploadKeyRequest(const UnsignedOneTimeKeys& oneTimeKeys) const;
DeviceKeys deviceKeys() const;
//! Remove the one time key used to create the supplied session.
- [[nodiscard]] std::optional<QOlmError> removeOneTimeKeys(const QOlmSessionPtr &session) const;
+ [[nodiscard]] std::optional<QOlmError> removeOneTimeKeys(
+ const QOlmSession& session);
//! 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<QOlmSessionPtr, QOlmError> createInboundSession(const QOlmMessage &preKeyMessage);
+ QOlmExpected<QOlmSessionPtr> createInboundSession(
+ const QOlmMessage& preKeyMessage);
//! Creates an inbound session for sending/receiving messages from a received 'prekey' message.
//!
//! \param theirIdentityKey - The identity key of the Olm account that
//! encrypted this Olm message.
- std::variant<QOlmSessionPtr, QOlmError> createInboundSessionFrom(const QByteArray &theirIdentityKey, const QOlmMessage &preKeyMessage);
+ QOlmExpected<QOlmSessionPtr> createInboundSessionFrom(
+ const QByteArray& theirIdentityKey, const QOlmMessage& preKeyMessage);
//! Creates an outbound session for sending messages to a specific
/// identity and one time key.
- std::variant<QOlmSessionPtr, QOlmError> createOutboundSession(const QByteArray &theirIdentityKey, const QByteArray &theirOneTimeKey);
+ QOlmExpected<QOlmSessionPtr> createOutboundSession(
+ const QByteArray& theirIdentityKey, const QByteArray& theirOneTimeKey);
void markKeysAsPublished();
@@ -103,7 +97,7 @@ public:
OlmAccount *data();
Q_SIGNALS:
- void needsSave() const;
+ void needsSave();
private:
OlmAccount *m_account = nullptr; // owning
diff --git a/lib/e2ee/qolminboundsession.cpp b/lib/e2ee/qolminboundsession.cpp
index 60d871ef..17f06205 100644
--- a/lib/e2ee/qolminboundsession.cpp
+++ b/lib/e2ee/qolminboundsession.cpp
@@ -70,7 +70,8 @@ QByteArray QOlmInboundGroupSession::pickle(const PicklingMode &mode) const
return pickledBuf;
}
-std::variant<std::unique_ptr<QOlmInboundGroupSession>, QOlmError> QOlmInboundGroupSession::unpickle(const QByteArray &pickled, const PicklingMode &mode)
+QOlmExpected<QOlmInboundGroupSessionPtr> QOlmInboundGroupSession::unpickle(
+ const QByteArray& pickled, const PicklingMode& mode)
{
QByteArray pickledBuf = pickled;
const auto groupSession = olm_inbound_group_session(new uint8_t[olm_inbound_group_session_size()]);
@@ -85,7 +86,8 @@ std::variant<std::unique_ptr<QOlmInboundGroupSession>, QOlmError> QOlmInboundGro
return std::make_unique<QOlmInboundGroupSession>(groupSession);
}
-std::variant<std::pair<QString, uint32_t>, QOlmError> QOlmInboundGroupSession::decrypt(const QByteArray &message)
+QOlmExpected<std::pair<QByteArray, uint32_t>> QOlmInboundGroupSession::decrypt(
+ const QByteArray& message)
{
// This is for capturing the output of olm_group_decrypt
uint32_t messageIndex = 0;
@@ -114,10 +116,10 @@ std::variant<std::pair<QString, uint32_t>, QOlmError> QOlmInboundGroupSession::d
QByteArray output(plaintextLen, '0');
std::memcpy(output.data(), plaintextBuf.data(), plaintextLen);
- return std::make_pair<QString, qint32>(QString(output), messageIndex);
+ return std::make_pair(output, messageIndex);
}
-std::variant<QByteArray, QOlmError> QOlmInboundGroupSession::exportSession(uint32_t messageIndex)
+QOlmExpected<QByteArray> QOlmInboundGroupSession::exportSession(uint32_t messageIndex)
{
const auto keyLength = olm_export_inbound_group_session_length(m_groupSession);
QByteArray keyBuf(keyLength, '0');
@@ -154,9 +156,9 @@ QString QOlmInboundGroupSession::olmSessionId() const
{
return m_olmSessionId;
}
-void QOlmInboundGroupSession::setOlmSessionId(const QString& olmSessionId)
+void QOlmInboundGroupSession::setOlmSessionId(const QString& newOlmSessionId)
{
- m_olmSessionId = olmSessionId;
+ m_olmSessionId = newOlmSessionId;
}
QString QOlmInboundGroupSession::senderId() const
diff --git a/lib/e2ee/qolminboundsession.h b/lib/e2ee/qolminboundsession.h
index 32112b97..1a9b4415 100644
--- a/lib/e2ee/qolminboundsession.h
+++ b/lib/e2ee/qolminboundsession.h
@@ -5,11 +5,8 @@
#pragma once
#include "e2ee/e2ee.h"
-#include "e2ee/qolmerrors.h"
-#include "olm/olm.h"
-#include <memory>
-#include <variant>
+#include <olm/olm.h>
namespace Quotient {
@@ -27,14 +24,13 @@ 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>, QOlmError>
- unpickle(const QByteArray& picked, const PicklingMode& mode);
+ static QOlmExpected<QOlmInboundGroupSessionPtr> unpickle(
+ const QByteArray& pickled, const PicklingMode& mode);
//! Decrypts ciphertext received for this group session.
- std::variant<std::pair<QString, uint32_t>, QOlmError> decrypt(
- const QByteArray& message);
+ QOlmExpected<std::pair<QByteArray, uint32_t> > 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, QOlmError> exportSession(uint32_t messageIndex);
+ QOlmExpected<QByteArray> 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.
@@ -44,7 +40,7 @@ public:
//! The olm session that this session was received from.
//! Required to get the device this session is from.
QString olmSessionId() const;
- void setOlmSessionId(const QString& setOlmSessionId);
+ void setOlmSessionId(const QString& newOlmSessionId);
//! The sender of this session.
QString senderId() const;
diff --git a/lib/e2ee/qolmmessage.cpp b/lib/e2ee/qolmmessage.cpp
index 81b166b0..f9b4a5c2 100644
--- a/lib/e2ee/qolmmessage.cpp
+++ b/lib/e2ee/qolmmessage.cpp
@@ -4,6 +4,8 @@
#include "qolmmessage.h"
+#include "util.h"
+
using namespace Quotient;
QOlmMessage::QOlmMessage(QByteArray ciphertext, QOlmMessage::Type type)
@@ -26,7 +28,7 @@ QOlmMessage::Type QOlmMessage::type() const
QByteArray QOlmMessage::toCiphertext() const
{
- return QByteArray(*this);
+ return SLICE(*this, QByteArray);
}
QOlmMessage QOlmMessage::fromCiphertext(const QByteArray &ciphertext)
diff --git a/lib/e2ee/qolmoutboundsession.cpp b/lib/e2ee/qolmoutboundsession.cpp
index 8852bcf3..a2eff2c8 100644
--- a/lib/e2ee/qolmoutboundsession.cpp
+++ b/lib/e2ee/qolmoutboundsession.cpp
@@ -13,8 +13,7 @@ QOlmError lastError(OlmOutboundGroupSession *session) {
QOlmOutboundGroupSession::QOlmOutboundGroupSession(OlmOutboundGroupSession *session)
: m_groupSession(session)
-{
-}
+{}
QOlmOutboundGroupSession::~QOlmOutboundGroupSession()
{
@@ -22,7 +21,7 @@ QOlmOutboundGroupSession::~QOlmOutboundGroupSession()
delete[](reinterpret_cast<uint8_t *>(m_groupSession));
}
-std::unique_ptr<QOlmOutboundGroupSession> QOlmOutboundGroupSession::create()
+QOlmOutboundGroupSessionPtr QOlmOutboundGroupSession::create()
{
auto *olmOutboundGroupSession = olm_outbound_group_session(new uint8_t[olm_outbound_group_session_size()]);
const auto randomLength = olm_init_outbound_group_session_random_length(olmOutboundGroupSession);
@@ -45,7 +44,7 @@ std::unique_ptr<QOlmOutboundGroupSession> QOlmOutboundGroupSession::create()
return std::make_unique<QOlmOutboundGroupSession>(olmOutboundGroupSession);
}
-std::variant<QByteArray, QOlmError> QOlmOutboundGroupSession::pickle(const PicklingMode &mode)
+QOlmExpected<QByteArray> QOlmOutboundGroupSession::pickle(const PicklingMode &mode) const
{
QByteArray pickledBuf(olm_pickle_outbound_group_session_length(m_groupSession), '0');
QByteArray key = toKey(mode);
@@ -61,7 +60,7 @@ std::variant<QByteArray, QOlmError> QOlmOutboundGroupSession::pickle(const Pickl
return pickledBuf;
}
-std::variant<std::unique_ptr<QOlmOutboundGroupSession>, QOlmError> QOlmOutboundGroupSession::unpickle(const QByteArray &pickled, const PicklingMode &mode)
+QOlmExpected<QOlmOutboundGroupSessionPtr> QOlmOutboundGroupSession::unpickle(const QByteArray &pickled, const PicklingMode &mode)
{
QByteArray pickledBuf = pickled;
auto *olmOutboundGroupSession = olm_outbound_group_session(new uint8_t[olm_outbound_group_session_size()]);
@@ -80,7 +79,7 @@ std::variant<std::unique_ptr<QOlmOutboundGroupSession>, QOlmError> QOlmOutboundG
return std::make_unique<QOlmOutboundGroupSession>(olmOutboundGroupSession);
}
-std::variant<QByteArray, QOlmError> QOlmOutboundGroupSession::encrypt(const QString &plaintext)
+QOlmExpected<QByteArray> QOlmOutboundGroupSession::encrypt(const QString &plaintext) const
{
QByteArray plaintextBuf = plaintext.toUtf8();
const auto messageMaxLength = olm_group_encrypt_message_length(m_groupSession, plaintextBuf.length());
@@ -112,12 +111,13 @@ QByteArray QOlmOutboundGroupSession::sessionId() const
return idBuffer;
}
-std::variant<QByteArray, QOlmError> QOlmOutboundGroupSession::sessionKey() const
+QOlmExpected<QByteArray> QOlmOutboundGroupSession::sessionKey() const
{
const auto keyMaxLength = olm_outbound_group_session_key_length(m_groupSession);
QByteArray keyBuffer(keyMaxLength, '0');
- const auto error = olm_outbound_group_session_key(m_groupSession, reinterpret_cast<uint8_t *>(keyBuffer.data()),
- keyMaxLength);
+ const auto error = olm_outbound_group_session_key(
+ m_groupSession, reinterpret_cast<uint8_t*>(keyBuffer.data()),
+ keyMaxLength);
if (error == olm_error()) {
return lastError(m_groupSession);
}
diff --git a/lib/e2ee/qolmoutboundsession.h b/lib/e2ee/qolmoutboundsession.h
index 10ca35c0..9a82d22a 100644
--- a/lib/e2ee/qolmoutboundsession.h
+++ b/lib/e2ee/qolmoutboundsession.h
@@ -4,10 +4,10 @@
#pragma once
-#include "olm/olm.h"
-#include "e2ee/qolmerrors.h"
#include "e2ee/e2ee.h"
+
#include <memory>
+#include <olm/olm.h>
namespace Quotient {
@@ -19,15 +19,16 @@ public:
~QOlmOutboundGroupSession();
//! Creates a new instance of `QOlmOutboundGroupSession`.
//! Throw OlmError on errors
- static std::unique_ptr<QOlmOutboundGroupSession> create();
+ static QOlmOutboundGroupSessionPtr create();
//! Serialises a `QOlmOutboundGroupSession` to encrypted Base64.
- std::variant<QByteArray, QOlmError> pickle(const PicklingMode &mode);
+ QOlmExpected<QByteArray> pickle(const PicklingMode &mode) const;
//! Deserialises from encrypted Base64 that was previously obtained by
//! pickling a `QOlmOutboundGroupSession`.
- static std::variant<std::unique_ptr<QOlmOutboundGroupSession>, QOlmError>
- unpickle(const QByteArray& pickled, const PicklingMode& mode);
+ static QOlmExpected<QOlmOutboundGroupSessionPtr> unpickle(
+ const QByteArray& pickled, const PicklingMode& mode);
+
//! Encrypts a plaintext message using the session.
- std::variant<QByteArray, QOlmError> encrypt(const QString &plaintext);
+ QOlmExpected<QByteArray> encrypt(const QString& plaintext) const;
//! Get the current message index for this session.
//!
@@ -42,7 +43,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, QOlmError> sessionKey() const;
+ QOlmExpected<QByteArray> sessionKey() const;
QOlmOutboundGroupSession(OlmOutboundGroupSession *groupSession);
int messageCount() const;
@@ -56,5 +57,4 @@ private:
QDateTime m_creationTime = QDateTime::currentDateTime();
};
-using QOlmOutboundGroupSessionPtr = std::unique_ptr<QOlmOutboundGroupSession>;
-}
+} // namespace Quotient
diff --git a/lib/e2ee/qolmsession.cpp b/lib/e2ee/qolmsession.cpp
index e575ff39..2a98d5d8 100644
--- a/lib/e2ee/qolmsession.cpp
+++ b/lib/e2ee/qolmsession.cpp
@@ -3,10 +3,12 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
#include "qolmsession.h"
+
#include "e2ee/qolmutils.h"
#include "logging.h"
+
#include <cstring>
-#include <QDebug>
+#include <olm/olm.h>
using namespace Quotient;
@@ -25,7 +27,9 @@ OlmSession* QOlmSession::create()
return olm_session(new uint8_t[olm_session_size()]);
}
-std::variant<QOlmSessionPtr, QOlmError> QOlmSession::createInbound(QOlmAccount *account, const QOlmMessage &preKeyMessage, bool from, const QString &theirIdentityKey)
+QOlmExpected<QOlmSessionPtr> QOlmSession::createInbound(
+ QOlmAccount* account, const QOlmMessage& preKeyMessage, bool from,
+ const QString& theirIdentityKey)
{
if (preKeyMessage.type() != QOlmMessage::PreKey) {
qCCritical(E2EE) << "The message is not a pre-key in when creating inbound session" << BadMessageFormat;
@@ -51,17 +55,22 @@ std::variant<QOlmSessionPtr, QOlmError> QOlmSession::createInbound(QOlmAccount *
return std::make_unique<QOlmSession>(olmSession);
}
-std::variant<QOlmSessionPtr, QOlmError> QOlmSession::createInboundSession(QOlmAccount *account, const QOlmMessage &preKeyMessage)
+QOlmExpected<QOlmSessionPtr> QOlmSession::createInboundSession(
+ QOlmAccount* account, const QOlmMessage& preKeyMessage)
{
return createInbound(account, preKeyMessage);
}
-std::variant<QOlmSessionPtr, QOlmError> QOlmSession::createInboundSessionFrom(QOlmAccount *account, const QString &theirIdentityKey, const QOlmMessage &preKeyMessage)
+QOlmExpected<QOlmSessionPtr> QOlmSession::createInboundSessionFrom(
+ QOlmAccount* account, const QString& theirIdentityKey,
+ const QOlmMessage& preKeyMessage)
{
return createInbound(account, preKeyMessage, true, theirIdentityKey);
}
-std::variant<QOlmSessionPtr, QOlmError> QOlmSession::createOutboundSession(QOlmAccount *account, const QString &theirIdentityKey, const QString &theirOneTimeKey)
+QOlmExpected<QOlmSessionPtr> QOlmSession::createOutboundSession(
+ QOlmAccount* account, const QString& theirIdentityKey,
+ const QString& theirOneTimeKey)
{
auto *olmOutboundSession = create();
const auto randomLen = olm_create_outbound_session_random_length(olmOutboundSession);
@@ -87,12 +96,13 @@ std::variant<QOlmSessionPtr, QOlmError> QOlmSession::createOutboundSession(QOlmA
return std::make_unique<QOlmSession>(olmOutboundSession);
}
-std::variant<QByteArray, QOlmError> QOlmSession::pickle(const PicklingMode &mode)
+QOlmExpected<QByteArray> QOlmSession::pickle(const PicklingMode &mode) const
{
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());
+ pickledBuf.data(),
+ pickledBuf.length());
if (error == olm_error()) {
return lastError(m_session);
@@ -103,7 +113,8 @@ std::variant<QByteArray, QOlmError> QOlmSession::pickle(const PicklingMode &mode
return pickledBuf;
}
-std::variant<QOlmSessionPtr, QOlmError> QOlmSession::unpickle(const QByteArray &pickled, const PicklingMode &mode)
+QOlmExpected<QOlmSessionPtr> QOlmSession::unpickle(const QByteArray& pickled,
+ const PicklingMode& mode)
{
QByteArray pickledBuf = pickled;
auto *olmSession = create();
@@ -138,7 +149,7 @@ QOlmMessage QOlmSession::encrypt(const QString &plaintext)
return QOlmMessage(messageBuf, messageType);
}
-std::variant<QString, QOlmError> QOlmSession::decrypt(const QOlmMessage &message) const
+QOlmExpected<QByteArray> QOlmSession::decrypt(const QOlmMessage &message) const
{
const auto messageType = message.type();
const auto ciphertext = message.toCiphertext();
@@ -207,45 +218,35 @@ bool QOlmSession::hasReceivedMessage() const
return olm_session_has_received_message(m_session);
}
-std::variant<bool, QOlmError> QOlmSession::matchesInboundSession(const QOlmMessage &preKeyMessage) const
+bool QOlmSession::matchesInboundSession(const QOlmMessage& preKeyMessage) const
{
Q_ASSERT(preKeyMessage.type() == QOlmMessage::Type::PreKey);
QByteArray oneTimeKeyBuf(preKeyMessage.data());
- const auto matchesResult = olm_matches_inbound_session(m_session, oneTimeKeyBuf.data(), oneTimeKeyBuf.length());
+ const auto maybeMatches =
+ olm_matches_inbound_session(m_session, oneTimeKeyBuf.data(),
+ oneTimeKeyBuf.length());
- if (matchesResult == olm_error()) {
+ if (maybeMatches == olm_error()) {
return lastError(m_session);
}
- switch (matchesResult) {
- case 0:
- return false;
- case 1:
- return true;
- default:
- return QOlmError::Unknown;
- }
+ return maybeMatches == 1;
}
-std::variant<bool, QOlmError> QOlmSession::matchesInboundSessionFrom(const QString &theirIdentityKey, const QOlmMessage &preKeyMessage) const
+
+bool QOlmSession::matchesInboundSessionFrom(
+ const QString& theirIdentityKey, const QOlmMessage& preKeyMessage) const
{
const auto theirIdentityKeyBuf = theirIdentityKey.toUtf8();
auto oneTimeKeyMessageBuf = preKeyMessage.toCiphertext();
- const auto error = olm_matches_inbound_session_from(m_session, theirIdentityKeyBuf.data(), theirIdentityKeyBuf.length(),
- oneTimeKeyMessageBuf.data(), oneTimeKeyMessageBuf.length());
+ const auto maybeMatches = olm_matches_inbound_session_from(
+ m_session, theirIdentityKeyBuf.data(), theirIdentityKeyBuf.length(),
+ oneTimeKeyMessageBuf.data(), oneTimeKeyMessageBuf.length());
- if (error == olm_error()) {
- return lastError(m_session);
- }
- switch (error) {
- case 0:
- return false;
- case 1:
- return true;
- default:
- return QOlmError::Unknown;
- }
+ if (maybeMatches == olm_error())
+ qCWarning(E2EE) << "Error matching an inbound session:"
+ << olm_session_last_error(m_session);
+ return maybeMatches == 1;
}
QOlmSession::QOlmSession(OlmSession *session)
: m_session(session)
-{
-}
+{}
diff --git a/lib/e2ee/qolmsession.h b/lib/e2ee/qolmsession.h
index f20c9837..021092c7 100644
--- a/lib/e2ee/qolmsession.h
+++ b/lib/e2ee/qolmsession.h
@@ -4,17 +4,14 @@
#pragma once
-#include <QDebug>
-#include <olm/olm.h> // FIXME: OlmSession
#include "e2ee/e2ee.h"
#include "e2ee/qolmmessage.h"
#include "e2ee/qolmerrors.h"
#include "e2ee/qolmaccount.h"
-namespace Quotient {
+struct OlmSession;
-class QOlmAccount;
-class QOlmSession;
+namespace Quotient {
//! Either an outbound or inbound session for secure communication.
class QUOTIENT_API QOlmSession
@@ -22,32 +19,31 @@ class QUOTIENT_API QOlmSession
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 QOlmExpected<QOlmSessionPtr> createInboundSession(
+ QOlmAccount* account, const QOlmMessage& preKeyMessage);
- static std::variant<std::unique_ptr<QOlmSession>, QOlmError>
- createInboundSessionFrom(QOlmAccount* account,
- const QString& theirIdentityKey,
- const QOlmMessage& preKeyMessage);
+ static QOlmExpected<QOlmSessionPtr> 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);
+ static QOlmExpected<QOlmSessionPtr> createOutboundSession(
+ QOlmAccount* account, const QString& theirIdentityKey,
+ const QString& theirOneTimeKey);
//! Serialises an `QOlmSession` to encrypted Base64.
- std::variant<QByteArray, QOlmError> pickle(const PicklingMode &mode);
+ QOlmExpected<QByteArray> pickle(const PicklingMode &mode) const;
//! Deserialises from encrypted Base64 that was previously obtained by pickling a `QOlmSession`.
- static std::variant<std::unique_ptr<QOlmSession>, QOlmError> unpickle(
+ static QOlmExpected<QOlmSessionPtr> unpickle(
const QByteArray& pickled, const PicklingMode& mode);
//! Encrypts a plaintext message using the session.
QOlmMessage encrypt(const QString &plaintext);
- //! Decrypts a message using this session. Decoding is lossy, meaing if
+ //! Decrypts a message using this session. Decoding is lossy, meaning 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;
+ QOlmExpected<QByteArray> decrypt(const QOlmMessage &message) const;
//! Get a base64-encoded identifier for this session.
QByteArray sessionId() const;
@@ -59,11 +55,10 @@ public:
bool hasReceivedMessage() const;
//! Checks if the 'prekey' message is for this in-bound session.
- std::variant<bool, QOlmError> matchesInboundSession(
- const QOlmMessage& preKeyMessage) const;
+ bool matchesInboundSession(const QOlmMessage& preKeyMessage) const;
//! Checks if the 'prekey' message is for this in-bound session.
- std::variant<bool, QOlmError> matchesInboundSessionFrom(
+ bool matchesInboundSessionFrom(
const QString& theirIdentityKey, const QOlmMessage& preKeyMessage) const;
friend bool operator<(const QOlmSession& lhs, const QOlmSession& rhs)
@@ -71,8 +66,7 @@ public:
return lhs.sessionId() < rhs.sessionId();
}
- friend bool operator<(const std::unique_ptr<QOlmSession>& lhs,
- const std::unique_ptr<QOlmSession>& rhs)
+ friend bool operator<(const QOlmSessionPtr& lhs, const QOlmSessionPtr& rhs)
{
return *lhs < *rhs;
}
@@ -83,7 +77,7 @@ public:
private:
//! Helper function for creating new sessions and handling errors.
static OlmSession* create();
- static std::variant<std::unique_ptr<QOlmSession>, QOlmError> createInbound(
+ static QOlmExpected<QOlmSessionPtr> createInbound(
QOlmAccount* account, const QOlmMessage& preKeyMessage,
bool from = false, const QString& theirIdentityKey = "");
OlmSession* m_session;
diff --git a/lib/e2ee/qolmutility.cpp b/lib/e2ee/qolmutility.cpp
index 9f09a37f..84559085 100644
--- a/lib/e2ee/qolmutility.cpp
+++ b/lib/e2ee/qolmutility.cpp
@@ -3,8 +3,8 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
#include "e2ee/qolmutility.h"
-#include "olm/olm.h"
-#include <QDebug>
+
+#include <olm/olm.h>
using namespace Quotient;
@@ -40,8 +40,9 @@ QString QOlmUtility::sha256Utf8Msg(const QString &message) const
return sha256Bytes(message.toUtf8());
}
-std::variant<bool, QOlmError> QOlmUtility::ed25519Verify(const QByteArray &key,
- const QByteArray &message, const QByteArray &signature)
+QOlmExpected<bool> QOlmUtility::ed25519Verify(const QByteArray& key,
+ const QByteArray& message,
+ const QByteArray& signature)
{
QByteArray signatureBuf(signature.length(), '0');
std::copy(signature.begin(), signature.end(), signatureBuf.begin());
@@ -57,8 +58,5 @@ std::variant<bool, QOlmError> QOlmUtility::ed25519Verify(const QByteArray &key,
return error;
}
- if (ret != 0) {
- return false;
- }
- return true;
+ return !ret; // ret == 0 means success
}
diff --git a/lib/e2ee/qolmutility.h b/lib/e2ee/qolmutility.h
index a12af49a..5f6bcdc5 100644
--- a/lib/e2ee/qolmutility.h
+++ b/lib/e2ee/qolmutility.h
@@ -4,15 +4,12 @@
#pragma once
-#include <variant>
-#include "e2ee/qolmerrors.h"
+#include "e2ee/e2ee.h"
struct OlmUtility;
namespace Quotient {
-class QOlmSession;
-
//! Allows you to make use of crytographic hashing via SHA-2 and
//! verifying ed25519 signatures.
class QUOTIENT_API QOlmUtility
@@ -32,7 +29,7 @@ public:
//! \param key QByteArray The public part of the ed25519 key that signed the message.
//! \param message QByteArray The message that was signed.
//! \param signature QByteArray The signature of the message.
- std::variant<bool, QOlmError> ed25519Verify(const QByteArray &key,
+ QOlmExpected<bool> ed25519Verify(const QByteArray &key,
const QByteArray &message, const QByteArray &signature);
private: