Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qcryptographichash.cpp
Go to the documentation of this file.
1// Copyright (C) 2023 The Qt Company Ltd.
2// Copyright (C) 2013 Ruslan Nigmatullin <euroelessar@yandex.ru>
3// Copyright (C) 2013 Richard J. Moore <rich@kde.org>.
4// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
5
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);
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
124
125template <size_t N>
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
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);
212 return 160 / 8;
216 return 224 / 8;
221 return 256 / 8;
225 return 384 / 8;
229 return 512 / 8;
230#endif
231#undef CASE
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;
243 for (int i = 0; i < A::NumAlgorithms; ++i)
244 result = std::max(result, hashLengthInternal(A(i)));
245 return result;
246}
247
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{
289 return true;
290
291 return false;
292}
293#endif // USING_OPENSSL30
294
296{
297public:
300 {
301 }
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
337 void reset() noexcept;
338 void finalizeUnchecked(HashResult &result) noexcept;
339 };
340#endif
341
342 union State {
345#ifdef USING_OPENSSL30
346 ~State() {}
347#endif
348
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;
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
373 // protects result in finalize()
376
378};
379
380#ifndef QT_CRYPTOGRAPHICHASH_ONLY_SHA1
381#ifndef USING_OPENSSL30
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(bitCount / 8);
408
410
411 switch (sha3Variant) {
413 sha3Update(&copy, reinterpret_cast<const BitSequence *>(&sha3FinalSuffix), 2);
414 break;
416 break;
417 }
418
419 sha3Final(&copy, result.data());
420}
421#endif // !QT_CONFIG(opensslv30)
422#endif
423
485{
486}
487
504{
505 delete d;
506}
507
533{
534 d->reset();
535}
536
543{
544 return d->method;
545}
546
547#ifdef USING_OPENSSL30
548
550{
554 new (&blake2bContext) blake2b_state;
555 reset(method);
559 new (&blake2sContext) blake2s_state;
560 reset(method);
561 } else {
562 new (&evp) EVP(method);
563 }
564}
565
567{
574 evp.~EVP();
575 }
576}
577
578QCryptographicHashPrivate::EVP::EVP(QCryptographicHash::Algorithm method)
579 : initializationFailed{true}
580{
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
614{
615 switch (method) {
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
626 new (&md4Context) md4_context;
627 break;
629 new (&md5Context) MD5Context;
630 break;
632 new (&sha224Context) SHA224Context;
633 break;
635 new (&sha256Context) SHA256Context;
636 break;
638 new (&sha384Context) SHA384Context;
639 break;
641 new (&sha512Context) SHA512Context;
642 break;
652 break;
657 new (&blake2bContext) blake2b_state;
658 break;
663 new (&blake2sContext) blake2s_state;
664 break;
665#endif
667 Q_UNREACHABLE();
668 }
669 reset(method);
670}
671
673{
674 static_assert(std::is_trivially_destructible_v<State>); // so nothing to do here
675}
676#endif // !USING_OPENSSL30
677
679{
680 result.clear();
682}
683
684#ifdef USING_OPENSSL30
685
687{
691 blake2b_init(&blake2bContext, hashLengthInternal(method));
695 blake2s_init(&blake2sContext, hashLengthInternal(method));
696 } else {
697 evp.reset();
698 }
699}
700
701void QCryptographicHashPrivate::EVP::reset() noexcept
702{
703 if (!initializationFailed) {
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
716{
717 switch (method) {
719 sha1InitState(&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
728 md4_init(&md4Context);
729 break;
731 MD5Init(&md5Context);
732 break;
734 SHA224Reset(&sha224Context);
735 break;
737 SHA256Reset(&sha256Context);
738 break;
740 SHA384Reset(&sha384Context);
741 break;
743 SHA512Reset(&sha512Context);
744 break;
753 sha3Init(&sha3Context, hashLengthInternal(method) * 8);
754 break;
759 blake2b_init(&blake2bContext, hashLengthInternal(method));
760 break;
765 blake2s_init(&blake2sContext, hashLengthInternal(method));
766 break;
767#endif
769 Q_UNREACHABLE();
770 }
771}
772
773#endif // USING_OPENSSL30
774
775#if QT_DEPRECATED_SINCE(6, 4)
784{
785 Q_ASSERT(length >= 0);
787}
788#endif
789
797{
798 d->addData(bytes);
799}
800
802{
803 state.addData(method, bytes);
804 result.clear();
805}
806
807#ifdef USING_OPENSSL30
808
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 {
819 blake2b_update(&blake2bContext, reinterpret_cast<const uint8_t *>(data), length);
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
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(qsizetype(std::numeric_limits<uint>::max()), remaining);
844#else
845 {
846#endif
847 switch (method) {
849 sha1Update(&sha1Context, (const unsigned char *)data, 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
858 md4_update(&md4Context, (const unsigned char *)data, length);
859 break;
861 MD5Update(&md5Context, (const unsigned char *)data, length);
862 break;
864 SHA224Input(&sha224Context, reinterpret_cast<const unsigned char *>(data), length);
865 break;
867 SHA256Input(&sha256Context, reinterpret_cast<const unsigned char *>(data), length);
868 break;
870 SHA384Input(&sha384Context, reinterpret_cast<const unsigned char *>(data), length);
871 break;
873 SHA512Input(&sha512Context, reinterpret_cast<const unsigned char *>(data), length);
874 break;
883 sha3Update(&sha3Context, reinterpret_cast<const BitSequence *>(data), uint64_t(length) * 8);
884 break;
889 blake2b_update(&blake2bContext, reinterpret_cast<const uint8_t *>(data), length);
890 break;
895 blake2s_update(&blake2sContext, reinterpret_cast<const uint8_t *>(data), length);
896 break;
897#endif
899 Q_UNREACHABLE();
900 }
901 }
902}
903#endif // !USING_OPENSSL30
904
911{
912 return d->addData(device);
913}
914
916{
917 if (!device->isReadable())
918 return false;
919
920 if (!device->isOpen())
921 return false;
922
923 char buffer[1024];
925
926 while ((length = device->read(buffer, sizeof(buffer))) > 0)
927 addData({buffer, qsizetype(length)}); // length always <= 1024
928
929 return device->atEnd();
930}
931
932
939{
940 return resultView().toByteArray();
941}
942
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
967{
968 const auto lock = qt_scoped_lock(finalizeMutex);
969 // check that no other thread already finalizeUnchecked()'ed before us:
970 if (!result.isEmpty())
971 return;
973}
974
982{
984}
985
986#ifdef USING_OPENSSL30
988 HashResult &result) noexcept
989{
993 const auto length = hashLengthInternal(method);
994 blake2b_state copy = blake2bContext;
995 result.resizeForOverwrite(length);
996 blake2b_final(&copy, result.data(), length);
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
1022 HashResult &result) noexcept
1023{
1024 switch (method) {
1026 Sha1State copy = sha1Context;
1027 result.resizeForOverwrite(20);
1028 sha1FinalizeState(&copy);
1029 sha1ToHash(&copy, 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
1039 md4_context copy = md4Context;
1040 result.resizeForOverwrite(MD4_RESULTLEN);
1041 md4_final(&copy, result.data());
1042 break;
1043 }
1045 MD5Context copy = md5Context;
1046 result.resizeForOverwrite(16);
1047 MD5Final(&copy, result.data());
1048 break;
1049 }
1051 SHA224Context copy = sha224Context;
1052 result.resizeForOverwrite(SHA224HashSize);
1053 SHA224Result(&copy, result.data());
1054 break;
1055 }
1057 SHA256Context copy = sha256Context;
1058 result.resizeForOverwrite(SHA256HashSize);
1059 SHA256Result(&copy, result.data());
1060 break;
1061 }
1063 SHA384Context copy = sha384Context;
1064 result.resizeForOverwrite(SHA384HashSize);
1065 SHA384Result(&copy, result.data());
1066 break;
1067 }
1069 SHA512Context copy = sha512Context;
1070 result.resizeForOverwrite(SHA512HashSize);
1071 SHA512Result(&copy, result.data());
1072 break;
1073 }
1078 sha3Finish(result, 8 * hashLengthInternal(method), Sha3Variant::Sha3);
1079 break;
1080 }
1085 sha3Finish(result, 8 * hashLengthInternal(method), Sha3Variant::Keccak);
1086 break;
1087 }
1092 const auto length = hashLengthInternal(method);
1093 blake2b_state copy = blake2bContext;
1094 result.resizeForOverwrite(length);
1095 blake2b_final(&copy, result.data(), length);
1096 break;
1097 }
1102 const auto length = hashLengthInternal(method);
1103 blake2s_state copy = blake2sContext;
1104 result.resizeForOverwrite(length);
1105 blake2s_final(&copy, result.data(), length);
1106 break;
1107 }
1108#endif
1110 Q_UNREACHABLE();
1111 }
1112}
1113#endif // !USING_OPENSSL30
1114
1122{
1124 hash.addData(data);
1125 hash.finalizeUnchecked(); // no mutex needed: no-one but us has access to 'hash'
1126 return hash.resultView().toByteArray();
1127}
1128
1135{
1136 return hashLengthInternal(method);
1137}
1138
1153{
1155}
1156
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) {
1176#ifndef QT_CRYPTOGRAPHICHASH_ONLY_SHA1
1199#endif
1200 return true;
1202 };
1203 return false;
1204#endif // !USING_OPENSSL3
1205}
1206
1208{
1209 switch (method) {
1211 return SHA1_Message_Block_Size;
1212#ifndef QT_CRYPTOGRAPHICHASH_ONLY_SHA1
1214 return 64;
1216 return 64;
1218 return SHA224_Message_Block_Size;
1220 return SHA256_Message_Block_Size;
1222 return SHA384_Message_Block_Size;
1224 return SHA512_Message_Block_Size;
1227 return 144;
1230 return 136;
1233 return 104;
1236 return 72;
1241 return BLAKE2B_BLOCKBYTES;
1246 return BLAKE2S_BLOCKBYTES;
1247#endif // QT_CRYPTOGRAPHICHASH_ONLY_SHA1
1249#if !defined(Q_GCC_ONLY) || Q_CC_GCC >= 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;
1262 for (int i = 0; i < A::NumAlgorithms ; ++i)
1263 result = std::max(result, qt_hash_block_size(A(i)));
1264 return result;
1265}
1266
1267[[maybe_unused]]
1268constexpr int minHashBlockSize()
1269{
1270 int result = INT_MAX;
1272 for (int i = 0; i < A::NumAlgorithms ; ++i)
1273 result = std::min(result, qt_hash_block_size(A(i)));
1274 return result;
1275}
1276
1277[[maybe_unused]]
1278constexpr int gcdHashBlockSize()
1279{
1280 int result = 0;
1282 for (int i = 0; i < A::NumAlgorithms ; ++i)
1283 result = std::gcd(result, qt_hash_block_size(A(i)));
1284 return result;
1285}
1286
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);
1296 result.resizeForOverwrite(block.size());
1297 for (qsizetype i = 0; i < block.size(); ++i)
1298 result[i] = block[i] ^ val;
1299 return result;
1300}
1301
1303{
1304public:
1306 : messageHash(m)
1307 {
1308 }
1309
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
1333{
1334 const int blockSize = qt_hash_block_size(messageHash.method);
1335
1336 if (newKey.size() > blockSize) {
1337 messageHash.addData(newKey);
1338 messageHash.finalizeUnchecked();
1339 static_assert([] {
1341 for (int i = 0; i < A::NumAlgorithms; ++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(newKey);
1351 }
1352
1353 if (key.size() < blockSize)
1354 key.resize(blockSize, '\0');
1355
1356 initMessageHash();
1357}
1358
1368{
1369 messageHash.addData(xored(key, 0x36));
1370}
1371
1406
1413
1417{
1418 d->setKey(key);
1419}
1420
1425{
1426 delete d;
1427}
1428
1466{
1467 d->messageHash.reset();
1468 d->initMessageHash();
1469}
1470
1504{
1505 d->messageHash.reset();
1506 d->setKey(key);
1507}
1508
1514{
1516}
1517
1526{
1527 d->messageHash.addData(data);
1528}
1529
1537{
1538 return d->messageHash.addData(device);
1539}
1540
1552{
1553 d->finalize();
1554 return d->messageHash.resultView();
1555}
1556
1563{
1564 return resultView().toByteArray();
1565}
1566
1568{
1569 const auto lock = qt_scoped_lock(messageHash.finalizeMutex);
1570 if (!messageHash.result.isEmpty())
1571 return;
1573}
1574
1576{
1578 const HashResult hashedMessage = messageHash.result;
1579
1581 messageHash.addData(xored(key, 0x5c));
1582 messageHash.addData(hashedMessage);
1584}
1585
1594{
1596 mac.setKey(key);
1598 mac.finalizeUnchecked();
1599 return mac.messageHash.resultView().toByteArray();
1600}
1601
1603
1604#ifndef QT_NO_QOBJECT
1605#include "moc_qcryptographichash.cpp"
1606#endif
NSData * m_data
IOBluetoothDevice * device
QByteArray toByteArray() const
Definition qbytearray.h:709
\inmodule QtCore
Definition qbytearray.h:57
const QCryptographicHash::Algorithm method
void addData(QByteArrayView bytes) noexcept
QCryptographicHashPrivate(QCryptographicHash::Algorithm method) noexcept
union QCryptographicHashPrivate::State state
QByteArrayView resultView() const noexcept
static bool supportsAlgorithm(QCryptographicHash::Algorithm method)
~QCryptographicHash()
Destroys the object.
static int hashLength(Algorithm method)
Returns the size of the output of the selected hash method in bytes.
QByteArrayView resultView() const noexcept
static QByteArray hash(QByteArrayView data, Algorithm method)
Returns the hash of data using method.
static bool supportsAlgorithm(Algorithm method)
Returns whether the selected algorithm method is supported and if result() will return a value when t...
void addData(QByteArrayView data) noexcept
Adds the characters in bytes to the cryptographic hash.
QByteArray result() const
Returns the final hash value.
QCryptographicHash(Algorithm method)
Constructs an object that can be used to create a cryptographic hash from data using method.
void reset() noexcept
Resets the object.
Algorithm algorithm() const noexcept
Returns the algorithm used to generate the cryptographic hash.
\inmodule QtCore \reentrant
Definition qiodevice.h:34
QMessageAuthenticationCodePrivate(QCryptographicHash::Algorithm m)
void setKey(QByteArrayView k) noexcept
~QMessageAuthenticationCode()
Destroys the object.
void setKey(QByteArrayView key) noexcept
Sets secret key.
QByteArrayView resultView() const noexcept
void addData(const char *data, qsizetype length)
This is an overloaded member function, provided for convenience. It differs from the above function o...
QByteArray result() const
Returns the final authentication code.
void reset() noexcept
Resets message data.
static QByteArray hash(QByteArrayView message, QByteArrayView key, QCryptographicHash::Algorithm method)
Returns the authentication code for the message message using the key key and the method method.
QMessageAuthenticationCode(QCryptographicHash::Algorithm method, QByteArrayView key={})
\inmodule QtCore
Definition qmutex.h:285
QSmallByteArray()=default
EGLContext ctx
QHash< int, QWidget * > hash
[35multi]
a resize(100000)
b clear()
else opt state
[0]
const PluginKeyMapConstIterator cend
Combined button and popup list for selecting options.
static void * context
static jboolean copy(JNIEnv *, jobject)
const int blockSize
static int SHA224_256AddLength(SHA256Context *context, unsigned int length)
static constexpr int hashLengthInternal(QCryptographicHash::Algorithm method) noexcept
constexpr int maxHashBlockSize()
static int SHA384_512AddLength(SHA512Context *context, unsigned int length)
static Q_CONSTINIT SHA3Update *const sha3Update
static constexpr int qt_hash_block_size(QCryptographicHash::Algorithm method)
static HashBlock xored(const HashBlock &block, quint8 val) noexcept
static constexpr int maxHashLength()
constexpr int minHashBlockSize()
constexpr int gcdHashBlockSize()
@ BAD_HASHLEN
static Q_CONSTINIT SHA3Init *const sha3Init
unsigned long long DataLength
HashReturn() SHA3Update(hashState *state, const BitSequence *data, DataLength databitlen)
spongeState SHA3Context
HashReturn() SHA3Final(hashState *state, BitSequence *hashval)
unsigned char BitSequence
spongeState hashState
#define CASE(Enum, Size)
HashReturn() SHA3Init(hashState *state, int hashbitlen)
static Q_CONSTINIT SHA3Final *const sha3Final
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char * method
@ Final
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
n varying highp vec2 A
GLsizei const GLfloat * v
[13]
const GLfloat * m
GLuint64 key
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint GLuint end
GLenum GLuint GLenum GLsizei length
GLenum GLuint buffer
GLuint GLsizei const GLchar * message
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLfloat n
GLboolean reset
const GLubyte * c
GLuint GLfloat * val
GLuint64EXT * result
[6]
GLdouble s
[6]
Definition qopenglext.h:235
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define Q_ASSERT_X(cond, x, msg)
Definition qrandom.cpp:48
QtPrivate::QRegularExpressionMatchIteratorRangeBasedForIterator begin(const QRegularExpressionMatchIterator &iterator)
ptrdiff_t qsizetype
Definition qtypes.h:70
long long qint64
Definition qtypes.h:55
unsigned char quint8
Definition qtypes.h:41
QReadWriteLock lock
[0]
setKey(0)
[0]
void addData(QCryptographicHash::Algorithm method, QByteArrayView data) noexcept
void sha3Finish(HashResult &result, int bitCount, Sha3Variant sha3Variant)
void finalizeUnchecked(QCryptographicHash::Algorithm method, HashResult &result) noexcept
void destroy(QCryptographicHash::Algorithm method)
State(QCryptographicHash::Algorithm method)
void reset(QCryptographicHash::Algorithm method) noexcept