aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/olm/e2ee.h11
-rw-r--r--lib/olm/qolmaccount.cpp83
-rw-r--r--lib/olm/qolmaccount.h35
-rw-r--r--lib/olm/qolmsession.cpp29
-rw-r--r--lib/olm/qolmsession.h49
5 files changed, 174 insertions, 33 deletions
diff --git a/lib/olm/e2ee.h b/lib/olm/e2ee.h
index 1dee0e42..74f876e4 100644
--- a/lib/olm/e2ee.h
+++ b/lib/olm/e2ee.h
@@ -66,6 +66,17 @@ struct OneTimeKeys
std::optional<QMap<QString, QString>> get(QString keyType) const;
};
+//! Struct representing the signed one-time keys.
+struct SignedOneTimeKey
+{
+ //! Required. The unpadded Base64-encoded 32-byte Curve25519 public key.
+ QString key;
+
+ //! Required. Signatures of the key object.
+ //! The signature is calculated using the process described at Signing JSON.
+ QMap<QString, QMap<QString, QString>> signatures;
+};
+
bool operator==(const IdentityKeys& lhs, const IdentityKeys& rhs);
} // namespace Quotient
diff --git a/lib/olm/qolmaccount.cpp b/lib/olm/qolmaccount.cpp
index 742d7d18..8872f66e 100644
--- a/lib/olm/qolmaccount.cpp
+++ b/lib/olm/qolmaccount.cpp
@@ -44,36 +44,37 @@ QByteArray getRandom(size_t bufferSize)
return buffer;
}
-QOlmAccount::QOlmAccount(OlmAccount *account)
- : m_account(account)
-{}
+QOlmAccount::QOlmAccount(const QString &userId, const QString &deviceId)
+ : m_userId(userId)
+ , m_deviceId(deviceId)
+{
+}
QOlmAccount::~QOlmAccount()
{
olm_clear_account(m_account);
+ delete[](reinterpret_cast<uint8_t *>(m_account));
}
-std::optional<QOlmAccount> QOlmAccount::create()
+void QOlmAccount::createNewAccount()
{
- auto account = olm_account(new uint8_t[olm_account_size()]);
- size_t randomSize = olm_create_account_random_length(account);
+ m_account = olm_account(new uint8_t[olm_account_size()]);
+ size_t randomSize = olm_create_account_random_length(m_account);
QByteArray randomData = getRandom(randomSize);
- const auto error = olm_create_account(account, randomData.data(), randomSize);
+ const auto error = olm_create_account(m_account, randomData.data(), randomSize);
if (error == olm_error()) {
- return std::nullopt;
+ throw lastError(m_account);
}
- return std::make_optional<QOlmAccount>(account);
}
-std::variant<QOlmAccount, OlmError> QOlmAccount::unpickle(QByteArray &pickled, const PicklingMode &mode)
+void QOlmAccount::unpickle(QByteArray &pickled, const PicklingMode &mode)
{
- auto account = olm_account(new uint8_t[olm_account_size()]);
+ m_account = olm_account(new uint8_t[olm_account_size()]);
const QByteArray key = toKey(mode);
- const auto error = olm_unpickle_account(account, key.data(), key.length(), pickled.data(), pickled.size());
+ const auto error = olm_unpickle_account(m_account, key.data(), key.length(), pickled.data(), pickled.size());
if (error == olm_error()) {
- return lastError(account);
+ throw lastError(m_account);
}
- return QOlmAccount(account);
}
std::variant<QByteArray, OlmError> QOlmAccount::pickle(const PicklingMode &mode)
@@ -89,13 +90,13 @@ std::variant<QByteArray, OlmError> QOlmAccount::pickle(const PicklingMode &mode)
return pickleBuffer;
}
-std::variant<IdentityKeys, OlmError> QOlmAccount::identityKeys()
+IdentityKeys QOlmAccount::identityKeys() const
{
const size_t keyLength = olm_account_identity_keys_length(m_account);
QByteArray keyBuffer(keyLength, '0');
const auto error = olm_account_identity_keys(m_account, keyBuffer.data(), keyLength);
if (error == olm_error()) {
- return lastError(m_account);
+ throw lastError(m_account);
}
const QJsonObject key = QJsonDocument::fromJson(keyBuffer).object();
return IdentityKeys {
@@ -104,7 +105,7 @@ std::variant<IdentityKeys, OlmError> QOlmAccount::identityKeys()
};
}
-std::variant<QString, OlmError> QOlmAccount::sign(const QString &message) const
+QByteArray QOlmAccount::sign(const QByteArray &message) const
{
const size_t signatureLength = olm_account_signature_length(m_account);
QByteArray signatureBuffer(signatureLength, '0');
@@ -112,9 +113,19 @@ std::variant<QString, OlmError> QOlmAccount::sign(const QString &message) const
signatureBuffer.data(), signatureLength);
if (error == olm_error()) {
- return lastError(m_account);
+ throw lastError(m_account);
}
- return QString::fromUtf8(signatureBuffer);
+ return signatureBuffer;
+}
+
+QByteArray QOlmAccount::signIdentityKeys() const
+{
+ const auto keys = identityKeys();
+ const QJsonObject j{ {Curve25519Key, QString(keys.curve25519)}, {Ed25519Key, QString(keys.ed25519)} };
+ QJsonDocument doc;
+ doc.setObject(j);
+ return sign(doc.toJson());
+
}
size_t QOlmAccount::maxNumberOfOneTimeKeys() const
@@ -122,26 +133,25 @@ size_t QOlmAccount::maxNumberOfOneTimeKeys() const
return olm_account_max_number_of_one_time_keys(m_account);
}
-std::optional<OlmError> QOlmAccount::generateOneTimeKeys(size_t numberOfKeys) const
+void QOlmAccount::generateOneTimeKeys(size_t numberOfKeys) const
{
const size_t randomLen = olm_account_generate_one_time_keys_random_length(m_account, numberOfKeys);
QByteArray randomBuffer = getRandom(randomLen);
const auto error = olm_account_generate_one_time_keys(m_account, numberOfKeys, randomBuffer.data(), randomLen);
if (error == olm_error()) {
- return lastError(m_account);
+ throw lastError(m_account);
}
- return std::nullopt;
}
-std::variant<OneTimeKeys, OlmError> QOlmAccount::oneTimeKeys() const
+OneTimeKeys QOlmAccount::oneTimeKeys() const
{
const size_t oneTimeKeyLength = olm_account_one_time_keys_length(m_account);
QByteArray oneTimeKeysBuffer(oneTimeKeyLength, '0');
const auto error = olm_account_one_time_keys(m_account, oneTimeKeysBuffer.data(), oneTimeKeyLength);
if (error == olm_error()) {
- return lastError(m_account);
+ throw lastError(m_account);
}
const auto json = QJsonDocument::fromJson(oneTimeKeysBuffer).object();
OneTimeKeys oneTimeKeys;
@@ -157,4 +167,29 @@ std::variant<OneTimeKeys, OlmError> QOlmAccount::oneTimeKeys() const
return oneTimeKeys;
}
+QMap<QString, SignedOneTimeKey> QOlmAccount::signOneTimeKeys(const OneTimeKeys &keys) const
+{
+ QMap<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);
+ }
+ 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
+{
+ QJsonDocument j(QJsonObject{{"key", key}});
+ return sign(j.toJson());
+}
+
#endif
diff --git a/lib/olm/qolmaccount.h b/lib/olm/qolmaccount.h
index c478c781..3b55212d 100644
--- a/lib/olm/qolmaccount.h
+++ b/lib/olm/qolmaccount.h
@@ -20,36 +20,53 @@ namespace Quotient {
class QOlmAccount
{
public:
+ QOlmAccount(const QString &userId, const QString &deviceId);
~QOlmAccount();
//! Creates a new instance of OlmAccount. During the instantiation
//! the Ed25519 fingerprint key pair and the Curve25519 identity key
//! pair are generated. For more information see <a
//! href="https://matrix.org/docs/guides/e2e_implementation.html#keys-used-in-end-to-end-encryption">here</a>.
- static std::optional<QOlmAccount> create();
- static std::variant<QOlmAccount, OlmError> unpickle(QByteArray &picked, const PicklingMode &mode);
+ //! This needs to be called before any other action or use unpickle() instead.
+ void createNewAccount();
+
+ //! Deserialises from encrypted Base64 that was previously obtained by pickling a `QOlmAccount`.
+ //! This needs to be called before any other action or use createNewAccount() instead.
+ void unpickle(QByteArray &picked, const PicklingMode &mode);
//! Serialises an OlmAccount to encrypted Base64.
std::variant<QByteArray, OlmError> pickle(const PicklingMode &mode);
- std::variant<IdentityKeys, OlmError> identityKeys();
+
+ //! Returns the account's public identity keys already formatted as JSON
+ IdentityKeys identityKeys() const;
//! Returns the signature of the supplied message.
- std::variant<QString, OlmError> sign(const QString &message) const;
+ QByteArray sign(const QByteArray &message) const;
+
+ //! Sign identity keys.
+ QByteArray signIdentityKeys() const;
//! Maximum number of one time keys that this OlmAccount can
//! currently hold.
size_t maxNumberOfOneTimeKeys() const;
//! Generates the supplied number of one time keys.
- std::optional<OlmError> generateOneTimeKeys(size_t numberOfKeys) const;
+ void generateOneTimeKeys(size_t numberOfKeys) const;
//! Gets the OlmAccount's one time keys formatted as JSON.
- std::variant<OneTimeKeys, OlmError> oneTimeKeys() const;
+ OneTimeKeys oneTimeKeys() const;
+
+ //! Sign all time key.
+ QMap<QString, SignedOneTimeKey> signOneTimeKeys(const OneTimeKeys &keys) const;
+
+ //! Sign one time key.
+ QByteArray signOneTimeKey(const QString &key) const;
- // HACK do not use directly
- QOlmAccount(OlmAccount *account);
+ SignedOneTimeKey signedOneTimeKey(const QByteArray &key, const QString &signature) const;
private:
- OlmAccount *m_account;
+ OlmAccount *m_account = nullptr;
+ QString m_userId;
+ QString m_deviceId;
};
} // namespace Quotient
diff --git a/lib/olm/qolmsession.cpp b/lib/olm/qolmsession.cpp
new file mode 100644
index 00000000..32a108a8
--- /dev/null
+++ b/lib/olm/qolmsession.cpp
@@ -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 Message { 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, 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));
+ }
+ }, message);
+}
diff --git a/lib/olm/qolmsession.h b/lib/olm/qolmsession.h
new file mode 100644
index 00000000..08f47331
--- /dev/null
+++ b/lib/olm/qolmsession.h
@@ -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 Message {
+ 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<Message, 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);
+//}
+
+}