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