summaryrefslogtreecommitdiffstats
path: root/src/network/ssl
diff options
context:
space:
mode:
authorMÃ¥rten Nordheim <marten.nordheim@qt.io>2018-01-19 12:27:58 +0100
committerSimon Hausmann <simon.hausmann@qt.io>2018-04-23 12:55:45 +0000
commit72bb1d95fd99ece1c79223ad889fc7dbddcc36c6 (patch)
treea8619d84f314e1c33362f519a3c47fca6a209248 /src/network/ssl
parentc45802e33a564bfca4745e31193bc1c2fb3520fa (diff)
Introduce QPasswordDigestor functions
Added a few functions to derive keys from passwords. Currently it supports PBKDF1 and PBKDF2 as defined in RFC 8018 ( https://tools.ietf.org/html/rfc8018 ). [ChangeLog][QtNetwork][QPasswordDigestor] Added QPasswordDigestor Task-number: QTBUG-30550 Change-Id: I2166b518bd8b54e3486514166e76fd9ba2f219c8 Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io> Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
Diffstat (limited to 'src/network/ssl')
-rw-r--r--src/network/ssl/qpassworddigestor.cpp187
-rw-r--r--src/network/ssl/qpassworddigestor.h60
-rw-r--r--src/network/ssl/ssl.pri3
3 files changed, 250 insertions, 0 deletions
diff --git a/src/network/ssl/qpassworddigestor.cpp b/src/network/ssl/qpassworddigestor.cpp
new file mode 100644
index 0000000000..127d94e849
--- /dev/null
+++ b/src/network/ssl/qpassworddigestor.cpp
@@ -0,0 +1,187 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qpassworddigestor.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QMessageAuthenticationCode>
+#include <QtCore/QtEndian>
+
+#include <limits>
+
+QT_BEGIN_NAMESPACE
+namespace QPasswordDigestor {
+
+/*!
+ \namespace QPasswordDigestor
+ \inmodule QtNetwork
+
+ \brief The QPasswordDigestor namespace contains functions which you can use
+ to generate hashes or keys.
+*/
+
+/*!
+ \since 5.12
+
+ Returns a hash computed using the PBKDF1-algorithm as defined in
+ \l {https://tools.ietf.org/html/rfc8018#section-5.1} {RFC 8018}.
+
+ The function takes the \a data and \a salt, and then hashes it repeatedly
+ for \a iterations iterations using the specified hash \a algorithm. If the
+ resulting hash is longer than \a dkLen then it is truncated before it is
+ returned.
+
+ This function only supports SHA-1 and MD5! The max output size is 160 bits
+ (20 bytes) when using SHA-1, or 128 bits (16 bytes) when using MD5.
+ Specifying a value for \a dkLen which is greater than this results in a
+ warning and an empty QByteArray is returned. To programmatically check this
+ limit you can use \l {QCryptographicHash::hashLength}. Furthermore: the
+ \a salt must always be 8 bytes long!
+
+ \note This function is provided for use with legacy applications and all
+ new applications are recommended to use \l {pbkdf2} {PBKDF2}.
+
+ \sa deriveKeyPbkdf2, QCryptographicHash, QCryptographicHash::hashLength
+*/
+Q_NETWORK_EXPORT QByteArray deriveKeyPbkdf1(QCryptographicHash::Algorithm algorithm,
+ const QByteArray &data, const QByteArray &salt,
+ int iterations, quint64 dkLen)
+{
+ // https://tools.ietf.org/html/rfc8018#section-5.1
+
+ if (algorithm != QCryptographicHash::Sha1
+#ifndef QT_CRYPTOGRAPHICHASH_ONLY_SHA1
+ && algorithm != QCryptographicHash::Md5
+#endif
+ ) {
+ qWarning("The only supported algorithms for pbkdf1 are SHA-1 and MD5!");
+ return QByteArray();
+ }
+
+ if (salt.size() != 8) {
+ qWarning("The salt must be 8 bytes long!");
+ return QByteArray();
+ }
+ if (iterations < 1 || dkLen < 1)
+ return QByteArray();
+
+ if (dkLen > quint64(QCryptographicHash::hashLength(algorithm))) {
+ qWarning() << "Derived key too long:\n"
+ << algorithm << "was chosen which produces output of length"
+ << QCryptographicHash::hashLength(algorithm) << "but" << dkLen
+ << "was requested.";
+ return QByteArray();
+ }
+
+ QCryptographicHash hash(algorithm);
+ hash.addData(data);
+ hash.addData(salt);
+ QByteArray key = hash.result();
+
+ for (int i = 1; i < iterations; i++) {
+ hash.reset();
+ hash.addData(key);
+ key = hash.result();
+ }
+ return key.left(dkLen);
+}
+
+/*!
+ \since 5.12
+
+ Derive a key using the PBKDF2-algorithm as defined in
+ \l {https://tools.ietf.org/html/rfc8018#section-5.2} {RFC 8018}.
+
+ This function takes the \a data and \a salt, and then applies HMAC-X, where
+ the X is \a algorithm, repeatedly. It internally concatenates intermediate
+ results to the final output until at least \a dkLen amount of bytes have
+ been computed and it will execute HMAC-X \a iterations times each time a
+ concatenation is required. The total number of times it will execute HMAC-X
+ depends on \a iterations, \a dkLen and \a algorithm and can be calculated
+ as
+ \c{iterations * ceil(dkLen / QCryptographicHash::hashLength(algorithm))}.
+
+ \sa deriveKeyPbkdf1, QMessageAuthenticationCode, QCryptographicHash
+*/
+Q_NETWORK_EXPORT QByteArray deriveKeyPbkdf2(QCryptographicHash::Algorithm algorithm,
+ const QByteArray &data, const QByteArray &salt,
+ int iterations, quint64 dkLen)
+{
+ // https://tools.ietf.org/html/rfc8018#section-5.2
+
+ // The RFC recommends checking that 'dkLen' is not greater than '(2^32 - 1) * hLen'
+ int hashLen = QCryptographicHash::hashLength(algorithm);
+ const quint64 maxLen = quint64(std::numeric_limits<quint32>::max() - 1) * hashLen;
+ if (dkLen > maxLen) {
+ qWarning().nospace() << "Derived key too long:\n"
+ << algorithm << " was chosen which produces output of length "
+ << maxLen << " but " << dkLen << " was requested.";
+ return QByteArray();
+ }
+
+ if (iterations < 1 || dkLen < 1)
+ return QByteArray();
+
+ QByteArray key;
+ quint32 currentIteration = 1;
+ QMessageAuthenticationCode hmac(algorithm, data);
+ QByteArray index(4, Qt::Uninitialized);
+ while (quint64(key.length()) < dkLen) {
+ hmac.addData(salt);
+
+ qToBigEndian(currentIteration, index.data());
+ hmac.addData(index);
+
+ QByteArray u = hmac.result();
+ hmac.reset();
+ QByteArray tkey = u;
+ for (int iter = 1; iter < iterations; iter++) {
+ hmac.addData(u);
+ u = hmac.result();
+ hmac.reset();
+ std::transform(tkey.cbegin(), tkey.cend(), u.cbegin(), tkey.begin(),
+ std::bit_xor<char>());
+ }
+ key += tkey;
+ currentIteration++;
+ }
+ return key.left(dkLen);
+}
+} // namespace QPasswordDigestor
+QT_END_NAMESPACE
diff --git a/src/network/ssl/qpassworddigestor.h b/src/network/ssl/qpassworddigestor.h
new file mode 100644
index 0000000000..0f88643298
--- /dev/null
+++ b/src/network/ssl/qpassworddigestor.h
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPASSWORDDIGESTOR_H
+#define QPASSWORDDIGESTOR_H
+
+#include <QtNetwork/qtnetworkglobal.h>
+#include <QtCore/QByteArray>
+#include <QtCore/QCryptographicHash>
+
+QT_BEGIN_NAMESPACE
+
+namespace QPasswordDigestor {
+Q_NETWORK_EXPORT QByteArray deriveKeyPbkdf1(QCryptographicHash::Algorithm algorithm,
+ const QByteArray &password, const QByteArray &salt,
+ int iterations, quint64 dkLen);
+Q_NETWORK_EXPORT QByteArray deriveKeyPbkdf2(QCryptographicHash::Algorithm algorithm,
+ const QByteArray &password, const QByteArray &salt,
+ int iterations, quint64 dkLen);
+} // namespace QPasswordDigestor
+
+QT_END_NAMESPACE
+
+#endif // QPASSWORDDIGESTOR_H
diff --git a/src/network/ssl/ssl.pri b/src/network/ssl/ssl.pri
index b8cbe83089..3529c8828b 100644
--- a/src/network/ssl/ssl.pri
+++ b/src/network/ssl/ssl.pri
@@ -102,3 +102,6 @@ qtConfig(ssl) {
}
}
}
+
+HEADERS += ssl/qpassworddigestor.h
+SOURCES += ssl/qpassworddigestor.cpp