diff --git a/src/corelib/tools/qcryptographichash.cpp b/src/corelib/tools/qcryptographichash.cpp index 7ae6fd97d1e..8e2abc2307a 100644 --- a/src/corelib/tools/qcryptographichash.cpp +++ b/src/corelib/tools/qcryptographichash.cpp @@ -31,6 +31,7 @@ #include "../../3rdparty/md5/md5.cpp" #include "../../3rdparty/md4/md4.h" #include "../../3rdparty/md4/md4.cpp" +#endif // !QT_CONFIG(openssl_hash) typedef unsigned char BitSequence; typedef unsigned long long DataLength; @@ -71,6 +72,7 @@ Q_CONSTINIT static SHA3Final * const sha3Final = Final; #endif +#if !QT_CONFIG(openssl_hash) /* These 2 functions replace macros of the same name in sha224-256.c and sha384-512.c. Originally, these macros relied on a global static 'addTemp' @@ -266,10 +268,6 @@ static constexpr const char * methodToName(QCryptographicHash::Algorithm method) CASE(RealSha3_256, "SHA3-256"); CASE(RealSha3_384, "SHA3-384"); CASE(RealSha3_512, "SHA3-512"); - CASE(Keccak_224, "SHA3-224"); - CASE(Keccak_256, "SHA3-256"); - CASE(Keccak_384, "SHA3-384"); - CASE(Keccak_512, "SHA3-512"); CASE(Blake2b_512, "BLAKE2B512"); CASE(Blake2s_256, "BLAKE2S256"); #undef CASE @@ -283,7 +281,9 @@ static constexpr const char * methodToName(QCryptographicHash::Algorithm method) */ static constexpr bool useNonOpenSSLFallback(QCryptographicHash::Algorithm method) noexcept { - if (method == QCryptographicHash::Blake2b_160 || method == QCryptographicHash::Blake2b_256 || + if (method == QCryptographicHash::Keccak_224 || method == QCryptographicHash::Keccak_256 || + method == QCryptographicHash::Keccak_384 || method == QCryptographicHash::Keccak_512 || + method == QCryptographicHash::Blake2b_160 || method == QCryptographicHash::Blake2b_256 || method == QCryptographicHash::Blake2b_384 || method == QCryptographicHash::Blake2s_128 || method == QCryptographicHash::Blake2s_160 || method == QCryptographicHash::Blake2s_224) return true; @@ -370,11 +370,11 @@ public: SHA256Context sha256Context; SHA384Context sha384Context; SHA512Context sha512Context; +#endif SHA3Context sha3Context; enum class Sha3Variant { Sha3, Keccak }; void sha3Finish(HashResult &result, int bitCount, Sha3Variant sha3Variant); -#endif blake2b_state blake2bContext; blake2s_state blake2sContext; #endif @@ -387,7 +387,6 @@ public: }; #ifndef QT_CRYPTOGRAPHICHASH_ONLY_SHA1 -#ifndef USING_OPENSSL30 void QCryptographicHashPrivate::State::sha3Finish(HashResult &result, int bitCount, Sha3Variant sha3Variant) { @@ -427,7 +426,6 @@ void QCryptographicHashPrivate::State::sha3Finish(HashResult &result, int bitCou sha3Final(©, result.data()); } -#endif // !QT_CONFIG(opensslv30) #endif /*! @@ -557,9 +555,15 @@ QCryptographicHash::Algorithm QCryptographicHash::algorithm() const noexcept QCryptographicHashPrivate::State::State(QCryptographicHash::Algorithm method) { - if (method == QCryptographicHash::Blake2b_160 || - method == QCryptographicHash::Blake2b_256 || - method == QCryptographicHash::Blake2b_384) { + if (method == QCryptographicHash::Keccak_224 || + method == QCryptographicHash::Keccak_256 || + method == QCryptographicHash::Keccak_384 || + method == QCryptographicHash::Keccak_512) { + new (&sha3Context) SHA3Context; + reset(method); + } else if (method == QCryptographicHash::Blake2b_160 || + method == QCryptographicHash::Blake2b_256 || + method == QCryptographicHash::Blake2b_384) { new (&blake2bContext) blake2b_state; reset(method); } else if (method == QCryptographicHash::Blake2s_128 || @@ -574,7 +578,11 @@ QCryptographicHashPrivate::State::State(QCryptographicHash::Algorithm method) void QCryptographicHashPrivate::State::destroy(QCryptographicHash::Algorithm method) { - if (method != QCryptographicHash::Blake2b_160 && + if (method != QCryptographicHash::Keccak_224 && + method != QCryptographicHash::Keccak_256 && + method != QCryptographicHash::Keccak_384 && + method != QCryptographicHash::Keccak_512 && + method != QCryptographicHash::Blake2b_160 && method != QCryptographicHash::Blake2b_256 && method != QCryptographicHash::Blake2b_384 && method != QCryptographicHash::Blake2s_128 && @@ -698,9 +706,14 @@ void QCryptographicHashPrivate::reset() noexcept void QCryptographicHashPrivate::State::reset(QCryptographicHash::Algorithm method) noexcept { - if (method == QCryptographicHash::Blake2b_160 || - method == QCryptographicHash::Blake2b_256 || - method == QCryptographicHash::Blake2b_384) { + if (method == QCryptographicHash::Keccak_224 || + method == QCryptographicHash::Keccak_256 || + method == QCryptographicHash::Keccak_384 || + method == QCryptographicHash::Keccak_512) { + sha3Init(&sha3Context, hashLengthInternal(method) * 8); + } else if (method == QCryptographicHash::Blake2b_160 || + method == QCryptographicHash::Blake2b_256 || + method == QCryptographicHash::Blake2b_384) { blake2b_init(&blake2bContext, hashLengthInternal(method)); } else if (method == QCryptographicHash::Blake2s_128 || method == QCryptographicHash::Blake2s_160 || @@ -826,9 +839,14 @@ void QCryptographicHashPrivate::State::addData(QCryptographicHash::Algorithm met auto length = bytes.size(); // all functions take size_t length, so we don't need to loop around them: { - if (method == QCryptographicHash::Blake2b_160 || - method == QCryptographicHash::Blake2b_256 || - method == QCryptographicHash::Blake2b_384) { + if (method == QCryptographicHash::Keccak_224 || + method == QCryptographicHash::Keccak_256 || + method == QCryptographicHash::Keccak_384 || + method == QCryptographicHash::Keccak_512) { + sha3Update(&sha3Context, reinterpret_cast(data), uint64_t(length) * 8); + } else if (method == QCryptographicHash::Blake2b_160 || + method == QCryptographicHash::Blake2b_256 || + method == QCryptographicHash::Blake2b_384) { blake2b_update(&blake2bContext, reinterpret_cast(data), length); } else if (method == QCryptographicHash::Blake2s_128 || method == QCryptographicHash::Blake2s_160 || @@ -1000,9 +1018,14 @@ void QCryptographicHashPrivate::finalizeUnchecked() noexcept void QCryptographicHashPrivate::State::finalizeUnchecked(QCryptographicHash::Algorithm method, HashResult &result) noexcept { - if (method == QCryptographicHash::Blake2b_160 || - method == QCryptographicHash::Blake2b_256 || - method == QCryptographicHash::Blake2b_384) { + if (method == QCryptographicHash::Keccak_224 || + method == QCryptographicHash::Keccak_256 || + method == QCryptographicHash::Keccak_384 || + method == QCryptographicHash::Keccak_512) { + sha3Finish(result, 8 * hashLengthInternal(method), Sha3Variant::Keccak); + } else if (method == QCryptographicHash::Blake2b_160 || + method == QCryptographicHash::Blake2b_256 || + method == QCryptographicHash::Blake2b_384) { const auto length = hashLengthInternal(method); blake2b_state copy = blake2bContext; result.resizeForOverwrite(length); diff --git a/tests/auto/corelib/tools/qcryptographichash/tst_qcryptographichash.cpp b/tests/auto/corelib/tools/qcryptographichash/tst_qcryptographichash.cpp index dca993010d4..d54d74fdfff 100644 --- a/tests/auto/corelib/tools/qcryptographichash/tst_qcryptographichash.cpp +++ b/tests/auto/corelib/tools/qcryptographichash/tst_qcryptographichash.cpp @@ -23,6 +23,8 @@ private slots: void sha1(); void sha3_data(); void sha3(); + void keccak(); + void keccak_data(); void blake2_data(); void blake2(); void files_data(); @@ -150,6 +152,27 @@ void tst_QCryptographicHash::intermediary_result_data() << QByteArray("abc") << QByteArray("abc") << QByteArray::fromHex("B751850B1A57168A5693CD924B6B096E08F621827444F70D884F5D0240D2712E10E116E9192AF3C91A7EC57647E3934057340B4CF408D5A56592F8274EEC53F0") << QByteArray::fromHex("BB582DA40D15399ACF62AFCBBD6CFC9EE1DD5129B1EF9935DD3B21668F1A73D7841018BE3B13F281C3A8E9DA7EDB60F57B9F9F1C04033DF4CE3654B7B2ADB310"); + + QTest::newRow("keccak_224_abc_abc") + << int(QCryptographicHash::Keccak_224) + << QByteArray("abc") << QByteArray("abc") + << QByteArray::fromHex("c30411768506ebe1c2871b1ee2e87d38df342317300a9b97a95ec6a8") + << QByteArray::fromHex("048330e7c7c8b4a41ab713b3a6f958d77b8cf3ee969930f1584dd550"); + QTest::newRow("keccak_256_abc_abc") + << int(QCryptographicHash::Keccak_256) + << QByteArray("abc") << QByteArray("abc") + << QByteArray::fromHex("4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45") + << QByteArray::fromHex("9f0adad0a59b05d2e04a1373342b10b9eb16c57c164c8a3bfcbf46dccee39a21"); + QTest::newRow("keccak_384_abc_abc") + << int(QCryptographicHash::Keccak_384) + << QByteArray("abc") << QByteArray("abc") + << QByteArray::fromHex("f7df1165f033337be098e7d288ad6a2f74409d7a60b49c36642218de161b1f99f8c681e4afaf31a34db29fb763e3c28e") + << QByteArray::fromHex("d733b87d392d270889d3da23ae113f349e25574b445f319cde4cd3f877c753e9e3c65980421339b3a131457ff393939f"); + QTest::newRow("keccak_512_abc_abc") + << int(QCryptographicHash::Keccak_512) + << QByteArray("abc") << QByteArray("abc") + << QByteArray::fromHex("18587dc2ea106b9a1563e32b3312421ca164c7f1f07bc922a9c83d77cea3a1e5d0c69910739025372dc14ac9642629379540c17e2a65b19d77aa511a9d00bb96") + << QByteArray::fromHex("a7c392d2a42155761ca76bddde1c47d55486b007edf465397bfb9dfa74d11c8f0d7c86cd29415283f1b5e7f655cec25b869c9e9c33a8986f0b38542fb12bfb93"); } void tst_QCryptographicHash::intermediary_result() @@ -256,6 +279,68 @@ void tst_QCryptographicHash::sha3() QCOMPARE(result, expectedResult); } +void tst_QCryptographicHash::keccak_data() +{ + QTest::addColumn("algorithm"); + QTest::addColumn("data"); + QTest::addColumn("expectedResult"); + +#define ROW(Tag, Algorithm, Input, Result) \ + QTest::newRow(Tag) << Algorithm << QByteArrayLiteral(Input) << QByteArray::fromHex(Result) + + ROW("keccak_224_pangram", + QCryptographicHash::Keccak_224, + "The quick brown fox jumps over the lazy dog", + "310aee6b30c47350576ac2873fa89fd190cdc488442f3ef654cf23fe"); + + ROW("keccak_224_pangram_dot", + QCryptographicHash::Keccak_224, + "The quick brown fox jumps over the lazy dog.", + "c59d4eaeac728671c635ff645014e2afa935bebffdb5fbd207ffdeab"); + + ROW("keccak_256_pangram", + QCryptographicHash::Keccak_256, + "The quick brown fox jumps over the lazy dog", + "4d741b6f1eb29cb2a9b9911c82f56fa8d73b04959d3d9d222895df6c0b28aa15"); + + ROW("keccak_256_pangram_dot", + QCryptographicHash::Keccak_256, + "The quick brown fox jumps over the lazy dog.", + "578951e24efd62a3d63a86f7cd19aaa53c898fe287d2552133220370240b572d"); + + ROW("keccak_384_pangram", + QCryptographicHash::Keccak_384, + "The quick brown fox jumps over the lazy dog", + "283990fa9d5fb731d786c5bbee94ea4db4910f18c62c03d173fc0a5e494422e8a0b3da7574dae7fa0baf005e504063b3"); + + ROW("keccak_384_pangram_dot", + QCryptographicHash::Keccak_384, + "The quick brown fox jumps over the lazy dog.", + "9ad8e17325408eddb6edee6147f13856ad819bb7532668b605a24a2d958f88bd5c169e56dc4b2f89ffd325f6006d820b"); + + ROW("skeccak_512_pangram", + QCryptographicHash::Keccak_512, + "The quick brown fox jumps over the lazy dog", + "d135bb84d0439dbac432247ee573a23ea7d3c9deb2a968eb31d47c4fb45f1ef4422d6c531b5b9bd6f449ebcc449ea94d0a8f05f62130fda612da53c79659f609"); + + ROW("keccak_512_pangram_dot", + QCryptographicHash::Keccak_512, + "The quick brown fox jumps over the lazy dog.", + "ab7192d2b11f51c7dd744e7b3441febf397ca07bf812cceae122ca4ded6387889064f8db9230f173f6d1ab6e24b6e50f065b039f799f5592360a6558eb52d760"); + +#undef ROW +} + +void tst_QCryptographicHash::keccak() +{ + QFETCH(QCryptographicHash::Algorithm, algorithm); + QFETCH(QByteArray, data); + QFETCH(QByteArray, expectedResult); + + const auto result = QCryptographicHash::hash(data, algorithm); + QCOMPARE(result, expectedResult); +} + void tst_QCryptographicHash::blake2_data() { QTest::addColumn("algorithm");