| 1 | // Copyright (C) 2023 The Qt Company Ltd. | 
| 2 | // Copyright (C) 2013 Ruslan Nigmatullin <euroelessar@yandex.ru> | 
| 3 | // Copyright (C) 2013 Richard J. Moore <rich@kde.org>. | 
| 4 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only | 
| 5 |  | 
| 6 | #include <qcryptographichash.h> | 
| 7 | #include <qmessageauthenticationcode.h> | 
| 8 |  | 
| 9 | #include <QtCore/private/qsmallbytearray_p.h> | 
| 10 | #include <qiodevice.h> | 
| 11 | #include <qmutex.h> | 
| 12 | #include <private/qlocking_p.h> | 
| 13 |  | 
| 14 | #include <array> | 
| 15 | #include <climits> | 
| 16 | #include <numeric> | 
| 17 |  | 
| 18 | #include "../../3rdparty/sha1/sha1.cpp" | 
| 19 |  | 
| 20 | #if defined(QT_BOOTSTRAPPED) && !defined(QT_CRYPTOGRAPHICHASH_ONLY_SHA1) | 
| 21 | #  error "Are you sure you need the other hashing algorithms besides SHA-1?" | 
| 22 | #endif | 
| 23 |  | 
| 24 | // Header from rfc6234 | 
| 25 | #include "../../3rdparty/rfc6234/sha.h" | 
| 26 |  | 
| 27 | #ifndef QT_CRYPTOGRAPHICHASH_ONLY_SHA1 | 
| 28 | #if !QT_CONFIG(openssl_hash) | 
| 29 | // qdoc and qmake only need SHA-1 | 
| 30 | #include "../../3rdparty/md5/md5.h" | 
| 31 | #include "../../3rdparty/md5/md5.cpp" | 
| 32 | #include "../../3rdparty/md4/md4.h" | 
| 33 | #include "../../3rdparty/md4/md4.cpp" | 
| 34 | #endif // !QT_CONFIG(openssl_hash) | 
| 35 |  | 
| 36 | typedef unsigned char BitSequence; | 
| 37 | typedef unsigned long long DataLength; | 
| 38 | typedef enum { SUCCESS = 0, FAIL = 1, BAD_HASHLEN = 2 } HashReturn; | 
| 39 |  | 
| 40 | #ifdef Q_OS_RTEMS | 
| 41 | #  undef ALIGN | 
| 42 | #endif | 
| 43 |  | 
| 44 | #include "../../3rdparty/sha3/KeccakSponge.c" | 
| 45 | typedef spongeState hashState; | 
| 46 |  | 
| 47 | #include "../../3rdparty/sha3/KeccakNISTInterface.c" | 
| 48 |  | 
| 49 | /* | 
| 50 |   This lets us choose between SHA3 implementations at build time. | 
| 51 |  */ | 
| 52 | typedef spongeState SHA3Context; | 
| 53 | typedef HashReturn (SHA3Init)(hashState *state, int hashbitlen); | 
| 54 | typedef HashReturn (SHA3Update)(hashState *state, const BitSequence *data, DataLength databitlen); | 
| 55 | typedef HashReturn (SHA3Final)(hashState *state, BitSequence *hashval); | 
| 56 |  | 
| 57 | #if Q_PROCESSOR_WORDSIZE == 8 // 64 bit version | 
| 58 |  | 
| 59 | #include "../../3rdparty/sha3/KeccakF-1600-opt64.c" | 
| 60 |  | 
| 61 | Q_CONSTINIT static SHA3Init * const sha3Init = Init; | 
| 62 | Q_CONSTINIT static SHA3Update * const sha3Update = Update; | 
| 63 | Q_CONSTINIT static SHA3Final * const sha3Final = Final; | 
| 64 |  | 
| 65 | #else // 32 bit optimised fallback | 
| 66 |  | 
| 67 | #include "../../3rdparty/sha3/KeccakF-1600-opt32.c" | 
| 68 |  | 
| 69 | Q_CONSTINIT static SHA3Init * const sha3Init = Init; | 
| 70 | Q_CONSTINIT static SHA3Update * const sha3Update = Update; | 
| 71 | Q_CONSTINIT static SHA3Final * const sha3Final = Final; | 
| 72 |  | 
| 73 | #endif | 
| 74 |  | 
| 75 | #if !QT_CONFIG(openssl_hash) | 
| 76 | /* | 
| 77 |     These 2 functions replace macros of the same name in sha224-256.c and | 
| 78 |     sha384-512.c. Originally, these macros relied on a global static 'addTemp' | 
| 79 |     variable. We do not want this for 2 reasons: | 
| 80 |  | 
| 81 |     1. since we are including the sources directly, the declaration of the 2 conflict | 
| 82 |  | 
| 83 |     2. static variables are not thread-safe, we do not want multiple threads | 
| 84 |     computing a hash to corrupt one another | 
| 85 | */ | 
| 86 | static int SHA224_256AddLength(SHA256Context *context, unsigned int length); | 
| 87 | static int SHA384_512AddLength(SHA512Context *context, unsigned int length); | 
| 88 |  | 
| 89 | // Sources from rfc6234, with 4 modifications: | 
| 90 | // sha224-256.c - commented out 'static uint32_t addTemp;' on line 68 | 
| 91 | // sha224-256.c - appended 'M' to the SHA224_256AddLength macro on line 70 | 
| 92 | #include "../../3rdparty/rfc6234/sha224-256.c" | 
| 93 | // sha384-512.c - commented out 'static uint64_t addTemp;' on line 302 | 
| 94 | // sha384-512.c - appended 'M' to the SHA224_256AddLength macro on line 304 | 
| 95 | #include "../../3rdparty/rfc6234/sha384-512.c" | 
| 96 |  | 
| 97 | static inline int SHA224_256AddLength(SHA256Context *context, unsigned int length) | 
| 98 | { | 
| 99 |   uint32_t addTemp; | 
| 100 |   return SHA224_256AddLengthM(context, length); | 
| 101 | } | 
| 102 | static inline int SHA384_512AddLength(SHA512Context *context, unsigned int length) | 
| 103 | { | 
| 104 |   uint64_t addTemp; | 
| 105 |   return SHA384_512AddLengthM(context, length); | 
| 106 | } | 
| 107 | #endif // !QT_CONFIG(opensslv30) | 
| 108 |  | 
| 109 | #include "qtcore-config_p.h" | 
| 110 |  | 
| 111 | #if QT_CONFIG(system_libb2) | 
| 112 | #include <blake2.h> | 
| 113 | #else | 
| 114 | QT_WARNING_PUSH | 
| 115 | QT_WARNING_DISABLE_CLANG("-Wunused-function" ) | 
| 116 | QT_WARNING_DISABLE_GCC("-Wunused-function" ) | 
| 117 | QT_WARNING_DISABLE_MSVC(4505) | 
| 118 | #include "../../3rdparty/blake2/src/blake2b-ref.c" | 
| 119 | #include "../../3rdparty/blake2/src/blake2s-ref.c" | 
| 120 | QT_WARNING_POP | 
| 121 | #endif | 
| 122 | #endif // QT_CRYPTOGRAPHICHASH_ONLY_SHA1 | 
| 123 |  | 
| 124 | #if !defined(QT_BOOTSTRAPPED) && QT_CONFIG(openssl_hash) | 
| 125 | #define USING_OPENSSL30 | 
| 126 | #include <openssl/evp.h> | 
| 127 | #include <openssl/provider.h> | 
| 128 | #endif | 
| 129 |  | 
| 130 | QT_BEGIN_NAMESPACE | 
| 131 |  | 
| 132 | static constexpr int hashLengthInternal(QCryptographicHash::Algorithm method) noexcept | 
| 133 | { | 
| 134 |     switch (method) { | 
| 135 | #define CASE(Enum, Size) \ | 
| 136 |     case QCryptographicHash:: Enum : \ | 
| 137 |         return Size \ | 
| 138 |     /*end*/ | 
| 139 |     CASE(Sha1, 20); | 
| 140 | #ifndef QT_CRYPTOGRAPHICHASH_ONLY_SHA1 | 
| 141 |     CASE(Md4, 16); | 
| 142 |     CASE(Md5, 16); | 
| 143 |     CASE(Sha224, SHA224HashSize); | 
| 144 |     CASE(Sha256, SHA256HashSize); | 
| 145 |     CASE(Sha384, SHA384HashSize); | 
| 146 |     CASE(Sha512, SHA512HashSize); | 
| 147 |     CASE(Blake2s_128, 128 / 8); | 
| 148 |     case QCryptographicHash::Blake2b_160: | 
| 149 |     case QCryptographicHash::Blake2s_160: | 
| 150 |         return 160 / 8; | 
| 151 |     case QCryptographicHash::RealSha3_224: | 
| 152 |     case QCryptographicHash::Keccak_224: | 
| 153 |     case QCryptographicHash::Blake2s_224: | 
| 154 |         return 224 / 8; | 
| 155 |     case QCryptographicHash::RealSha3_256: | 
| 156 |     case QCryptographicHash::Keccak_256: | 
| 157 |     case QCryptographicHash::Blake2b_256: | 
| 158 |     case QCryptographicHash::Blake2s_256: | 
| 159 |         return 256 / 8; | 
| 160 |     case QCryptographicHash::RealSha3_384: | 
| 161 |     case QCryptographicHash::Keccak_384: | 
| 162 |     case QCryptographicHash::Blake2b_384: | 
| 163 |         return 384 / 8; | 
| 164 |     case QCryptographicHash::RealSha3_512: | 
| 165 |     case QCryptographicHash::Keccak_512: | 
| 166 |     case QCryptographicHash::Blake2b_512: | 
| 167 |         return 512 / 8; | 
| 168 | #endif | 
| 169 | #undef CASE | 
| 170 |     case QCryptographicHash::NumAlgorithms: ; | 
| 171 |         // fall through | 
| 172 |         // Q_UNREACHABLE() would be BiC here, as hashLength(~~invalid~~) worked in 6.4 | 
| 173 |     } | 
| 174 |     return 0; | 
| 175 | } | 
| 176 |  | 
| 177 | static constexpr int maxHashLength() | 
| 178 | { | 
| 179 |     int result = 0; | 
| 180 |     using A = QCryptographicHash::Algorithm; | 
| 181 |     for (int i = 0; i < A::NumAlgorithms; ++i) | 
| 182 |         result = std::max(a: result, b: hashLengthInternal(method: A(i))); | 
| 183 |     return result; | 
| 184 | } | 
| 185 |  | 
| 186 | using HashResult = QSmallByteArray<maxHashLength()>; | 
| 187 |  | 
| 188 | #ifdef USING_OPENSSL30 | 
| 189 | static constexpr const char * methodToName(QCryptographicHash::Algorithm method) noexcept | 
| 190 | { | 
| 191 |     switch (method) { | 
| 192 | #define CASE(Enum, Name) \ | 
| 193 |     case QCryptographicHash:: Enum : \ | 
| 194 |         return Name \ | 
| 195 |     /*end*/ | 
| 196 |     CASE(Sha1, "SHA1" ); | 
| 197 |     CASE(Md4, "MD4" ); | 
| 198 |     CASE(Md5, "MD5" ); | 
| 199 |     CASE(Sha224, "SHA224" ); | 
| 200 |     CASE(Sha256, "SHA256" ); | 
| 201 |     CASE(Sha384, "SHA384" ); | 
| 202 |     CASE(Sha512, "SHA512" ); | 
| 203 |     CASE(RealSha3_224, "SHA3-224" ); | 
| 204 |     CASE(RealSha3_256, "SHA3-256" ); | 
| 205 |     CASE(RealSha3_384, "SHA3-384" ); | 
| 206 |     CASE(RealSha3_512, "SHA3-512" ); | 
| 207 |     CASE(Blake2b_512, "BLAKE2B512" ); | 
| 208 |     CASE(Blake2s_256, "BLAKE2S256" ); | 
| 209 |     // not supported by OpenSSL: | 
| 210 |     CASE(Keccak_224, nullptr); | 
| 211 |     CASE(Keccak_256, nullptr); | 
| 212 |     CASE(Keccak_384, nullptr); | 
| 213 |     CASE(Keccak_512, nullptr); | 
| 214 |     CASE(Blake2b_160, nullptr); | 
| 215 |     CASE(Blake2b_256, nullptr); | 
| 216 |     CASE(Blake2b_384, nullptr); | 
| 217 |     CASE(Blake2s_128, nullptr); | 
| 218 |     CASE(Blake2s_160, nullptr); | 
| 219 |     CASE(Blake2s_224, nullptr); | 
| 220 |     CASE(NumAlgorithms, nullptr); | 
| 221 | #undef CASE | 
| 222 |     } | 
| 223 |     return nullptr; | 
| 224 | } | 
| 225 |  | 
| 226 | /* | 
| 227 |     Checks whether given method is not provided by OpenSSL and whether we will | 
| 228 |     have a fallback to non-OpenSSL implementation. | 
| 229 | */ | 
| 230 | static constexpr bool useNonOpenSSLFallback(QCryptographicHash::Algorithm method) noexcept | 
| 231 | { | 
| 232 |     if (method == QCryptographicHash::Keccak_224 || method == QCryptographicHash::Keccak_256 || | 
| 233 |         method == QCryptographicHash::Keccak_384 || method == QCryptographicHash::Keccak_512 || | 
| 234 |         method == QCryptographicHash::Blake2b_160 || method == QCryptographicHash::Blake2b_256 || | 
| 235 |         method == QCryptographicHash::Blake2b_384 || method == QCryptographicHash::Blake2s_128 || | 
| 236 |         method == QCryptographicHash::Blake2s_160 || method == QCryptographicHash::Blake2s_224) | 
| 237 |         return true; | 
| 238 |  | 
| 239 |     return false; | 
| 240 | } | 
| 241 | #endif // USING_OPENSSL30 | 
| 242 |  | 
| 243 | class QCryptographicHashPrivate | 
| 244 | { | 
| 245 | public: | 
| 246 |     explicit QCryptographicHashPrivate(QCryptographicHash::Algorithm method) noexcept | 
| 247 |         : state(method), method(method) | 
| 248 |     { | 
| 249 |     } | 
| 250 |     ~QCryptographicHashPrivate() | 
| 251 |     { | 
| 252 |         state.destroy(method); | 
| 253 |     } | 
| 254 |  | 
| 255 |     void reset() noexcept; | 
| 256 |     void addData(QByteArrayView bytes) noexcept; | 
| 257 |     bool addData(QIODevice *dev); | 
| 258 |     void finalize() noexcept; | 
| 259 |     // when not called from the static hash() function, this function needs to be | 
| 260 |     // called with finalizeMutex held (finalize() will do that): | 
| 261 |     void finalizeUnchecked() noexcept; | 
| 262 |     // END functions that need to be called with finalizeMutex held | 
| 263 |     QByteArrayView resultView() const noexcept { return result.toByteArrayView(); } | 
| 264 |     static bool supportsAlgorithm(QCryptographicHash::Algorithm method); | 
| 265 |  | 
| 266 | #ifdef USING_OPENSSL30 | 
| 267 |     struct EVP_MD_CTX_deleter { | 
| 268 |         void operator()(EVP_MD_CTX *ctx) const noexcept { | 
| 269 |             EVP_MD_CTX_free(ctx); | 
| 270 |         } | 
| 271 |     }; | 
| 272 |     struct EVP_MD_deleter { | 
| 273 |         void operator()(EVP_MD *md) const noexcept { | 
| 274 |             EVP_MD_free(md); | 
| 275 |         } | 
| 276 |     }; | 
| 277 |     struct OSSL_PROVIDER_deleter { | 
| 278 |         void operator()(OSSL_PROVIDER *provider) const noexcept { | 
| 279 |             OSSL_PROVIDER_unload(provider); | 
| 280 |         } | 
| 281 |     }; | 
| 282 |  | 
| 283 |     using EVP_MD_CTX_ptr = std::unique_ptr<EVP_MD_CTX, EVP_MD_CTX_deleter>; | 
| 284 |     using EVP_MD_ptr = std::unique_ptr<EVP_MD, EVP_MD_deleter>; | 
| 285 |     using OSSL_PROVIDER_ptr = std::unique_ptr<OSSL_PROVIDER, OSSL_PROVIDER_deleter>; | 
| 286 |     struct EVP { | 
| 287 |         EVP_MD_ptr algorithm; | 
| 288 |         EVP_MD_CTX_ptr context; | 
| 289 |         OSSL_PROVIDER_ptr defaultProvider; | 
| 290 |         OSSL_PROVIDER_ptr legacyProvider; | 
| 291 |         bool initializationFailed; | 
| 292 |  | 
| 293 |         explicit EVP(QCryptographicHash::Algorithm method); | 
| 294 |         void reset() noexcept; | 
| 295 |         void finalizeUnchecked(HashResult &result) noexcept; | 
| 296 |     }; | 
| 297 | #endif | 
| 298 |  | 
| 299 |     union State { | 
| 300 |         explicit State(QCryptographicHash::Algorithm method); | 
| 301 |         void destroy(QCryptographicHash::Algorithm method); | 
| 302 | #ifdef USING_OPENSSL30 | 
| 303 |         ~State() {} | 
| 304 | #endif | 
| 305 |  | 
| 306 |         void reset(QCryptographicHash::Algorithm method) noexcept; | 
| 307 |         void addData(QCryptographicHash::Algorithm method, QByteArrayView data) noexcept; | 
| 308 |         void finalizeUnchecked(QCryptographicHash::Algorithm method, HashResult &result) noexcept; | 
| 309 |  | 
| 310 |         Sha1State sha1Context; | 
| 311 | #ifndef QT_CRYPTOGRAPHICHASH_ONLY_SHA1 | 
| 312 | #ifdef USING_OPENSSL30 | 
| 313 |         EVP evp; | 
| 314 | #else | 
| 315 |         MD5Context md5Context; | 
| 316 |         md4_context md4Context; | 
| 317 |         SHA224Context sha224Context; | 
| 318 |         SHA256Context sha256Context; | 
| 319 |         SHA384Context sha384Context; | 
| 320 |         SHA512Context sha512Context; | 
| 321 | #endif | 
| 322 |         SHA3Context sha3Context; | 
| 323 |  | 
| 324 |         enum class Sha3Variant { Sha3, Keccak }; | 
| 325 |         static void sha3Finish(SHA3Context &ctx, HashResult &result, int bitCount, Sha3Variant sha3Variant); | 
| 326 |         blake2b_state blake2bContext; | 
| 327 |         blake2s_state blake2sContext; | 
| 328 | #endif | 
| 329 |     } state; | 
| 330 |     // protects result in finalize() | 
| 331 |     QBasicMutex finalizeMutex; | 
| 332 |     HashResult result; | 
| 333 |  | 
| 334 |     const QCryptographicHash::Algorithm method; | 
| 335 | }; | 
| 336 |  | 
| 337 | #ifndef QT_CRYPTOGRAPHICHASH_ONLY_SHA1 | 
| 338 | void QCryptographicHashPrivate::State::sha3Finish(SHA3Context &ctx, HashResult &result, | 
| 339 |                                                   int bitCount, Sha3Variant sha3Variant) | 
| 340 | { | 
| 341 |     /* | 
| 342 |         FIPS 202 §6.1 defines SHA-3 in terms of calculating the Keccak function | 
| 343 |         over the original message with the two-bit suffix "01" appended to it. | 
| 344 |         This variable stores that suffix (and it's fed into the calculations | 
| 345 |         when the hash is returned to users). | 
| 346 |  | 
| 347 |         Only 2 bits of this variable are actually used (see the call to sha3Update | 
| 348 |         below). The Keccak implementation we're using will actually use the | 
| 349 |         *leftmost* 2 bits, and interpret them right-to-left. In other words, the | 
| 350 |         bits must appear in order of *increasing* significance; and as the two most | 
| 351 |         significant bits of the byte -- the rightmost 6 are ignored. (Yes, this | 
| 352 |         seems self-contradictory, but it's the way it is...) | 
| 353 |  | 
| 354 |         Overall, this means: | 
| 355 |         * the leftmost two bits must be "10" (not "01"!); | 
| 356 |         * we don't care what the other six bits are set to (they can be set to | 
| 357 |         any value), but we arbitrarily set them to 0; | 
| 358 |  | 
| 359 |         and for an unsigned char this gives us 0b10'00'00'00, or 0x80. | 
| 360 |     */ | 
| 361 |     static const unsigned char sha3FinalSuffix = 0x80; | 
| 362 |  | 
| 363 |     result.resizeForOverwrite(s: bitCount / 8); | 
| 364 |  | 
| 365 |     switch (sha3Variant) { | 
| 366 |     case Sha3Variant::Sha3: | 
| 367 |         sha3Update(&ctx, reinterpret_cast<const BitSequence *>(&sha3FinalSuffix), 2); | 
| 368 |         break; | 
| 369 |     case Sha3Variant::Keccak: | 
| 370 |         break; | 
| 371 |     } | 
| 372 |  | 
| 373 |     sha3Final(&ctx, result.data()); | 
| 374 | } | 
| 375 | #endif | 
| 376 |  | 
| 377 | /*! | 
| 378 |   \class QCryptographicHash | 
| 379 |   \inmodule QtCore | 
| 380 |  | 
| 381 |   \brief The QCryptographicHash class provides a way to generate cryptographic hashes. | 
| 382 |  | 
| 383 |   \since 4.3 | 
| 384 |  | 
| 385 |   \ingroup tools | 
| 386 |   \reentrant | 
| 387 |  | 
| 388 |   QCryptographicHash can be used to generate cryptographic hashes of binary or text data. | 
| 389 |  | 
| 390 |   Refer to the documentation of the \l QCryptographicHash::Algorithm enum for a | 
| 391 |   list of the supported algorithms. | 
| 392 | */ | 
| 393 |  | 
| 394 | /*! | 
| 395 |   \enum QCryptographicHash::Algorithm | 
| 396 |  | 
| 397 |   \note In Qt versions before 5.9, when asked to generate a SHA3 hash sum, | 
| 398 |   QCryptographicHash actually calculated Keccak. If you need compatibility with | 
| 399 |   SHA-3 hashes produced by those versions of Qt, use the \c{Keccak_} | 
| 400 |   enumerators. Alternatively, if source compatibility is required, define the | 
| 401 |   macro \c QT_SHA3_KECCAK_COMPAT. | 
| 402 |  | 
| 403 |   \value Md4 Generate an MD4 hash sum | 
| 404 |   \value Md5 Generate an MD5 hash sum | 
| 405 |   \value Sha1 Generate an SHA-1 hash sum | 
| 406 |   \value Sha224 Generate an SHA-224 hash sum (SHA-2). Introduced in Qt 5.0 | 
| 407 |   \value Sha256 Generate an SHA-256 hash sum (SHA-2). Introduced in Qt 5.0 | 
| 408 |   \value Sha384 Generate an SHA-384 hash sum (SHA-2). Introduced in Qt 5.0 | 
| 409 |   \value Sha512 Generate an SHA-512 hash sum (SHA-2). Introduced in Qt 5.0 | 
| 410 |   \value Sha3_224 Generate an SHA3-224 hash sum. Introduced in Qt 5.1 | 
| 411 |   \value Sha3_256 Generate an SHA3-256 hash sum. Introduced in Qt 5.1 | 
| 412 |   \value Sha3_384 Generate an SHA3-384 hash sum. Introduced in Qt 5.1 | 
| 413 |   \value Sha3_512 Generate an SHA3-512 hash sum. Introduced in Qt 5.1 | 
| 414 |   \value Keccak_224 Generate a Keccak-224 hash sum. Introduced in Qt 5.9.2 | 
| 415 |   \value Keccak_256 Generate a Keccak-256 hash sum. Introduced in Qt 5.9.2 | 
| 416 |   \value Keccak_384 Generate a Keccak-384 hash sum. Introduced in Qt 5.9.2 | 
| 417 |   \value Keccak_512 Generate a Keccak-512 hash sum. Introduced in Qt 5.9.2 | 
| 418 |   \value Blake2b_160 Generate a BLAKE2b-160 hash sum. Introduced in Qt 6.0 | 
| 419 |   \value Blake2b_256 Generate a BLAKE2b-256 hash sum. Introduced in Qt 6.0 | 
| 420 |   \value Blake2b_384 Generate a BLAKE2b-384 hash sum. Introduced in Qt 6.0 | 
| 421 |   \value Blake2b_512 Generate a BLAKE2b-512 hash sum. Introduced in Qt 6.0 | 
| 422 |   \value Blake2s_128 Generate a BLAKE2s-128 hash sum. Introduced in Qt 6.0 | 
| 423 |   \value Blake2s_160 Generate a BLAKE2s-160 hash sum. Introduced in Qt 6.0 | 
| 424 |   \value Blake2s_224 Generate a BLAKE2s-224 hash sum. Introduced in Qt 6.0 | 
| 425 |   \value Blake2s_256 Generate a BLAKE2s-256 hash sum. Introduced in Qt 6.0 | 
| 426 |   \omitvalue RealSha3_224 | 
| 427 |   \omitvalue RealSha3_256 | 
| 428 |   \omitvalue RealSha3_384 | 
| 429 |   \omitvalue RealSha3_512 | 
| 430 |   \omitvalue NumAlgorithms | 
| 431 | */ | 
| 432 |  | 
| 433 | /*! | 
| 434 |   Constructs an object that can be used to create a cryptographic hash from data using \a method. | 
| 435 | */ | 
| 436 | QCryptographicHash::QCryptographicHash(Algorithm method) | 
| 437 |     : d(new QCryptographicHashPrivate{method}) | 
| 438 | { | 
| 439 | } | 
| 440 |  | 
| 441 | /*! | 
| 442 |     \fn QCryptographicHash::QCryptographicHash(QCryptographicHash &&other) | 
| 443 |  | 
| 444 |     Move-constructs a new QCryptographicHash from \a other. | 
| 445 |  | 
| 446 |     \note The moved-from object \a other is placed in a | 
| 447 |     partially-formed state, in which the only valid operations are | 
| 448 |     destruction and assignment of a new value. | 
| 449 |  | 
| 450 |     \since 6.5 | 
| 451 | */ | 
| 452 |  | 
| 453 | /*! | 
| 454 |   Destroys the object. | 
| 455 | */ | 
| 456 | QCryptographicHash::~QCryptographicHash() | 
| 457 | { | 
| 458 |     delete d; | 
| 459 | } | 
| 460 |  | 
| 461 | /*! | 
| 462 |     \fn QCryptographicHash &QCryptographicHash::operator=(QCryptographicHash &&other) | 
| 463 |  | 
| 464 |     Move-assigns \a other to this QCryptographicHash instance. | 
| 465 |  | 
| 466 |     \note The moved-from object \a other is placed in a | 
| 467 |     partially-formed state, in which the only valid operations are | 
| 468 |     destruction and assignment of a new value. | 
| 469 |  | 
| 470 |     \since 6.5 | 
| 471 | */ | 
| 472 |  | 
| 473 | /*! | 
| 474 |     \fn void QCryptographicHash::swap(QCryptographicHash &other) | 
| 475 |     \memberswap{cryptographic hash} | 
| 476 |     \since 6.5 | 
| 477 | */ | 
| 478 |  | 
| 479 | /*! | 
| 480 |   Resets the object. | 
| 481 | */ | 
| 482 | void QCryptographicHash::reset() noexcept | 
| 483 | { | 
| 484 |     d->reset(); | 
| 485 | } | 
| 486 |  | 
| 487 | /*! | 
| 488 |     Returns the algorithm used to generate the cryptographic hash. | 
| 489 |  | 
| 490 |     \since 6.5 | 
| 491 | */ | 
| 492 | QCryptographicHash::Algorithm QCryptographicHash::algorithm() const noexcept | 
| 493 | { | 
| 494 |     return d->method; | 
| 495 | } | 
| 496 |  | 
| 497 | #ifdef USING_OPENSSL30 | 
| 498 |  | 
| 499 | QCryptographicHashPrivate::State::State(QCryptographicHash::Algorithm method) | 
| 500 | { | 
| 501 |     if (method == QCryptographicHash::Keccak_224 || | 
| 502 |         method == QCryptographicHash::Keccak_256 || | 
| 503 |         method == QCryptographicHash::Keccak_384 || | 
| 504 |         method == QCryptographicHash::Keccak_512) { | 
| 505 |         new (&sha3Context) SHA3Context; | 
| 506 |         reset(method); | 
| 507 |     } else if (method == QCryptographicHash::Blake2b_160 || | 
| 508 |                method == QCryptographicHash::Blake2b_256 || | 
| 509 |                method == QCryptographicHash::Blake2b_384) { | 
| 510 |         new (&blake2bContext) blake2b_state; | 
| 511 |         reset(method); | 
| 512 |     } else if (method == QCryptographicHash::Blake2s_128 || | 
| 513 |                method == QCryptographicHash::Blake2s_160 || | 
| 514 |                method == QCryptographicHash::Blake2s_224) { | 
| 515 |         new (&blake2sContext) blake2s_state; | 
| 516 |         reset(method); | 
| 517 |     } else { | 
| 518 |         new (&evp) EVP(method); | 
| 519 |     } | 
| 520 | } | 
| 521 |  | 
| 522 | void QCryptographicHashPrivate::State::destroy(QCryptographicHash::Algorithm method) | 
| 523 | { | 
| 524 |     if (method != QCryptographicHash::Keccak_224 && | 
| 525 |         method != QCryptographicHash::Keccak_256 && | 
| 526 |         method != QCryptographicHash::Keccak_384 && | 
| 527 |         method != QCryptographicHash::Keccak_512 && | 
| 528 |         method != QCryptographicHash::Blake2b_160 && | 
| 529 |         method != QCryptographicHash::Blake2b_256 && | 
| 530 |         method != QCryptographicHash::Blake2b_384 && | 
| 531 |         method != QCryptographicHash::Blake2s_128 && | 
| 532 |         method != QCryptographicHash::Blake2s_160 && | 
| 533 |         method != QCryptographicHash::Blake2s_224) { | 
| 534 |         evp.~EVP(); | 
| 535 |     } | 
| 536 | } | 
| 537 |  | 
| 538 | QCryptographicHashPrivate::EVP::EVP(QCryptographicHash::Algorithm method) | 
| 539 |     : initializationFailed{true} | 
| 540 | { | 
| 541 |     if (method == QCryptographicHash::Md4) { | 
| 542 |         /* | 
| 543 |          * We need to load the legacy provider in order to have the MD4 | 
| 544 |          * algorithm available. | 
| 545 |          */ | 
| 546 |         legacyProvider = OSSL_PROVIDER_ptr(OSSL_PROVIDER_load(nullptr, "legacy" )); | 
| 547 |  | 
| 548 |         if (!legacyProvider) | 
| 549 |             return; | 
| 550 |     } | 
| 551 |  | 
| 552 |     defaultProvider = OSSL_PROVIDER_ptr(OSSL_PROVIDER_load(nullptr, "default" )); | 
| 553 |     if (!defaultProvider) | 
| 554 |         return; | 
| 555 |  | 
| 556 |     context = EVP_MD_CTX_ptr(EVP_MD_CTX_new()); | 
| 557 |  | 
| 558 |     if (!context) { | 
| 559 |         return; | 
| 560 |     } | 
| 561 |  | 
| 562 |     /* | 
| 563 |      * Using the "-fips" option will disable the global "fips=yes" for | 
| 564 |      * this one lookup and the algorithm can be fetched from any provider | 
| 565 |      * that implements the algorithm (including the FIPS provider). | 
| 566 |      */ | 
| 567 |     algorithm = EVP_MD_ptr(EVP_MD_fetch(nullptr, methodToName(method), "-fips" )); | 
| 568 |     if (!algorithm) { | 
| 569 |         return; | 
| 570 |     } | 
| 571 |  | 
| 572 |     initializationFailed = !EVP_DigestInit_ex(context.get(), algorithm.get(), nullptr); | 
| 573 | } | 
| 574 |  | 
| 575 | #else // USING_OPENSSL30 | 
| 576 |  | 
| 577 | QCryptographicHashPrivate::State::State(QCryptographicHash::Algorithm method) | 
| 578 | { | 
| 579 |     switch (method) { | 
| 580 |     case QCryptographicHash::Sha1: | 
| 581 |         new (&sha1Context) Sha1State; | 
| 582 |         break; | 
| 583 | #ifdef QT_CRYPTOGRAPHICHASH_ONLY_SHA1 | 
| 584 |     default: | 
| 585 |         Q_ASSERT_X(false, "QCryptographicHash" , "Method not compiled in" ); | 
| 586 |         Q_UNREACHABLE(); | 
| 587 |         break; | 
| 588 | #else | 
| 589 |     case QCryptographicHash::Md4: | 
| 590 |         new (&md4Context) md4_context; | 
| 591 |         break; | 
| 592 |     case QCryptographicHash::Md5: | 
| 593 |         new (&md5Context) MD5Context; | 
| 594 |         break; | 
| 595 |     case QCryptographicHash::Sha224: | 
| 596 |         new (&sha224Context) SHA224Context; | 
| 597 |         break; | 
| 598 |     case QCryptographicHash::Sha256: | 
| 599 |         new (&sha256Context) SHA256Context; | 
| 600 |         break; | 
| 601 |     case QCryptographicHash::Sha384: | 
| 602 |         new (&sha384Context) SHA384Context; | 
| 603 |         break; | 
| 604 |     case QCryptographicHash::Sha512: | 
| 605 |         new (&sha512Context) SHA512Context; | 
| 606 |         break; | 
| 607 |     case QCryptographicHash::RealSha3_224: | 
| 608 |     case QCryptographicHash::Keccak_224: | 
| 609 |     case QCryptographicHash::RealSha3_256: | 
| 610 |     case QCryptographicHash::Keccak_256: | 
| 611 |     case QCryptographicHash::RealSha3_384: | 
| 612 |     case QCryptographicHash::Keccak_384: | 
| 613 |     case QCryptographicHash::RealSha3_512: | 
| 614 |     case QCryptographicHash::Keccak_512: | 
| 615 |         new (&sha3Context) SHA3Context; | 
| 616 |         break; | 
| 617 |     case QCryptographicHash::Blake2b_160: | 
| 618 |     case QCryptographicHash::Blake2b_256: | 
| 619 |     case QCryptographicHash::Blake2b_384: | 
| 620 |     case QCryptographicHash::Blake2b_512: | 
| 621 |         new (&blake2bContext) blake2b_state; | 
| 622 |         break; | 
| 623 |     case QCryptographicHash::Blake2s_128: | 
| 624 |     case QCryptographicHash::Blake2s_160: | 
| 625 |     case QCryptographicHash::Blake2s_224: | 
| 626 |     case QCryptographicHash::Blake2s_256: | 
| 627 |         new (&blake2sContext) blake2s_state; | 
| 628 |         break; | 
| 629 | #endif | 
| 630 |     case QCryptographicHash::NumAlgorithms: | 
| 631 |         Q_UNREACHABLE(); | 
| 632 |     } | 
| 633 |     reset(method); | 
| 634 | } | 
| 635 |  | 
| 636 | void QCryptographicHashPrivate::State::destroy(QCryptographicHash::Algorithm) | 
| 637 | { | 
| 638 |     static_assert(std::is_trivially_destructible_v<State>); // so nothing to do here | 
| 639 | } | 
| 640 | #endif // !USING_OPENSSL30 | 
| 641 |  | 
| 642 | void QCryptographicHashPrivate::reset() noexcept | 
| 643 | { | 
| 644 |     result.clear(); | 
| 645 |     state.reset(method); | 
| 646 | } | 
| 647 |  | 
| 648 | #ifdef USING_OPENSSL30 | 
| 649 |  | 
| 650 | void QCryptographicHashPrivate::State::reset(QCryptographicHash::Algorithm method) noexcept | 
| 651 | { | 
| 652 |     if (method == QCryptographicHash::Keccak_224 || | 
| 653 |         method == QCryptographicHash::Keccak_256 || | 
| 654 |         method == QCryptographicHash::Keccak_384 || | 
| 655 |         method == QCryptographicHash::Keccak_512) { | 
| 656 |         sha3Init(&sha3Context, hashLengthInternal(method) * 8); | 
| 657 |    } else if (method == QCryptographicHash::Blake2b_160 || | 
| 658 |               method == QCryptographicHash::Blake2b_256 || | 
| 659 |               method == QCryptographicHash::Blake2b_384) { | 
| 660 |         blake2b_init(&blake2bContext, hashLengthInternal(method)); | 
| 661 |     } else if (method == QCryptographicHash::Blake2s_128 || | 
| 662 |                method == QCryptographicHash::Blake2s_160 || | 
| 663 |                method == QCryptographicHash::Blake2s_224) { | 
| 664 |         blake2s_init(&blake2sContext, hashLengthInternal(method)); | 
| 665 |     } else { | 
| 666 |         evp.reset(); | 
| 667 |     } | 
| 668 | } | 
| 669 |  | 
| 670 | void QCryptographicHashPrivate::EVP::reset() noexcept | 
| 671 | { | 
| 672 |     if (!initializationFailed) { | 
| 673 |         Q_ASSERT(context); | 
| 674 |         Q_ASSERT(algorithm); | 
| 675 |         // everything already set up - just reset the context | 
| 676 |         EVP_MD_CTX_reset(context.get()); | 
| 677 |         initializationFailed = !EVP_DigestInit_ex(context.get(), algorithm.get(), nullptr); | 
| 678 |     } | 
| 679 |     // if initializationFailed first time around, it will not succeed this time, either | 
| 680 | } | 
| 681 |  | 
| 682 | #else // USING_OPENSSL30 | 
| 683 |  | 
| 684 | void QCryptographicHashPrivate::State::reset(QCryptographicHash::Algorithm method) noexcept | 
| 685 | { | 
| 686 |     switch (method) { | 
| 687 |     case QCryptographicHash::Sha1: | 
| 688 |         sha1InitState(state: &sha1Context); | 
| 689 |         break; | 
| 690 | #ifdef QT_CRYPTOGRAPHICHASH_ONLY_SHA1 | 
| 691 |     default: | 
| 692 |         Q_ASSERT_X(false, "QCryptographicHash" , "Method not compiled in" ); | 
| 693 |         Q_UNREACHABLE(); | 
| 694 |         break; | 
| 695 | #else | 
| 696 |     case QCryptographicHash::Md4: | 
| 697 |         md4_init(ctx: &md4Context); | 
| 698 |         break; | 
| 699 |     case QCryptographicHash::Md5: | 
| 700 |         MD5Init(ctx: &md5Context); | 
| 701 |         break; | 
| 702 |     case QCryptographicHash::Sha224: | 
| 703 |         SHA224Reset(context: &sha224Context); | 
| 704 |         break; | 
| 705 |     case QCryptographicHash::Sha256: | 
| 706 |         SHA256Reset(context: &sha256Context); | 
| 707 |         break; | 
| 708 |     case QCryptographicHash::Sha384: | 
| 709 |         SHA384Reset(context: &sha384Context); | 
| 710 |         break; | 
| 711 |     case QCryptographicHash::Sha512: | 
| 712 |         SHA512Reset(context: &sha512Context); | 
| 713 |         break; | 
| 714 |     case QCryptographicHash::RealSha3_224: | 
| 715 |     case QCryptographicHash::Keccak_224: | 
| 716 |     case QCryptographicHash::RealSha3_256: | 
| 717 |     case QCryptographicHash::Keccak_256: | 
| 718 |     case QCryptographicHash::RealSha3_384: | 
| 719 |     case QCryptographicHash::Keccak_384: | 
| 720 |     case QCryptographicHash::RealSha3_512: | 
| 721 |     case QCryptographicHash::Keccak_512: | 
| 722 |         sha3Init(&sha3Context, hashLengthInternal(method) * 8); | 
| 723 |         break; | 
| 724 |     case QCryptographicHash::Blake2b_160: | 
| 725 |     case QCryptographicHash::Blake2b_256: | 
| 726 |     case QCryptographicHash::Blake2b_384: | 
| 727 |     case QCryptographicHash::Blake2b_512: | 
| 728 |         blake2b_init(S: &blake2bContext, outlen: hashLengthInternal(method)); | 
| 729 |         break; | 
| 730 |     case QCryptographicHash::Blake2s_128: | 
| 731 |     case QCryptographicHash::Blake2s_160: | 
| 732 |     case QCryptographicHash::Blake2s_224: | 
| 733 |     case QCryptographicHash::Blake2s_256: | 
| 734 |         blake2s_init(S: &blake2sContext, outlen: hashLengthInternal(method)); | 
| 735 |         break; | 
| 736 | #endif | 
| 737 |     case QCryptographicHash::NumAlgorithms: | 
| 738 |         Q_UNREACHABLE(); | 
| 739 |     } | 
| 740 | } | 
| 741 |  | 
| 742 | #endif // USING_OPENSSL30 | 
| 743 |  | 
| 744 | #if QT_DEPRECATED_SINCE(6, 4) | 
| 745 | /*! | 
| 746 |     Adds the first \a length chars of \a data to the cryptographic | 
| 747 |     hash. | 
| 748 |  | 
| 749 |     \obsolete | 
| 750 |     Use the QByteArrayView overload instead. | 
| 751 | */ | 
| 752 | void QCryptographicHash::addData(const char *data, qsizetype length) | 
| 753 | { | 
| 754 |     Q_ASSERT(length >= 0); | 
| 755 |     addData(data: QByteArrayView{data, length}); | 
| 756 | } | 
| 757 | #endif | 
| 758 |  | 
| 759 | /*! | 
| 760 |     Adds the characters in \a bytes to the cryptographic hash. | 
| 761 |  | 
| 762 |     \note In Qt versions prior to 6.3, this function took QByteArray, | 
| 763 |     not QByteArrayView. | 
| 764 | */ | 
| 765 | void QCryptographicHash::addData(QByteArrayView bytes) noexcept | 
| 766 | { | 
| 767 |     d->addData(bytes); | 
| 768 | } | 
| 769 |  | 
| 770 | void QCryptographicHashPrivate::addData(QByteArrayView bytes) noexcept | 
| 771 | { | 
| 772 |     state.addData(method, data: bytes); | 
| 773 |     result.clear(); | 
| 774 | } | 
| 775 |  | 
| 776 | #ifdef USING_OPENSSL30 | 
| 777 |  | 
| 778 | void QCryptographicHashPrivate::State::addData(QCryptographicHash::Algorithm method, | 
| 779 |                                                QByteArrayView bytes) noexcept | 
| 780 | { | 
| 781 |     const char *data = bytes.data(); | 
| 782 |     auto length = bytes.size(); | 
| 783 |     // all functions take size_t length, so we don't need to loop around them: | 
| 784 |     { | 
| 785 |         if (method == QCryptographicHash::Keccak_224 || | 
| 786 |             method == QCryptographicHash::Keccak_256 || | 
| 787 |             method == QCryptographicHash::Keccak_384 || | 
| 788 |             method == QCryptographicHash::Keccak_512) { | 
| 789 |             sha3Update(&sha3Context, reinterpret_cast<const BitSequence *>(data), uint64_t(length) * 8); | 
| 790 |         } else if (method == QCryptographicHash::Blake2b_160 || | 
| 791 |                    method == QCryptographicHash::Blake2b_256 || | 
| 792 |                    method == QCryptographicHash::Blake2b_384) { | 
| 793 |             blake2b_update(&blake2bContext, reinterpret_cast<const uint8_t *>(data), length); | 
| 794 |         } else if (method == QCryptographicHash::Blake2s_128 || | 
| 795 |                 method == QCryptographicHash::Blake2s_160 || | 
| 796 |                 method == QCryptographicHash::Blake2s_224) { | 
| 797 |             blake2s_update(&blake2sContext, reinterpret_cast<const uint8_t *>(data), length); | 
| 798 |         } else if (!evp.initializationFailed) { | 
| 799 |             EVP_DigestUpdate(evp.context.get(), (const unsigned char *)data, length); | 
| 800 |         } | 
| 801 |     } | 
| 802 | } | 
| 803 |  | 
| 804 | #else // USING_OPENSSL30 | 
| 805 |  | 
| 806 | void QCryptographicHashPrivate::State::addData(QCryptographicHash::Algorithm method, | 
| 807 |                                                QByteArrayView bytes) noexcept | 
| 808 | { | 
| 809 |     const char *data = bytes.data(); | 
| 810 |     auto length = bytes.size(); | 
| 811 |  | 
| 812 | #if QT_POINTER_SIZE == 8 | 
| 813 |     // feed the data UINT_MAX bytes at a time, as some of the methods below | 
| 814 |     // take a uint (of course, feeding more than 4G of data into the hashing | 
| 815 |     // functions will be pretty slow anyway) | 
| 816 |     for (auto remaining = length; remaining; remaining -= length, data += length) { | 
| 817 |         length = qMin(a: qsizetype(std::numeric_limits<uint>::max()), b: remaining); | 
| 818 | #else | 
| 819 |     { | 
| 820 | #endif | 
| 821 |         switch (method) { | 
| 822 |         case QCryptographicHash::Sha1: | 
| 823 |             sha1Update(state: &sha1Context, data: (const unsigned char *)data, len: length); | 
| 824 |             break; | 
| 825 | #ifdef QT_CRYPTOGRAPHICHASH_ONLY_SHA1 | 
| 826 |         default: | 
| 827 |             Q_ASSERT_X(false, "QCryptographicHash" , "Method not compiled in" ); | 
| 828 |             Q_UNREACHABLE(); | 
| 829 |             break; | 
| 830 | #else | 
| 831 |         case QCryptographicHash::Md4: | 
| 832 |             md4_update(ctx: &md4Context, data: (const unsigned char *)data, size: length); | 
| 833 |             break; | 
| 834 |         case QCryptographicHash::Md5: | 
| 835 |             MD5Update(ctx: &md5Context, buf: (const unsigned char *)data, len: length); | 
| 836 |             break; | 
| 837 |         case QCryptographicHash::Sha224: | 
| 838 |             SHA224Input(context: &sha224Context, message_array: reinterpret_cast<const unsigned char *>(data), length); | 
| 839 |             break; | 
| 840 |         case QCryptographicHash::Sha256: | 
| 841 |             SHA256Input(context: &sha256Context, message_array: reinterpret_cast<const unsigned char *>(data), length); | 
| 842 |             break; | 
| 843 |         case QCryptographicHash::Sha384: | 
| 844 |             SHA384Input(context: &sha384Context, message_array: reinterpret_cast<const unsigned char *>(data), length); | 
| 845 |             break; | 
| 846 |         case QCryptographicHash::Sha512: | 
| 847 |             SHA512Input(context: &sha512Context, message_array: reinterpret_cast<const unsigned char *>(data), length); | 
| 848 |             break; | 
| 849 |         case QCryptographicHash::RealSha3_224: | 
| 850 |         case QCryptographicHash::Keccak_224: | 
| 851 |         case QCryptographicHash::RealSha3_256: | 
| 852 |         case QCryptographicHash::Keccak_256: | 
| 853 |         case QCryptographicHash::RealSha3_384: | 
| 854 |         case QCryptographicHash::Keccak_384: | 
| 855 |         case QCryptographicHash::RealSha3_512: | 
| 856 |         case QCryptographicHash::Keccak_512: | 
| 857 |             sha3Update(&sha3Context, reinterpret_cast<const BitSequence *>(data), uint64_t(length) * 8); | 
| 858 |             break; | 
| 859 |         case QCryptographicHash::Blake2b_160: | 
| 860 |         case QCryptographicHash::Blake2b_256: | 
| 861 |         case QCryptographicHash::Blake2b_384: | 
| 862 |         case QCryptographicHash::Blake2b_512: | 
| 863 |             blake2b_update(S: &blake2bContext, pin: reinterpret_cast<const uint8_t *>(data), inlen: length); | 
| 864 |             break; | 
| 865 |         case QCryptographicHash::Blake2s_128: | 
| 866 |         case QCryptographicHash::Blake2s_160: | 
| 867 |         case QCryptographicHash::Blake2s_224: | 
| 868 |         case QCryptographicHash::Blake2s_256: | 
| 869 |             blake2s_update(S: &blake2sContext, pin: reinterpret_cast<const uint8_t *>(data), inlen: length); | 
| 870 |             break; | 
| 871 | #endif | 
| 872 |         case QCryptographicHash::NumAlgorithms: | 
| 873 |             Q_UNREACHABLE(); | 
| 874 |         } | 
| 875 |     } | 
| 876 | } | 
| 877 | #endif // !USING_OPENSSL30 | 
| 878 |  | 
| 879 | /*! | 
| 880 |   Reads the data from the open QIODevice \a device until it ends | 
| 881 |   and hashes it. Returns \c true if reading was successful. | 
| 882 |   \since 5.0 | 
| 883 |  */ | 
| 884 | bool QCryptographicHash::addData(QIODevice *device) | 
| 885 | { | 
| 886 |     return d->addData(dev: device); | 
| 887 | } | 
| 888 |  | 
| 889 | bool QCryptographicHashPrivate::addData(QIODevice *device) | 
| 890 | { | 
| 891 |     if (!device->isReadable()) | 
| 892 |         return false; | 
| 893 |  | 
| 894 |     if (!device->isOpen()) | 
| 895 |         return false; | 
| 896 |  | 
| 897 |     char buffer[1024]; | 
| 898 |     qint64 length; | 
| 899 |  | 
| 900 |     while ((length = device->read(data: buffer, maxlen: sizeof(buffer))) > 0) | 
| 901 |         addData(bytes: {buffer, qsizetype(length)}); // length always <= 1024 | 
| 902 |  | 
| 903 |     return device->atEnd(); | 
| 904 | } | 
| 905 |  | 
| 906 |  | 
| 907 | /*! | 
| 908 |   Returns the final hash value. | 
| 909 |  | 
| 910 |   \sa resultView(), QByteArray::toHex() | 
| 911 | */ | 
| 912 | QByteArray QCryptographicHash::result() const | 
| 913 | { | 
| 914 |     return resultView().toByteArray(); | 
| 915 | } | 
| 916 |  | 
| 917 | /*! | 
| 918 |   \since 6.3 | 
| 919 |  | 
| 920 |   Returns the final hash value. | 
| 921 |  | 
| 922 |   Note that the returned view remains valid only as long as the QCryptographicHash object is | 
| 923 |   not modified by other means. | 
| 924 |  | 
| 925 |   \sa result() | 
| 926 | */ | 
| 927 | QByteArrayView QCryptographicHash::resultView() const noexcept | 
| 928 | { | 
| 929 |     // resultView() is a const function, so concurrent calls are allowed; protect: | 
| 930 |     d->finalize(); | 
| 931 |     // resultView() remains(!) valid even after we dropped the mutex in finalize() | 
| 932 |     return d->resultView(); | 
| 933 | } | 
| 934 |  | 
| 935 | /*! | 
| 936 |     \internal | 
| 937 |  | 
| 938 |     Calls finalizeUnchecked(), if needed, under finalizeMutex protection. | 
| 939 | */ | 
| 940 | void QCryptographicHashPrivate::finalize() noexcept | 
| 941 | { | 
| 942 |     const auto lock = qt_scoped_lock(mutex&: finalizeMutex); | 
| 943 |     // check that no other thread already finalizeUnchecked()'ed before us: | 
| 944 |     if (!result.isEmpty()) | 
| 945 |         return; | 
| 946 |     finalizeUnchecked(); | 
| 947 | } | 
| 948 |  | 
| 949 | /*! | 
| 950 |     \internal | 
| 951 |  | 
| 952 |     Must be called with finalizeMutex held (except from static hash() function, | 
| 953 |     where no sharing can take place). | 
| 954 | */ | 
| 955 | void QCryptographicHashPrivate::finalizeUnchecked() noexcept | 
| 956 | { | 
| 957 |     state.finalizeUnchecked(method, result); | 
| 958 | } | 
| 959 |  | 
| 960 | #ifdef USING_OPENSSL30 | 
| 961 | void QCryptographicHashPrivate::State::finalizeUnchecked(QCryptographicHash::Algorithm method, | 
| 962 |                                                          HashResult &result) noexcept | 
| 963 | { | 
| 964 |     if (method == QCryptographicHash::Keccak_224 || | 
| 965 |         method == QCryptographicHash::Keccak_256 || | 
| 966 |         method == QCryptographicHash::Keccak_384 || | 
| 967 |         method == QCryptographicHash::Keccak_512) { | 
| 968 |         SHA3Context copy = sha3Context; | 
| 969 |         sha3Finish(copy, result, 8 * hashLengthInternal(method), Sha3Variant::Keccak); | 
| 970 |     } else if (method == QCryptographicHash::Blake2b_160 || | 
| 971 |                method == QCryptographicHash::Blake2b_256 || | 
| 972 |                method == QCryptographicHash::Blake2b_384) { | 
| 973 |         const auto length = hashLengthInternal(method); | 
| 974 |         blake2b_state copy = blake2bContext; | 
| 975 |         result.resizeForOverwrite(length); | 
| 976 |         blake2b_final(©, result.data(), length); | 
| 977 |     } else if (method == QCryptographicHash::Blake2s_128 || | 
| 978 |                method == QCryptographicHash::Blake2s_160 || | 
| 979 |                method == QCryptographicHash::Blake2s_224) { | 
| 980 |         const auto length = hashLengthInternal(method); | 
| 981 |         blake2s_state copy = blake2sContext; | 
| 982 |         result.resizeForOverwrite(length); | 
| 983 |         blake2s_final(©, result.data(), length); | 
| 984 |     } else { | 
| 985 |         evp.finalizeUnchecked(result); | 
| 986 |     } | 
| 987 | } | 
| 988 |  | 
| 989 | void QCryptographicHashPrivate::EVP::finalizeUnchecked(HashResult &result) noexcept | 
| 990 | { | 
| 991 |     if (!initializationFailed) { | 
| 992 |         EVP_MD_CTX_ptr copy = EVP_MD_CTX_ptr(EVP_MD_CTX_new()); | 
| 993 |         EVP_MD_CTX_copy_ex(copy.get(), context.get()); | 
| 994 |         result.resizeForOverwrite(EVP_MD_get_size(algorithm.get())); | 
| 995 |         EVP_DigestFinal_ex(copy.get(), result.data(), nullptr); | 
| 996 |     } | 
| 997 | } | 
| 998 |  | 
| 999 | #else // USING_OPENSSL30 | 
| 1000 |  | 
| 1001 | void QCryptographicHashPrivate::State::finalizeUnchecked(QCryptographicHash::Algorithm method, | 
| 1002 |                                                          HashResult &result) noexcept | 
| 1003 | { | 
| 1004 |     switch (method) { | 
| 1005 |     case QCryptographicHash::Sha1: { | 
| 1006 |         Sha1State copy = sha1Context; | 
| 1007 |         result.resizeForOverwrite(s: 20); | 
| 1008 |         sha1FinalizeState(state: ©); | 
| 1009 |         sha1ToHash(state: ©, buffer: result.data()); | 
| 1010 |         break; | 
| 1011 |     } | 
| 1012 | #ifdef QT_CRYPTOGRAPHICHASH_ONLY_SHA1 | 
| 1013 |     default: | 
| 1014 |         Q_ASSERT_X(false, "QCryptographicHash" , "Method not compiled in" ); | 
| 1015 |         Q_UNREACHABLE(); | 
| 1016 |         break; | 
| 1017 | #else | 
| 1018 |     case QCryptographicHash::Md4: { | 
| 1019 |         md4_context copy = md4Context; | 
| 1020 |         result.resizeForOverwrite(MD4_RESULTLEN); | 
| 1021 |         md4_final(ctx: ©, result: result.data()); | 
| 1022 |         break; | 
| 1023 |     } | 
| 1024 |     case QCryptographicHash::Md5: { | 
| 1025 |         MD5Context copy = md5Context; | 
| 1026 |         result.resizeForOverwrite(s: 16); | 
| 1027 |         MD5Final(ctx: ©, digest: result.data()); | 
| 1028 |         break; | 
| 1029 |     } | 
| 1030 |     case QCryptographicHash::Sha224: { | 
| 1031 |         SHA224Context copy = sha224Context; | 
| 1032 |         result.resizeForOverwrite(s: SHA224HashSize); | 
| 1033 |         SHA224Result(context: ©, Message_Digest: result.data()); | 
| 1034 |         break; | 
| 1035 |     } | 
| 1036 |     case QCryptographicHash::Sha256: { | 
| 1037 |         SHA256Context copy = sha256Context; | 
| 1038 |         result.resizeForOverwrite(s: SHA256HashSize); | 
| 1039 |         SHA256Result(context: ©, Message_Digest: result.data()); | 
| 1040 |         break; | 
| 1041 |     } | 
| 1042 |     case QCryptographicHash::Sha384: { | 
| 1043 |         SHA384Context copy = sha384Context; | 
| 1044 |         result.resizeForOverwrite(s: SHA384HashSize); | 
| 1045 |         SHA384Result(context: ©, Message_Digest: result.data()); | 
| 1046 |         break; | 
| 1047 |     } | 
| 1048 |     case QCryptographicHash::Sha512: { | 
| 1049 |         SHA512Context copy = sha512Context; | 
| 1050 |         result.resizeForOverwrite(s: SHA512HashSize); | 
| 1051 |         SHA512Result(context: ©, Message_Digest: result.data()); | 
| 1052 |         break; | 
| 1053 |     } | 
| 1054 |     case QCryptographicHash::RealSha3_224: | 
| 1055 |     case QCryptographicHash::RealSha3_256: | 
| 1056 |     case QCryptographicHash::RealSha3_384: | 
| 1057 |     case QCryptographicHash::RealSha3_512: { | 
| 1058 |         SHA3Context copy = sha3Context; | 
| 1059 |         sha3Finish(ctx&: copy, result, bitCount: 8 * hashLengthInternal(method), sha3Variant: Sha3Variant::Sha3); | 
| 1060 |         break; | 
| 1061 |     } | 
| 1062 |     case QCryptographicHash::Keccak_224: | 
| 1063 |     case QCryptographicHash::Keccak_256: | 
| 1064 |     case QCryptographicHash::Keccak_384: | 
| 1065 |     case QCryptographicHash::Keccak_512: { | 
| 1066 |         SHA3Context copy = sha3Context; | 
| 1067 |         sha3Finish(ctx&: copy, result, bitCount: 8 * hashLengthInternal(method), sha3Variant: Sha3Variant::Keccak); | 
| 1068 |         break; | 
| 1069 |     } | 
| 1070 |     case QCryptographicHash::Blake2b_160: | 
| 1071 |     case QCryptographicHash::Blake2b_256: | 
| 1072 |     case QCryptographicHash::Blake2b_384: | 
| 1073 |     case QCryptographicHash::Blake2b_512: { | 
| 1074 |         const auto length = hashLengthInternal(method); | 
| 1075 |         blake2b_state copy = blake2bContext; | 
| 1076 |         result.resizeForOverwrite(s: length); | 
| 1077 |         blake2b_final(S: ©, out: result.data(), outlen: length); | 
| 1078 |         break; | 
| 1079 |     } | 
| 1080 |     case QCryptographicHash::Blake2s_128: | 
| 1081 |     case QCryptographicHash::Blake2s_160: | 
| 1082 |     case QCryptographicHash::Blake2s_224: | 
| 1083 |     case QCryptographicHash::Blake2s_256: { | 
| 1084 |         const auto length = hashLengthInternal(method); | 
| 1085 |         blake2s_state copy = blake2sContext; | 
| 1086 |         result.resizeForOverwrite(s: length); | 
| 1087 |         blake2s_final(S: ©, out: result.data(), outlen: length); | 
| 1088 |         break; | 
| 1089 |     } | 
| 1090 | #endif | 
| 1091 |     case QCryptographicHash::NumAlgorithms: | 
| 1092 |         Q_UNREACHABLE(); | 
| 1093 |     } | 
| 1094 | } | 
| 1095 | #endif // !USING_OPENSSL30 | 
| 1096 |  | 
| 1097 | /*! | 
| 1098 |   Returns the hash of \a data using \a method. | 
| 1099 |  | 
| 1100 |   \note In Qt versions prior to 6.3, this function took QByteArray, | 
| 1101 |   not QByteArrayView. | 
| 1102 |  | 
| 1103 |   \sa hashInto() | 
| 1104 | */ | 
| 1105 | QByteArray QCryptographicHash::hash(QByteArrayView data, Algorithm method) | 
| 1106 | { | 
| 1107 |     QByteArray ba(hashLengthInternal(method), Qt::Uninitialized); | 
| 1108 |     [[maybe_unused]] const auto r = hashInto(buffer: ba, data, method); | 
| 1109 |     Q_ASSERT(r.size() == ba.size()); | 
| 1110 |     return ba; | 
| 1111 | } | 
| 1112 |  | 
| 1113 | /*! | 
| 1114 |     \since 6.8 | 
| 1115 |     \fn QCryptographicHash::hashInto(QSpan<char> buffer, QSpan<const QByteArrayView> data, Algorithm method); | 
| 1116 |     \fn QCryptographicHash::hashInto(QSpan<uchar> buffer, QSpan<const QByteArrayView> data, Algorithm method); | 
| 1117 |     \fn QCryptographicHash::hashInto(QSpan<std::byte> buffer, QSpan<const QByteArrayView> data, Algorithm method); | 
| 1118 |     \fn QCryptographicHash::hashInto(QSpan<char> buffer, QByteArrayView data, Algorithm method); | 
| 1119 |     \fn QCryptographicHash::hashInto(QSpan<uchar> buffer, QByteArrayView data, Algorithm method); | 
| 1120 |     \fn QCryptographicHash::hashInto(QSpan<std::byte> buffer, QByteArrayView data, Algorithm method); | 
| 1121 |  | 
| 1122 |     Returns the hash of \a data using \a method, using \a buffer to store the result. | 
| 1123 |  | 
| 1124 |     If \a data is a span, adds all the byte array views to the hash, in the order given. | 
| 1125 |  | 
| 1126 |     The return value will be a sub-span of \a buffer, unless \a buffer is of | 
| 1127 |     insufficient size, in which case a null QByteArrayView is returned. | 
| 1128 |  | 
| 1129 |     \sa hash() | 
| 1130 | */ | 
| 1131 | QByteArrayView QCryptographicHash::hashInto(QSpan<std::byte> buffer, | 
| 1132 |                                             QSpan<const QByteArrayView> data, | 
| 1133 |                                             Algorithm method) noexcept | 
| 1134 | { | 
| 1135 |     if (buffer.size() < hashLengthInternal(method)) | 
| 1136 |         return {}; // buffer too small | 
| 1137 |  | 
| 1138 |     QCryptographicHashPrivate hash(method); | 
| 1139 |     for (QByteArrayView part : data) | 
| 1140 |         hash.addData(bytes: part); | 
| 1141 |     hash.finalizeUnchecked(); // no mutex needed: no-one but us has access to 'hash' | 
| 1142 |     auto result = hash.resultView(); | 
| 1143 |     Q_ASSERT(buffer.size() >= result.size()); | 
| 1144 |     // ### optimize: have the method directly write into `buffer` | 
| 1145 |     memcpy(dest: buffer.data(), src: result.data(), n: result.size()); | 
| 1146 |     return buffer.first(n: result.size()); | 
| 1147 | } | 
| 1148 |  | 
| 1149 | /*! | 
| 1150 |   Returns the size of the output of the selected hash \a method in bytes. | 
| 1151 |  | 
| 1152 |   \since 5.12 | 
| 1153 | */ | 
| 1154 | int QCryptographicHash::hashLength(QCryptographicHash::Algorithm method) | 
| 1155 | { | 
| 1156 |     return hashLengthInternal(method); | 
| 1157 | } | 
| 1158 |  | 
| 1159 | /*! | 
| 1160 |   Returns whether the selected algorithm \a method is supported and if | 
| 1161 |   result() will return a value when the \a method is used. | 
| 1162 |  | 
| 1163 |   \note OpenSSL will be responsible for providing this information when | 
| 1164 |   used as a provider, otherwise \c true will be returned as the non-OpenSSL | 
| 1165 |   implementation doesn't have any restrictions. | 
| 1166 |   We return \c false if we fail to query OpenSSL. | 
| 1167 |  | 
| 1168 |   \since 6.5 | 
| 1169 | */ | 
| 1170 |  | 
| 1171 |  | 
| 1172 | bool QCryptographicHash::supportsAlgorithm(QCryptographicHash::Algorithm method) | 
| 1173 | { | 
| 1174 |     return QCryptographicHashPrivate::supportsAlgorithm(method); | 
| 1175 | } | 
| 1176 |  | 
| 1177 | bool QCryptographicHashPrivate::supportsAlgorithm(QCryptographicHash::Algorithm method) | 
| 1178 | { | 
| 1179 | #ifdef USING_OPENSSL30 | 
| 1180 |     // OpenSSL doesn't support Blake2b{60,236,384} and Blake2s{128,160,224} | 
| 1181 |     // and these would automatically return FALSE in that case, while they are | 
| 1182 |     // actually supported by our non-OpenSSL implementation. | 
| 1183 |     if (useNonOpenSSLFallback(method)) | 
| 1184 |         return true; | 
| 1185 |  | 
| 1186 |     auto legacyProvider = OSSL_PROVIDER_ptr(OSSL_PROVIDER_load(nullptr, "legacy" )); | 
| 1187 |     auto defaultProvider = OSSL_PROVIDER_ptr(OSSL_PROVIDER_load(nullptr, "default" )); | 
| 1188 |  | 
| 1189 |     const char *restriction = "-fips" ; | 
| 1190 |     EVP_MD_ptr algorithm = EVP_MD_ptr(EVP_MD_fetch(nullptr, methodToName(method), restriction)); | 
| 1191 |  | 
| 1192 |     return algorithm != nullptr; | 
| 1193 | #else | 
| 1194 |     switch (method) { | 
| 1195 |     case QCryptographicHash::Sha1: | 
| 1196 | #ifndef QT_CRYPTOGRAPHICHASH_ONLY_SHA1 | 
| 1197 |     case QCryptographicHash::Md4: | 
| 1198 |     case QCryptographicHash::Md5: | 
| 1199 |     case QCryptographicHash::Sha224: | 
| 1200 |     case QCryptographicHash::Sha256: | 
| 1201 |     case QCryptographicHash::Sha384: | 
| 1202 |     case QCryptographicHash::Sha512: | 
| 1203 |     case QCryptographicHash::RealSha3_224: | 
| 1204 |     case QCryptographicHash::Keccak_224: | 
| 1205 |     case QCryptographicHash::RealSha3_256: | 
| 1206 |     case QCryptographicHash::Keccak_256: | 
| 1207 |     case QCryptographicHash::RealSha3_384: | 
| 1208 |     case QCryptographicHash::Keccak_384: | 
| 1209 |     case QCryptographicHash::RealSha3_512: | 
| 1210 |     case QCryptographicHash::Keccak_512: | 
| 1211 |     case QCryptographicHash::Blake2b_160: | 
| 1212 |     case QCryptographicHash::Blake2b_256: | 
| 1213 |     case QCryptographicHash::Blake2b_384: | 
| 1214 |     case QCryptographicHash::Blake2b_512: | 
| 1215 |     case QCryptographicHash::Blake2s_128: | 
| 1216 |     case QCryptographicHash::Blake2s_160: | 
| 1217 |     case QCryptographicHash::Blake2s_224: | 
| 1218 |     case QCryptographicHash::Blake2s_256: | 
| 1219 | #endif | 
| 1220 |         return true; | 
| 1221 |     case QCryptographicHash::NumAlgorithms: ; | 
| 1222 |     }; | 
| 1223 |     return false; | 
| 1224 | #endif // !USING_OPENSSL3 | 
| 1225 | } | 
| 1226 |  | 
| 1227 | static constexpr int qt_hash_block_size(QCryptographicHash::Algorithm method) | 
| 1228 | { | 
| 1229 |     switch (method) { | 
| 1230 |     case QCryptographicHash::Sha1: | 
| 1231 |         return SHA1_Message_Block_Size; | 
| 1232 | #ifndef QT_CRYPTOGRAPHICHASH_ONLY_SHA1 | 
| 1233 |     case QCryptographicHash::Md4: | 
| 1234 |         return 64; | 
| 1235 |     case QCryptographicHash::Md5: | 
| 1236 |         return 64; | 
| 1237 |     case QCryptographicHash::Sha224: | 
| 1238 |         return SHA224_Message_Block_Size; | 
| 1239 |     case QCryptographicHash::Sha256: | 
| 1240 |         return SHA256_Message_Block_Size; | 
| 1241 |     case QCryptographicHash::Sha384: | 
| 1242 |         return SHA384_Message_Block_Size; | 
| 1243 |     case QCryptographicHash::Sha512: | 
| 1244 |         return SHA512_Message_Block_Size; | 
| 1245 |     case QCryptographicHash::RealSha3_224: | 
| 1246 |     case QCryptographicHash::Keccak_224: | 
| 1247 |         return 144; | 
| 1248 |     case QCryptographicHash::RealSha3_256: | 
| 1249 |     case QCryptographicHash::Keccak_256: | 
| 1250 |         return 136; | 
| 1251 |     case QCryptographicHash::RealSha3_384: | 
| 1252 |     case QCryptographicHash::Keccak_384: | 
| 1253 |         return 104; | 
| 1254 |     case QCryptographicHash::RealSha3_512: | 
| 1255 |     case QCryptographicHash::Keccak_512: | 
| 1256 |         return 72; | 
| 1257 |     case QCryptographicHash::Blake2b_160: | 
| 1258 |     case QCryptographicHash::Blake2b_256: | 
| 1259 |     case QCryptographicHash::Blake2b_384: | 
| 1260 |     case QCryptographicHash::Blake2b_512: | 
| 1261 |         return BLAKE2B_BLOCKBYTES; | 
| 1262 |     case QCryptographicHash::Blake2s_128: | 
| 1263 |     case QCryptographicHash::Blake2s_160: | 
| 1264 |     case QCryptographicHash::Blake2s_224: | 
| 1265 |     case QCryptographicHash::Blake2s_256: | 
| 1266 |         return BLAKE2S_BLOCKBYTES; | 
| 1267 | #endif // QT_CRYPTOGRAPHICHASH_ONLY_SHA1 | 
| 1268 |     case QCryptographicHash::NumAlgorithms: | 
| 1269 | #if !defined(Q_CC_GNU_ONLY) || Q_CC_GNU >= 900 | 
| 1270 |         // GCC 8 has trouble with Q_UNREACHABLE() in constexpr functions | 
| 1271 |         Q_UNREACHABLE(); | 
| 1272 | #endif | 
| 1273 |         break; | 
| 1274 |     } | 
| 1275 |     return 0; | 
| 1276 | } | 
| 1277 |  | 
| 1278 | constexpr int maxHashBlockSize() | 
| 1279 | { | 
| 1280 |     int result = 0; | 
| 1281 |     using A = QCryptographicHash::Algorithm; | 
| 1282 |     for (int i = 0; i < A::NumAlgorithms ; ++i) | 
| 1283 |         result = std::max(a: result, b: qt_hash_block_size(method: A(i))); | 
| 1284 |     return result; | 
| 1285 | } | 
| 1286 |  | 
| 1287 | [[maybe_unused]] | 
| 1288 | constexpr int minHashBlockSize() | 
| 1289 | { | 
| 1290 |     int result = INT_MAX; | 
| 1291 |     using A = QCryptographicHash::Algorithm; | 
| 1292 |     for (int i = 0; i < A::NumAlgorithms ; ++i) | 
| 1293 |         result = std::min(a: result, b: qt_hash_block_size(method: A(i))); | 
| 1294 |     return result; | 
| 1295 | } | 
| 1296 |  | 
| 1297 | [[maybe_unused]] | 
| 1298 | constexpr int gcdHashBlockSize() | 
| 1299 | { | 
| 1300 |     int result = 0; | 
| 1301 |     using A = QCryptographicHash::Algorithm; | 
| 1302 |     for (int i = 0; i < A::NumAlgorithms ; ++i) | 
| 1303 |         result = std::gcd(m: result, n: qt_hash_block_size(method: A(i))); | 
| 1304 |     return result; | 
| 1305 | } | 
| 1306 |  | 
| 1307 | using HashBlock = QSmallByteArray<maxHashBlockSize()>; | 
| 1308 |  | 
| 1309 | static HashBlock xored(const HashBlock &block, quint8 val) noexcept | 
| 1310 | { | 
| 1311 |     // some hints for the optimizer: | 
| 1312 |     Q_ASSERT(block.size() >= minHashBlockSize()); | 
| 1313 |     Q_ASSERT(block.size() <= maxHashBlockSize()); | 
| 1314 |     Q_ASSERT(block.size() % gcdHashBlockSize() == 0); | 
| 1315 |     HashBlock result; | 
| 1316 |     result.resizeForOverwrite(s: block.size()); | 
| 1317 |     for (qsizetype i = 0; i < block.size(); ++i) | 
| 1318 |         result[i] = block[i] ^ val; | 
| 1319 |     return result; | 
| 1320 | } | 
| 1321 |  | 
| 1322 | class QMessageAuthenticationCodePrivate | 
| 1323 | { | 
| 1324 | public: | 
| 1325 |     explicit QMessageAuthenticationCodePrivate(QCryptographicHash::Algorithm m) noexcept | 
| 1326 |         : messageHash(m) | 
| 1327 |     { | 
| 1328 |     } | 
| 1329 |  | 
| 1330 |     HashBlock key; | 
| 1331 |     QCryptographicHashPrivate messageHash; | 
| 1332 |  | 
| 1333 |     void setKey(QByteArrayView k) noexcept; | 
| 1334 |     void initMessageHash() noexcept; | 
| 1335 |     void finalize(); | 
| 1336 |  | 
| 1337 |     // when not called from the static hash() function, this function needs to be | 
| 1338 |     // called with messageHash.finalizeMutex held: | 
| 1339 |     void finalizeUnchecked() noexcept; | 
| 1340 |     // END functions that need to be called with finalizeMutex held | 
| 1341 | }; | 
| 1342 |  | 
| 1343 | /*! | 
| 1344 |     \internal | 
| 1345 |  | 
| 1346 |     Transforms key \a newKey into a block-sized format and stores it in member | 
| 1347 |     \c key. | 
| 1348 |  | 
| 1349 |     This function assumes it can use messageHash (i.e. it's in its initial | 
| 1350 |     state (reset() has been called)). | 
| 1351 | */ | 
| 1352 | void QMessageAuthenticationCodePrivate::setKey(QByteArrayView newKey) noexcept | 
| 1353 | { | 
| 1354 |     const int blockSize = qt_hash_block_size(method: messageHash.method); | 
| 1355 |  | 
| 1356 |     if (newKey.size() > blockSize) { | 
| 1357 |         messageHash.addData(bytes: newKey); | 
| 1358 |         messageHash.finalizeUnchecked(); | 
| 1359 |         static_assert([] { | 
| 1360 |                 using A = QCryptographicHash::Algorithm; | 
| 1361 |                 for (int i = 0; i < A::NumAlgorithms; ++i) { | 
| 1362 |                     if (hashLengthInternal(method: A(i)) > qt_hash_block_size(method: A(i))) | 
| 1363 |                         return false; | 
| 1364 |                 } | 
| 1365 |                 return true; | 
| 1366 |             }(), "this code assumes that a hash's result always fits into that hash's block size" ); | 
| 1367 |         key = messageHash.result; | 
| 1368 |         messageHash.reset(); | 
| 1369 |     } else { | 
| 1370 |         key.assign(c: newKey); | 
| 1371 |     } | 
| 1372 |  | 
| 1373 |     if (key.size() < blockSize) | 
| 1374 |         key.resize(s: blockSize, v: '\0'); | 
| 1375 |  | 
| 1376 |     initMessageHash(); | 
| 1377 | } | 
| 1378 |  | 
| 1379 | /*! | 
| 1380 |     \internal | 
| 1381 |  | 
| 1382 |     Seeds messageHash from \c key. | 
| 1383 |  | 
| 1384 |     This function assumes that messageHash is in its initial state (reset() has | 
| 1385 |     been called). | 
| 1386 | */ | 
| 1387 | void QMessageAuthenticationCodePrivate::initMessageHash() noexcept | 
| 1388 | { | 
| 1389 |     messageHash.addData(bytes: xored(block: key, val: 0x36)); | 
| 1390 | } | 
| 1391 |  | 
| 1392 | /*! | 
| 1393 |     \class QMessageAuthenticationCode | 
| 1394 |     \inmodule QtCore | 
| 1395 |  | 
| 1396 |     \brief The QMessageAuthenticationCode class provides a way to generate | 
| 1397 |     hash-based message authentication codes. | 
| 1398 |  | 
| 1399 |     \since 5.1 | 
| 1400 |  | 
| 1401 |     \ingroup tools | 
| 1402 |     \reentrant | 
| 1403 |  | 
| 1404 |     Use the QMessageAuthenticationCode class to generate hash-based message | 
| 1405 |     authentication codes (HMACs). The class supports all cryptographic | 
| 1406 |     hash algorithms from \l QCryptographicHash (see also | 
| 1407 |     \l{QCryptographicHash::Algorithm}). | 
| 1408 |  | 
| 1409 |     To generate a message authentication code, pass a suitable hash | 
| 1410 |     algorithm and secret key to the constructor. Then process the message | 
| 1411 |     data by calling \l addData() one or more times. After the full | 
| 1412 |     message has been processed, get the final authentication code | 
| 1413 |     via the \l result() function: | 
| 1414 |  | 
| 1415 |     \snippet qmessageauthenticationcode/main.cpp 0 | 
| 1416 |     \dots | 
| 1417 |     \snippet qmessageauthenticationcode/main.cpp 1 | 
| 1418 |  | 
| 1419 |     For simple cases like above, you can also use the static | 
| 1420 |     \l hash() function: | 
| 1421 |  | 
| 1422 |     \snippet qmessageauthenticationcode/main.cpp 2 | 
| 1423 |  | 
| 1424 |  | 
| 1425 |     \note The cryptographic strength of the HMAC depends upon the | 
| 1426 |     size of the secret key, and the security of the | 
| 1427 |     underlying hash function. | 
| 1428 |  | 
| 1429 |     \sa QCryptographicHash, QCryptographicHash::Algorithm | 
| 1430 | */ | 
| 1431 |  | 
| 1432 | /*! | 
| 1433 |     Constructs an object that can be used to create a cryptographic hash from data | 
| 1434 |     using method \a method and key \a key. | 
| 1435 |  | 
| 1436 | //! [qba-to-qbav-6.6] | 
| 1437 |     \note In Qt versions prior to 6.6, this function took its arguments as | 
| 1438 |     QByteArray, not QByteArrayView. If you experience compile errors, it's | 
| 1439 |     because your code is passing objects that are implicitly convertible to | 
| 1440 |     QByteArray, but not QByteArrayView. Wrap the corresponding argument in | 
| 1441 |     \c{QByteArray{~~~}} to make the cast explicit. This is backwards-compatible | 
| 1442 |     with old Qt versions. | 
| 1443 | //! [qba-to-qbav-6.6] | 
| 1444 | */ | 
| 1445 | QMessageAuthenticationCode::QMessageAuthenticationCode(QCryptographicHash::Algorithm method, | 
| 1446 |                                                        QByteArrayView key) | 
| 1447 |     : d(new QMessageAuthenticationCodePrivate(method)) | 
| 1448 | { | 
| 1449 |     d->setKey(key); | 
| 1450 | } | 
| 1451 |  | 
| 1452 | /*! | 
| 1453 |     Destroys the object. | 
| 1454 | */ | 
| 1455 | QMessageAuthenticationCode::~QMessageAuthenticationCode() | 
| 1456 | { | 
| 1457 |     delete d; | 
| 1458 | } | 
| 1459 |  | 
| 1460 | /*! | 
| 1461 |     \fn QMessageAuthenticationCode::QMessageAuthenticationCode(QMessageAuthenticationCode &&other) | 
| 1462 |  | 
| 1463 |     Move-constructs a new QMessageAuthenticationCode from \a other. | 
| 1464 |  | 
| 1465 |     \note The moved-from object \a other is placed in a | 
| 1466 |     partially-formed state, in which the only valid operations are | 
| 1467 |     destruction and assignment of a new object. | 
| 1468 |  | 
| 1469 |     \since 6.6 | 
| 1470 | */ | 
| 1471 |  | 
| 1472 | /*! | 
| 1473 |     \fn QMessageAuthenticationCode &QMessageAuthenticationCode::operator=(QMessageAuthenticationCode &&other) | 
| 1474 |  | 
| 1475 |     Move-assigns \a other to this QMessageAuthenticationCode instance. | 
| 1476 |  | 
| 1477 |     \note The moved-from object \a other is placed in a | 
| 1478 |     partially-formed state, in which the only valid operations are | 
| 1479 |     destruction and assignment of a new object. | 
| 1480 |  | 
| 1481 |     \since 6.6 | 
| 1482 | */ | 
| 1483 |  | 
| 1484 | /*! | 
| 1485 |     \fn void QMessageAuthenticationCode::swap(QMessageAuthenticationCode &other) | 
| 1486 |     \memberswap{message authentication code} | 
| 1487 |     \since 6.6 | 
| 1488 | */ | 
| 1489 |  | 
| 1490 | /*! | 
| 1491 |     Resets message data. Calling this function doesn't affect the key. | 
| 1492 | */ | 
| 1493 | void QMessageAuthenticationCode::reset() noexcept | 
| 1494 | { | 
| 1495 |     d->messageHash.reset(); | 
| 1496 |     d->initMessageHash(); | 
| 1497 | } | 
| 1498 |  | 
| 1499 | /*! | 
| 1500 |     Sets secret \a key. Calling this function automatically resets the object state. | 
| 1501 |  | 
| 1502 |     For optimal performance, call this function only to \e change the active key, | 
| 1503 |     not to set an \e initial key, as in | 
| 1504 |  | 
| 1505 |     \code | 
| 1506 |     QMessageAuthenticationCode mac(method); | 
| 1507 |     mac.setKey(key); // does extra work | 
| 1508 |     use(mac); | 
| 1509 |     \endcode | 
| 1510 |  | 
| 1511 |     Prefer to pass initial keys as the constructor argument: | 
| 1512 |  | 
| 1513 |     \code | 
| 1514 |     QMessageAuthenticationCode mac(method, key); // OK, optimal | 
| 1515 |     use(mac); | 
| 1516 |     \endcode | 
| 1517 |  | 
| 1518 |     You can use std::optional to delay construction of a | 
| 1519 |     QMessageAuthenticationCode until you know the key: | 
| 1520 |  | 
| 1521 |     \code | 
| 1522 |     std::optional<QMessageAuthenticationCode> mac; | 
| 1523 |     ~~~ | 
| 1524 |     key = ~~~; | 
| 1525 |     mac.emplace(method, key); | 
| 1526 |     use(*mac); | 
| 1527 |     \endcode | 
| 1528 |  | 
| 1529 |     \include qcryptographichash.cpp {qba-to-qbav-6.6} | 
| 1530 | */ | 
| 1531 | void QMessageAuthenticationCode::setKey(QByteArrayView key) noexcept | 
| 1532 | { | 
| 1533 |     d->messageHash.reset(); | 
| 1534 |     d->setKey(key); | 
| 1535 | } | 
| 1536 |  | 
| 1537 | /*! | 
| 1538 |     \overload | 
| 1539 |     Adds the first \a length chars of \a data to the message. | 
| 1540 | */ | 
| 1541 | void QMessageAuthenticationCode::addData(const char *data, qsizetype length) | 
| 1542 | { | 
| 1543 |     d->messageHash.addData(bytes: {data, length}); | 
| 1544 | } | 
| 1545 |  | 
| 1546 | /*! | 
| 1547 |     Adds \a data to the message. | 
| 1548 |  | 
| 1549 |     \include qcryptographichash.cpp {qba-to-qbav-6.6} | 
| 1550 |  | 
| 1551 |     \sa resultView(), result() | 
| 1552 | */ | 
| 1553 | void QMessageAuthenticationCode::addData(QByteArrayView data) noexcept | 
| 1554 | { | 
| 1555 |     d->messageHash.addData(bytes: data); | 
| 1556 | } | 
| 1557 |  | 
| 1558 | /*! | 
| 1559 |     Reads the data from the open QIODevice \a device until it ends | 
| 1560 |     and adds it to message. Returns \c true if reading was successful. | 
| 1561 |  | 
| 1562 |     \note \a device must be already opened. | 
| 1563 |  */ | 
| 1564 | bool QMessageAuthenticationCode::addData(QIODevice *device) | 
| 1565 | { | 
| 1566 |     return d->messageHash.addData(device); | 
| 1567 | } | 
| 1568 |  | 
| 1569 | /*! | 
| 1570 |     \since 6.6 | 
| 1571 |  | 
| 1572 |     Returns the final hash value. | 
| 1573 |  | 
| 1574 |     Note that the returned view remains valid only as long as the | 
| 1575 |     QMessageAuthenticationCode object is not modified by other means. | 
| 1576 |  | 
| 1577 |     \sa result() | 
| 1578 | */ | 
| 1579 | QByteArrayView QMessageAuthenticationCode::resultView() const noexcept | 
| 1580 | { | 
| 1581 |     d->finalize(); | 
| 1582 |     return d->messageHash.resultView(); | 
| 1583 | } | 
| 1584 |  | 
| 1585 | /*! | 
| 1586 |     Returns the final authentication code. | 
| 1587 |  | 
| 1588 |     \sa resultView(), QByteArray::toHex() | 
| 1589 | */ | 
| 1590 | QByteArray QMessageAuthenticationCode::result() const | 
| 1591 | { | 
| 1592 |     return resultView().toByteArray(); | 
| 1593 | } | 
| 1594 |  | 
| 1595 | void QMessageAuthenticationCodePrivate::finalize() | 
| 1596 | { | 
| 1597 |     const auto lock = qt_scoped_lock(mutex&: messageHash.finalizeMutex); | 
| 1598 |     if (!messageHash.result.isEmpty()) | 
| 1599 |         return; | 
| 1600 |     finalizeUnchecked(); | 
| 1601 | } | 
| 1602 |  | 
| 1603 | void QMessageAuthenticationCodePrivate::finalizeUnchecked() noexcept | 
| 1604 | { | 
| 1605 |     messageHash.finalizeUnchecked(); | 
| 1606 |     const HashResult hashedMessage = messageHash.result; | 
| 1607 |  | 
| 1608 |     messageHash.reset(); | 
| 1609 |     messageHash.addData(bytes: xored(block: key, val: 0x5c)); | 
| 1610 |     messageHash.addData(bytes: hashedMessage); | 
| 1611 |     messageHash.finalizeUnchecked(); | 
| 1612 | } | 
| 1613 |  | 
| 1614 | /*! | 
| 1615 |     Returns the authentication code for the message \a message using | 
| 1616 |     the key \a key and the method \a method. | 
| 1617 |  | 
| 1618 |     \include qcryptographichash.cpp {qba-to-qbav-6.6} | 
| 1619 |  | 
| 1620 |     \sa hashInto() | 
| 1621 | */ | 
| 1622 | QByteArray QMessageAuthenticationCode::hash(QByteArrayView message, QByteArrayView key, | 
| 1623 |                                             QCryptographicHash::Algorithm method) | 
| 1624 | { | 
| 1625 |     QByteArray ba(hashLengthInternal(method), Qt::Uninitialized); | 
| 1626 |     [[maybe_unused]] const auto r = hashInto(buffer: ba, message, key, method); | 
| 1627 |     Q_ASSERT(r.size() == ba.size()); | 
| 1628 |     return ba; | 
| 1629 | } | 
| 1630 |  | 
| 1631 | /*! | 
| 1632 |     \since 6.8 | 
| 1633 |     \fn QMessageAuthenticationCode::hashInto(QSpan<char> buffer, QSpan<const QByteArrayView> messageParts, QByteArrayView key, QCryptographicHash::Algorithm method); | 
| 1634 |     \fn QMessageAuthenticationCode::hashInto(QSpan<uchar> buffer, QSpan<const QByteArrayView> messageParts, QByteArrayView key, QCryptographicHash::Algorithm method); | 
| 1635 |     \fn QMessageAuthenticationCode::hashInto(QSpan<std::byte> buffer, QSpan<const QByteArrayView> messageParts, QByteArrayView key, QCryptographicHash::Algorithm method); | 
| 1636 |     \fn QMessageAuthenticationCode::hashInto(QSpan<char> buffer, QByteArrayView message, QByteArrayView key, QCryptographicHash::Algorithm method); | 
| 1637 |     \fn QMessageAuthenticationCode::hashInto(QSpan<uchar> buffer, QByteArrayView message, QByteArrayView key, QCryptographicHash::Algorithm method); | 
| 1638 |     \fn QMessageAuthenticationCode::hashInto(QSpan<std::byte> buffer, QByteArrayView message, QByteArrayView key, QCryptographicHash::Algorithm method); | 
| 1639 |  | 
| 1640 |     Returns the authentication code for the message (\a message or, for the | 
| 1641 |     QSpan overloads, the concatenation of \a messageParts) using the key \a key | 
| 1642 |     and the method \a method. | 
| 1643 |  | 
| 1644 |     The return value will be a sub-span of \a buffer, unless \a buffer is of | 
| 1645 |     insufficient size, in which case a null QByteArrayView is returned. | 
| 1646 |  | 
| 1647 |     \sa hash() | 
| 1648 | */ | 
| 1649 | QByteArrayView QMessageAuthenticationCode::hashInto(QSpan<std::byte> buffer, | 
| 1650 |                                                     QSpan<const QByteArrayView> messageParts, | 
| 1651 |                                                     QByteArrayView key, | 
| 1652 |                                                     QCryptographicHash::Algorithm method) noexcept | 
| 1653 | { | 
| 1654 |     QMessageAuthenticationCodePrivate mac(method); | 
| 1655 |     mac.setKey(key); | 
| 1656 |     for (QByteArrayView part : messageParts) | 
| 1657 |         mac.messageHash.addData(bytes: part); | 
| 1658 |     mac.finalizeUnchecked(); | 
| 1659 |     auto result = mac.messageHash.resultView(); | 
| 1660 |     if (buffer.size() < result.size()) | 
| 1661 |         return {}; // buffer too small | 
| 1662 |     // ### optimize: have the method directly write into `buffer` | 
| 1663 |     memcpy(dest: buffer.data(), src: result.data(), n: result.size()); | 
| 1664 |     return buffer.first(n: result.size()); | 
| 1665 | } | 
| 1666 |  | 
| 1667 | QT_END_NAMESPACE | 
| 1668 |  | 
| 1669 | #ifndef QT_NO_QOBJECT | 
| 1670 | #include "moc_qcryptographichash.cpp" | 
| 1671 | #endif | 
| 1672 |  |