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#if QT_CONFIG(system_libb2)
105#include <blake2.h>
106#else
107QT_WARNING_PUSH
108QT_WARNING_DISABLE_CLANG("-Wunused-function")
109QT_WARNING_DISABLE_GCC("-Wunused-function")
110QT_WARNING_DISABLE_MSVC(4505)
111#include "../../3rdparty/blake2/src/blake2b-ref.c"
112#include "../../3rdparty/blake2/src/blake2s-ref.c"
114#endif
115
116#if !defined(QT_BOOTSTRAPPED) && QT_CONFIG(openssl_hash)
117#define USING_OPENSSL30
118#include <openssl/evp.h>
119#include <openssl/provider.h>
120#endif
121
123
124static constexpr int hashLengthInternal(QCryptographicHash::Algorithm method) noexcept
125{
126 switch (method) {
127#define CASE(Enum, Size)
128 case QCryptographicHash:: Enum :
129 return Size
130 /*end*/
131 CASE(Sha1, 20);
132 CASE(Md4, 16);
133 CASE(Md5, 16);
134 CASE(Sha224, SHA224HashSize);
135 CASE(Sha256, SHA256HashSize);
136 CASE(Sha384, SHA384HashSize);
137 CASE(Sha512, SHA512HashSize);
138 CASE(Blake2s_128, 128 / 8);
139 case QCryptographicHash::Blake2b_160:
140 case QCryptographicHash::Blake2s_160:
141 return 160 / 8;
142 case QCryptographicHash::RealSha3_224:
143 case QCryptographicHash::Keccak_224:
144 case QCryptographicHash::Blake2s_224:
145 return 224 / 8;
146 case QCryptographicHash::RealSha3_256:
147 case QCryptographicHash::Keccak_256:
148 case QCryptographicHash::Blake2b_256:
149 case QCryptographicHash::Blake2s_256:
150 return 256 / 8;
151 case QCryptographicHash::RealSha3_384:
152 case QCryptographicHash::Keccak_384:
153 case QCryptographicHash::Blake2b_384:
154 return 384 / 8;
155 case QCryptographicHash::RealSha3_512:
156 case QCryptographicHash::Keccak_512:
157 case QCryptographicHash::Blake2b_512:
158 return 512 / 8;
159#undef CASE
160 case QCryptographicHash::NumAlgorithms: ;
161 // fall through
162 // Q_UNREACHABLE() would be BiC here, as hashLength(~~invalid~~) worked in 6.4
163 }
164 return 0;
165}
166
167static constexpr int maxHashLength()
168{
169 int result = 0;
170 using A = QCryptographicHash::Algorithm;
171 for (int i = 0; i < A::NumAlgorithms; ++i)
172 result = std::max(result, hashLengthInternal(A(i)));
173 return result;
174}
175
176using HashResult = QSmallByteArray<maxHashLength()>;
177
178#ifdef USING_OPENSSL30
179static constexpr const char * methodToName(QCryptographicHash::Algorithm method) noexcept
180{
181 switch (method) {
182#define CASE(Enum, Name)
183 case QCryptographicHash:: Enum :
184 return Name
185 /*end*/
186 CASE(Sha1, "SHA1");
187 CASE(Md4, "MD4");
188 CASE(Md5, "MD5");
189 CASE(Sha224, "SHA224");
190 CASE(Sha256, "SHA256");
191 CASE(Sha384, "SHA384");
192 CASE(Sha512, "SHA512");
193 CASE(RealSha3_224, "SHA3-224");
194 CASE(RealSha3_256, "SHA3-256");
195 CASE(RealSha3_384, "SHA3-384");
196 CASE(RealSha3_512, "SHA3-512");
197 CASE(Blake2b_512, "BLAKE2B512");
198 CASE(Blake2s_256, "BLAKE2S256");
199 // not supported by OpenSSL:
200 CASE(Keccak_224, nullptr);
201 CASE(Keccak_256, nullptr);
202 CASE(Keccak_384, nullptr);
203 CASE(Keccak_512, nullptr);
204 CASE(Blake2b_160, nullptr);
205 CASE(Blake2b_256, nullptr);
206 CASE(Blake2b_384, nullptr);
207 CASE(Blake2s_128, nullptr);
208 CASE(Blake2s_160, nullptr);
209 CASE(Blake2s_224, nullptr);
210 CASE(NumAlgorithms, nullptr);
211#undef CASE
212 }
213 return nullptr;
214}
215#endif // USING_OPENSSL30
216
218{
219public:
225 {
226 state.destroy(method);
227 }
228
229 void reset() noexcept;
230 void addData(QByteArrayView bytes) noexcept;
231 bool addData(QIODevice *dev);
232 void finalize() noexcept;
233 // when not called from the static hash() function, this function needs to be
234 // called with finalizeMutex held (finalize() will do that):
235 void finalizeUnchecked() noexcept;
236 QSpan<uchar> finalizeUnchecked(QSpan<uchar> buffer) noexcept;
237
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(QSpan<uchar> buffer) 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, QSpan<uchar> 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, QSpan<uchar> 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/*!
985 \internal
986
987 Must be called with finalizeMutex held, except when called from the static
988 hash() function, where no sharing can take place.
989*/
991{
992 buffer = buffer.first(hashLengthInternal(method));
993 state.finalizeUnchecked(method, buffer);
994 Q_ASSERT(result.size() == 0); // internal buffer wasn't used
995 return buffer;
996}
997
998#ifdef USING_OPENSSL30
999void QCryptographicHashPrivate::State::finalizeUnchecked(QCryptographicHash::Algorithm method,
1000 QSpan<uchar> result) noexcept
1001{
1002 switch (method) {
1003 case QCryptographicHash::Keccak_224:
1004 case QCryptographicHash::Keccak_256:
1005 case QCryptographicHash::Keccak_384:
1006 case QCryptographicHash::Keccak_512: {
1007 SHA3Context copy = sha3Context;
1008 sha3Finish(copy, result, Sha3Variant::Keccak);
1009 break;
1010 }
1011 case QCryptographicHash::Blake2b_160:
1012 case QCryptographicHash::Blake2b_256:
1013 case QCryptographicHash::Blake2b_384: {
1014 const auto length = hashLengthInternal(method);
1015 blake2b_state copy = blake2bContext;
1016 blake2b_final(&copy, result.data(), length);
1017 break;
1018 }
1019 case QCryptographicHash::Blake2s_128:
1020 case QCryptographicHash::Blake2s_160:
1021 case QCryptographicHash::Blake2s_224: {
1022 const auto length = hashLengthInternal(method);
1023 blake2s_state copy = blake2sContext;
1024 blake2s_final(&copy, result.data(), length);
1025 break;
1026 }
1027 case QCryptographicHash::Sha1:
1028 case QCryptographicHash::Md4:
1029 case QCryptographicHash::Md5:
1030 case QCryptographicHash::Sha224:
1031 case QCryptographicHash::Sha256:
1032 case QCryptographicHash::Sha384:
1033 case QCryptographicHash::Sha512:
1034 case QCryptographicHash::RealSha3_224:
1035 case QCryptographicHash::RealSha3_256:
1036 case QCryptographicHash::RealSha3_384:
1037 case QCryptographicHash::RealSha3_512:
1038 case QCryptographicHash::Blake2b_512:
1039 case QCryptographicHash::Blake2s_256:
1040 evp.finalizeUnchecked(result);
1041 break;
1042 case QCryptographicHash::NumAlgorithms:
1043 Q_UNREACHABLE();
1044 }
1045}
1046
1047void QCryptographicHashPrivate::EVP::finalizeUnchecked(QSpan<uchar> result) noexcept
1048{
1049 if (!initializationFailed) {
1050 EVP_MD_CTX_ptr copy = EVP_MD_CTX_ptr(EVP_MD_CTX_new());
1051 EVP_MD_CTX_copy_ex(copy.get(), context.get());
1052 Q_ASSERT(result.size() == EVP_MD_get_size(algorithm.get()));
1053 EVP_DigestFinal_ex(copy.get(), result.data(), nullptr);
1054 }
1055}
1056
1057#else // USING_OPENSSL30
1058
1059void QCryptographicHashPrivate::State::finalizeUnchecked(QCryptographicHash::Algorithm method,
1060 QSpan<uchar> result) noexcept
1061{
1062 switch (method) {
1063 case QCryptographicHash::Sha1: {
1064 Sha1State copy = sha1Context;
1065 sha1FinalizeState(&copy);
1066 sha1ToHash(&copy, result.data());
1067 break;
1068 }
1069 case QCryptographicHash::Md4: {
1070 md4_context copy = md4Context;
1071 md4_final(&copy, result.data());
1072 break;
1073 }
1074 case QCryptographicHash::Md5: {
1075 MD5Context copy = md5Context;
1076 MD5Final(&copy, result.data());
1077 break;
1078 }
1079 case QCryptographicHash::Sha224: {
1080 SHA224Context copy = sha224Context;
1081 SHA224Result(&copy, result.data());
1082 break;
1083 }
1084 case QCryptographicHash::Sha256: {
1085 SHA256Context copy = sha256Context;
1086 SHA256Result(&copy, result.data());
1087 break;
1088 }
1089 case QCryptographicHash::Sha384: {
1090 SHA384Context copy = sha384Context;
1091 SHA384Result(&copy, result.data());
1092 break;
1093 }
1094 case QCryptographicHash::Sha512: {
1095 SHA512Context copy = sha512Context;
1096 SHA512Result(&copy, result.data());
1097 break;
1098 }
1099 case QCryptographicHash::RealSha3_224:
1100 case QCryptographicHash::RealSha3_256:
1101 case QCryptographicHash::RealSha3_384:
1102 case QCryptographicHash::RealSha3_512: {
1103 SHA3Context copy = sha3Context;
1104 sha3Finish(copy, result, Sha3Variant::Sha3);
1105 break;
1106 }
1107 case QCryptographicHash::Keccak_224:
1108 case QCryptographicHash::Keccak_256:
1109 case QCryptographicHash::Keccak_384:
1110 case QCryptographicHash::Keccak_512: {
1111 SHA3Context copy = sha3Context;
1112 sha3Finish(copy, result, Sha3Variant::Keccak);
1113 break;
1114 }
1115 case QCryptographicHash::Blake2b_160:
1116 case QCryptographicHash::Blake2b_256:
1117 case QCryptographicHash::Blake2b_384:
1118 case QCryptographicHash::Blake2b_512: {
1119 const auto length = hashLengthInternal(method);
1120 blake2b_state copy = blake2bContext;
1121 blake2b_final(&copy, result.data(), length);
1122 break;
1123 }
1124 case QCryptographicHash::Blake2s_128:
1125 case QCryptographicHash::Blake2s_160:
1126 case QCryptographicHash::Blake2s_224:
1127 case QCryptographicHash::Blake2s_256: {
1128 const auto length = hashLengthInternal(method);
1129 blake2s_state copy = blake2sContext;
1130 blake2s_final(&copy, result.data(), length);
1131 break;
1132 }
1133 case QCryptographicHash::NumAlgorithms:
1134 Q_UNREACHABLE();
1135 }
1136}
1137#endif // !USING_OPENSSL30
1138
1139/*!
1140 Returns the hash of \a data using \a method.
1141
1142 \note In Qt versions prior to 6.3, this function took QByteArray,
1143 not QByteArrayView.
1144
1145 \sa hashInto()
1146*/
1147QByteArray QCryptographicHash::hash(QByteArrayView data, Algorithm method)
1148{
1149 QByteArray ba(hashLengthInternal(method), Qt::Uninitialized);
1150 [[maybe_unused]] const auto r = hashInto(ba, data, method);
1151 Q_ASSERT(r.size() == ba.size());
1152 return ba;
1153}
1154
1155/*!
1156 \since 6.8
1157 \fn QCryptographicHash::hashInto(QSpan<char> buffer, QSpan<const QByteArrayView> data, Algorithm method);
1158 \fn QCryptographicHash::hashInto(QSpan<uchar> buffer, QSpan<const QByteArrayView> data, Algorithm method);
1159 \fn QCryptographicHash::hashInto(QSpan<std::byte> buffer, QSpan<const QByteArrayView> data, Algorithm method);
1160 \fn QCryptographicHash::hashInto(QSpan<char> buffer, QByteArrayView data, Algorithm method);
1161 \fn QCryptographicHash::hashInto(QSpan<uchar> buffer, QByteArrayView data, Algorithm method);
1162 \fn QCryptographicHash::hashInto(QSpan<std::byte> buffer, QByteArrayView data, Algorithm method);
1163
1164 Returns the hash of \a data using \a method, using \a buffer to store the result.
1165
1166 If \a data is a span, adds all the byte array views to the hash, in the order given.
1167
1168 The return value will be a sub-span of \a buffer, unless \a buffer is of
1169 insufficient size, in which case a null QByteArrayView is returned.
1170
1171 \sa hash()
1172*/
1173QByteArrayView QCryptographicHash::hashInto(QSpan<std::byte> buffer,
1174 QSpan<const QByteArrayView> data,
1175 Algorithm method) noexcept
1176{
1177 if (buffer.size() < hashLengthInternal(method))
1178 return {}; // buffer too small
1179
1180 QCryptographicHashPrivate hash(method);
1181 for (QByteArrayView part : data)
1182 hash.addData(part);
1183 auto span = QSpan{reinterpret_cast<uchar *>(buffer.data()), buffer.size()};
1184 return hash.finalizeUnchecked(span); // no mutex needed: no-one but us has access to 'hash'
1185}
1186
1187/*!
1188 Returns the size of the output of the selected hash \a method in bytes.
1189
1190 \since 5.12
1191*/
1192int QCryptographicHash::hashLength(QCryptographicHash::Algorithm method)
1193{
1194 return hashLengthInternal(method);
1195}
1196
1197/*!
1198 Returns whether the selected algorithm \a method is supported and if
1199 result() will return a value when the \a method is used.
1200
1201 \note OpenSSL will be responsible for providing this information when
1202 used as a provider, otherwise \c true will be returned as the non-OpenSSL
1203 implementation doesn't have any restrictions.
1204 We return \c false if we fail to query OpenSSL.
1205
1206 \since 6.5
1207*/
1208
1209
1210bool QCryptographicHash::supportsAlgorithm(QCryptographicHash::Algorithm method)
1211{
1212 return QCryptographicHashPrivate::supportsAlgorithm(method);
1213}
1214
1215#ifdef USING_OPENSSL30
1216bool QCryptographicHashPrivate::supportsAlgorithm(QCryptographicHash::Algorithm method)
1217{
1218 // OpenSSL doesn't support Keccak*, Blake2b{160,256,384} and Blake2s{128,160,224},
1219 // and these would automatically return FALSE in that case, while they are
1220 // actually supported by our non-OpenSSL implementation.
1221 switch (method) {
1222 case QCryptographicHash::Keccak_224:
1223 case QCryptographicHash::Keccak_256:
1224 case QCryptographicHash::Keccak_384:
1225 case QCryptographicHash::Keccak_512:
1226 case QCryptographicHash::Blake2b_160:
1227 case QCryptographicHash::Blake2b_256:
1228 case QCryptographicHash::Blake2b_384:
1229 case QCryptographicHash::Blake2s_128:
1230 case QCryptographicHash::Blake2s_160:
1231 case QCryptographicHash::Blake2s_224:
1232 return true;
1233 case QCryptographicHash::Sha1:
1234 case QCryptographicHash::Md4:
1235 case QCryptographicHash::Md5:
1236 case QCryptographicHash::Sha224:
1237 case QCryptographicHash::Sha256:
1238 case QCryptographicHash::Sha384:
1239 case QCryptographicHash::Sha512:
1240 case QCryptographicHash::RealSha3_224:
1241 case QCryptographicHash::RealSha3_256:
1242 case QCryptographicHash::RealSha3_384:
1243 case QCryptographicHash::RealSha3_512:
1244 case QCryptographicHash::Blake2b_512:
1245 case QCryptographicHash::Blake2s_256: {
1246 auto legacyProvider = OSSL_PROVIDER_ptr(OSSL_PROVIDER_load(nullptr, "legacy"));
1247 auto defaultProvider = OSSL_PROVIDER_ptr(OSSL_PROVIDER_load(nullptr, "default"));
1248
1249 const char *restriction = "-fips";
1250 EVP_MD_ptr algorithm = EVP_MD_ptr(EVP_MD_fetch(nullptr, methodToName(method), restriction));
1251
1252 return algorithm != nullptr;
1253
1254 }
1255 case QCryptographicHash::NumAlgorithms:
1256 ;
1257 }
1258 return false;
1259
1260}
1261#else
1262bool QCryptographicHashPrivate::supportsAlgorithm(QCryptographicHash::Algorithm method)
1263{
1264 switch (method) {
1265 case QCryptographicHash::Sha1:
1266 case QCryptographicHash::Md4:
1267 case QCryptographicHash::Md5:
1268 case QCryptographicHash::Sha224:
1269 case QCryptographicHash::Sha256:
1270 case QCryptographicHash::Sha384:
1271 case QCryptographicHash::Sha512:
1272 case QCryptographicHash::RealSha3_224:
1273 case QCryptographicHash::Keccak_224:
1274 case QCryptographicHash::RealSha3_256:
1275 case QCryptographicHash::Keccak_256:
1276 case QCryptographicHash::RealSha3_384:
1277 case QCryptographicHash::Keccak_384:
1278 case QCryptographicHash::RealSha3_512:
1279 case QCryptographicHash::Keccak_512:
1280 case QCryptographicHash::Blake2b_160:
1281 case QCryptographicHash::Blake2b_256:
1282 case QCryptographicHash::Blake2b_384:
1283 case QCryptographicHash::Blake2b_512:
1284 case QCryptographicHash::Blake2s_128:
1285 case QCryptographicHash::Blake2s_160:
1286 case QCryptographicHash::Blake2s_224:
1287 case QCryptographicHash::Blake2s_256:
1288 return true;
1289 case QCryptographicHash::NumAlgorithms: ;
1290 };
1291 return false;
1292}
1293#endif // !USING_OPENSSL3
1294
1295static constexpr int qt_hash_block_size(QCryptographicHash::Algorithm method)
1296{
1297 switch (method) {
1298 case QCryptographicHash::Sha1:
1299 return SHA1_Message_Block_Size;
1300 case QCryptographicHash::Md4:
1301 return 64;
1302 case QCryptographicHash::Md5:
1303 return 64;
1304 case QCryptographicHash::Sha224:
1305 return SHA224_Message_Block_Size;
1306 case QCryptographicHash::Sha256:
1307 return SHA256_Message_Block_Size;
1308 case QCryptographicHash::Sha384:
1309 return SHA384_Message_Block_Size;
1310 case QCryptographicHash::Sha512:
1311 return SHA512_Message_Block_Size;
1312 case QCryptographicHash::RealSha3_224:
1313 case QCryptographicHash::Keccak_224:
1314 return 144;
1315 case QCryptographicHash::RealSha3_256:
1316 case QCryptographicHash::Keccak_256:
1317 return 136;
1318 case QCryptographicHash::RealSha3_384:
1319 case QCryptographicHash::Keccak_384:
1320 return 104;
1321 case QCryptographicHash::RealSha3_512:
1322 case QCryptographicHash::Keccak_512:
1323 return 72;
1324 case QCryptographicHash::Blake2b_160:
1325 case QCryptographicHash::Blake2b_256:
1326 case QCryptographicHash::Blake2b_384:
1327 case QCryptographicHash::Blake2b_512:
1328 return BLAKE2B_BLOCKBYTES;
1329 case QCryptographicHash::Blake2s_128:
1330 case QCryptographicHash::Blake2s_160:
1331 case QCryptographicHash::Blake2s_224:
1332 case QCryptographicHash::Blake2s_256:
1333 return BLAKE2S_BLOCKBYTES;
1334 case QCryptographicHash::NumAlgorithms:
1335#if !defined(Q_CC_GNU_ONLY) || Q_CC_GNU >= 900
1336 // GCC 8 has trouble with Q_UNREACHABLE() in constexpr functions
1337 Q_UNREACHABLE();
1338#endif
1339 break;
1340 }
1341 return 0;
1342}
1343
1344constexpr int maxHashBlockSize()
1345{
1346 int result = 0;
1347 using A = QCryptographicHash::Algorithm;
1348 for (int i = 0; i < A::NumAlgorithms ; ++i)
1349 result = std::max(result, qt_hash_block_size(A(i)));
1350 return result;
1351}
1352
1353[[maybe_unused]]
1354constexpr int minHashBlockSize()
1355{
1356 int result = INT_MAX;
1357 using A = QCryptographicHash::Algorithm;
1358 for (int i = 0; i < A::NumAlgorithms ; ++i)
1359 result = std::min(result, qt_hash_block_size(A(i)));
1360 return result;
1361}
1362
1363[[maybe_unused]]
1364constexpr int gcdHashBlockSize()
1365{
1366 int result = 0;
1367 using A = QCryptographicHash::Algorithm;
1368 for (int i = 0; i < A::NumAlgorithms ; ++i)
1369 result = std::gcd(result, qt_hash_block_size(A(i)));
1370 return result;
1371}
1372
1373using HashBlock = QSmallByteArray<maxHashBlockSize()>;
1374
1375static HashBlock xored(const HashBlock &block, quint8 val) noexcept
1376{
1377 // some hints for the optimizer:
1378 Q_ASSERT(block.size() >= minHashBlockSize());
1379 Q_ASSERT(block.size() <= maxHashBlockSize());
1380 Q_ASSERT(block.size() % gcdHashBlockSize() == 0);
1381 HashBlock result;
1382 result.resizeForOverwrite(block.size());
1383 for (qsizetype i = 0; i < block.size(); ++i)
1384 result[i] = block[i] ^ val;
1385 return result;
1386}
1387
1389{
1390public:
1395
1398
1399 void setKey(QByteArrayView k) noexcept;
1400 void initMessageHash() noexcept;
1401 void finalize();
1402
1403 // when not called from the static hash() function, this function needs to be
1404 // called with messageHash.finalizeMutex held:
1405 void finalizeUnchecked() noexcept;
1406 // END functions that need to be called with finalizeMutex held
1407};
1408
1409/*!
1410 \internal
1411
1412 Transforms key \a newKey into a block-sized format and stores it in member
1413 \c key.
1414
1415 This function assumes it can use messageHash (i.e. it's in its initial
1416 state (reset() has been called)).
1417*/
1418void QMessageAuthenticationCodePrivate::setKey(QByteArrayView newKey) noexcept
1419{
1420 const int blockSize = qt_hash_block_size(messageHash.method);
1421
1422 if (newKey.size() > blockSize) {
1423 messageHash.addData(newKey);
1424 messageHash.finalizeUnchecked();
1425 static_assert([] {
1426 using A = QCryptographicHash::Algorithm;
1427 for (int i = 0; i < A::NumAlgorithms; ++i) {
1428 if (hashLengthInternal(A(i)) > qt_hash_block_size(A(i)))
1429 return false;
1430 }
1431 return true;
1432 }(), "this code assumes that a hash's result always fits into that hash's block size");
1433 key = messageHash.result;
1434 messageHash.reset();
1435 } else {
1436 key.assign(newKey);
1437 }
1438
1439 if (key.size() < blockSize)
1440 key.resize(blockSize, '\0');
1441
1443}
1444
1445/*!
1446 \internal
1447
1448 Seeds messageHash from \c key.
1449
1450 This function assumes that messageHash is in its initial state (reset() has
1451 been called).
1452*/
1454{
1455 messageHash.addData(xored(key, 0x36));
1456}
1457
1458/*!
1459 \class QMessageAuthenticationCode
1460 \inmodule QtCore
1461
1462 \brief The QMessageAuthenticationCode class provides a way to generate
1463 hash-based message authentication codes.
1464
1465 \since 5.1
1466
1467 \ingroup tools
1468 \reentrant
1469
1470 Use the QMessageAuthenticationCode class to generate hash-based message
1471 authentication codes (HMACs). The class supports all cryptographic
1472 hash algorithms from \l QCryptographicHash (see also
1473 \l{QCryptographicHash::Algorithm}).
1474
1475 To generate a message authentication code, pass a suitable hash
1476 algorithm and secret key to the constructor. Then process the message
1477 data by calling \l addData() one or more times. After the full
1478 message has been processed, get the final authentication code
1479 via the \l result() function:
1480
1481 \snippet qmessageauthenticationcode/main.cpp 0
1482 \dots
1483 \snippet qmessageauthenticationcode/main.cpp 1
1484
1485 For simple cases like above, you can also use the static
1486 \l hash() function:
1487
1488 \snippet qmessageauthenticationcode/main.cpp 2
1489
1490
1491 \note The cryptographic strength of the HMAC depends upon the
1492 size of the secret key, and the security of the
1493 underlying hash function.
1494
1495 \sa QCryptographicHash, QCryptographicHash::Algorithm
1496*/
1497
1498/*!
1499 Constructs an object that can be used to create a cryptographic hash from data
1500 using method \a method and key \a key.
1501
1502//! [qba-to-qbav-6.6]
1503 \note In Qt versions prior to 6.6, this function took its arguments as
1504 QByteArray, not QByteArrayView. If you experience compile errors, it's
1505 because your code is passing objects that are implicitly convertible to
1506 QByteArray, but not QByteArrayView. Wrap the corresponding argument in
1507 \c{QByteArray{~~~}} to make the cast explicit. This is backwards-compatible
1508 with old Qt versions.
1509//! [qba-to-qbav-6.6]
1510*/
1511QMessageAuthenticationCode::QMessageAuthenticationCode(QCryptographicHash::Algorithm method,
1512 QByteArrayView key)
1513 : d(new QMessageAuthenticationCodePrivate(method))
1514{
1515 d->setKey(key);
1516}
1517
1518/*!
1519 Destroys the object.
1520*/
1521QMessageAuthenticationCode::~QMessageAuthenticationCode()
1522{
1523 delete d;
1524}
1525
1526/*!
1527 \fn QMessageAuthenticationCode::QMessageAuthenticationCode(QMessageAuthenticationCode &&other)
1528
1529 Move-constructs a new QMessageAuthenticationCode from \a other.
1530
1531 \note The moved-from object \a other is placed in a
1532 partially-formed state, in which the only valid operations are
1533 destruction and assignment of a new object.
1534
1535 \since 6.6
1536*/
1537
1538/*!
1539 \fn QMessageAuthenticationCode &QMessageAuthenticationCode::operator=(QMessageAuthenticationCode &&other)
1540
1541 Move-assigns \a other to this QMessageAuthenticationCode instance.
1542
1543 \note The moved-from object \a other is placed in a
1544 partially-formed state, in which the only valid operations are
1545 destruction and assignment of a new object.
1546
1547 \since 6.6
1548*/
1549
1550/*!
1551 \fn void QMessageAuthenticationCode::swap(QMessageAuthenticationCode &other)
1552 \memberswap{message authentication code}
1553 \since 6.6
1554*/
1555
1556/*!
1557 Resets message data. Calling this function doesn't affect the key.
1558*/
1559void QMessageAuthenticationCode::reset() noexcept
1560{
1561 d->messageHash.reset();
1562 d->initMessageHash();
1563}
1564
1565/*!
1566 Sets secret \a key. Calling this function automatically resets the object state.
1567
1568 For optimal performance, call this function only to \e change the active key,
1569 not to set an \e initial key, as in
1570
1571 \code
1572 QMessageAuthenticationCode mac(method);
1573 mac.setKey(key); // does extra work
1574 use(mac);
1575 \endcode
1576
1577 Prefer to pass initial keys as the constructor argument:
1578
1579 \code
1580 QMessageAuthenticationCode mac(method, key); // OK, optimal
1581 use(mac);
1582 \endcode
1583
1584 You can use std::optional to delay construction of a
1585 QMessageAuthenticationCode until you know the key:
1586
1587 \code
1588 std::optional<QMessageAuthenticationCode> mac;
1589 ~~~
1590 key = ~~~;
1591 mac.emplace(method, key);
1592 use(*mac);
1593 \endcode
1594
1595 \include qcryptographichash.cpp {qba-to-qbav-6.6}
1596*/
1597void QMessageAuthenticationCode::setKey(QByteArrayView key) noexcept
1598{
1599 d->messageHash.reset();
1600 d->setKey(key);
1601}
1602
1603/*!
1604 \overload
1605 Adds the first \a length chars of \a data to the message.
1606*/
1607void QMessageAuthenticationCode::addData(const char *data, qsizetype length)
1608{
1609 d->messageHash.addData({data, length});
1610}
1611
1612/*!
1613 Adds \a data to the message.
1614
1615 \include qcryptographichash.cpp {qba-to-qbav-6.6}
1616
1617 \sa resultView(), result()
1618*/
1619void QMessageAuthenticationCode::addData(QByteArrayView data) noexcept
1620{
1621 d->messageHash.addData(data);
1622}
1623
1624/*!
1625 Reads the data from the open QIODevice \a device until it ends
1626 and adds it to message. Returns \c true if reading was successful.
1627
1628 \note \a device must be already opened.
1629 */
1630bool QMessageAuthenticationCode::addData(QIODevice *device)
1631{
1632 return d->messageHash.addData(device);
1633}
1634
1635/*!
1636 \since 6.6
1637
1638 Returns the final hash value.
1639
1640 Note that the returned view remains valid only as long as the
1641 QMessageAuthenticationCode object is not modified by other means.
1642
1643 \sa result()
1644*/
1645QByteArrayView QMessageAuthenticationCode::resultView() const noexcept
1646{
1647 d->finalize();
1648 return d->messageHash.resultView();
1649}
1650
1651/*!
1652 Returns the final authentication code.
1653
1654 \sa resultView(), QByteArray::toHex()
1655*/
1656QByteArray QMessageAuthenticationCode::result() const
1657{
1658 return resultView().toByteArray();
1659}
1660
1662{
1663 const auto lock = qt_scoped_lock(messageHash.finalizeMutex);
1664 if (!messageHash.result.isEmpty())
1665 return;
1667}
1668
1670{
1671 messageHash.finalizeUnchecked();
1672 const HashResult hashedMessage = messageHash.result;
1673
1674 messageHash.reset();
1675 messageHash.addData(xored(key, 0x5c));
1676 messageHash.addData(hashedMessage);
1677 messageHash.finalizeUnchecked();
1678}
1679
1680/*!
1681 Returns the authentication code for the message \a message using
1682 the key \a key and the method \a method.
1683
1684 \include qcryptographichash.cpp {qba-to-qbav-6.6}
1685
1686 \sa hashInto()
1687*/
1688QByteArray QMessageAuthenticationCode::hash(QByteArrayView message, QByteArrayView key,
1689 QCryptographicHash::Algorithm method)
1690{
1691 QByteArray ba(hashLengthInternal(method), Qt::Uninitialized);
1692 [[maybe_unused]] const auto r = hashInto(ba, message, key, method);
1693 Q_ASSERT(r.size() == ba.size());
1694 return ba;
1695}
1696
1697/*!
1698 \since 6.8
1699 \fn QMessageAuthenticationCode::hashInto(QSpan<char> buffer, QSpan<const QByteArrayView> messageParts, QByteArrayView key, QCryptographicHash::Algorithm method);
1700 \fn QMessageAuthenticationCode::hashInto(QSpan<uchar> buffer, QSpan<const QByteArrayView> messageParts, QByteArrayView key, QCryptographicHash::Algorithm method);
1701 \fn QMessageAuthenticationCode::hashInto(QSpan<std::byte> buffer, QSpan<const QByteArrayView> messageParts, QByteArrayView key, QCryptographicHash::Algorithm method);
1702 \fn QMessageAuthenticationCode::hashInto(QSpan<char> buffer, QByteArrayView message, QByteArrayView key, QCryptographicHash::Algorithm method);
1703 \fn QMessageAuthenticationCode::hashInto(QSpan<uchar> buffer, QByteArrayView message, QByteArrayView key, QCryptographicHash::Algorithm method);
1704 \fn QMessageAuthenticationCode::hashInto(QSpan<std::byte> buffer, QByteArrayView message, QByteArrayView key, QCryptographicHash::Algorithm method);
1705
1706 Returns the authentication code for the message (\a message or, for the
1707 QSpan overloads, the concatenation of \a messageParts) using the key \a key
1708 and the method \a method.
1709
1710 The return value will be a sub-span of \a buffer, unless \a buffer is of
1711 insufficient size, in which case a null QByteArrayView is returned.
1712
1713 \sa hash()
1714*/
1715QByteArrayView QMessageAuthenticationCode::hashInto(QSpan<std::byte> buffer,
1716 QSpan<const QByteArrayView> messageParts,
1717 QByteArrayView key,
1718 QCryptographicHash::Algorithm method) noexcept
1719{
1720 QMessageAuthenticationCodePrivate mac(method);
1721 mac.setKey(key);
1722 for (QByteArrayView part : messageParts)
1723 mac.messageHash.addData(part);
1724 mac.finalizeUnchecked();
1725 auto result = mac.messageHash.resultView();
1726 if (buffer.size() < result.size())
1727 return {}; // buffer too small
1728 // ### optimize: have the method directly write into `buffer`
1729 memcpy(buffer.data(), result.data(), result.size());
1730 return buffer.first(result.size());
1731}
1732
1733QT_END_NAMESPACE
1734
1735#ifndef QT_NO_QOBJECT
1736#include "moc_qcryptographichash.cpp"
1737#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