aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarl Schwan <carl@carlschwan.eu>2021-01-24 01:45:43 +0100
committerTobias Fella <fella@posteo.de>2021-12-01 21:34:52 +0100
commit8706c055e69b01097b702403aaa0d222e5ab0d29 (patch)
tree063534b589d598a14af2018c516ce5eb992399ff
parentc8d67f737e84bbec98a54fc19a8aa56dbc39d542 (diff)
downloadlibquotient-8706c055e69b01097b702403aaa0d222e5ab0d29.tar.gz
libquotient-8706c055e69b01097b702403aaa0d222e5ab0d29.zip
Implement outboundsession
-rw-r--r--CMakeLists.txt4
-rw-r--r--autotests/CMakeLists.txt1
-rw-r--r--autotests/testgroupsession.cpp39
-rw-r--r--autotests/testgroupsession.h15
-rw-r--r--autotests/testolmaccount.cpp2
-rw-r--r--lib/olm/errors.h2
-rw-r--r--lib/olm/qolmaccount.cpp27
-rw-r--r--lib/olm/qolminboundsession.cpp51
-rw-r--r--lib/olm/qolminboundsession.h9
-rw-r--r--lib/olm/qolmoutboundsession.cpp121
-rw-r--r--lib/olm/qolmoutboundsession.h47
-rw-r--r--lib/olm/utils.cpp22
-rw-r--r--lib/olm/utils.h13
13 files changed, 291 insertions, 62 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b4d4ef8b..18a7b622 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -172,6 +172,10 @@ list(APPEND lib_SRCS
lib/jobs/mediathumbnailjob.cpp
lib/jobs/downloadfilejob.cpp
lib/olm/qolmaccount.cpp
+ lib/olm/qolminboundsession.cpp
+ lib/olm/qolmoutboundsession.cpp
+ lib/olm/utils.cpp
+ lib/olm/errors.cpp
)
# Configure API files generation
diff --git a/autotests/CMakeLists.txt b/autotests/CMakeLists.txt
index 07c22ad6..31cdb446 100644
--- a/autotests/CMakeLists.txt
+++ b/autotests/CMakeLists.txt
@@ -13,3 +13,4 @@ endfunction()
quotient_add_test(NAME callcandidateseventtest)
quotient_add_test(NAME testolmaccount)
+quotient_add_test(NAME testgroupsession)
diff --git a/autotests/testgroupsession.cpp b/autotests/testgroupsession.cpp
new file mode 100644
index 00000000..02892366
--- /dev/null
+++ b/autotests/testgroupsession.cpp
@@ -0,0 +1,39 @@
+// SPDX-FileCopyrightText: 2021 Carl Schwan <carlschwan@kde.org>
+//
+// SPDX-License-Identifier: LGPL-2.1-or-later
+
+#ifdef Quotient_E2EE_ENABLED
+#include "testgroupsession.h"
+#include "olm/qolminboundsession.h"
+#include "olm/qolmoutboundsession.h"
+#include "olm/utils.h"
+
+using namespace Quotient;
+
+void TestOlmSession::groupSessionPicklingValid()
+{
+ auto ogs = std::get<QOlmOutboundGroupSession>(QOlmOutboundGroupSession::create());
+ const auto ogsId = std::get<QByteArray>(ogs.sessionId());
+ QVERIFY(QByteArray::fromBase64Encoding(ogsId).decodingStatus == QByteArray::Base64DecodingStatus::Ok);
+ QCOMPARE(0, ogs.sessionMessageIndex());
+
+ auto ogsPickled = std::get<QByteArray>(ogs.pickle(Unencrypted {}));
+ ogs = std::get<QOlmOutboundGroupSession>(QOlmOutboundGroupSession::unpickle(ogsPickled, Unencrypted {}));
+ QCOMPARE(ogsId, std::get<QByteArray>(ogs.sessionId()));
+
+ qDebug() << std::get<QByteArray>(ogs.sessionKey());
+ auto igs = std::get<QOlmInboundGroupSession>(QOlmInboundGroupSession::create(std::get<QByteArray>(ogs.sessionKey())));
+ const auto igsId = std::get<QByteArray>(igs.sessionId());
+ // ID is valid base64?
+ QVERIFY(QByteArray::fromBase64Encoding(igsId).decodingStatus == QByteArray::Base64DecodingStatus::Ok);
+
+ //// no messages have been sent yet
+ QCOMPARE(0, igs.firstKnownIndex());
+
+ auto igsPickled = std::get<QByteArray>(igs.pickle(Unencrypted {}));
+ igs = std::get<QOlmInboundGroupSession>(QOlmInboundGroupSession::unpickle(igsPickled, Unencrypted {}));
+ QCOMPARE(igsId, std::get<QByteArray>(igs.sessionId()));
+}
+
+QTEST_MAIN(TestOlmSession)
+#endif
diff --git a/autotests/testgroupsession.h b/autotests/testgroupsession.h
new file mode 100644
index 00000000..28ebf4c9
--- /dev/null
+++ b/autotests/testgroupsession.h
@@ -0,0 +1,15 @@
+// SPDX-FileCopyrightText: 2021 Carl Schwan <carlschwan@kde.org>
+//
+// SPDX-License-Identifier: LGPL-2.1-or-later
+
+#ifdef Quotient_E2EE_ENABLED
+#include <QtTest/QtTest>
+
+class TestOlmSession : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+ void groupSessionPicklingValid();
+};
+#endif
diff --git a/autotests/testolmaccount.cpp b/autotests/testolmaccount.cpp
index 549f07ea..45a7e3a5 100644
--- a/autotests/testolmaccount.cpp
+++ b/autotests/testolmaccount.cpp
@@ -6,6 +6,8 @@
#include "testolmaccount.h"
#include "olm/qolmaccount.h"
+using namespace Quotient;
+
void TestOlmAccount::pickleUnpickedTest()
{
auto olmAccount = QOlmAccount::create().value();
diff --git a/lib/olm/errors.h b/lib/olm/errors.h
index fc2ae2e9..3dc4c796 100644
--- a/lib/olm/errors.h
+++ b/lib/olm/errors.h
@@ -24,6 +24,8 @@ enum OlmError
Unknown,
};
+OlmError fromString(const std::string &error_raw);
+
} //namespace Quotient
#endif
diff --git a/lib/olm/qolmaccount.cpp b/lib/olm/qolmaccount.cpp
index bde9b712..89d82832 100644
--- a/lib/olm/qolmaccount.cpp
+++ b/lib/olm/qolmaccount.cpp
@@ -4,6 +4,7 @@
#ifdef Quotient_E2EE_ENABLED
#include "qolmaccount.h"
+#include "olm/utils.h"
#include <QJsonObject>
#include <QJsonDocument>
#include <QDebug>
@@ -24,37 +25,11 @@ std::optional<QMap<QString, QString>> OneTimeKeys::get(QString keyType) const
return keys[keyType];
}
-// Convert PicklingMode to key
-QByteArray toKey(const PicklingMode &mode)
-{
- if (std::holds_alternative<Unencrypted>(mode)) {
- return "";
- }
- return std::get<Encrypted>(mode).key;
-}
-
bool operator==(const IdentityKeys& lhs, const IdentityKeys& rhs)
{
return lhs.curve25519 == rhs.curve25519 &&& lhs.ed25519 == rhs.ed25519;
}
-// TODO use impl from errors.cpp
-OlmError fromString(const std::string &error_raw) {
- if (error_raw.compare("BAD_ACCOUNT_KEY")) {
- return OlmError::BadAccountKey;
- } else if (error_raw.compare("BAD_MESSAGE_KEY_ID")) {
- return OlmError::BadMessageKeyId;
- } else if (error_raw.compare("INVALID_BASE64")) {
- return OlmError::InvalidBase64;
- } else if (error_raw.compare("NOT_ENOUGH_RANDOM")) {
- return OlmError::NotEnoughRandom;
- } else if (error_raw.compare("OUTPUT_BUFFER_TOO_SMALL")) {
- return OlmError::OutputBufferTooSmall;
- } else {
- return OlmError::Unknown;
- }
-}
-
// Conver olm error to enum
OlmError lastError(OlmAccount *account) {
const std::string error_raw = olm_account_last_error(account);
diff --git a/lib/olm/qolminboundsession.cpp b/lib/olm/qolminboundsession.cpp
index 62de138f..37dd60f8 100644
--- a/lib/olm/qolminboundsession.cpp
+++ b/lib/olm/qolminboundsession.cpp
@@ -3,64 +3,51 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
#include "olm/qolminboundsession.h"
-#include <QString>
-#include <QByteArray>
-
+#include <QDebug>
+#include <iostream>
using namespace Quotient;
-// TODO move to errors.cpp
-OlmError fromString(const std::string &error_raw) {
- if (error_raw.compare("BAD_ACCOUNT_KEY")) {
- return OlmError::BadAccountKey;
- } else if (error_raw.compare("BAD_MESSAGE_KEY_ID")) {
- return OlmError::BadMessageKeyId;
- } else if (error_raw.compare("INVALID_BASE64")) {
- return OlmError::InvalidBase64;
- } else if (error_raw.compare("NOT_ENOUGH_RANDOM")) {
- return OlmError::NotEnoughRandom;
- } else if (error_raw.compare("OUTPUT_BUFFER_TOO_SMALL")) {
- return OlmError::OutputBufferTooSmall;
- } else {
- return OlmError::Unknown;
- }
-}
-
OlmError lastError(OlmInboundGroupSession *session) {
const std::string error_raw = olm_inbound_group_session_last_error(session);
+ std::cout << error_raw;
return fromString(error_raw);
}
-QOlmInboundGroupSession::QOlmInboundGroupSession(OlmInboundGroupSession *session, const QByteArray &buffer)
+QOlmInboundGroupSession::QOlmInboundGroupSession(OlmInboundGroupSession *session, QByteArray buffer)
: m_groupSession(session)
, m_buffer(buffer)
{
}
-std::variant<QOlmInboundGroupSession, OlmError> QOlmInboundGroupSession::create(const QString &key)
+QOlmInboundGroupSession::~QOlmInboundGroupSession()
{
- auto olmInboundGroupSessionBuf = QByteArray(olm_inbound_group_session_size(), '0');
+ olm_clear_inbound_group_session(m_groupSession);
+}
+std::variant<QOlmInboundGroupSession, OlmError> QOlmInboundGroupSession::create(const QByteArray &key)
+{
+ QByteArray olmInboundGroupSessionBuf(olm_inbound_group_session_size(), '0');
const auto olmInboundGroupSession = olm_inbound_group_session(olmInboundGroupSessionBuf.data());
- QByteArray keyBuf = key.toUtf8();
+ const auto temp = key;
const auto error = olm_init_inbound_group_session(olmInboundGroupSession,
- reinterpret_cast<const uint8_t *>(keyBuf.data()), keyBuf.size());
+ reinterpret_cast<const uint8_t *>(temp.data()), temp.size());
if (error == olm_error()) {
return lastError(olmInboundGroupSession);
}
- return QOlmInboundGroupSession(olmInboundGroupSession, olmInboundGroupSessionBuf);
+ return QOlmInboundGroupSession(olmInboundGroupSession, std::move(olmInboundGroupSessionBuf));
}
-std::variant<QOlmInboundGroupSession, OlmError> QOlmInboundGroupSession::import(const QString &key)
+std::variant<QOlmInboundGroupSession, OlmError> QOlmInboundGroupSession::import(const QByteArray &key)
{
- auto olmInboundGroupSessionBuf = QByteArray(olm_inbound_group_session_size(), '0');
+ QByteArray olmInboundGroupSessionBuf(olm_inbound_group_session_size(), '0');
const auto olmInboundGroupSession = olm_inbound_group_session(olmInboundGroupSessionBuf.data());
- QByteArray keyBuf = key.toUtf8();
+ QByteArray keyBuf = key;
const auto error = olm_import_inbound_group_session(olmInboundGroupSession,
reinterpret_cast<const uint8_t *>(keyBuf.data()), keyBuf.size());
@@ -68,7 +55,7 @@ std::variant<QOlmInboundGroupSession, OlmError> QOlmInboundGroupSession::import(
return lastError(olmInboundGroupSession);
}
- return QOlmInboundGroupSession(olmInboundGroupSession, olmInboundGroupSessionBuf);
+ return QOlmInboundGroupSession(olmInboundGroupSession, std::move(olmInboundGroupSessionBuf));
}
QByteArray toKey(const PicklingMode &mode)
@@ -91,7 +78,7 @@ std::variant<QByteArray, OlmError> QOlmInboundGroupSession::pickle(const Picklin
return pickledBuf;
}
-std::variant<QOlmInboundGroupSession, OlmError> QOlmInboundGroupSession::unpicke(QByteArray &picked, const PicklingMode &mode)
+std::variant<QOlmInboundGroupSession, OlmError> QOlmInboundGroupSession::unpickle(QByteArray &picked, const PicklingMode &mode)
{
QByteArray groupSessionBuf(olm_inbound_group_session_size(), '0');
auto groupSession = olm_inbound_group_session(groupSessionBuf.data());
@@ -100,7 +87,7 @@ std::variant<QOlmInboundGroupSession, OlmError> QOlmInboundGroupSession::unpicke
if (error == olm_error()) {
return lastError(groupSession);
}
- return QOlmInboundGroupSession(groupSession, groupSessionBuf);
+ return QOlmInboundGroupSession(groupSession, std::move(groupSessionBuf));
}
std::variant<std::pair<QString, uint32_t>, OlmError> QOlmInboundGroupSession::decrypt(QString &message)
diff --git a/lib/olm/qolminboundsession.h b/lib/olm/qolminboundsession.h
index c75b7285..82802520 100644
--- a/lib/olm/qolminboundsession.h
+++ b/lib/olm/qolminboundsession.h
@@ -17,15 +17,16 @@ namespace Quotient {
struct QOlmInboundGroupSession
{
public:
+ ~QOlmInboundGroupSession();
//! Creates a new instance of `OlmInboundGroupSession`.
- static std::variant<QOlmInboundGroupSession, OlmError> create(const QString &key);
+ static std::variant<QOlmInboundGroupSession, OlmError> create(const QByteArray &key);
//! Import an inbound group session, from a previous export.
- static std::variant<QOlmInboundGroupSession, OlmError> import(const QString &key);
+ static std::variant<QOlmInboundGroupSession, OlmError> import(const QByteArray &key);
//! Serialises an `OlmInboundGroupSession` to encrypted Base64.
std::variant<QByteArray, OlmError> pickle(const PicklingMode &mode) const;
//! Deserialises from encrypted Base64 that was previously obtained by pickling
//! an `OlmInboundGroupSession`.
- static std::variant<QOlmInboundGroupSession, OlmError> unpicke(QByteArray &picked, const PicklingMode &mode);
+ static std::variant<QOlmInboundGroupSession, OlmError> unpickle(QByteArray &picked, const PicklingMode &mode);
//! Decrypts ciphertext received for this group session.
std::variant<std::pair<QString, uint32_t>, OlmError> decrypt(QString &message);
//! Export the base64-encoded ratchet key for this session, at the given index,
@@ -37,7 +38,7 @@ public:
std::variant<QByteArray, OlmError> sessionId() const;
bool isVerified() const;
private:
- QOlmInboundGroupSession(OlmInboundGroupSession *session, const QByteArray &buffer);
+ QOlmInboundGroupSession(OlmInboundGroupSession *session, QByteArray buffer);
OlmInboundGroupSession *m_groupSession;
QByteArray m_buffer;
};
diff --git a/lib/olm/qolmoutboundsession.cpp b/lib/olm/qolmoutboundsession.cpp
new file mode 100644
index 00000000..8a6b966b
--- /dev/null
+++ b/lib/olm/qolmoutboundsession.cpp
@@ -0,0 +1,121 @@
+// SPDX-FileCopyrightText: 2021 Carl Schwan <carlschwan@kde.org>
+//
+// SPDX-License-Identifier: LGPL-2.1-or-later
+//
+#include "olm/qolmoutboundsession.h"
+#include "olm/utils.h"
+
+using namespace Quotient;
+
+OlmError lastError(OlmOutboundGroupSession *session) {
+ const std::string error_raw = olm_outbound_group_session_last_error(session);
+
+ return fromString(error_raw);
+}
+
+QOlmOutboundGroupSession::QOlmOutboundGroupSession(OlmOutboundGroupSession *session, const QByteArray &buffer)
+ : m_groupSession(session)
+ , m_buffer(buffer)
+{
+}
+
+QOlmOutboundGroupSession::~QOlmOutboundGroupSession()
+{
+ olm_clear_outbound_group_session(m_groupSession);
+}
+
+std::variant<QOlmOutboundGroupSession, OlmError> QOlmOutboundGroupSession::create()
+{
+ QByteArray sessionBuffer(olm_outbound_group_session_size(), '0');
+ auto *olmOutboundGroupSession = olm_outbound_group_session(sessionBuffer.data());
+ const auto randomLen = olm_init_outbound_group_session_random_length(olmOutboundGroupSession);
+ QByteArray randomBuf = getRandom(randomLen);
+
+ const auto error = olm_init_outbound_group_session(olmOutboundGroupSession,
+ reinterpret_cast<uint8_t *>(randomBuf.data()), randomBuf.length());
+
+ if (error == olm_error()) {
+ return lastError(olmOutboundGroupSession);
+ }
+
+ randomBuf.clear();
+
+ return QOlmOutboundGroupSession(olmOutboundGroupSession, sessionBuffer);
+}
+
+std::variant<QByteArray, OlmError> QOlmOutboundGroupSession::pickle(const PicklingMode &mode)
+{
+ QByteArray pickledBuf(olm_pickle_outbound_group_session_length(m_groupSession), '0');
+ QByteArray key = toKey(mode);
+ const auto error = olm_pickle_outbound_group_session(m_groupSession, key.data(), key.length(),
+ pickledBuf.data(), pickledBuf.length());
+
+ if (error == olm_error()) {
+ return lastError(m_groupSession);
+ }
+
+ key.clear();
+
+ return pickledBuf;
+}
+
+
+std::variant<QOlmOutboundGroupSession, OlmError> QOlmOutboundGroupSession::unpickle(QByteArray &pickled, const PicklingMode &mode)
+{
+ QByteArray pickledBuf = pickled;
+ QByteArray olmOutboundGroupSessionBuf(olm_outbound_group_session_size(), '0');
+ QByteArray key = toKey(mode);
+ auto olmOutboundGroupSession = olm_outbound_group_session(reinterpret_cast<uint8_t *>(olmOutboundGroupSessionBuf.data()));
+ const auto error = olm_unpickle_outbound_group_session(olmOutboundGroupSession, key.data(), key.length(),
+ pickled.data(), pickled.length());
+ if (error == olm_error()) {
+ return lastError(olmOutboundGroupSession);
+ }
+
+ key.clear();
+ return QOlmOutboundGroupSession(olmOutboundGroupSession, olmOutboundGroupSessionBuf);
+}
+
+std::variant<QString, OlmError> QOlmOutboundGroupSession::encrypt(QString &plaintext)
+{
+ QByteArray plaintextBuf = plaintext.toUtf8();
+ const auto messageMaxLen = olm_group_encrypt_message_length(m_groupSession, plaintextBuf.length());
+ QByteArray messageBuf(messageMaxLen, '0');
+ const auto error = olm_group_encrypt(m_groupSession, reinterpret_cast<uint8_t *>(plaintextBuf.data()),
+ plaintextBuf.length(), reinterpret_cast<uint8_t *>(messageBuf.data()), messageBuf.length());
+
+ if (error == olm_error()) {
+ return lastError(m_groupSession);
+ }
+
+ return messageBuf;
+}
+
+uint32_t QOlmOutboundGroupSession::sessionMessageIndex() const
+{
+ return olm_outbound_group_session_message_index(m_groupSession);
+}
+
+std::variant<QByteArray, OlmError> QOlmOutboundGroupSession::sessionId() const
+{
+ const auto idMaxLength = olm_outbound_group_session_id_length(m_groupSession);
+ QByteArray idBuffer(idMaxLength, '0');
+ const auto error = olm_outbound_group_session_id(m_groupSession, reinterpret_cast<uint8_t *>(idBuffer.data()),
+ idBuffer.length());
+ if (error == olm_error()) {
+ return lastError(m_groupSession);
+ }
+ return idBuffer;
+}
+
+std::variant<QByteArray, OlmError> 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);
+ if (error == olm_error()) {
+ return lastError(m_groupSession);
+ }
+ return keyBuffer;
+}
diff --git a/lib/olm/qolmoutboundsession.h b/lib/olm/qolmoutboundsession.h
new file mode 100644
index 00000000..147c0e03
--- /dev/null
+++ b/lib/olm/qolmoutboundsession.h
@@ -0,0 +1,47 @@
+// SPDX-FileCopyrightText: 2021 Carl Schwan <carlschwan@kde.org>
+//
+// SPDX-License-Identifier: LGPL-2.1-or-later
+#pragma once
+
+#include "olm/olm.h" // from Olm
+#include "olm/errors.h"
+#include "olm/e2ee.h"
+
+namespace Quotient {
+
+//! An out-bound group session is responsible for encrypting outgoing
+//! communication in a Megolm session.
+class QOlmOutboundGroupSession
+{
+public:
+ ~QOlmOutboundGroupSession();
+ //! Creates a new instance of `QOlmOutboundGroupSession`.
+ static std::variant<QOlmOutboundGroupSession, OlmError> create();
+ //! Serialises an `QOlmOutboundGroupSession` to encrypted Base64.
+ std::variant<QByteArray, OlmError> pickle(const PicklingMode &mode);
+ //! Deserialises from encrypted Base64 that was previously obtained by
+ //! pickling an `QOlmOutboundGroupSession`.
+ static std::variant<QOlmOutboundGroupSession, OlmError> unpickle(QByteArray &pickled, const PicklingMode &mode);
+ //! Encrypts a plaintext message using the session.
+ std::variant<QString, OlmError> encrypt(QString &plaintext);
+
+ //! Get the current message index for this session.
+ //!
+ //! Each message is sent with an increasing index; this returns the
+ //! index for the next message.
+ uint32_t sessionMessageIndex() const;
+
+ //! Get a base64-encoded identifier for this session.
+ std::variant<QByteArray, OlmError> sessionId() const;
+
+ //! Get the base64-encoded current ratchet key for this session.
+ //!
+ //! 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;
+private:
+ QOlmOutboundGroupSession(OlmOutboundGroupSession *groupSession, const QByteArray &groupSessionBuf);
+ OlmOutboundGroupSession *m_groupSession;
+ QByteArray m_buffer;
+};
+}
diff --git a/lib/olm/utils.cpp b/lib/olm/utils.cpp
new file mode 100644
index 00000000..4966af15
--- /dev/null
+++ b/lib/olm/utils.cpp
@@ -0,0 +1,22 @@
+// SPDX-FileCopyrightText: 2021 Carl Schwan <carlschwan@kde.org>
+//
+// SPDX-License-Identifier: LGPL-2.1-or-later
+
+#include "olm/utils.h"
+
+using namespace Quotient;
+
+QByteArray Quotient::toKey(const Quotient::PicklingMode &mode)
+{
+ if (std::holds_alternative<Quotient::Unencrypted>(mode)) {
+ return "";
+ }
+ return std::get<Quotient::Encrypted>(mode).key;
+}
+
+QByteArray Quotient::getRandom(size_t bufferSize)
+{
+ QByteArray buffer(bufferSize, '0');
+ std::generate(buffer.begin(), buffer.end(), std::rand);
+ return buffer;
+}
diff --git a/lib/olm/utils.h b/lib/olm/utils.h
new file mode 100644
index 00000000..ec0da784
--- /dev/null
+++ b/lib/olm/utils.h
@@ -0,0 +1,13 @@
+// SPDX-FileCopyrightText: 2021 Carl Schwan <carlschwan@kde.org>
+//
+// SPDX-License-Identifier: LGPL-2.1-or-later
+
+#pragma once
+
+#include "olm/e2ee.h"
+
+namespace Quotient {
+// Convert PicklingMode to key
+QByteArray toKey(const PicklingMode &mode);
+QByteArray getRandom(size_t bufferSize);
+}