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 | |
36 | typedef unsigned char BitSequence; |
37 | typedef unsigned long long DataLength; |
38 | typedef 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" |
45 | typedef spongeState hashState; |
46 | |
47 | #include "../../3rdparty/sha3/KeccakNISTInterface.c" |
48 | |
49 | /* |
50 | This lets us choose between SHA3 implementations at build time. |
51 | */ |
52 | typedef spongeState SHA3Context; |
53 | typedef HashReturn (SHA3Init)(hashState *state, int hashbitlen); |
54 | typedef HashReturn (SHA3Update)(hashState *state, const BitSequence *data, DataLength databitlen); |
55 | typedef 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 | |
61 | Q_CONSTINIT static SHA3Init * const sha3Init = Init; |
62 | Q_CONSTINIT static SHA3Update * const sha3Update = Update; |
63 | Q_CONSTINIT static SHA3Final * const sha3Final = Final; |
64 | |
65 | #else // 32 bit optimised fallback |
66 | |
67 | #include "../../3rdparty/sha3/KeccakF-1600-opt32.c" |
68 | |
69 | Q_CONSTINIT static SHA3Init * const sha3Init = Init; |
70 | Q_CONSTINIT static SHA3Update * const sha3Update = Update; |
71 | Q_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 | */ |
86 | static int SHA224_256AddLength(SHA256Context *context, unsigned int length); |
87 | static 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 | |
97 | static inline int SHA224_256AddLength(SHA256Context *context, unsigned int length) |
98 | { |
99 | uint32_t addTemp; |
100 | return SHA224_256AddLengthM(context, length); |
101 | } |
102 | static 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 | |
125 | QT_BEGIN_NAMESPACE |
126 | |
127 | static 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 | |
172 | static 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 | |
181 | using HashResult = QSmallByteArray<maxHashLength()>; |
182 | |
183 | #ifdef USING_OPENSSL30 |
184 | static 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 | */ |
225 | static 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 | |
238 | class QCryptographicHashPrivate |
239 | { |
240 | public: |
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 |
333 | void 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 | */ |
431 | QCryptographicHash::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 | */ |
451 | QCryptographicHash::~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 | */ |
480 | void 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 | */ |
490 | QCryptographicHash::Algorithm QCryptographicHash::algorithm() const noexcept |
491 | { |
492 | return d->method; |
493 | } |
494 | |
495 | #ifdef USING_OPENSSL30 |
496 | |
497 | QCryptographicHashPrivate::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 | |
520 | void 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 | |
536 | QCryptographicHashPrivate::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 | |
575 | QCryptographicHashPrivate::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 | |
634 | void 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 | |
640 | void QCryptographicHashPrivate::reset() noexcept |
641 | { |
642 | result.clear(); |
643 | state.reset(method); |
644 | } |
645 | |
646 | #ifdef USING_OPENSSL30 |
647 | |
648 | void 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 | |
668 | void 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 | |
682 | void 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 | */ |
750 | void 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 | */ |
763 | void QCryptographicHash::addData(QByteArrayView bytes) noexcept |
764 | { |
765 | d->addData(bytes); |
766 | } |
767 | |
768 | void QCryptographicHashPrivate::addData(QByteArrayView bytes) noexcept |
769 | { |
770 | state.addData(method, data: bytes); |
771 | result.clear(); |
772 | } |
773 | |
774 | #ifdef USING_OPENSSL30 |
775 | |
776 | void 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 | |
804 | void 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 | */ |
882 | bool QCryptographicHash::addData(QIODevice *device) |
883 | { |
884 | return d->addData(dev: device); |
885 | } |
886 | |
887 | bool 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 | */ |
910 | QByteArray 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 | */ |
925 | QByteArrayView 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 | */ |
938 | void 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 | */ |
953 | void QCryptographicHashPrivate::finalizeUnchecked() noexcept |
954 | { |
955 | state.finalizeUnchecked(method, result); |
956 | } |
957 | |
958 | #ifdef USING_OPENSSL30 |
959 | void 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(©, 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(©, result.data(), length); |
982 | } else { |
983 | evp.finalizeUnchecked(result); |
984 | } |
985 | } |
986 | |
987 | void 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 | |
999 | void 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: ©); |
1007 | sha1ToHash(state: ©, 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: ©, result: result.data()); |
1020 | break; |
1021 | } |
1022 | case QCryptographicHash::Md5: { |
1023 | MD5Context copy = md5Context; |
1024 | result.resizeForOverwrite(s: 16); |
1025 | MD5Final(ctx: ©, digest: result.data()); |
1026 | break; |
1027 | } |
1028 | case QCryptographicHash::Sha224: { |
1029 | SHA224Context copy = sha224Context; |
1030 | result.resizeForOverwrite(s: SHA224HashSize); |
1031 | SHA224Result(context: ©, Message_Digest: result.data()); |
1032 | break; |
1033 | } |
1034 | case QCryptographicHash::Sha256: { |
1035 | SHA256Context copy = sha256Context; |
1036 | result.resizeForOverwrite(s: SHA256HashSize); |
1037 | SHA256Result(context: ©, Message_Digest: result.data()); |
1038 | break; |
1039 | } |
1040 | case QCryptographicHash::Sha384: { |
1041 | SHA384Context copy = sha384Context; |
1042 | result.resizeForOverwrite(s: SHA384HashSize); |
1043 | SHA384Result(context: ©, Message_Digest: result.data()); |
1044 | break; |
1045 | } |
1046 | case QCryptographicHash::Sha512: { |
1047 | SHA512Context copy = sha512Context; |
1048 | result.resizeForOverwrite(s: SHA512HashSize); |
1049 | SHA512Result(context: ©, 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: ©, 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: ©, 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 | */ |
1103 | QByteArray 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 | */ |
1129 | QByteArrayView 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 | */ |
1150 | int 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 | |
1168 | bool QCryptographicHash::supportsAlgorithm(QCryptographicHash::Algorithm method) |
1169 | { |
1170 | return QCryptographicHashPrivate::supportsAlgorithm(method); |
1171 | } |
1172 | |
1173 | bool 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 | |
1223 | static 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 | |
1274 | constexpr 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]] |
1284 | constexpr 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]] |
1294 | constexpr 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 | |
1303 | using HashBlock = QSmallByteArray<maxHashBlockSize()>; |
1304 | |
1305 | static 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 | |
1318 | class QMessageAuthenticationCodePrivate |
1319 | { |
1320 | public: |
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 | */ |
1348 | void 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 | */ |
1383 | void 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 | */ |
1441 | QMessageAuthenticationCode::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 | */ |
1451 | QMessageAuthenticationCode::~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 | */ |
1492 | void 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 | */ |
1530 | void 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 | */ |
1540 | void 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 | */ |
1552 | void 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 | */ |
1563 | bool 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 | */ |
1578 | QByteArrayView 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 | */ |
1589 | QByteArray QMessageAuthenticationCode::result() const |
1590 | { |
1591 | return resultView().toByteArray(); |
1592 | } |
1593 | |
1594 | void QMessageAuthenticationCodePrivate::finalize() |
1595 | { |
1596 | const auto lock = qt_scoped_lock(mutex&: messageHash.finalizeMutex); |
1597 | if (!messageHash.result.isEmpty()) |
1598 | return; |
1599 | finalizeUnchecked(); |
1600 | } |
1601 | |
1602 | void 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 | */ |
1621 | QByteArray 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 | */ |
1648 | QByteArrayView 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 | |
1666 | QT_END_NAMESPACE |
1667 | |
1668 | #ifndef QT_NO_QOBJECT |
1669 | #include "moc_qcryptographichash.cpp" |
1670 | #endif |
1671 |
Definitions
- sha3Init
- sha3Update
- sha3Final
- SHA224_256AddLength
- SHA384_512AddLength
- hashLengthInternal
- maxHashLength
- QCryptographicHashPrivate
- QCryptographicHashPrivate
- ~QCryptographicHashPrivate
- resultView
- State
- Sha3Variant
- sha3Finish
- QCryptographicHash
- ~QCryptographicHash
- reset
- algorithm
- State
- destroy
- reset
- reset
- addData
- addData
- addData
- addData
- addData
- addData
- result
- resultView
- finalize
- finalizeUnchecked
- finalizeUnchecked
- hash
- hashInto
- hashLength
- supportsAlgorithm
- supportsAlgorithm
- qt_hash_block_size
- maxHashBlockSize
- minHashBlockSize
- gcdHashBlockSize
- xored
- QMessageAuthenticationCodePrivate
- QMessageAuthenticationCodePrivate
- setKey
- initMessageHash
- QMessageAuthenticationCode
- ~QMessageAuthenticationCode
- reset
- setKey
- addData
- addData
- addData
- resultView
- result
- finalize
- finalizeUnchecked
- hash
Start learning QML with our Intro Training
Find out more