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

Provided by KDAB

Privacy Policy
Start learning QML with our Intro Training
Find out more

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