diff --git a/src/corelib/tools/qcryptographichash.cpp b/src/corelib/tools/qcryptographichash.cpp index 09ab5da9cca..063a15cdd9c 100644 --- a/src/corelib/tools/qcryptographichash.cpp +++ b/src/corelib/tools/qcryptographichash.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include "../../3rdparty/sha1/sha1.cpp" @@ -165,7 +166,10 @@ public: void reset() noexcept; void addData(QByteArrayView bytes) noexcept; - void finalize() noexcept; + // when not called from the static hash() function, this function needs to be + // called with finalizeMutex held: + void finalizeUnchecked() noexcept; + // END functions that need to be called with finalizeMutex held QByteArrayView resultView() const noexcept { return result.toByteArrayView(); } const QCryptographicHash::Algorithm method; @@ -183,7 +187,16 @@ public: blake2s_state blake2sContext; #endif }; - +#ifndef QT_CRYPTOGRAPHICHASH_ONLY_SHA1 +#ifndef USING_OPENSSL30 + enum class Sha3Variant + { + Sha3, + Keccak + }; + void sha3Finish(int bitCount, Sha3Variant sha3Variant); +#endif +#endif class SmallByteArray { std::array m_data; static_assert(MaxHashLength <= std::numeric_limits::max()); @@ -201,24 +214,13 @@ public: QByteArrayView toByteArrayView() const noexcept { return QByteArrayView{m_data.data(), size()}; } }; - - // Only write to the result under this mutex + // protects result in finalize() QBasicMutex finalizeMutex; SmallByteArray result; - -#if !defined(QT_CRYPTOGRAPHICHASH_ONLY_SHA1) && !defined(USING_OPENSSL30) - enum class Sha3Variant - { - Sha3, - Keccak - }; - void sha3Finish(SmallByteArray *tmpresult, int bitCount, Sha3Variant sha3Variant); -#endif }; #ifndef QT_CRYPTOGRAPHICHASH_ONLY_SHA1 -void QCryptographicHashPrivate::sha3Finish(SmallByteArray *tmpresult, int bitCount, - Sha3Variant sha3Variant) +void QCryptographicHashPrivate::sha3Finish(int bitCount, Sha3Variant sha3Variant) { /* FIPS 202 ยง6.1 defines SHA-3 in terms of calculating the Keccak function @@ -242,7 +244,7 @@ void QCryptographicHashPrivate::sha3Finish(SmallByteArray *tmpresult, int bitCou */ static const unsigned char sha3FinalSuffix = 0x80; - tmpresult->resizeForOverwrite(bitCount / 8); + result.resizeForOverwrite(bitCount / 8); SHA3Context copy = sha3Context; @@ -254,7 +256,7 @@ void QCryptographicHashPrivate::sha3Finish(SmallByteArray *tmpresult, int bitCou break; } - sha3Final(©, tmpresult->data()); + sha3Final(©, result.data()); } #endif @@ -545,22 +547,31 @@ QByteArray QCryptographicHash::result() const */ QByteArrayView QCryptographicHash::resultView() const noexcept { - d->finalize(); + // resultView() is a const function, so concurrent calls are allowed; protect: + { + const auto lock = qt_scoped_lock(d->finalizeMutex); + // check that no other thread already finalizeUnchecked()'ed before us: + if (d->result.isEmpty()) + d->finalizeUnchecked(); + } + // resultView() remains(!) valid even after we dropped the mutex return d->resultView(); } -void QCryptographicHashPrivate::finalize() noexcept -{ - if (!result.isEmpty()) - return; +/*! + \internal - SmallByteArray tmpresult; + Must be called with finalizeMutex held (except from static hash() function, + where no sharing can take place). +*/ +void QCryptographicHashPrivate::finalizeUnchecked() noexcept +{ switch (method) { case QCryptographicHash::Sha1: { Sha1State copy = sha1Context; - tmpresult.resizeForOverwrite(20); + result.resizeForOverwrite(20); sha1FinalizeState(©); - sha1ToHash(©, tmpresult.data()); + sha1ToHash(©, result.data()); break; } #ifdef QT_CRYPTOGRAPHICHASH_ONLY_SHA1 @@ -571,52 +582,52 @@ void QCryptographicHashPrivate::finalize() noexcept #else case QCryptographicHash::Md4: { md4_context copy = md4Context; - tmpresult.resizeForOverwrite(MD4_RESULTLEN); - md4_final(©, tmpresult.data()); + result.resizeForOverwrite(MD4_RESULTLEN); + md4_final(©, result.data()); break; } case QCryptographicHash::Md5: { MD5Context copy = md5Context; - tmpresult.resizeForOverwrite(16); - MD5Final(©, tmpresult.data()); + result.resizeForOverwrite(16); + MD5Final(©, result.data()); break; } case QCryptographicHash::Sha224: { SHA224Context copy = sha224Context; - tmpresult.resizeForOverwrite(SHA224HashSize); - SHA224Result(©, tmpresult.data()); + result.resizeForOverwrite(SHA224HashSize); + SHA224Result(©, result.data()); break; } case QCryptographicHash::Sha256: { SHA256Context copy = sha256Context; - tmpresult.resizeForOverwrite(SHA256HashSize); - SHA256Result(©, tmpresult.data()); + result.resizeForOverwrite(SHA256HashSize); + SHA256Result(©, result.data()); break; } case QCryptographicHash::Sha384: { SHA384Context copy = sha384Context; - tmpresult.resizeForOverwrite(SHA384HashSize); - SHA384Result(©, tmpresult.data()); + result.resizeForOverwrite(SHA384HashSize); + SHA384Result(©, result.data()); break; } case QCryptographicHash::Sha512: { SHA512Context copy = sha512Context; - tmpresult.resizeForOverwrite(SHA512HashSize); - SHA512Result(©, tmpresult.data()); + result.resizeForOverwrite(SHA512HashSize); + SHA512Result(©, result.data()); break; } case QCryptographicHash::RealSha3_224: case QCryptographicHash::RealSha3_256: case QCryptographicHash::RealSha3_384: case QCryptographicHash::RealSha3_512: { - sha3Finish(&tmpresult, 8 * hashLengthInternal(method), Sha3Variant::Sha3); + sha3Finish(8 * hashLengthInternal(method), Sha3Variant::Sha3); break; } case QCryptographicHash::Keccak_224: case QCryptographicHash::Keccak_256: case QCryptographicHash::Keccak_384: case QCryptographicHash::Keccak_512: { - sha3Finish(&tmpresult, 8 * hashLengthInternal(method), Sha3Variant::Keccak); + sha3Finish(8 * hashLengthInternal(method), Sha3Variant::Keccak); break; } case QCryptographicHash::Blake2b_160: @@ -625,8 +636,8 @@ void QCryptographicHashPrivate::finalize() noexcept case QCryptographicHash::Blake2b_512: { const auto length = hashLengthInternal(method); blake2b_state copy = blake2bContext; - tmpresult.resizeForOverwrite(length); - blake2b_final(©, tmpresult.data(), length); + result.resizeForOverwrite(length); + blake2b_final(©, result.data(), length); break; } case QCryptographicHash::Blake2s_128: @@ -635,17 +646,12 @@ void QCryptographicHashPrivate::finalize() noexcept case QCryptographicHash::Blake2s_256: { const auto length = hashLengthInternal(method); blake2s_state copy = blake2sContext; - tmpresult.resizeForOverwrite(length); - blake2s_final(©, tmpresult.data(), length); + result.resizeForOverwrite(length); + blake2s_final(©, result.data(), length); break; } #endif } - - // we're called from a const function, so only write to this->result under - // a mutex - QMutexLocker locker(&finalizeMutex); - result = std::move(tmpresult); } /*! @@ -658,7 +664,7 @@ QByteArray QCryptographicHash::hash(QByteArrayView data, Algorithm method) { QCryptographicHashPrivate hash(method); hash.addData(data); - hash.finalize(); + hash.finalizeUnchecked(); // no mutex needed: no-one but us has access to 'hash' return hash.resultView().toByteArray(); }