summaryrefslogtreecommitdiffstats
path: root/src/corelib/tools
diff options
context:
space:
mode:
authorMarc Mutz <marc.mutz@kdab.com>2021-07-06 20:48:36 +0200
committerMarc Mutz <marc.mutz@kdab.com>2021-07-15 17:56:23 +0200
commit27d6314b9598908cbb9c2a589fb62f3653fa9062 (patch)
tree49b848a31aacec4c5540cf70af6616b7d9521cfa /src/corelib/tools
parentc6e092a5f84b7fc72556897b50c7697152967925 (diff)
QCryptographicHash: use a std::array to hold result (was: QByteArray)
The maximum size for a hash result is 64 atm. Even if, and esp when, we'll get to 128 and 256 bytes in the future, there's no reason to use dynamic memory, because the sizes will always be statically known. So use, essentially, a std::array<char, 64> to hold the result internally. Add a bit of convenience API on top to limit impact on the rest of the code and add a few static_asserts that ensure this is large enough. Then give users access to the internal buffer by adding QByteArrayView resultView() const noexcept. The documentation snippet is taken from QString::data(), suitably adjusted. Use resultView() in a few places instead of result(). [ChangeLog][QtCore][QCryptographicHash] Changed to use a statically-sized buffer internally. Added resultView() to access it. Change-Id: I96c35e55acacbe94529446d720c18325273ffd2f Reviewed-by: Edward Welbourne <edward.welbourne@qt.io> Reviewed-by: MÃ¥rten Nordheim <marten.nordheim@qt.io>
Diffstat (limited to 'src/corelib/tools')
-rw-r--r--src/corelib/tools/qcryptographichash.cpp91
-rw-r--r--src/corelib/tools/qcryptographichash.h3
-rw-r--r--src/corelib/tools/qmessageauthenticationcode.cpp2
3 files changed, 69 insertions, 27 deletions
diff --git a/src/corelib/tools/qcryptographichash.cpp b/src/corelib/tools/qcryptographichash.cpp
index 512d38b02b..f44dee89d4 100644
--- a/src/corelib/tools/qcryptographichash.cpp
+++ b/src/corelib/tools/qcryptographichash.cpp
@@ -138,47 +138,53 @@ static inline int SHA384_512AddLength(SHA512Context *context, unsigned int lengt
QT_BEGIN_NAMESPACE
+static constexpr qsizetype MaxHashLength = 64;
+
static constexpr int hashLengthInternal(QCryptographicHash::Algorithm method) noexcept
{
switch (method) {
- case QCryptographicHash::Sha1:
- return 20;
+#define CASE(Enum, Size) \
+ case QCryptographicHash:: Enum : \
+ /* if this triggers, then increase MaxHashLength accordingly */ \
+ static_assert(MaxHashLength >= qsizetype(Size) ); \
+ return Size \
+ /*end*/
+ CASE(Sha1, 20);
#ifndef QT_CRYPTOGRAPHICHASH_ONLY_SHA1
- case QCryptographicHash::Md4:
- return 16;
- case QCryptographicHash::Md5:
- return 16;
- case QCryptographicHash::Sha224:
- return SHA224HashSize;
- case QCryptographicHash::Sha256:
- return SHA256HashSize;
- case QCryptographicHash::Sha384:
- return SHA384HashSize;
- case QCryptographicHash::Sha512:
- return SHA512HashSize;
- case QCryptographicHash::Blake2s_128:
- return 128 / 8;
+ CASE(Md4, 16);
+ CASE(Md5, 16);
+ CASE(Sha224, SHA224HashSize);
+ CASE(Sha256, SHA256HashSize);
+ CASE(Sha384, SHA384HashSize);
+ CASE(Sha512, SHA512HashSize);
+ CASE(Blake2s_128, 128 / 8);
case QCryptographicHash::Blake2b_160:
case QCryptographicHash::Blake2s_160:
+ static_assert(160 / 8 <= MaxHashLength);
return 160 / 8;
case QCryptographicHash::RealSha3_224:
case QCryptographicHash::Keccak_224:
case QCryptographicHash::Blake2s_224:
+ static_assert(224 / 8 <= MaxHashLength);
return 224 / 8;
case QCryptographicHash::RealSha3_256:
case QCryptographicHash::Keccak_256:
case QCryptographicHash::Blake2b_256:
case QCryptographicHash::Blake2s_256:
+ static_assert(256 / 8 <= MaxHashLength);
return 256 / 8;
case QCryptographicHash::RealSha3_384:
case QCryptographicHash::Keccak_384:
case QCryptographicHash::Blake2b_384:
+ static_assert(384 / 8 <= MaxHashLength);
return 384 / 8;
case QCryptographicHash::RealSha3_512:
case QCryptographicHash::Keccak_512:
case QCryptographicHash::Blake2b_512:
+ static_assert(512 / 8 <= MaxHashLength);
return 512 / 8;
#endif
+#undef CASE
}
return 0;
}
@@ -194,7 +200,8 @@ public:
void reset() noexcept;
void addData(QByteArrayView bytes) noexcept;
- QByteArray finalize();
+ void finalize() noexcept;
+ QByteArrayView resultView() const noexcept { return result.toByteArrayView(); }
const QCryptographicHash::Algorithm method;
union {
@@ -219,7 +226,25 @@ public:
};
void sha3Finish(int bitCount, Sha3Variant sha3Variant);
#endif
- QByteArray result;
+ class SmallByteArray {
+ std::array<char, MaxHashLength> m_data;
+ static_assert(MaxHashLength <= std::numeric_limits<std::uint8_t>::max());
+ std::uint8_t m_size;
+ public:
+ char *data() noexcept { return m_data.data(); }
+ const char *data() const noexcept { return m_data.data(); }
+ qsizetype size() const noexcept { return qsizetype{m_size}; }
+ bool isEmpty() const noexcept { return size() == 0; }
+ void clear() noexcept { m_size = 0; }
+ void resize(qsizetype s) {
+ Q_ASSERT(s >= 0);
+ Q_ASSERT(s <= MaxHashLength);
+ m_size = std::uint8_t(s);
+ }
+ QByteArrayView toByteArrayView() const noexcept
+ { return QByteArrayView{data(), size()}; }
+ };
+ SmallByteArray result;
};
#ifndef QT_CRYPTOGRAPHICHASH_ONLY_SHA1
@@ -337,7 +362,7 @@ QCryptographicHash::~QCryptographicHash()
/*!
Resets the object.
*/
-void QCryptographicHash::reset()
+void QCryptographicHash::reset() noexcept
{
d->reset();
}
@@ -532,17 +557,33 @@ bool QCryptographicHash::addData(QIODevice *device)
/*!
Returns the final hash value.
- \sa QByteArray::toHex()
+ \sa resultView(), QByteArray::toHex()
*/
QByteArray QCryptographicHash::result() const
{
- return d->finalize();
+ return resultView().toByteArray();
+}
+
+/*!
+ \since 6.3
+
+ Returns the final hash value.
+
+ Note that the returned view remains valid only as long as the QCryptographicHash object is
+ not modified by other means.
+
+ \sa result(), QByteArrayView::toHex()
+*/
+QByteArrayView QCryptographicHash::resultView() const noexcept
+{
+ d->finalize();
+ return d->resultView();
}
-QByteArray QCryptographicHashPrivate::finalize()
+void QCryptographicHashPrivate::finalize() noexcept
{
if (!result.isEmpty())
- return result;
+ return;
switch (method) {
case QCryptographicHash::Sha1: {
@@ -630,7 +671,6 @@ QByteArray QCryptographicHashPrivate::finalize()
}
#endif
}
- return result;
}
/*!
@@ -643,7 +683,8 @@ QByteArray QCryptographicHash::hash(QByteArrayView data, Algorithm method)
{
QCryptographicHashPrivate hash(method);
hash.addData(data);
- return hash.finalize();
+ hash.finalize();
+ return hash.resultView().toByteArray();
}
/*!
diff --git a/src/corelib/tools/qcryptographichash.h b/src/corelib/tools/qcryptographichash.h
index aecf8995d5..b3ab9c6126 100644
--- a/src/corelib/tools/qcryptographichash.h
+++ b/src/corelib/tools/qcryptographichash.h
@@ -102,7 +102,7 @@ public:
explicit QCryptographicHash(Algorithm method);
~QCryptographicHash();
- void reset();
+ void reset() noexcept;
#if QT_DEPRECATED_SINCE(6, 4)
QT_DEPRECATED_VERSION_X_6_4("Use the QByteArrayView overload instead")
@@ -115,6 +115,7 @@ public:
bool addData(QIODevice *device);
QByteArray result() const;
+ QByteArrayView resultView() const noexcept;
#ifdef QT_BUILD_FUNCTIONS_REMOVED_IN_6_3
static QByteArray hash(const QByteArray &data, Algorithm method);
diff --git a/src/corelib/tools/qmessageauthenticationcode.cpp b/src/corelib/tools/qmessageauthenticationcode.cpp
index 9580b024c2..767a7a14d4 100644
--- a/src/corelib/tools/qmessageauthenticationcode.cpp
+++ b/src/corelib/tools/qmessageauthenticationcode.cpp
@@ -251,7 +251,7 @@ QByteArray QMessageAuthenticationCode::result() const
const int blockSize = qt_hash_block_size(d->method);
- QByteArray hashedMessage = d->messageHash.result();
+ QByteArrayView hashedMessage = d->messageHash.resultView();
QVarLengthArray<char> oKeyPad(blockSize);
const char * const keyData = d->key.constData();