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

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