From bc1ded73bedf593acda80b00eb7da32f688c4843 Mon Sep 17 00:00:00 2001 From: Alexey Rusakov Date: Wed, 21 Sep 2022 16:11:39 +0200 Subject: RandomBuffer A convenient abstraction swallowing all the type casts and, more importantly, cleanup on destruction (previous code only cleaned up the buffer upon a successful call to Olm API but not upon an error). --- lib/connection.cpp | 2 +- lib/e2ee/qolmaccount.cpp | 9 +++------ lib/e2ee/qolmoutboundsession.cpp | 9 +++------ lib/e2ee/qolmsession.cpp | 12 +++++------- lib/e2ee/qolmutils.cpp | 7 +++---- lib/e2ee/qolmutils.h | 23 ++++++++++++++++++++++- lib/events/filesourceinfo.cpp | 8 +++----- lib/keyverificationsession.cpp | 3 +-- 8 files changed, 41 insertions(+), 32 deletions(-) diff --git a/lib/connection.cpp b/lib/connection.cpp index f38bb751..cd8ee727 100644 --- a/lib/connection.cpp +++ b/lib/connection.cpp @@ -614,7 +614,7 @@ void Connection::Private::completeSetup(const QString& mxId) loop.exec(); if (job.error() == QKeychain::Error::EntryNotFound) { - picklingMode = Encrypted { getRandom(128) }; + picklingMode = Encrypted { RandomBuffer(128) }; QKeychain::WritePasswordJob job(qAppName()); job.setAutoDelete(false); job.setKey(accountSettings.userId() + QStringLiteral("-Pickle")); diff --git a/lib/e2ee/qolmaccount.cpp b/lib/e2ee/qolmaccount.cpp index 556a8274..b56272ef 100644 --- a/lib/e2ee/qolmaccount.cpp +++ b/lib/e2ee/qolmaccount.cpp @@ -44,8 +44,7 @@ void QOlmAccount::createNewAccount() { m_account = olm_account(new uint8_t[olm_account_size()]); const auto randomLength = olm_create_account_random_length(m_account); - QByteArray randomData = getRandom(randomLength); - if (olm_create_account(m_account, randomData.data(), randomLength) + if (olm_create_account(m_account, RandomBuffer(randomLength), randomLength) == olm_error()) { throw lastError(); } @@ -133,10 +132,8 @@ size_t QOlmAccount::generateOneTimeKeys(size_t numberOfKeys) const auto randomLength = olm_account_generate_one_time_keys_random_length(m_account, numberOfKeys); - QByteArray randomBuffer = getRandom(randomLength); - const auto result = - olm_account_generate_one_time_keys(m_account, numberOfKeys, - randomBuffer.data(), randomLength); + const auto result = olm_account_generate_one_time_keys( + m_account, numberOfKeys, RandomBuffer(randomLength), randomLength); if (result == olm_error()) { throw lastError(); diff --git a/lib/e2ee/qolmoutboundsession.cpp b/lib/e2ee/qolmoutboundsession.cpp index 22107a21..3d176274 100644 --- a/lib/e2ee/qolmoutboundsession.cpp +++ b/lib/e2ee/qolmoutboundsession.cpp @@ -34,11 +34,10 @@ 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); - QByteArray randomBuf = getRandom(randomLength); - if (olm_init_outbound_group_session( - olmOutboundGroupSession, - reinterpret_cast(randomBuf.data()), randomBuf.length()) + if (olm_init_outbound_group_session(olmOutboundGroupSession, + RandomBuffer(randomLength).bytes(), + randomLength) == olm_error()) { // FIXME: create the session object earlier and use lastError() throw olm_outbound_group_session_last_error_code(olmOutboundGroupSession); @@ -50,8 +49,6 @@ QOlmOutboundGroupSessionPtr QOlmOutboundGroupSession::create() olm_outbound_group_session_key(olmOutboundGroupSession, reinterpret_cast(keyBuffer.data()), keyMaxLength); - randomBuf.clear(); - return std::make_unique(olmOutboundGroupSession); } diff --git a/lib/e2ee/qolmsession.cpp b/lib/e2ee/qolmsession.cpp index e252c37f..7c102a96 100644 --- a/lib/e2ee/qolmsession.cpp +++ b/lib/e2ee/qolmsession.cpp @@ -80,13 +80,13 @@ QOlmExpected QOlmSession::createOutboundSession( const QByteArray& theirOneTimeKey) { auto* olmOutboundSession = create(); - auto randomBuf = getRandom( - olm_create_outbound_session_random_length(olmOutboundSession)); + const auto randomLength = + olm_create_outbound_session_random_length(olmOutboundSession); if (olm_create_outbound_session( olmOutboundSession, account->data(), theirIdentityKey.data(), theirIdentityKey.length(), theirOneTimeKey.data(), - theirOneTimeKey.length(), randomBuf.data(), randomBuf.length()) + theirOneTimeKey.length(), RandomBuffer(randomLength), randomLength) == olm_error()) { // FIXME: the QOlmSession object should be created earlier const auto lastErr = olm_session_last_error_code(olmOutboundSession); @@ -96,7 +96,6 @@ QOlmExpected QOlmSession::createOutboundSession( return lastErr; } - randomBuf.clear(); return std::make_unique(olmOutboundSession); } @@ -136,15 +135,14 @@ QOlmMessage QOlmSession::encrypt(const QByteArray& plaintext) QByteArray messageBuf(messageMaxLength, '0'); // NB: The type has to be calculated before calling olm_encrypt() const auto messageType = olm_encrypt_message_type(m_session); - auto randomBuf = getRandom(olm_encrypt_random_length(m_session)); + const auto randomLength = olm_encrypt_random_length(m_session); if (olm_encrypt(m_session, plaintext.data(), plaintext.length(), - randomBuf.data(), randomBuf.length(), messageBuf.data(), + RandomBuffer(randomLength), randomLength, messageBuf.data(), messageBuf.length()) == olm_error()) { throw lastError(); } - randomBuf.clear(); return QOlmMessage(messageBuf, QOlmMessage::Type(messageType)); } diff --git a/lib/e2ee/qolmutils.cpp b/lib/e2ee/qolmutils.cpp index 6f7937e8..c6e51bcd 100644 --- a/lib/e2ee/qolmutils.cpp +++ b/lib/e2ee/qolmutils.cpp @@ -15,9 +15,8 @@ QByteArray Quotient::toKey(const Quotient::PicklingMode &mode) return std::get(mode).key; } -QByteArray Quotient::getRandom(size_t bufferSize) +RandomBuffer::RandomBuffer(size_t size) + : QByteArray(static_cast(size), '\0') { - QByteArray buffer(bufferSize, '0'); - QRandomGenerator::system()->generate(buffer.begin(), buffer.end()); - return buffer; + QRandomGenerator::system()->generate(begin(), end()); } diff --git a/lib/e2ee/qolmutils.h b/lib/e2ee/qolmutils.h index 7a8511c3..da9d2d18 100644 --- a/lib/e2ee/qolmutils.h +++ b/lib/e2ee/qolmutils.h @@ -12,5 +12,26 @@ namespace Quotient { // Convert PicklingMode to key QUOTIENT_API QByteArray toKey(const PicklingMode &mode); -QUOTIENT_API QByteArray getRandom(size_t bufferSize); + +class QUOTIENT_API RandomBuffer : public QByteArray { +public: + explicit RandomBuffer(size_t size); + ~RandomBuffer() { clear(); } + + // NOLINTNEXTLINE(google-explicit-constructor) + QUO_IMPLICIT operator void*() { return data(); } + char* chars() { return data(); } + uint8_t* bytes() { return reinterpret_cast(data()); } + + Q_DISABLE_COPY(RandomBuffer) + RandomBuffer(RandomBuffer&&) = default; + void operator=(RandomBuffer&&) = delete; +}; + +[[deprecated("Create RandomBuffer directly")]] inline auto getRandom( + size_t bufferSize) +{ + return RandomBuffer(bufferSize); } + +} // namespace Quotient diff --git a/lib/events/filesourceinfo.cpp b/lib/events/filesourceinfo.cpp index 6abe6a08..a60d86d2 100644 --- a/lib/events/filesourceinfo.cpp +++ b/lib/events/filesourceinfo.cpp @@ -59,19 +59,17 @@ std::pair Quotient::encryptFile( const QByteArray& plainText) { #ifdef Quotient_E2EE_ENABLED - auto k = getRandom(32); + auto k = RandomBuffer(32); auto kBase64 = k.toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals); - auto iv = getRandom(16); + auto iv = RandomBuffer(16); JWK key = { "oct"_ls, { "encrypt"_ls, "decrypt"_ls }, "A256CTR"_ls, kBase64, true }; int length = -1; auto* ctx = EVP_CIPHER_CTX_new(); - EVP_EncryptInit_ex(ctx, EVP_aes_256_ctr(), nullptr, - reinterpret_cast(k.data()), - reinterpret_cast(iv.data())); + EVP_EncryptInit_ex(ctx, EVP_aes_256_ctr(), nullptr, k.bytes(), iv.bytes()); const auto blockSize = EVP_CIPHER_CTX_block_size(ctx); QByteArray cipherText(plainText.size() + blockSize - 1, '\0'); EVP_EncryptUpdate(ctx, reinterpret_cast(cipherText.data()), diff --git a/lib/keyverificationsession.cpp b/lib/keyverificationsession.cpp index 0f24c743..171596c0 100644 --- a/lib/keyverificationsession.cpp +++ b/lib/keyverificationsession.cpp @@ -72,8 +72,7 @@ void KeyVerificationSession::init(milliseconds timeout) m_sas = olm_sas(new std::byte[olm_sas_size()]); const auto randomLength = olm_create_sas_random_length(m_sas); - auto random = getRandom(randomLength); - olm_create_sas(m_sas, random.data(), randomLength); + olm_create_sas(m_sas, RandomBuffer(randomLength), randomLength); } KeyVerificationSession::~KeyVerificationSession() -- cgit v1.2.3