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