Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
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#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);
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
126
127template <size_t N>
129{
130 std::array<quint8, N> m_data;
131 static_assert(N <= std::numeric_limits<std::uint8_t>::max());
132 quint8 m_size = 0;
133public:
134 QSmallByteArray() = default;
135 // all compiler-generated SMFs are ok!
136 template <std::size_t M, std::enable_if_t<M < N, bool> = true> // M == N is for copy ctor!
137 constexpr QSmallByteArray(const QSmallByteArray<M> &other) noexcept
138 {
139 assign(other);
140 }
141 template <std::size_t M, std::enable_if_t<M < N, bool> = true> // M == N is for copy-assignment op!
142 constexpr QSmallByteArray &operator=(const QSmallByteArray<M> &other) noexcept
143 {
144 assign(other);
145 return *this;
146 }
147
148 template <typename Container> // ### underconstrained
149 constexpr void assign(const Container &c)
150 {
151 const size_t otherSize = size_t(std::size(c));
152 Q_ASSERT(otherSize < N);
153 memcpy(data(), std::data(c), otherSize);
154 m_size = quint8(otherSize);
155 }
156
157 constexpr quint8 *data() noexcept { return m_data.data(); }
158 constexpr const quint8 *data() const noexcept { return m_data.data(); }
159 constexpr qsizetype size() const noexcept { return qsizetype{m_size}; }
160 constexpr quint8 &operator[](qsizetype n)
161 {
162 Q_ASSERT(n < size());
163 return data()[n];
164 }
165 constexpr const quint8 &operator[](qsizetype n) const
166 {
167 Q_ASSERT(n < size());
168 return data()[n];
169 }
170 constexpr bool isEmpty() const noexcept { return size() == 0; }
171 constexpr void clear() noexcept { m_size = 0; }
172 constexpr void resizeForOverwrite(qsizetype s)
173 {
174 Q_ASSERT(s >= 0);
175 Q_ASSERT(size_t(s) <= N);
176 m_size = std::uint8_t(s);
177 }
178 constexpr void resize(qsizetype s, quint8 v)
179 {
180 const auto oldSize = size();
181 resizeForOverwrite(s);
182 if (s > oldSize)
183 memset(data() + oldSize, v, size() - oldSize);
184 }
185 constexpr QByteArrayView toByteArrayView() const noexcept
186 { return *this; }
187
188 constexpr auto begin() noexcept { return data(); }
189 constexpr auto begin() const noexcept { return data(); }
190 constexpr auto cbegin() const noexcept { return begin(); }
191 constexpr auto end() noexcept { return data() + size(); }
192 constexpr auto end() const noexcept { return data() + size(); }
193 constexpr auto cend() const noexcept { return end(); }
194};
195
197{
198 switch (method) {
199#define CASE(Enum, Size) \
200 case QCryptographicHash:: Enum : \
201 return Size \
202 /*end*/
203 CASE(Sha1, 20);
204#ifndef QT_CRYPTOGRAPHICHASH_ONLY_SHA1
205 CASE(Md4, 16);
206 CASE(Md5, 16);
207 CASE(Sha224, SHA224HashSize);
208 CASE(Sha256, SHA256HashSize);
209 CASE(Sha384, SHA384HashSize);
210 CASE(Sha512, SHA512HashSize);
211 CASE(Blake2s_128, 128 / 8);
214 return 160 / 8;
218 return 224 / 8;
223 return 256 / 8;
227 return 384 / 8;
231 return 512 / 8;
232#endif
233#undef CASE
235 // fall through
236 // Q_UNREACHABLE() would be BiC here, as hashLength(~~invalid~~) worked in 6.4
237 }
238 return 0;
239}
240
241static constexpr int maxHashLength()
242{
243 int result = 0;
245 for (int i = 0; i < A::NumAlgorithms; ++i)
246 result = std::max(result, hashLengthInternal(A(i)));
247 return result;
248}
249
251
252#ifdef USING_OPENSSL30
253static constexpr const char * methodToName(QCryptographicHash::Algorithm method) noexcept
254{
255 switch (method) {
256#define CASE(Enum, Name) \
257 case QCryptographicHash:: Enum : \
258 return Name \
259 /*end*/
260 CASE(Sha1, "SHA1");
261 CASE(Md4, "MD4");
262 CASE(Md5, "MD5");
263 CASE(Sha224, "SHA224");
264 CASE(Sha256, "SHA256");
265 CASE(Sha384, "SHA384");
266 CASE(Sha512, "SHA512");
267 CASE(RealSha3_224, "SHA3-224");
268 CASE(RealSha3_256, "SHA3-256");
269 CASE(RealSha3_384, "SHA3-384");
270 CASE(RealSha3_512, "SHA3-512");
271 CASE(Blake2b_512, "BLAKE2B512");
272 CASE(Blake2s_256, "BLAKE2S256");
273#undef CASE
274 default: return nullptr;
275 }
276}
277
278/*
279 Checks whether given method is not provided by OpenSSL and whether we will
280 have a fallback to non-OpenSSL implementation.
281*/
282static constexpr bool useNonOpenSSLFallback(QCryptographicHash::Algorithm method) noexcept
283{
289 return true;
290
291 return false;
292}
293#endif // USING_OPENSSL30
294
296{
297public:
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 struct OSSL_PROVIDER_deleter {
330 void operator()(OSSL_PROVIDER *provider) const noexcept {
331 OSSL_PROVIDER_unload(provider);
332 }
333 };
334
335 using EVP_MD_CTX_ptr = std::unique_ptr<EVP_MD_CTX, EVP_MD_CTX_deleter>;
336 using EVP_MD_ptr = std::unique_ptr<EVP_MD, EVP_MD_deleter>;
337 using OSSL_PROVIDER_ptr = std::unique_ptr<OSSL_PROVIDER, OSSL_PROVIDER_deleter>;
338 struct EVP {
339 EVP_MD_ptr algorithm;
340 EVP_MD_CTX_ptr context;
341 OSSL_PROVIDER_ptr defaultProvider;
342 OSSL_PROVIDER_ptr legacyProvider;
343 bool initializationFailed;
344
346 void reset() noexcept;
347 void finalizeUnchecked(HashResult &result) noexcept;
348 };
349#endif
350
351 union State {
354#ifdef USING_OPENSSL30
355 ~State() {}
356#endif
357
360 void finalizeUnchecked(QCryptographicHash::Algorithm method, HashResult &result) noexcept;
361
362 Sha1State sha1Context;
363#ifndef QT_CRYPTOGRAPHICHASH_ONLY_SHA1
364#ifdef USING_OPENSSL30
365 EVP evp;
366#else
367 MD5Context md5Context;
368 md4_context md4Context;
369 SHA224Context sha224Context;
370 SHA256Context sha256Context;
371 SHA384Context sha384Context;
372 SHA512Context sha512Context;
373#endif
375
376 enum class Sha3Variant { Sha3, Keccak };
377 void sha3Finish(HashResult &result, int bitCount, Sha3Variant sha3Variant);
378 blake2b_state blake2bContext;
379 blake2s_state blake2sContext;
380#endif
382 // protects result in finalize()
385
387};
388
389#ifndef QT_CRYPTOGRAPHICHASH_ONLY_SHA1
391 Sha3Variant sha3Variant)
392{
393 /*
394 FIPS 202 §6.1 defines SHA-3 in terms of calculating the Keccak function
395 over the original message with the two-bit suffix "01" appended to it.
396 This variable stores that suffix (and it's fed into the calculations
397 when the hash is returned to users).
398
399 Only 2 bits of this variable are actually used (see the call to sha3Update
400 below). The Keccak implementation we're using will actually use the
401 *leftmost* 2 bits, and interpret them right-to-left. In other words, the
402 bits must appear in order of *increasing* significance; and as the two most
403 significant bits of the byte -- the rightmost 6 are ignored. (Yes, this
404 seems self-contradictory, but it's the way it is...)
405
406 Overall, this means:
407 * the leftmost two bits must be "10" (not "01"!);
408 * we don't care what the other six bits are set to (they can be set to
409 any value), but we arbitrarily set them to 0;
410
411 and for an unsigned char this gives us 0b10'00'00'00, or 0x80.
412 */
413 static const unsigned char sha3FinalSuffix = 0x80;
414
415 result.resizeForOverwrite(bitCount / 8);
416
418
419 switch (sha3Variant) {
421 sha3Update(&copy, reinterpret_cast<const BitSequence *>(&sha3FinalSuffix), 2);
422 break;
424 break;
425 }
426
427 sha3Final(&copy, result.data());
428}
429#endif
430
494
514
540{
541 d->reset();
542}
543
553
554#ifdef USING_OPENSSL30
555
557{
563 reset(method);
567 new (&blake2bContext) blake2b_state;
568 reset(method);
572 new (&blake2sContext) blake2s_state;
573 reset(method);
574 } else {
575 new (&evp) EVP(method);
576 }
577}
578
580{
591 evp.~EVP();
592 }
593}
594
595QCryptographicHashPrivate::EVP::EVP(QCryptographicHash::Algorithm method)
596 : initializationFailed{true}
597{
599 /*
600 * We need to load the legacy provider in order to have the MD4
601 * algorithm available.
602 */
603 legacyProvider = OSSL_PROVIDER_ptr(OSSL_PROVIDER_load(nullptr, "legacy"));
604
605 if (!legacyProvider)
606 return;
607 }
608
609 defaultProvider = OSSL_PROVIDER_ptr(OSSL_PROVIDER_load(nullptr, "default"));
610 if (!defaultProvider)
611 return;
612
613 context = EVP_MD_CTX_ptr(EVP_MD_CTX_new());
614
615 if (!context) {
616 return;
617 }
618
619 /*
620 * Using the "-fips" option will disable the global "fips=yes" for
621 * this one lookup and the algorithm can be fetched from any provider
622 * that implements the algorithm (including the FIPS provider).
623 */
624 algorithm = EVP_MD_ptr(EVP_MD_fetch(nullptr, methodToName(method), "-fips"));
625 if (!algorithm) {
626 return;
627 }
628
629 initializationFailed = !EVP_DigestInit_ex(context.get(), algorithm.get(), nullptr);
630}
631
632#else // USING_OPENSSL30
633
635{
636 switch (method) {
638 new (&sha1Context) Sha1State;
639 break;
640#ifdef QT_CRYPTOGRAPHICHASH_ONLY_SHA1
641 default:
642 Q_ASSERT_X(false, "QCryptographicHash", "Method not compiled in");
643 Q_UNREACHABLE();
644 break;
645#else
647 new (&md4Context) md4_context;
648 break;
650 new (&md5Context) MD5Context;
651 break;
653 new (&sha224Context) SHA224Context;
654 break;
656 new (&sha256Context) SHA256Context;
657 break;
659 new (&sha384Context) SHA384Context;
660 break;
662 new (&sha512Context) SHA512Context;
663 break;
673 break;
678 new (&blake2bContext) blake2b_state;
679 break;
684 new (&blake2sContext) blake2s_state;
685 break;
686#endif
688 Q_UNREACHABLE();
689 }
690 reset(method);
691}
692
694{
695 static_assert(std::is_trivially_destructible_v<State>); // so nothing to do here
696}
697#endif // !USING_OPENSSL30
698
700{
701 result.clear();
702 state.reset(method);
703}
704
705#ifdef USING_OPENSSL30
706
708{
713 sha3Init(&sha3Context, hashLengthInternal(method) * 8);
717 blake2b_init(&blake2bContext, hashLengthInternal(method));
721 blake2s_init(&blake2sContext, hashLengthInternal(method));
722 } else {
723 evp.reset();
724 }
725}
726
727void QCryptographicHashPrivate::EVP::reset() noexcept
728{
729 if (!initializationFailed) {
731 Q_ASSERT(algorithm);
732 // everything already set up - just reset the context
733 EVP_MD_CTX_reset(context.get());
734 initializationFailed = !EVP_DigestInit_ex(context.get(), algorithm.get(), nullptr);
735 }
736 // if initializationFailed first time around, it will not succeed this time, either
737}
738
739#else // USING_OPENSSL30
740
742{
743 switch (method) {
745 sha1InitState(&sha1Context);
746 break;
747#ifdef QT_CRYPTOGRAPHICHASH_ONLY_SHA1
748 default:
749 Q_ASSERT_X(false, "QCryptographicHash", "Method not compiled in");
750 Q_UNREACHABLE();
751 break;
752#else
754 md4_init(&md4Context);
755 break;
757 MD5Init(&md5Context);
758 break;
760 SHA224Reset(&sha224Context);
761 break;
763 SHA256Reset(&sha256Context);
764 break;
766 SHA384Reset(&sha384Context);
767 break;
769 SHA512Reset(&sha512Context);
770 break;
779 sha3Init(&sha3Context, hashLengthInternal(method) * 8);
780 break;
785 blake2b_init(&blake2bContext, hashLengthInternal(method));
786 break;
791 blake2s_init(&blake2sContext, hashLengthInternal(method));
792 break;
793#endif
795 Q_UNREACHABLE();
796 }
797}
798
799#endif // USING_OPENSSL30
800
801#if QT_DEPRECATED_SINCE(6, 4)
810{
811 Q_ASSERT(length >= 0);
813}
814#endif
815
823{
824 d->addData(bytes);
825}
826
828{
829 state.addData(method, bytes);
830 result.clear();
831}
832
833#ifdef USING_OPENSSL30
834
836 QByteArrayView bytes) noexcept
837{
838 const char *data = bytes.data();
839 auto length = bytes.size();
840 // all functions take size_t length, so we don't need to loop around them:
841 {
846 sha3Update(&sha3Context, reinterpret_cast<const BitSequence *>(data), uint64_t(length) * 8);
850 blake2b_update(&blake2bContext, reinterpret_cast<const uint8_t *>(data), length);
854 blake2s_update(&blake2sContext, reinterpret_cast<const uint8_t *>(data), length);
855 } else if (!evp.initializationFailed) {
856 EVP_DigestUpdate(evp.context.get(), (const unsigned char *)data, length);
857 }
858 }
859}
860
861#else // USING_OPENSSL30
862
864 QByteArrayView bytes) noexcept
865{
866 const char *data = bytes.data();
867 auto length = bytes.size();
868
869#if QT_POINTER_SIZE == 8
870 // feed the data UINT_MAX bytes at a time, as some of the methods below
871 // take a uint (of course, feeding more than 4G of data into the hashing
872 // functions will be pretty slow anyway)
873 for (auto remaining = length; remaining; remaining -= length, data += length) {
874 length = qMin(qsizetype(std::numeric_limits<uint>::max()), remaining);
875#else
876 {
877#endif
878 switch (method) {
880 sha1Update(&sha1Context, (const unsigned char *)data, length);
881 break;
882#ifdef QT_CRYPTOGRAPHICHASH_ONLY_SHA1
883 default:
884 Q_ASSERT_X(false, "QCryptographicHash", "Method not compiled in");
885 Q_UNREACHABLE();
886 break;
887#else
889 md4_update(&md4Context, (const unsigned char *)data, length);
890 break;
892 MD5Update(&md5Context, (const unsigned char *)data, length);
893 break;
895 SHA224Input(&sha224Context, reinterpret_cast<const unsigned char *>(data), length);
896 break;
898 SHA256Input(&sha256Context, reinterpret_cast<const unsigned char *>(data), length);
899 break;
901 SHA384Input(&sha384Context, reinterpret_cast<const unsigned char *>(data), length);
902 break;
904 SHA512Input(&sha512Context, reinterpret_cast<const unsigned char *>(data), length);
905 break;
914 sha3Update(&sha3Context, reinterpret_cast<const BitSequence *>(data), uint64_t(length) * 8);
915 break;
920 blake2b_update(&blake2bContext, reinterpret_cast<const uint8_t *>(data), length);
921 break;
926 blake2s_update(&blake2sContext, reinterpret_cast<const uint8_t *>(data), length);
927 break;
928#endif
930 Q_UNREACHABLE();
931 }
932 }
933}
934#endif // !USING_OPENSSL30
935
942{
943 return d->addData(device);
944}
945
947{
948 if (!device->isReadable())
949 return false;
950
951 if (!device->isOpen())
952 return false;
953
954 char buffer[1024];
956
957 while ((length = device->read(buffer, sizeof(buffer))) > 0)
958 addData({buffer, qsizetype(length)}); // length always <= 1024
959
960 return device->atEnd();
961}
962
963
973
985{
986 // resultView() is a const function, so concurrent calls are allowed; protect:
987 d->finalize();
988 // resultView() remains(!) valid even after we dropped the mutex in finalize()
989 return d->resultView();
990}
991
998{
999 const auto lock = qt_scoped_lock(finalizeMutex);
1000 // check that no other thread already finalizeUnchecked()'ed before us:
1001 if (!result.isEmpty())
1002 return;
1004}
1005
1013{
1014 state.finalizeUnchecked(method, result);
1015}
1016
1017#ifdef USING_OPENSSL30
1019 HashResult &result) noexcept
1020{
1025 sha3Finish(result, 8 * hashLengthInternal(method), Sha3Variant::Keccak);
1029 const auto length = hashLengthInternal(method);
1030 blake2b_state copy = blake2bContext;
1031 result.resizeForOverwrite(length);
1032 blake2b_final(&copy, result.data(), length);
1036 const auto length = hashLengthInternal(method);
1037 blake2s_state copy = blake2sContext;
1038 result.resizeForOverwrite(length);
1039 blake2s_final(&copy, result.data(), length);
1040 } else {
1041 evp.finalizeUnchecked(result);
1042 }
1043}
1044
1045void QCryptographicHashPrivate::EVP::finalizeUnchecked(HashResult &result) noexcept
1046{
1047 if (!initializationFailed) {
1048 EVP_MD_CTX_ptr copy = EVP_MD_CTX_ptr(EVP_MD_CTX_new());
1049 EVP_MD_CTX_copy_ex(copy.get(), context.get());
1050 result.resizeForOverwrite(EVP_MD_get_size(algorithm.get()));
1051 EVP_DigestFinal_ex(copy.get(), result.data(), nullptr);
1052 }
1053}
1054
1055#else // USING_OPENSSL30
1056
1058 HashResult &result) noexcept
1059{
1060 switch (method) {
1062 Sha1State copy = sha1Context;
1063 result.resizeForOverwrite(20);
1064 sha1FinalizeState(&copy);
1065 sha1ToHash(&copy, result.data());
1066 break;
1067 }
1068#ifdef QT_CRYPTOGRAPHICHASH_ONLY_SHA1
1069 default:
1070 Q_ASSERT_X(false, "QCryptographicHash", "Method not compiled in");
1071 Q_UNREACHABLE();
1072 break;
1073#else
1075 md4_context copy = md4Context;
1076 result.resizeForOverwrite(MD4_RESULTLEN);
1077 md4_final(&copy, result.data());
1078 break;
1079 }
1081 MD5Context copy = md5Context;
1082 result.resizeForOverwrite(16);
1083 MD5Final(&copy, result.data());
1084 break;
1085 }
1087 SHA224Context copy = sha224Context;
1088 result.resizeForOverwrite(SHA224HashSize);
1089 SHA224Result(&copy, result.data());
1090 break;
1091 }
1093 SHA256Context copy = sha256Context;
1094 result.resizeForOverwrite(SHA256HashSize);
1095 SHA256Result(&copy, result.data());
1096 break;
1097 }
1099 SHA384Context copy = sha384Context;
1100 result.resizeForOverwrite(SHA384HashSize);
1101 SHA384Result(&copy, result.data());
1102 break;
1103 }
1105 SHA512Context copy = sha512Context;
1106 result.resizeForOverwrite(SHA512HashSize);
1107 SHA512Result(&copy, result.data());
1108 break;
1109 }
1114 sha3Finish(result, 8 * hashLengthInternal(method), Sha3Variant::Sha3);
1115 break;
1116 }
1121 sha3Finish(result, 8 * hashLengthInternal(method), Sha3Variant::Keccak);
1122 break;
1123 }
1128 const auto length = hashLengthInternal(method);
1129 blake2b_state copy = blake2bContext;
1130 result.resizeForOverwrite(length);
1131 blake2b_final(&copy, result.data(), length);
1132 break;
1133 }
1138 const auto length = hashLengthInternal(method);
1139 blake2s_state copy = blake2sContext;
1140 result.resizeForOverwrite(length);
1141 blake2s_final(&copy, result.data(), length);
1142 break;
1143 }
1144#endif
1146 Q_UNREACHABLE();
1147 }
1148}
1149#endif // !USING_OPENSSL30
1150
1158{
1160 hash.addData(data);
1161 hash.finalizeUnchecked(); // no mutex needed: no-one but us has access to 'hash'
1162 return hash.resultView().toByteArray();
1163}
1164
1174
1192
1194{
1195#ifdef USING_OPENSSL30
1196 // OpenSSL doesn't support Blake2b{60,236,384} and Blake2s{128,160,224}
1197 // and these would automatically return FALSE in that case, while they are
1198 // actually supported by our non-OpenSSL implementation.
1199 if (useNonOpenSSLFallback(method))
1200 return true;
1201
1202 auto legacyProvider = OSSL_PROVIDER_ptr(OSSL_PROVIDER_load(nullptr, "legacy"));
1203 auto defaultProvider = OSSL_PROVIDER_ptr(OSSL_PROVIDER_load(nullptr, "default"));
1204
1205 const char *restriction = "-fips";
1206 EVP_MD_ptr algorithm = EVP_MD_ptr(EVP_MD_fetch(nullptr, methodToName(method), restriction));
1207
1208 return algorithm != nullptr;
1209#else
1210 switch (method) {
1212#ifndef QT_CRYPTOGRAPHICHASH_ONLY_SHA1
1235#endif
1236 return true;
1238 };
1239 return false;
1240#endif // !USING_OPENSSL3
1241}
1242
1244{
1245 switch (method) {
1247 return SHA1_Message_Block_Size;
1248#ifndef QT_CRYPTOGRAPHICHASH_ONLY_SHA1
1250 return 64;
1252 return 64;
1254 return SHA224_Message_Block_Size;
1256 return SHA256_Message_Block_Size;
1258 return SHA384_Message_Block_Size;
1260 return SHA512_Message_Block_Size;
1263 return 144;
1266 return 136;
1269 return 104;
1272 return 72;
1277 return BLAKE2B_BLOCKBYTES;
1282 return BLAKE2S_BLOCKBYTES;
1283#endif // QT_CRYPTOGRAPHICHASH_ONLY_SHA1
1285#if !defined(Q_CC_GNU_ONLY) || Q_CC_GNU >= 900
1286 // GCC 8 has trouble with Q_UNREACHABLE() in constexpr functions
1287 Q_UNREACHABLE();
1288#endif
1289 break;
1290 }
1291 return 0;
1292}
1293
1294constexpr int maxHashBlockSize()
1295{
1296 int result = 0;
1298 for (int i = 0; i < A::NumAlgorithms ; ++i)
1299 result = std::max(result, qt_hash_block_size(A(i)));
1300 return result;
1301}
1302
1303[[maybe_unused]]
1304constexpr int minHashBlockSize()
1305{
1306 int result = INT_MAX;
1308 for (int i = 0; i < A::NumAlgorithms ; ++i)
1309 result = std::min(result, qt_hash_block_size(A(i)));
1310 return result;
1311}
1312
1313[[maybe_unused]]
1314constexpr int gcdHashBlockSize()
1315{
1316 int result = 0;
1318 for (int i = 0; i < A::NumAlgorithms ; ++i)
1319 result = std::gcd(result, qt_hash_block_size(A(i)));
1320 return result;
1321}
1322
1324
1325static HashBlock xored(const HashBlock &block, quint8 val) noexcept
1326{
1327 // some hints for the optimizer:
1328 Q_ASSERT(block.size() >= minHashBlockSize());
1329 Q_ASSERT(block.size() <= maxHashBlockSize());
1330 Q_ASSERT(block.size() % gcdHashBlockSize() == 0);
1332 result.resizeForOverwrite(block.size());
1333 for (qsizetype i = 0; i < block.size(); ++i)
1334 result[i] = block[i] ^ val;
1335 return result;
1336}
1337
1339{
1340public:
1345
1348
1349 void setKey(QByteArrayView k) noexcept;
1350 void initMessageHash() noexcept;
1351 void finalize();
1352
1353 // when not called from the static hash() function, this function needs to be
1354 // called with messageHash.finalizeMutex held:
1355 void finalizeUnchecked() noexcept;
1356 // END functions that need to be called with finalizeMutex held
1357};
1358
1369{
1370 const int blockSize = qt_hash_block_size(messageHash.method);
1371
1372 if (newKey.size() > blockSize) {
1373 messageHash.addData(newKey);
1374 messageHash.finalizeUnchecked();
1375 static_assert([] {
1377 for (int i = 0; i < A::NumAlgorithms; ++i) {
1379 return false;
1380 }
1381 return true;
1382 }(), "this code assumes that a hash's result always fits into that hash's block size");
1383 key = messageHash.result;
1384 messageHash.reset();
1385 } else {
1386 key.assign(newKey);
1387 }
1388
1389 if (key.size() < blockSize)
1390 key.resize(blockSize, '\0');
1391
1392 initMessageHash();
1393}
1394
1404{
1405 messageHash.addData(xored(key, 0x36));
1406}
1407
1453
1460
1467
1475
1513{
1514 d->messageHash.reset();
1515 d->initMessageHash();
1516}
1517
1551{
1552 d->messageHash.reset();
1553 d->setKey(key);
1554}
1555
1564
1573{
1574 d->messageHash.addData(data);
1575}
1576
1587
1599{
1600 d->finalize();
1601 return d->messageHash.resultView();
1602}
1603
1613
1615{
1616 const auto lock = qt_scoped_lock(messageHash.finalizeMutex);
1617 if (!messageHash.result.isEmpty())
1618 return;
1620}
1621
1623{
1625 const HashResult hashedMessage = messageHash.result;
1626
1628 messageHash.addData(xored(key, 0x5c));
1629 messageHash.addData(hashedMessage);
1631}
1632
1641{
1643 mac.setKey(key);
1644 mac.messageHash.addData(message);
1645 mac.finalizeUnchecked();
1646 return mac.messageHash.resultView().toByteArray();
1647}
1648
1650
1651#ifndef QT_NO_QOBJECT
1652#include "moc_qcryptographichash.cpp"
1653#endif
NSData * m_data
IOBluetoothDevice * device
QByteArray toByteArray() const
Definition qbytearray.h:796
\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:281
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)
HashReturn SHA3Update(hashState *state, const BitSequence *data, DataLength databitlen)
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
HashReturn SHA3Init(hashState *state, int hashbitlen)
static Q_CONSTINIT SHA3Init *const sha3Init
unsigned long long DataLength
spongeState SHA3Context
HashReturn SHA3Final(hashState *state, BitSequence *hashval)
unsigned char BitSequence
spongeState hashState
#define CASE(Enum, Size)
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
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum GLuint buffer
GLuint GLsizei const GLchar * message
GLfloat n
GLdouble s
[6]
Definition qopenglext.h:235
GLboolean reset
const GLubyte * c
GLuint GLfloat * val
GLuint64EXT * result
[6]
#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:165
long long qint64
Definition qtypes.h:60
unsigned char quint8
Definition qtypes.h:46
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