From 1fb0dca140c1dbf3e66b322af837b7bf650f2e77 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Thu, 23 Feb 2023 18:45:47 +0100 Subject: [PATCH] QMessageAuthenticationCode: use QSmallByteArray for the key MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add more API to QSmallByteArray: - const op[] overload - copy construction and -assignment from QSmallByteArrays with smaller N (for implicitly converting a HashResult into a HashBlock, incl. a static assertion that it always fits - STL-style assign() This allows us to use HashBlock for the key, instead of a QByteArray. To make-it-cool®, add a method that xor's all bytes in a QSmallByteArray with a given value and returns the result. We use that algorithm twice in the implementation, and the code simplification at the call sites is amazing. Pick-to: 6.5 Change-Id: I7fbc11538544b4a8d1771dc8ad025be154d446df Reviewed-by: Mårten Nordheim --- src/corelib/tools/qcryptographichash.cpp | 65 +++++++++++++++--------- 1 file changed, 42 insertions(+), 23 deletions(-) diff --git a/src/corelib/tools/qcryptographichash.cpp b/src/corelib/tools/qcryptographichash.cpp index e4b8fa78f65..78ab9836a1b 100644 --- a/src/corelib/tools/qcryptographichash.cpp +++ b/src/corelib/tools/qcryptographichash.cpp @@ -127,7 +127,29 @@ class QSmallByteArray static_assert(N <= std::numeric_limits::max()); quint8 m_size = 0; public: - // all SMFs are ok! + QSmallByteArray() = default; + // all compiler-generated SMFs are ok! + template = true> // M == N is for copy ctor! + QSmallByteArray(const QSmallByteArray &other) noexcept + { + assign(other); + } + template = true> // M == N is for copy-assignment op! + QSmallByteArray &operator=(const QSmallByteArray &other) noexcept + { + assign(other); + return *this; + } + + template // ### underconstrained + void assign(const Container &c) + { + const size_t otherSize = size_t(std::size(c)); + Q_ASSERT(otherSize < N); + memcpy(data(), std::data(c), otherSize); + m_size = quint8(otherSize); + } + quint8 *data() noexcept { return m_data.data(); } const quint8 *data() const noexcept { return m_data.data(); } qsizetype size() const noexcept { return qsizetype{m_size}; } @@ -136,6 +158,11 @@ public: Q_ASSERT(n < size()); return data()[n]; } + const quint8 &operator[](qsizetype n) const + { + Q_ASSERT(n < size()); + return data()[n]; + } bool isEmpty() const noexcept { return size() == 0; } void clear() noexcept { m_size = 0; } void resizeForOverwrite(qsizetype s) @@ -1074,6 +1101,15 @@ constexpr int maxHashBlockSize() using HashBlock = QSmallByteArray; +static HashBlock xored(const HashBlock &block, quint8 val) noexcept +{ + HashBlock result; + result.resizeForOverwrite(block.size()); + for (qsizetype i = 0; i < block.size(); ++i) + result[i] = block[i] ^ val; + return result; +} + class QMessageAuthenticationCodePrivate { public: @@ -1082,7 +1118,7 @@ public: { } - QByteArray key; + HashBlock key; HashResult result; QBasicMutex finalizeMutex; QCryptographicHashPrivate messageHash; @@ -1115,10 +1151,10 @@ void QMessageAuthenticationCodePrivate::setKey(const QByteArray &newKey) messageHash.addData(newKey); messageHash.finalizeUnchecked(); static_assert(maxHashLength() <= maxHashBlockSize()); - key = messageHash.resultView().toByteArray(); + key = messageHash.result; messageHash.reset(); } else { - key = newKey; + key.assign(newKey); } if (key.size() < blockSize) @@ -1135,15 +1171,7 @@ void QMessageAuthenticationCodePrivate::setKey(const QByteArray &newKey) */ void QMessageAuthenticationCodePrivate::initMessageHash() { - const int blockSize = qt_hash_block_size(method); - - QVarLengthArray iKeyPad(blockSize); - const char * const keyData = key.constData(); - - for (int i = 0; i < blockSize; ++i) - iKeyPad[i] = keyData[i] ^ 0x36; - - messageHash.addData(iKeyPad); + messageHash.addData(xored(key, 0x36)); } /*! @@ -1291,20 +1319,11 @@ void QMessageAuthenticationCodePrivate::finalize() void QMessageAuthenticationCodePrivate::finalizeUnchecked() noexcept { - const int blockSize = qt_hash_block_size(method); - messageHash.finalizeUnchecked(); const HashResult hashedMessage = messageHash.result; - HashBlock oKeyPad; - oKeyPad.resizeForOverwrite(blockSize); - const char * const keyData = key.constData(); - - for (int i = 0; i < blockSize; ++i) - oKeyPad[i] = keyData[i] ^ 0x5c; - messageHash.reset(); - messageHash.addData(oKeyPad); + messageHash.addData(xored(key, 0x5c)); messageHash.addData(hashedMessage); messageHash.finalizeUnchecked();