Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/keepassxreboot/keepassxc.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/keys/CompositeKey.cpp')
-rw-r--r--src/keys/CompositeKey.cpp180
1 files changed, 49 insertions, 131 deletions
diff --git a/src/keys/CompositeKey.cpp b/src/keys/CompositeKey.cpp
index 3b1a82a22..e5e507c77 100644
--- a/src/keys/CompositeKey.cpp
+++ b/src/keys/CompositeKey.cpp
@@ -17,18 +17,13 @@
*/
#include "CompositeKey.h"
-#include "CompositeKey_p.h"
-#include "ChallengeResponseKey.h"
-
-#include <QElapsedTimer>
#include <QFile>
#include <QtConcurrent>
+#include <format/KeePass2.h>
#include "core/Global.h"
+#include "crypto/kdf/AesKdf.h"
#include "crypto/CryptoHash.h"
-#include "crypto/SymmetricCipher.h"
-#include "keys/FileKey.h"
-#include "keys/PasswordKey.h"
CompositeKey::CompositeKey()
{
@@ -80,30 +75,31 @@ CompositeKey& CompositeKey::operator=(const CompositeKey& key)
return *this;
}
-/*
- * Read a key from a line of input.
- * If the line references a valid file
- * path, the key is loaded from file.
+/**
+ * Get raw key hash as bytes.
+ *
+ * The key hash does not contain contributions by challenge-response components for
+ * backwards compatibility with KeePassXC's pre-KDBX4 challenge-response
+ * implementation. To include challenge-response in the raw key,
+ * use \link CompositeKey::rawKey(const QByteArray*) instead.
+ *
+ * @return key hash
*/
-CompositeKey CompositeKey::readFromLine(QString line)
+QByteArray CompositeKey::rawKey() const
{
-
- CompositeKey key;
- if (QFile::exists(line)) {
- FileKey fileKey;
- fileKey.load(line);
- key.addKey(fileKey);
- }
- else {
- PasswordKey password;
- password.setPassword(line);
- key.addKey(password);
- }
- return key;
-
+ return rawKey(nullptr);
}
-QByteArray CompositeKey::rawKey() const
+/**
+ * Get raw key hash as bytes.
+ *
+ * Challenge-response key components will use the provided <tt>transformSeed</tt>
+ * as a challenge to acquire their key contribution.
+ *
+ * @param transformSeed transform seed to challenge or nullptr to exclude challenge-response components
+ * @return key hash
+ */
+QByteArray CompositeKey::rawKey(const QByteArray* transformSeed) const
{
CryptoHash cryptoHash(CryptoHash::Sha256);
@@ -111,67 +107,38 @@ QByteArray CompositeKey::rawKey() const
cryptoHash.addData(key->rawKey());
}
- return cryptoHash.result();
-}
-
-QByteArray CompositeKey::transform(const QByteArray& seed, quint64 rounds,
- bool* ok, QString* errorString) const
-{
- Q_ASSERT(seed.size() == 32);
- Q_ASSERT(rounds > 0);
-
- bool okLeft;
- QString errorStringLeft;
- bool okRight;
- QString errorStringRight;
-
- QByteArray key = rawKey();
-
- QFuture<QByteArray> future = QtConcurrent::run(transformKeyRaw, key.left(16), seed, rounds,
- &okLeft, &errorStringLeft);
- QByteArray result2 = transformKeyRaw(key.right(16), seed, rounds, &okRight, &errorStringRight);
-
- QByteArray transformed;
- transformed.append(future.result());
- transformed.append(result2);
-
- *ok = (okLeft && okRight);
-
- if (!okLeft) {
- *errorString = errorStringLeft;
- return QByteArray();
+ if (transformSeed) {
+ QByteArray challengeResult;
+ challenge(*transformSeed, challengeResult);
+ cryptoHash.addData(challengeResult);
}
- if (!okRight) {
- *errorString = errorStringRight;
- return QByteArray();
- }
-
- return CryptoHash::hash(transformed, CryptoHash::Sha256);
+ return cryptoHash.result();
}
-QByteArray CompositeKey::transformKeyRaw(const QByteArray& key, const QByteArray& seed,
- quint64 rounds, bool* ok, QString* errorString)
+/**
+ * Transform this composite key.
+ *
+ * If using AES-KDF as transform function, the transformed key will not include
+ * any challenge-response components. Only static key components will be hashed
+ * for backwards-compatibility with KeePassXC's KDBX3 implementation, which added
+ * challenge response key components after key transformation.
+ * KDBX4+ KDFs transform the whole key including challenge-response components.
+ *
+ * @param kdf key derivation function
+ * @param result transformed key hash
+ * @return true on success
+ */
+bool CompositeKey::transform(const Kdf& kdf, QByteArray& result) const
{
- QByteArray iv(16, 0);
- SymmetricCipher cipher(SymmetricCipher::Aes256, SymmetricCipher::Ecb,
- SymmetricCipher::Encrypt);
- if (!cipher.init(seed, iv)) {
- *ok = false;
- *errorString = cipher.errorString();
- return QByteArray();
+ if (kdf.uuid() == KeePass2::KDF_AES_KDBX3) {
+ // legacy KDBX3 AES-KDF, challenge response is added later to the hash
+ return kdf.transform(rawKey(), result);
}
- QByteArray result = key;
-
- if (!cipher.processInPlace(result, rounds)) {
- *ok = false;
- *errorString = cipher.errorString();
- return QByteArray();
- }
-
- *ok = true;
- return result;
+ QByteArray seed = kdf.seed();
+ Q_ASSERT(!seed.isEmpty());
+ return kdf.transform(rawKey(&seed), result);
}
bool CompositeKey::challenge(const QByteArray& seed, QByteArray& result) const
@@ -188,6 +155,7 @@ bool CompositeKey::challenge(const QByteArray& seed, QByteArray& result) const
for (const auto key : m_challengeResponseKeys) {
// if the device isn't present or fails, return an error
if (!key->challenge(seed)) {
+ qWarning("Failed to issue challenge");
return false;
}
cryptoHash.addData(key->rawKey());
@@ -206,53 +174,3 @@ void CompositeKey::addChallengeResponseKey(QSharedPointer<ChallengeResponseKey>
{
m_challengeResponseKeys.append(key);
}
-
-
-int CompositeKey::transformKeyBenchmark(int msec)
-{
- TransformKeyBenchmarkThread thread1(msec);
- TransformKeyBenchmarkThread thread2(msec);
-
- thread1.start();
- thread2.start();
-
- thread1.wait();
- thread2.wait();
-
- return qMin(thread1.rounds(), thread2.rounds());
-}
-
-
-TransformKeyBenchmarkThread::TransformKeyBenchmarkThread(int msec)
- : m_msec(msec)
- , m_rounds(0)
-{
- Q_ASSERT(msec > 0);
-}
-
-int TransformKeyBenchmarkThread::rounds()
-{
- return m_rounds;
-}
-
-void TransformKeyBenchmarkThread::run()
-{
- QByteArray key = QByteArray(16, '\x7E');
- QByteArray seed = QByteArray(32, '\x4B');
- QByteArray iv(16, 0);
-
- SymmetricCipher cipher(SymmetricCipher::Aes256, SymmetricCipher::Ecb,
- SymmetricCipher::Encrypt);
- cipher.init(seed, iv);
-
- QElapsedTimer t;
- t.start();
-
- do {
- if (!cipher.processInPlace(key, 10000)) {
- m_rounds = -1;
- return;
- }
- m_rounds += 10000;
- } while (!t.hasExpired(m_msec));
-}