QMessageAuthenticationCode: remove lazy initialization of messageHash

This just complicates the code, for the small benefit of avoiding a
messageHash seeding from an empty key that then has to be reset.

This lazy initialization is in the way of using QCH's SmallByteArray
for the key, which this author thinks is the more important
optimization, because it will allow passing keys by QByteArrayView,
removing the impedance mismatch between QMAC and QCH.

Since the QMAC API doesn't distinguish between the absence of a key,
and the presence of a null (ie. empty) key, we can't not call
initMessageHash() when the key is empty, so we should suggest to pass
the actual key to the constructor as often as possible, and use
setKey() only to change the key afterwards.

[ChangeLog][QtCore][QMessageAuthenticationCode] No longer delays
processing of the key to the first setData() or result() call. While
passing a default-constructed key to the constructor and then calling
setKey() continues to work, for optimal performance, we suggest to
pass the actual key as a constructor argument and call setKey() only
to change the key.

Pick-to: 6.5
Change-Id: If0a078f37a16f8306f77d2b2bd5dacf23ce5c3e2
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
This commit is contained in:
Marc Mutz 2023-02-22 15:50:31 +01:00
parent dff0d5133f
commit 2a2fc4d16d
2 changed files with 33 additions and 14 deletions

View File

@ -1,3 +1,4 @@
// Copyright (C) 2023 The Qt Company Ltd.
// Copyright (C) 2016 Ruslan Nigmatullin <euroelessar@yandex.ru>
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
@ -13,8 +14,7 @@ int main(int argc, char *argv[])
//! [0]
//! [1]
QMessageAuthenticationCode code(QCryptographicHash::Sha1);
code.setKey(key);
QMessageAuthenticationCode code(QCryptographicHash::Sha1, key);
code.addData(message);
code.result().toHex(); // returns "de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9"
//! [1]

View File

@ -983,7 +983,7 @@ class QMessageAuthenticationCodePrivate
{
public:
QMessageAuthenticationCodePrivate(QCryptographicHash::Algorithm m)
: messageHash(m), method(m), messageHashInited(false)
: messageHash(m), method(m)
{
}
@ -992,7 +992,6 @@ public:
QBasicMutex finalizeMutex;
QCryptographicHash messageHash;
const QCryptographicHash::Algorithm method;
bool messageHashInited;
void initMessageHash();
void finalize();
@ -1005,10 +1004,6 @@ public:
void QMessageAuthenticationCodePrivate::initMessageHash()
{
if (messageHashInited)
return;
messageHashInited = true;
const int blockSize = qt_hash_block_size(method);
if (key.size() > blockSize) {
@ -1068,6 +1063,7 @@ QMessageAuthenticationCode::QMessageAuthenticationCode(QCryptographicHash::Algor
: d(new QMessageAuthenticationCodePrivate(method))
{
d->key = key;
d->initMessageHash();
}
/*!
@ -1085,16 +1081,43 @@ void QMessageAuthenticationCode::reset()
{
d->result.clear();
d->messageHash.reset();
d->messageHashInited = false;
d->initMessageHash();
}
/*!
Sets secret \a key. Calling this method automatically resets the object state.
For optimal performance, call this method only to \e change the active key,
not to set an \e initial key, as in
\code
QMessageAuthenticationCode mac(method);
mac.setKey(key); // does extra work
use(mac);
\endcode
Perfer to pass initial keys as the constructor argument:
\code
QMessageAuthenticationCode mac(method, key); // OK, optimal
use(mac);
\endcode
You can use std::optional to delay construction of a
QMessageAuthenticationCode until you know the key:
\code
std::optional<QMessageAuthenticationCode> mac;
~~~
key = ~~~;
mac.emplace(method, key);
use(*mac);
\endcode
*/
void QMessageAuthenticationCode::setKey(const QByteArray &key)
{
reset();
d->key = key;
reset();
}
/*!
@ -1102,7 +1125,6 @@ void QMessageAuthenticationCode::setKey(const QByteArray &key)
*/
void QMessageAuthenticationCode::addData(const char *data, qsizetype length)
{
d->initMessageHash();
d->messageHash.addData({data, length});
}
@ -1111,7 +1133,6 @@ void QMessageAuthenticationCode::addData(const char *data, qsizetype length)
*/
void QMessageAuthenticationCode::addData(const QByteArray &data)
{
d->initMessageHash();
d->messageHash.addData(data);
}
@ -1123,7 +1144,6 @@ void QMessageAuthenticationCode::addData(const QByteArray &data)
*/
bool QMessageAuthenticationCode::addData(QIODevice *device)
{
d->initMessageHash();
return d->messageHash.addData(device);
}
@ -1143,7 +1163,6 @@ void QMessageAuthenticationCodePrivate::finalize()
const auto lock = qt_scoped_lock(finalizeMutex);
if (!result.isEmpty())
return;
initMessageHash();
finalizeUnchecked();
}