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
36typedef unsigned char BitSequence;
37typedef unsigned long long DataLength;
38typedef 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"
45typedef spongeState hashState;
46
47#include "../../3rdparty/sha3/KeccakNISTInterface.c"
48
49/*
50 This lets us choose between SHA3 implementations at build time.
51 */
52typedef spongeState SHA3Context;
53typedef HashReturn (SHA3Init)(hashState *state, int hashbitlen);
54typedef HashReturn (SHA3Update)(hashState *state, const BitSequence *data, DataLength databitlen);
55typedef 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
61Q_CONSTINIT static SHA3Init * const sha3Init = Init;
62Q_CONSTINIT static SHA3Update * const sha3Update = Update;
63Q_CONSTINIT static SHA3Final * const sha3Final = Final;
64
65#else // 32 bit optimised fallback
66
67#include "../../3rdparty/sha3/KeccakF-1600-opt32.c"
68
69Q_CONSTINIT static SHA3Init * const sha3Init = Init;
70Q_CONSTINIT static SHA3Update * const sha3Update = Update;
71Q_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*/
86static int SHA224_256AddLength(SHA256Context *context, unsigned int length);
87static 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
97static inline int SHA224_256AddLength(SHA256Context *context, unsigned int length)
98{
99 uint32_t addTemp;
100 return SHA224_256AddLengthM(context, length);
101}
102static 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
114QT_WARNING_PUSH
115QT_WARNING_DISABLE_CLANG("-Wunused-function")
116QT_WARNING_DISABLE_GCC("-Wunused-function")
117QT_WARNING_DISABLE_MSVC(4505)
118#include "../../3rdparty/blake2/src/blake2b-ref.c"
119#include "../../3rdparty/blake2/src/blake2s-ref.c"
120QT_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
130QT_BEGIN_NAMESPACE
131
132static 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
177static 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
186using HashResult = QSmallByteArray<maxHashLength()>;
187
188#ifdef USING_OPENSSL30
189static 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*/
230static 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
243class QCryptographicHashPrivate
244{
245public:
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
338void 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*/
436QCryptographicHash::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*/
456QCryptographicHash::~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*/
482void 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*/
492QCryptographicHash::Algorithm QCryptographicHash::algorithm() const noexcept
493{
494 return d->method;
495}
496
497#ifdef USING_OPENSSL30
498
499QCryptographicHashPrivate::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
522void 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
538QCryptographicHashPrivate::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
577QCryptographicHashPrivate::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
636void 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
642void QCryptographicHashPrivate::reset() noexcept
643{
644 result.clear();
645 state.reset(method);
646}
647
648#ifdef USING_OPENSSL30
649
650void 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
670void 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
684void 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*/
752void 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*/
765void QCryptographicHash::addData(QByteArrayView bytes) noexcept
766{
767 d->addData(bytes);
768}
769
770void QCryptographicHashPrivate::addData(QByteArrayView bytes) noexcept
771{
772 state.addData(method, data: bytes);
773 result.clear();
774}
775
776#ifdef USING_OPENSSL30
777
778void 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
806void 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 */
884bool QCryptographicHash::addData(QIODevice *device)
885{
886 return d->addData(dev: device);
887}
888
889bool 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*/
912QByteArray 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*/
927QByteArrayView 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*/
940void 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*/
955void QCryptographicHashPrivate::finalizeUnchecked() noexcept
956{
957 state.finalizeUnchecked(method, result);
958}
959
960#ifdef USING_OPENSSL30
961void 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(&copy, 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(&copy, result.data(), length);
984 } else {
985 evp.finalizeUnchecked(result);
986 }
987}
988
989void 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
1001void 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: &copy);
1009 sha1ToHash(state: &copy, 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: &copy, result: result.data());
1022 break;
1023 }
1024 case QCryptographicHash::Md5: {
1025 MD5Context copy = md5Context;
1026 result.resizeForOverwrite(s: 16);
1027 MD5Final(ctx: &copy, digest: result.data());
1028 break;
1029 }
1030 case QCryptographicHash::Sha224: {
1031 SHA224Context copy = sha224Context;
1032 result.resizeForOverwrite(s: SHA224HashSize);
1033 SHA224Result(context: &copy, Message_Digest: result.data());
1034 break;
1035 }
1036 case QCryptographicHash::Sha256: {
1037 SHA256Context copy = sha256Context;
1038 result.resizeForOverwrite(s: SHA256HashSize);
1039 SHA256Result(context: &copy, Message_Digest: result.data());
1040 break;
1041 }
1042 case QCryptographicHash::Sha384: {
1043 SHA384Context copy = sha384Context;
1044 result.resizeForOverwrite(s: SHA384HashSize);
1045 SHA384Result(context: &copy, Message_Digest: result.data());
1046 break;
1047 }
1048 case QCryptographicHash::Sha512: {
1049 SHA512Context copy = sha512Context;
1050 result.resizeForOverwrite(s: SHA512HashSize);
1051 SHA512Result(context: &copy, 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: &copy, 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: &copy, 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*/
1105QByteArray 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*/
1131QByteArrayView 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*/
1154int 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
1172bool QCryptographicHash::supportsAlgorithm(QCryptographicHash::Algorithm method)
1173{
1174 return QCryptographicHashPrivate::supportsAlgorithm(method);
1175}
1176
1177bool 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
1227static 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
1278constexpr 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]]
1288constexpr 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]]
1298constexpr 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
1307using HashBlock = QSmallByteArray<maxHashBlockSize()>;
1308
1309static 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
1322class QMessageAuthenticationCodePrivate
1323{
1324public:
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*/
1352void 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*/
1387void 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*/
1445QMessageAuthenticationCode::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*/
1455QMessageAuthenticationCode::~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*/
1493void 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*/
1531void 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*/
1541void 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*/
1553void 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 */
1564bool 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*/
1579QByteArrayView 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*/
1590QByteArray QMessageAuthenticationCode::result() const
1591{
1592 return resultView().toByteArray();
1593}
1594
1595void QMessageAuthenticationCodePrivate::finalize()
1596{
1597 const auto lock = qt_scoped_lock(mutex&: messageHash.finalizeMutex);
1598 if (!messageHash.result.isEmpty())
1599 return;
1600 finalizeUnchecked();
1601}
1602
1603void 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*/
1622QByteArray 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*/
1649QByteArrayView 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
1667QT_END_NAMESPACE
1668
1669#ifndef QT_NO_QOBJECT
1670#include "moc_qcryptographichash.cpp"
1671#endif
1672

source code of qtbase/src/corelib/tools/qcryptographichash.cpp