From ca1b03be697176233a0680aeab37f4161599b6cc Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Fri, 24 Feb 2023 08:50:14 +0100 Subject: [PATCH] QCryptographicHash: split initialization from reset()ing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before the OpenSSL3 mode was added, these operations were the same. The placement-new of the active union member was arguably not even necessary, as just naming it should start their lifetime; certainly all initialization was vacuous, anyway. So it didn't really matter that we re-did it on each reset(). But OpenSSL3 mode is different: initialization allocates (and can fail) whereas reset() does not¹, so it makes sense to separate them, so as to re-establish the lost proper noexcept'ness of reset(). ¹ or so we assume This will also help when moving the EVP members into the union later. Pick-to: 6.5 Change-Id: Id1c9a00cddb95fb2235162409c2301dd4c35228a Reviewed-by: Mårten Nordheim --- src/corelib/tools/qcryptographichash.cpp | 105 +++++++++++++++++++---- 1 file changed, 86 insertions(+), 19 deletions(-) diff --git a/src/corelib/tools/qcryptographichash.cpp b/src/corelib/tools/qcryptographichash.cpp index 258a97b8e18..b6dfe646517 100644 --- a/src/corelib/tools/qcryptographichash.cpp +++ b/src/corelib/tools/qcryptographichash.cpp @@ -298,9 +298,11 @@ public: explicit QCryptographicHashPrivate(QCryptographicHash::Algorithm method) noexcept : method(method) { + init(); reset(); } + void init(); void reset() noexcept; void addData(QByteArrayView bytes) noexcept; bool addData(QIODevice *dev); @@ -529,30 +531,22 @@ QCryptographicHash::Algorithm QCryptographicHash::algorithm() const noexcept return d->method; } -void QCryptographicHashPrivate::reset() noexcept +void QCryptographicHashPrivate::init() { - result.clear(); #ifdef USING_OPENSSL30 if (method == QCryptographicHash::Blake2b_160 || method == QCryptographicHash::Blake2b_256 || method == QCryptographicHash::Blake2b_384) { new (&blake2bContext) blake2b_state; - blake2b_init(&blake2bContext, hashLengthInternal(method)); return; } else if (method == QCryptographicHash::Blake2s_128 || method == QCryptographicHash::Blake2s_160 || method == QCryptographicHash::Blake2s_224) { new (&blake2sContext) blake2s_state; - blake2s_init(&blake2sContext, hashLengthInternal(method)); return; } - if (context && !initializationFailed) { - // everything already set up - just reset the context - EVP_MD_CTX_reset(context.get()); - initializationFailed = !EVP_DigestInit_ex(context.get(), algorithm.get(), nullptr); - return; - } + Q_ASSERT(!context); initializationFailed = true; @@ -588,7 +582,6 @@ void QCryptographicHashPrivate::reset() noexcept switch (method) { case QCryptographicHash::Sha1: new (&sha1Context) Sha1State; - sha1InitState(&sha1Context); break; #ifdef QT_CRYPTOGRAPHICHASH_ONLY_SHA1 default: @@ -598,27 +591,21 @@ void QCryptographicHashPrivate::reset() noexcept #else case QCryptographicHash::Md4: new (&md4Context) md4_context; - md4_init(&md4Context); break; case QCryptographicHash::Md5: new (&md5Context) MD5Context; - MD5Init(&md5Context); break; case QCryptographicHash::Sha224: new (&sha224Context) SHA224Context; - SHA224Reset(&sha224Context); break; case QCryptographicHash::Sha256: new (&sha256Context) SHA256Context; - SHA256Reset(&sha256Context); break; case QCryptographicHash::Sha384: new (&sha384Context) SHA384Context; - SHA384Reset(&sha384Context); break; case QCryptographicHash::Sha512: new (&sha512Context) SHA512Context; - SHA512Reset(&sha512Context); break; case QCryptographicHash::RealSha3_224: case QCryptographicHash::Keccak_224: @@ -629,20 +616,100 @@ void QCryptographicHashPrivate::reset() noexcept case QCryptographicHash::RealSha3_512: case QCryptographicHash::Keccak_512: new (&sha3Context) SHA3Context; - sha3Init(&sha3Context, hashLengthInternal(method) * 8); break; case QCryptographicHash::Blake2b_160: case QCryptographicHash::Blake2b_256: case QCryptographicHash::Blake2b_384: case QCryptographicHash::Blake2b_512: new (&blake2bContext) blake2b_state; - blake2b_init(&blake2bContext, hashLengthInternal(method)); break; case QCryptographicHash::Blake2s_128: case QCryptographicHash::Blake2s_160: case QCryptographicHash::Blake2s_224: case QCryptographicHash::Blake2s_256: new (&blake2sContext) blake2s_state; + break; +#endif + case QCryptographicHash::NumAlgorithms: + Q_UNREACHABLE(); + } +#endif +} + +void QCryptographicHashPrivate::reset() noexcept +{ + result.clear(); +#ifdef USING_OPENSSL30 + if (method == QCryptographicHash::Blake2b_160 || + method == QCryptographicHash::Blake2b_256 || + method == QCryptographicHash::Blake2b_384) { + blake2b_init(&blake2bContext, hashLengthInternal(method)); + return; + } else if (method == QCryptographicHash::Blake2s_128 || + method == QCryptographicHash::Blake2s_160 || + method == QCryptographicHash::Blake2s_224) { + blake2s_init(&blake2sContext, hashLengthInternal(method)); + return; + } + + if (!initializationFailed) { + Q_ASSERT(context); + Q_ASSERT(algorithm); + // everything already set up - just reset the context + EVP_MD_CTX_reset(context.get()); + initializationFailed = !EVP_DigestInit_ex(context.get(), algorithm.get(), nullptr); + } + // if initializationFailed first time around, it will not succeed this time, either + +#else + switch (method) { + case QCryptographicHash::Sha1: + sha1InitState(&sha1Context); + break; +#ifdef QT_CRYPTOGRAPHICHASH_ONLY_SHA1 + default: + Q_ASSERT_X(false, "QCryptographicHash", "Method not compiled in"); + Q_UNREACHABLE(); + break; +#else + case QCryptographicHash::Md4: + md4_init(&md4Context); + break; + case QCryptographicHash::Md5: + MD5Init(&md5Context); + break; + case QCryptographicHash::Sha224: + SHA224Reset(&sha224Context); + break; + case QCryptographicHash::Sha256: + SHA256Reset(&sha256Context); + break; + case QCryptographicHash::Sha384: + SHA384Reset(&sha384Context); + break; + case QCryptographicHash::Sha512: + SHA512Reset(&sha512Context); + break; + case QCryptographicHash::RealSha3_224: + case QCryptographicHash::Keccak_224: + case QCryptographicHash::RealSha3_256: + case QCryptographicHash::Keccak_256: + case QCryptographicHash::RealSha3_384: + case QCryptographicHash::Keccak_384: + case QCryptographicHash::RealSha3_512: + case QCryptographicHash::Keccak_512: + sha3Init(&sha3Context, hashLengthInternal(method) * 8); + break; + case QCryptographicHash::Blake2b_160: + case QCryptographicHash::Blake2b_256: + case QCryptographicHash::Blake2b_384: + case QCryptographicHash::Blake2b_512: + blake2b_init(&blake2bContext, hashLengthInternal(method)); + break; + case QCryptographicHash::Blake2s_128: + case QCryptographicHash::Blake2s_160: + case QCryptographicHash::Blake2s_224: + case QCryptographicHash::Blake2s_256: blake2s_init(&blake2sContext, hashLengthInternal(method)); break; #endif