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