mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2025-05-22 00:11:04 -04:00
Reformat code, fix minor style issues, make kdf() getter const
This commit is contained in:
parent
d1a19a1009
commit
0d6ca0945b
24 changed files with 324 additions and 473 deletions
|
@ -485,7 +485,7 @@ QString Database::saveToFile(QString filePath)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Kdf* Database::kdf() {
|
Kdf* Database::kdf() const {
|
||||||
return m_data.kdf;
|
return m_data.kdf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -92,7 +92,7 @@ public:
|
||||||
|
|
||||||
Uuid cipher() const;
|
Uuid cipher() const;
|
||||||
Database::CompressionAlgorithm compressionAlgo() const;
|
Database::CompressionAlgorithm compressionAlgo() const;
|
||||||
Kdf* kdf();
|
Kdf* kdf() const;
|
||||||
QByteArray transformedMasterKey() const;
|
QByteArray transformedMasterKey() const;
|
||||||
const CompositeKey& key() const;
|
const CompositeKey& key() const;
|
||||||
QByteArray challengeResponseKey() const;
|
QByteArray challengeResponseKey() const;
|
||||||
|
|
|
@ -28,10 +28,7 @@ public:
|
||||||
int hashLen;
|
int hashLen;
|
||||||
};
|
};
|
||||||
|
|
||||||
CryptoHash::CryptoHash(CryptoHash::Algorithm algo)
|
CryptoHash::CryptoHash(Algorithm algo, bool hmac)
|
||||||
: CryptoHash::CryptoHash(algo, false) {}
|
|
||||||
|
|
||||||
CryptoHash::CryptoHash(CryptoHash::Algorithm algo, bool hmac)
|
|
||||||
: d_ptr(new CryptoHashPrivate())
|
: d_ptr(new CryptoHashPrivate())
|
||||||
{
|
{
|
||||||
Q_D(CryptoHash);
|
Q_D(CryptoHash);
|
||||||
|
@ -86,14 +83,14 @@ void CryptoHash::addData(const QByteArray& data)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
gcry_md_write(d->ctx, data.constData(), data.size());
|
gcry_md_write(d->ctx, data.constData(), static_cast<size_t>(data.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CryptoHash::setKey(const QByteArray& data)
|
void CryptoHash::setKey(const QByteArray& data)
|
||||||
{
|
{
|
||||||
Q_D(CryptoHash);
|
Q_D(CryptoHash);
|
||||||
|
|
||||||
gcry_error_t error = gcry_md_setkey(d->ctx, data.constData(), data.size());
|
gcry_error_t error = gcry_md_setkey(d->ctx, data.constData(), static_cast<size_t>(data.size()));
|
||||||
if (error) {
|
if (error) {
|
||||||
qWarning("Gcrypt error (setKey): %s", gcry_strerror(error));
|
qWarning("Gcrypt error (setKey): %s", gcry_strerror(error));
|
||||||
qWarning("Gcrypt error (setKey): %s", gcry_strsource(error));
|
qWarning("Gcrypt error (setKey): %s", gcry_strsource(error));
|
||||||
|
@ -112,11 +109,11 @@ QByteArray CryptoHash::result() const
|
||||||
{
|
{
|
||||||
Q_D(const CryptoHash);
|
Q_D(const CryptoHash);
|
||||||
|
|
||||||
const char* result = reinterpret_cast<const char*>(gcry_md_read(d->ctx, 0));
|
const auto* result = reinterpret_cast<const char*>(gcry_md_read(d->ctx, 0));
|
||||||
return QByteArray(result, d->hashLen);
|
return QByteArray(result, d->hashLen);
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray CryptoHash::hash(const QByteArray& data, CryptoHash::Algorithm algo)
|
QByteArray CryptoHash::hash(const QByteArray& data, Algorithm algo)
|
||||||
{
|
{
|
||||||
// replace with gcry_md_hash_buffer()?
|
// replace with gcry_md_hash_buffer()?
|
||||||
CryptoHash cryptoHash(algo);
|
CryptoHash cryptoHash(algo);
|
||||||
|
@ -124,7 +121,7 @@ QByteArray CryptoHash::hash(const QByteArray& data, CryptoHash::Algorithm algo)
|
||||||
return cryptoHash.result();
|
return cryptoHash.result();
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray CryptoHash::hmac(const QByteArray& data, const QByteArray& key, CryptoHash::Algorithm algo)
|
QByteArray CryptoHash::hmac(const QByteArray& data, const QByteArray& key, Algorithm algo)
|
||||||
{
|
{
|
||||||
// replace with gcry_md_hash_buffer()?
|
// replace with gcry_md_hash_buffer()?
|
||||||
CryptoHash cryptoHash(algo, true);
|
CryptoHash cryptoHash(algo, true);
|
||||||
|
|
|
@ -31,15 +31,14 @@ public:
|
||||||
Sha512
|
Sha512
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit CryptoHash(CryptoHash::Algorithm algo);
|
explicit CryptoHash(Algorithm algo, bool hmac = false);
|
||||||
explicit CryptoHash(CryptoHash::Algorithm algo, bool hmac);
|
|
||||||
~CryptoHash();
|
~CryptoHash();
|
||||||
void addData(const QByteArray& data);
|
void addData(const QByteArray& data);
|
||||||
void reset();
|
void reset();
|
||||||
QByteArray result() const;
|
QByteArray result() const;
|
||||||
void setKey(const QByteArray& data);
|
void setKey(const QByteArray& data);
|
||||||
|
|
||||||
static QByteArray hash(const QByteArray& data, CryptoHash::Algorithm algo);
|
static QByteArray hash(const QByteArray& data, Algorithm algo);
|
||||||
static QByteArray hmac(const QByteArray& data, const QByteArray& key, Algorithm algo);
|
static QByteArray hmac(const QByteArray& data, const QByteArray& key, Algorithm algo);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -20,8 +20,7 @@
|
||||||
#include "config-keepassx.h"
|
#include "config-keepassx.h"
|
||||||
#include "crypto/SymmetricCipherGcrypt.h"
|
#include "crypto/SymmetricCipherGcrypt.h"
|
||||||
|
|
||||||
SymmetricCipher::SymmetricCipher(SymmetricCipher::Algorithm algo, SymmetricCipher::Mode mode,
|
SymmetricCipher::SymmetricCipher(Algorithm algo, Mode mode, Direction direction)
|
||||||
SymmetricCipher::Direction direction)
|
|
||||||
: m_backend(createBackend(algo, mode, direction))
|
: m_backend(createBackend(algo, mode, direction))
|
||||||
, m_initialized(false)
|
, m_initialized(false)
|
||||||
, m_algo(algo)
|
, m_algo(algo)
|
||||||
|
@ -55,14 +54,13 @@ bool SymmetricCipher::isInitalized() const
|
||||||
return m_initialized;
|
return m_initialized;
|
||||||
}
|
}
|
||||||
|
|
||||||
SymmetricCipherBackend* SymmetricCipher::createBackend(SymmetricCipher::Algorithm algo, SymmetricCipher::Mode mode,
|
SymmetricCipherBackend* SymmetricCipher::createBackend(Algorithm algo, Mode mode, Direction direction)
|
||||||
SymmetricCipher::Direction direction)
|
|
||||||
{
|
{
|
||||||
switch (algo) {
|
switch (algo) {
|
||||||
case SymmetricCipher::Aes256:
|
case Aes256:
|
||||||
case SymmetricCipher::Twofish:
|
case Twofish:
|
||||||
case SymmetricCipher::Salsa20:
|
case Salsa20:
|
||||||
case SymmetricCipher::ChaCha20:
|
case ChaCha20:
|
||||||
return new SymmetricCipherGcrypt(algo, mode, direction);
|
return new SymmetricCipherGcrypt(algo, mode, direction);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -94,25 +92,25 @@ QString SymmetricCipher::errorString() const
|
||||||
SymmetricCipher::Algorithm SymmetricCipher::cipherToAlgorithm(Uuid cipher)
|
SymmetricCipher::Algorithm SymmetricCipher::cipherToAlgorithm(Uuid cipher)
|
||||||
{
|
{
|
||||||
if (cipher == KeePass2::CIPHER_AES) {
|
if (cipher == KeePass2::CIPHER_AES) {
|
||||||
return SymmetricCipher::Aes256;
|
return Aes256;
|
||||||
} else if (cipher == KeePass2::CIPHER_CHACHA20) {
|
} else if (cipher == KeePass2::CIPHER_CHACHA20) {
|
||||||
return SymmetricCipher::ChaCha20;
|
return ChaCha20;
|
||||||
} else if (cipher == KeePass2::CIPHER_TWOFISH) {
|
} else if (cipher == KeePass2::CIPHER_TWOFISH) {
|
||||||
return SymmetricCipher::Twofish;
|
return Twofish;
|
||||||
}
|
}
|
||||||
|
|
||||||
qWarning("SymmetricCipher::cipherToAlgorithm: invalid Uuid %s", cipher.toByteArray().toHex().data());
|
qWarning("SymmetricCipher::cipherToAlgorithm: invalid Uuid %s", cipher.toByteArray().toHex().data());
|
||||||
return InvalidAlgorithm;
|
return InvalidAlgorithm;
|
||||||
}
|
}
|
||||||
|
|
||||||
Uuid SymmetricCipher::algorithmToCipher(SymmetricCipher::Algorithm algo)
|
Uuid SymmetricCipher::algorithmToCipher(Algorithm algo)
|
||||||
{
|
{
|
||||||
switch (algo) {
|
switch (algo) {
|
||||||
case SymmetricCipher::Aes256:
|
case Aes256:
|
||||||
return KeePass2::CIPHER_AES;
|
return KeePass2::CIPHER_AES;
|
||||||
case SymmetricCipher::ChaCha20:
|
case ChaCha20:
|
||||||
return KeePass2::CIPHER_CHACHA20;
|
return KeePass2::CIPHER_CHACHA20;
|
||||||
case SymmetricCipher::Twofish:
|
case Twofish:
|
||||||
return KeePass2::CIPHER_TWOFISH;
|
return KeePass2::CIPHER_TWOFISH;
|
||||||
default:
|
default:
|
||||||
qWarning("SymmetricCipher::algorithmToCipher: invalid algorithm %d", algo);
|
qWarning("SymmetricCipher::algorithmToCipher: invalid algorithm %d", algo);
|
||||||
|
@ -120,12 +118,14 @@ Uuid SymmetricCipher::algorithmToCipher(SymmetricCipher::Algorithm algo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int SymmetricCipher::algorithmIvSize(SymmetricCipher::Algorithm algo) {
|
int SymmetricCipher::algorithmIvSize(Algorithm algo)
|
||||||
|
{
|
||||||
switch (algo) {
|
switch (algo) {
|
||||||
case SymmetricCipher::ChaCha20:
|
case ChaCha20:
|
||||||
return 12;
|
return 12;
|
||||||
case SymmetricCipher::Aes256:
|
case Aes256:
|
||||||
case SymmetricCipher::Twofish:
|
return 16;
|
||||||
|
case Twofish:
|
||||||
return 16;
|
return 16;
|
||||||
default:
|
default:
|
||||||
qWarning("SymmetricCipher::algorithmIvSize: invalid algorithm %d", algo);
|
qWarning("SymmetricCipher::algorithmIvSize: invalid algorithm %d", algo);
|
||||||
|
@ -133,19 +133,21 @@ int SymmetricCipher::algorithmIvSize(SymmetricCipher::Algorithm algo) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SymmetricCipher::Mode SymmetricCipher::algorithmMode(SymmetricCipher::Algorithm algo) {
|
SymmetricCipher::Mode SymmetricCipher::algorithmMode(Algorithm algo)
|
||||||
|
{
|
||||||
switch (algo) {
|
switch (algo) {
|
||||||
case SymmetricCipher::ChaCha20:
|
case ChaCha20:
|
||||||
return SymmetricCipher::Stream;
|
return Stream;
|
||||||
case SymmetricCipher::Aes256:
|
case Aes256:
|
||||||
case SymmetricCipher::Twofish:
|
case Twofish:
|
||||||
return SymmetricCipher::Cbc;
|
return Cbc;
|
||||||
default:
|
default:
|
||||||
qWarning("SymmetricCipher::algorithmMode: invalid algorithm %d", algo);
|
qWarning("SymmetricCipher::algorithmMode: invalid algorithm %d", algo);
|
||||||
return SymmetricCipher::InvalidMode;
|
return InvalidMode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SymmetricCipher::Algorithm SymmetricCipher::algorithm() const {
|
SymmetricCipher::Algorithm SymmetricCipher::algorithm() const
|
||||||
|
{
|
||||||
return m_algo;
|
return m_algo;
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,22 +53,25 @@ public:
|
||||||
Encrypt
|
Encrypt
|
||||||
};
|
};
|
||||||
|
|
||||||
SymmetricCipher(SymmetricCipher::Algorithm algo, SymmetricCipher::Mode mode,
|
SymmetricCipher(Algorithm algo, Mode mode, Direction direction);
|
||||||
SymmetricCipher::Direction direction);
|
|
||||||
~SymmetricCipher();
|
~SymmetricCipher();
|
||||||
|
Q_DISABLE_COPY(SymmetricCipher)
|
||||||
|
|
||||||
bool init(const QByteArray& key, const QByteArray& iv);
|
bool init(const QByteArray& key, const QByteArray& iv);
|
||||||
bool isInitalized() const;
|
bool isInitalized() const;
|
||||||
|
|
||||||
inline QByteArray process(const QByteArray& data, bool* ok) {
|
inline QByteArray process(const QByteArray& data, bool* ok)
|
||||||
|
{
|
||||||
return m_backend->process(data, ok);
|
return m_backend->process(data, ok);
|
||||||
}
|
}
|
||||||
|
|
||||||
Q_REQUIRED_RESULT inline bool processInPlace(QByteArray& data) {
|
Q_REQUIRED_RESULT inline bool processInPlace(QByteArray& data)
|
||||||
|
{
|
||||||
return m_backend->processInPlace(data);
|
return m_backend->processInPlace(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
Q_REQUIRED_RESULT inline bool processInPlace(QByteArray& data, quint64 rounds) {
|
Q_REQUIRED_RESULT inline bool processInPlace(QByteArray& data, quint64 rounds)
|
||||||
|
{
|
||||||
Q_ASSERT(rounds > 0);
|
Q_ASSERT(rounds > 0);
|
||||||
return m_backend->processInPlace(data, rounds);
|
return m_backend->processInPlace(data, rounds);
|
||||||
}
|
}
|
||||||
|
@ -85,14 +88,11 @@ public:
|
||||||
static Mode algorithmMode(Algorithm algo);
|
static Mode algorithmMode(Algorithm algo);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static SymmetricCipherBackend* createBackend(SymmetricCipher::Algorithm algo, SymmetricCipher::Mode mode,
|
static SymmetricCipherBackend* createBackend(Algorithm algo, Mode mode, Direction direction);
|
||||||
SymmetricCipher::Direction direction);
|
|
||||||
|
|
||||||
const QScopedPointer<SymmetricCipherBackend> m_backend;
|
const QScopedPointer<SymmetricCipherBackend> m_backend;
|
||||||
bool m_initialized;
|
bool m_initialized;
|
||||||
Algorithm m_algo;
|
Algorithm m_algo;
|
||||||
|
|
||||||
Q_DISABLE_COPY(SymmetricCipher)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // KEEPASSX_SYMMETRICCIPHER_H
|
#endif // KEEPASSX_SYMMETRICCIPHER_H
|
||||||
|
|
|
@ -145,8 +145,7 @@ QByteArray SymmetricCipherGcrypt::process(const QByteArray& data, bool* ok)
|
||||||
|
|
||||||
if (m_direction == SymmetricCipher::Decrypt) {
|
if (m_direction == SymmetricCipher::Decrypt) {
|
||||||
error = gcry_cipher_decrypt(m_ctx, result.data(), data.size(), data.constData(), data.size());
|
error = gcry_cipher_decrypt(m_ctx, result.data(), data.size(), data.constData(), data.size());
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
error = gcry_cipher_encrypt(m_ctx, result.data(), data.size(), data.constData(), data.size());
|
error = gcry_cipher_encrypt(m_ctx, result.data(), data.size(), data.constData(), data.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,8 +167,7 @@ bool SymmetricCipherGcrypt::processInPlace(QByteArray& data)
|
||||||
|
|
||||||
if (m_direction == SymmetricCipher::Decrypt) {
|
if (m_direction == SymmetricCipher::Decrypt) {
|
||||||
error = gcry_cipher_decrypt(m_ctx, data.data(), data.size(), nullptr, 0);
|
error = gcry_cipher_decrypt(m_ctx, data.data(), data.size(), nullptr, 0);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
error = gcry_cipher_encrypt(m_ctx, data.data(), data.size(), nullptr, 0);
|
error = gcry_cipher_encrypt(m_ctx, data.data(), data.size(), nullptr, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -199,8 +197,7 @@ bool SymmetricCipherGcrypt::processInPlace(QByteArray& data, quint64 rounds)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
for (quint64 i = 0; i != rounds; ++i) {
|
for (quint64 i = 0; i != rounds; ++i) {
|
||||||
error = gcry_cipher_encrypt(m_ctx, rawData, size, nullptr, 0);
|
error = gcry_cipher_encrypt(m_ctx, rawData, size, nullptr, 0);
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2017 KeePassXC Team
|
* Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -67,7 +67,8 @@ bool AesKdf::transformKeyRaw(const QByteArray& key, const QByteArray& seed, quin
|
||||||
*result = key;
|
*result = key;
|
||||||
|
|
||||||
if (!cipher.processInPlace(*result, rounds)) {
|
if (!cipher.processInPlace(*result, rounds)) {
|
||||||
qWarning("AesKdf::transformKeyRaw: error in SymmetricCipher::processInPlace: %s", cipher.errorString().toUtf8().data());
|
qWarning("AesKdf::transformKeyRaw: error in SymmetricCipher::processInPlace: %s",
|
||||||
|
cipher.errorString().toUtf8().data());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,7 +166,8 @@ int AesKdf::benchmarkImpl(int msec) const
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
rounds += 10000;
|
rounds += 10000;
|
||||||
} while (!t.hasExpired(msec));
|
}
|
||||||
|
while (!t.hasExpired(msec));
|
||||||
|
|
||||||
return rounds;
|
return rounds;
|
||||||
}
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2017 KeePassXC Team
|
* Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -55,7 +55,10 @@ private:
|
||||||
quint64 m_rounds;
|
quint64 m_rounds;
|
||||||
QByteArray m_seed;
|
QByteArray m_seed;
|
||||||
|
|
||||||
static bool transformKeyRaw(const QByteArray& key, const QByteArray& seed, quint64 rounds, QByteArray* result) Q_REQUIRED_RESULT;
|
static bool transformKeyRaw(const QByteArray& key,
|
||||||
|
const QByteArray& seed,
|
||||||
|
quint64 rounds,
|
||||||
|
QByteArray* result) Q_REQUIRED_RESULT;
|
||||||
static QList<Kdf::Field> initFields();
|
static QList<Kdf::Field> initFields();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2017 KeePassXC Team
|
* Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -71,8 +71,7 @@ int Kdf::benchmark(int msec) const
|
||||||
}
|
}
|
||||||
|
|
||||||
Kdf::BenchmarkThread::BenchmarkThread(int msec, const Kdf* kdf)
|
Kdf::BenchmarkThread::BenchmarkThread(int msec, const Kdf* kdf)
|
||||||
: m_msec(msec)
|
: m_msec(msec), m_kdf(kdf)
|
||||||
, m_kdf(kdf)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,6 +80,7 @@ int Kdf::BenchmarkThread::rounds()
|
||||||
return m_rounds;
|
return m_rounds;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Kdf::BenchmarkThread::run() {
|
void Kdf::BenchmarkThread::run()
|
||||||
|
{
|
||||||
m_rounds = m_kdf->benchmarkImpl(m_msec);
|
m_rounds = m_kdf->benchmarkImpl(m_msec);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2017 KeePassXC Team
|
* Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -25,11 +25,13 @@
|
||||||
class Kdf
|
class Kdf
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
enum class Type {
|
enum class Type
|
||||||
|
{
|
||||||
AES
|
AES
|
||||||
};
|
};
|
||||||
|
|
||||||
class Field {
|
class Field
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
Field(quint32 id, const QString& name, quint64 min, quint64 max, bool benchmark = false);
|
Field(quint32 id, const QString& name, quint64 min, quint64 max, bool benchmark = false);
|
||||||
|
|
||||||
|
@ -48,9 +50,11 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
virtual ~Kdf() {}
|
virtual ~Kdf() {}
|
||||||
|
|
||||||
|
virtual QByteArray seed() const = 0;
|
||||||
|
virtual Type type() const = 0;
|
||||||
virtual bool transform(const QByteArray& raw, QByteArray& result) const = 0;
|
virtual bool transform(const QByteArray& raw, QByteArray& result) const = 0;
|
||||||
virtual void randomizeTransformSalt() = 0;
|
virtual void randomizeTransformSalt() = 0;
|
||||||
virtual Type type() const = 0;
|
|
||||||
virtual Kdf* clone() const = 0;
|
virtual Kdf* clone() const = 0;
|
||||||
|
|
||||||
virtual const QList<Field> fields() const = 0;
|
virtual const QList<Field> fields() const = 0;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2017 KeePassXC Team
|
* Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
|
|
@ -75,8 +75,7 @@ Database* Kdbx3Reader::readDatabase(QIODevice* device, const CompositeKey& key,
|
||||||
"This is a one-way migration. You won't be able to open the imported "
|
"This is a one-way migration. You won't be able to open the imported "
|
||||||
"database with the old KeePassX 0.4 version."));
|
"database with the old KeePassX 0.4 version."));
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
} else if (!ok || signature2 != KeePass2::SIGNATURE_2) {
|
||||||
else if (!ok || signature2 != KeePass2::SIGNATURE_2) {
|
|
||||||
raiseError(tr("Not a KeePass database."));
|
raiseError(tr("Not a KeePass database."));
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -152,8 +151,7 @@ Database* Kdbx3Reader::readDatabase(QIODevice* device, const CompositeKey& key,
|
||||||
|
|
||||||
if (m_db->compressionAlgo() == Database::CompressionNone) {
|
if (m_db->compressionAlgo() == Database::CompressionNone) {
|
||||||
xmlDevice = &hashedStream;
|
xmlDevice = &hashedStream;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
ioCompressor.reset(new QtIOCompressor(&hashedStream));
|
ioCompressor.reset(new QtIOCompressor(&hashedStream));
|
||||||
ioCompressor->setStreamFormat(QtIOCompressor::GzipFormat);
|
ioCompressor->setStreamFormat(QtIOCompressor::GzipFormat);
|
||||||
if (!ioCompressor->open(QIODevice::ReadOnly)) {
|
if (!ioCompressor->open(QIODevice::ReadOnly)) {
|
||||||
|
@ -185,8 +183,7 @@ Database* Kdbx3Reader::readDatabase(QIODevice* device, const CompositeKey& key,
|
||||||
raiseError(xmlReader.errorString());
|
raiseError(xmlReader.errorString());
|
||||||
if (keepDatabase) {
|
if (keepDatabase) {
|
||||||
return db.take();
|
return db.take();
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -297,14 +294,12 @@ void Kdbx3Reader::setCompressionFlags(const QByteArray& data)
|
||||||
{
|
{
|
||||||
if (data.size() != 4) {
|
if (data.size() != 4) {
|
||||||
raiseError("Invalid compression flags length");
|
raiseError("Invalid compression flags length");
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
quint32 id = Endian::bytesToSizedInt<quint32>(data, KeePass2::BYTEORDER);
|
quint32 id = Endian::bytesToSizedInt<quint32>(data, KeePass2::BYTEORDER);
|
||||||
|
|
||||||
if (id > Database::CompressionAlgorithmMax) {
|
if (id > Database::CompressionAlgorithmMax) {
|
||||||
raiseError("Unsupported compression algorithm");
|
raiseError("Unsupported compression algorithm");
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
m_db->setCompressionAlgo(static_cast<Database::CompressionAlgorithm>(id));
|
m_db->setCompressionAlgo(static_cast<Database::CompressionAlgorithm>(id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -314,8 +309,7 @@ void Kdbx3Reader::setMasterSeed(const QByteArray& data)
|
||||||
{
|
{
|
||||||
if (data.size() != 32) {
|
if (data.size() != 32) {
|
||||||
raiseError("Invalid master seed size");
|
raiseError("Invalid master seed size");
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
m_masterSeed = data;
|
m_masterSeed = data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -324,8 +318,7 @@ void Kdbx3Reader::setTransformSeed(const QByteArray& data)
|
||||||
{
|
{
|
||||||
if (data.size() != 32) {
|
if (data.size() != 32) {
|
||||||
raiseError("Invalid transform seed size");
|
raiseError("Invalid transform seed size");
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
AesKdf* aesKdf;
|
AesKdf* aesKdf;
|
||||||
if (m_db->kdf()->type() == Kdf::Type::AES) {
|
if (m_db->kdf()->type() == Kdf::Type::AES) {
|
||||||
aesKdf = static_cast<AesKdf*>(m_db->kdf());
|
aesKdf = static_cast<AesKdf*>(m_db->kdf());
|
||||||
|
@ -342,8 +335,7 @@ void Kdbx3Reader::setTransformRounds(const QByteArray& data)
|
||||||
{
|
{
|
||||||
if (data.size() != 8) {
|
if (data.size() != 8) {
|
||||||
raiseError("Invalid transform rounds size");
|
raiseError("Invalid transform rounds size");
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
quint64 rounds = Endian::bytesToSizedInt<quint64>(data, KeePass2::BYTEORDER);
|
quint64 rounds = Endian::bytesToSizedInt<quint64>(data, KeePass2::BYTEORDER);
|
||||||
|
|
||||||
AesKdf* aesKdf;
|
AesKdf* aesKdf;
|
||||||
|
@ -372,8 +364,7 @@ void Kdbx3Reader::setStreamStartBytes(const QByteArray& data)
|
||||||
{
|
{
|
||||||
if (data.size() != 32) {
|
if (data.size() != 32) {
|
||||||
raiseError("Invalid start bytes size");
|
raiseError("Invalid start bytes size");
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
m_streamStartBytes = data;
|
m_streamStartBytes = data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -120,8 +120,7 @@ bool Kdbx3Writer::writeDatabase(QIODevice* device, Database* db)
|
||||||
|
|
||||||
if (db->compressionAlgo() == Database::CompressionNone) {
|
if (db->compressionAlgo() == Database::CompressionNone) {
|
||||||
m_device = &hashedStream;
|
m_device = &hashedStream;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
ioCompressor.reset(new QtIOCompressor(&hashedStream));
|
ioCompressor.reset(new QtIOCompressor(&hashedStream));
|
||||||
ioCompressor->setStreamFormat(QtIOCompressor::GzipFormat);
|
ioCompressor->setStreamFormat(QtIOCompressor::GzipFormat);
|
||||||
if (!ioCompressor->open(QIODevice::WriteOnly)) {
|
if (!ioCompressor->open(QIODevice::WriteOnly)) {
|
||||||
|
@ -166,8 +165,7 @@ bool Kdbx3Writer::writeData(const QByteArray& data)
|
||||||
if (m_device->write(data) != data.size()) {
|
if (m_device->write(data) != data.size()) {
|
||||||
raiseError(m_device->errorString());
|
raiseError(m_device->errorString());
|
||||||
return false;
|
return false;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -150,14 +150,12 @@ QString Kdbx3XmlReader::errorString()
|
||||||
{
|
{
|
||||||
if (m_error) {
|
if (m_error) {
|
||||||
return m_errorStr;
|
return m_errorStr;
|
||||||
}
|
} else if (m_xml.hasError()) {
|
||||||
else if (m_xml.hasError()) {
|
|
||||||
return QString("XML error:\n%1\nLine %2, column %3")
|
return QString("XML error:\n%1\nLine %2, column %3")
|
||||||
.arg(m_xml.errorString())
|
.arg(m_xml.errorString())
|
||||||
.arg(m_xml.lineNumber())
|
.arg(m_xml.lineNumber())
|
||||||
.arg(m_xml.columnNumber());
|
.arg(m_xml.columnNumber());
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -183,18 +181,15 @@ bool Kdbx3XmlReader::parseKeePassFile()
|
||||||
while (!m_xml.error() && m_xml.readNextStartElement()) {
|
while (!m_xml.error() && m_xml.readNextStartElement()) {
|
||||||
if (m_xml.name() == "Meta") {
|
if (m_xml.name() == "Meta") {
|
||||||
parseMeta();
|
parseMeta();
|
||||||
}
|
} else if (m_xml.name() == "Root") {
|
||||||
else if (m_xml.name() == "Root") {
|
|
||||||
if (rootElementFound) {
|
if (rootElementFound) {
|
||||||
rootParsedSuccessfully = false;
|
rootParsedSuccessfully = false;
|
||||||
raiseError("Multiple root elements");
|
raiseError("Multiple root elements");
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
rootParsedSuccessfully = parseRoot();
|
rootParsedSuccessfully = parseRoot();
|
||||||
rootElementFound = true;
|
rootElementFound = true;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
skipCurrentElement();
|
skipCurrentElement();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -209,95 +204,67 @@ void Kdbx3XmlReader::parseMeta()
|
||||||
while (!m_xml.error() && m_xml.readNextStartElement()) {
|
while (!m_xml.error() && m_xml.readNextStartElement()) {
|
||||||
if (m_xml.name() == "Generator") {
|
if (m_xml.name() == "Generator") {
|
||||||
m_meta->setGenerator(readString());
|
m_meta->setGenerator(readString());
|
||||||
}
|
} else if (m_xml.name() == "HeaderHash") {
|
||||||
else if (m_xml.name() == "HeaderHash") {
|
|
||||||
m_headerHash = readBinary();
|
m_headerHash = readBinary();
|
||||||
}
|
} else if (m_xml.name() == "DatabaseName") {
|
||||||
else if (m_xml.name() == "DatabaseName") {
|
|
||||||
m_meta->setName(readString());
|
m_meta->setName(readString());
|
||||||
}
|
} else if (m_xml.name() == "DatabaseNameChanged") {
|
||||||
else if (m_xml.name() == "DatabaseNameChanged") {
|
|
||||||
m_meta->setNameChanged(readDateTime());
|
m_meta->setNameChanged(readDateTime());
|
||||||
}
|
} else if (m_xml.name() == "DatabaseDescription") {
|
||||||
else if (m_xml.name() == "DatabaseDescription") {
|
|
||||||
m_meta->setDescription(readString());
|
m_meta->setDescription(readString());
|
||||||
}
|
} else if (m_xml.name() == "DatabaseDescriptionChanged") {
|
||||||
else if (m_xml.name() == "DatabaseDescriptionChanged") {
|
|
||||||
m_meta->setDescriptionChanged(readDateTime());
|
m_meta->setDescriptionChanged(readDateTime());
|
||||||
}
|
} else if (m_xml.name() == "DefaultUserName") {
|
||||||
else if (m_xml.name() == "DefaultUserName") {
|
|
||||||
m_meta->setDefaultUserName(readString());
|
m_meta->setDefaultUserName(readString());
|
||||||
}
|
} else if (m_xml.name() == "DefaultUserNameChanged") {
|
||||||
else if (m_xml.name() == "DefaultUserNameChanged") {
|
|
||||||
m_meta->setDefaultUserNameChanged(readDateTime());
|
m_meta->setDefaultUserNameChanged(readDateTime());
|
||||||
}
|
} else if (m_xml.name() == "MaintenanceHistoryDays") {
|
||||||
else if (m_xml.name() == "MaintenanceHistoryDays") {
|
|
||||||
m_meta->setMaintenanceHistoryDays(readNumber());
|
m_meta->setMaintenanceHistoryDays(readNumber());
|
||||||
}
|
} else if (m_xml.name() == "Color") {
|
||||||
else if (m_xml.name() == "Color") {
|
|
||||||
m_meta->setColor(readColor());
|
m_meta->setColor(readColor());
|
||||||
}
|
} else if (m_xml.name() == "MasterKeyChanged") {
|
||||||
else if (m_xml.name() == "MasterKeyChanged") {
|
|
||||||
m_meta->setMasterKeyChanged(readDateTime());
|
m_meta->setMasterKeyChanged(readDateTime());
|
||||||
}
|
} else if (m_xml.name() == "MasterKeyChangeRec") {
|
||||||
else if (m_xml.name() == "MasterKeyChangeRec") {
|
|
||||||
m_meta->setMasterKeyChangeRec(readNumber());
|
m_meta->setMasterKeyChangeRec(readNumber());
|
||||||
}
|
} else if (m_xml.name() == "MasterKeyChangeForce") {
|
||||||
else if (m_xml.name() == "MasterKeyChangeForce") {
|
|
||||||
m_meta->setMasterKeyChangeForce(readNumber());
|
m_meta->setMasterKeyChangeForce(readNumber());
|
||||||
}
|
} else if (m_xml.name() == "MemoryProtection") {
|
||||||
else if (m_xml.name() == "MemoryProtection") {
|
|
||||||
parseMemoryProtection();
|
parseMemoryProtection();
|
||||||
}
|
} else if (m_xml.name() == "CustomIcons") {
|
||||||
else if (m_xml.name() == "CustomIcons") {
|
|
||||||
parseCustomIcons();
|
parseCustomIcons();
|
||||||
}
|
} else if (m_xml.name() == "RecycleBinEnabled") {
|
||||||
else if (m_xml.name() == "RecycleBinEnabled") {
|
|
||||||
m_meta->setRecycleBinEnabled(readBool());
|
m_meta->setRecycleBinEnabled(readBool());
|
||||||
}
|
} else if (m_xml.name() == "RecycleBinUUID") {
|
||||||
else if (m_xml.name() == "RecycleBinUUID") {
|
|
||||||
m_meta->setRecycleBin(getGroup(readUuid()));
|
m_meta->setRecycleBin(getGroup(readUuid()));
|
||||||
}
|
} else if (m_xml.name() == "RecycleBinChanged") {
|
||||||
else if (m_xml.name() == "RecycleBinChanged") {
|
|
||||||
m_meta->setRecycleBinChanged(readDateTime());
|
m_meta->setRecycleBinChanged(readDateTime());
|
||||||
}
|
} else if (m_xml.name() == "EntryTemplatesGroup") {
|
||||||
else if (m_xml.name() == "EntryTemplatesGroup") {
|
|
||||||
m_meta->setEntryTemplatesGroup(getGroup(readUuid()));
|
m_meta->setEntryTemplatesGroup(getGroup(readUuid()));
|
||||||
}
|
} else if (m_xml.name() == "EntryTemplatesGroupChanged") {
|
||||||
else if (m_xml.name() == "EntryTemplatesGroupChanged") {
|
|
||||||
m_meta->setEntryTemplatesGroupChanged(readDateTime());
|
m_meta->setEntryTemplatesGroupChanged(readDateTime());
|
||||||
}
|
} else if (m_xml.name() == "LastSelectedGroup") {
|
||||||
else if (m_xml.name() == "LastSelectedGroup") {
|
|
||||||
m_meta->setLastSelectedGroup(getGroup(readUuid()));
|
m_meta->setLastSelectedGroup(getGroup(readUuid()));
|
||||||
}
|
} else if (m_xml.name() == "LastTopVisibleGroup") {
|
||||||
else if (m_xml.name() == "LastTopVisibleGroup") {
|
|
||||||
m_meta->setLastTopVisibleGroup(getGroup(readUuid()));
|
m_meta->setLastTopVisibleGroup(getGroup(readUuid()));
|
||||||
}
|
} else if (m_xml.name() == "HistoryMaxItems") {
|
||||||
else if (m_xml.name() == "HistoryMaxItems") {
|
|
||||||
int value = readNumber();
|
int value = readNumber();
|
||||||
if (value >= -1) {
|
if (value >= -1) {
|
||||||
m_meta->setHistoryMaxItems(value);
|
m_meta->setHistoryMaxItems(value);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
raiseError("HistoryMaxItems invalid number");
|
raiseError("HistoryMaxItems invalid number");
|
||||||
}
|
}
|
||||||
}
|
} else if (m_xml.name() == "HistoryMaxSize") {
|
||||||
else if (m_xml.name() == "HistoryMaxSize") {
|
|
||||||
int value = readNumber();
|
int value = readNumber();
|
||||||
if (value >= -1) {
|
if (value >= -1) {
|
||||||
m_meta->setHistoryMaxSize(value);
|
m_meta->setHistoryMaxSize(value);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
raiseError("HistoryMaxSize invalid number");
|
raiseError("HistoryMaxSize invalid number");
|
||||||
}
|
}
|
||||||
}
|
} else if (m_xml.name() == "Binaries") {
|
||||||
else if (m_xml.name() == "Binaries") {
|
|
||||||
parseBinaries();
|
parseBinaries();
|
||||||
}
|
} else if (m_xml.name() == "CustomData") {
|
||||||
else if (m_xml.name() == "CustomData") {
|
|
||||||
parseCustomData();
|
parseCustomData();
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
skipCurrentElement();
|
skipCurrentElement();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -310,20 +277,15 @@ void Kdbx3XmlReader::parseMemoryProtection()
|
||||||
while (!m_xml.error() && m_xml.readNextStartElement()) {
|
while (!m_xml.error() && m_xml.readNextStartElement()) {
|
||||||
if (m_xml.name() == "ProtectTitle") {
|
if (m_xml.name() == "ProtectTitle") {
|
||||||
m_meta->setProtectTitle(readBool());
|
m_meta->setProtectTitle(readBool());
|
||||||
}
|
} else if (m_xml.name() == "ProtectUserName") {
|
||||||
else if (m_xml.name() == "ProtectUserName") {
|
|
||||||
m_meta->setProtectUsername(readBool());
|
m_meta->setProtectUsername(readBool());
|
||||||
}
|
} else if (m_xml.name() == "ProtectPassword") {
|
||||||
else if (m_xml.name() == "ProtectPassword") {
|
|
||||||
m_meta->setProtectPassword(readBool());
|
m_meta->setProtectPassword(readBool());
|
||||||
}
|
} else if (m_xml.name() == "ProtectURL") {
|
||||||
else if (m_xml.name() == "ProtectURL") {
|
|
||||||
m_meta->setProtectUrl(readBool());
|
m_meta->setProtectUrl(readBool());
|
||||||
}
|
} else if (m_xml.name() == "ProtectNotes") {
|
||||||
else if (m_xml.name() == "ProtectNotes") {
|
|
||||||
m_meta->setProtectNotes(readBool());
|
m_meta->setProtectNotes(readBool());
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
skipCurrentElement();
|
skipCurrentElement();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -336,8 +298,7 @@ void Kdbx3XmlReader::parseCustomIcons()
|
||||||
while (!m_xml.error() && m_xml.readNextStartElement()) {
|
while (!m_xml.error() && m_xml.readNextStartElement()) {
|
||||||
if (m_xml.name() == "Icon") {
|
if (m_xml.name() == "Icon") {
|
||||||
parseIcon();
|
parseIcon();
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
skipCurrentElement();
|
skipCurrentElement();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -356,20 +317,17 @@ void Kdbx3XmlReader::parseIcon()
|
||||||
if (m_xml.name() == "UUID") {
|
if (m_xml.name() == "UUID") {
|
||||||
uuid = readUuid();
|
uuid = readUuid();
|
||||||
uuidSet = !uuid.isNull();
|
uuidSet = !uuid.isNull();
|
||||||
}
|
} else if (m_xml.name() == "Data") {
|
||||||
else if (m_xml.name() == "Data") {
|
|
||||||
icon.loadFromData(readBinary());
|
icon.loadFromData(readBinary());
|
||||||
iconSet = true;
|
iconSet = true;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
skipCurrentElement();
|
skipCurrentElement();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uuidSet && iconSet) {
|
if (uuidSet && iconSet) {
|
||||||
m_meta->addCustomIcon(uuid, icon);
|
m_meta->addCustomIcon(uuid, icon);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
raiseError("Missing icon uuid or data");
|
raiseError("Missing icon uuid or data");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -387,8 +345,7 @@ void Kdbx3XmlReader::parseBinaries()
|
||||||
QByteArray data;
|
QByteArray data;
|
||||||
if (attr.value("Compressed").compare(QLatin1String("True"), Qt::CaseInsensitive) == 0) {
|
if (attr.value("Compressed").compare(QLatin1String("True"), Qt::CaseInsensitive) == 0) {
|
||||||
data = readCompressedBinary();
|
data = readCompressedBinary();
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
data = readBinary();
|
data = readBinary();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -398,8 +355,7 @@ void Kdbx3XmlReader::parseBinaries()
|
||||||
}
|
}
|
||||||
|
|
||||||
m_binaryPool.insert(id, data);
|
m_binaryPool.insert(id, data);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
skipCurrentElement();
|
skipCurrentElement();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -412,8 +368,7 @@ void Kdbx3XmlReader::parseCustomData()
|
||||||
while (!m_xml.error() && m_xml.readNextStartElement()) {
|
while (!m_xml.error() && m_xml.readNextStartElement()) {
|
||||||
if (m_xml.name() == "Item") {
|
if (m_xml.name() == "Item") {
|
||||||
parseCustomDataItem();
|
parseCustomDataItem();
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
skipCurrentElement();
|
skipCurrentElement();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -432,20 +387,17 @@ void Kdbx3XmlReader::parseCustomDataItem()
|
||||||
if (m_xml.name() == "Key") {
|
if (m_xml.name() == "Key") {
|
||||||
key = readString();
|
key = readString();
|
||||||
keySet = true;
|
keySet = true;
|
||||||
}
|
} else if (m_xml.name() == "Value") {
|
||||||
else if (m_xml.name() == "Value") {
|
|
||||||
value = readString();
|
value = readString();
|
||||||
valueSet = true;
|
valueSet = true;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
skipCurrentElement();
|
skipCurrentElement();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keySet && valueSet) {
|
if (keySet && valueSet) {
|
||||||
m_meta->addCustomField(key, value);
|
m_meta->addCustomField(key, value);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
raiseError("Missing custom data key or value");
|
raiseError("Missing custom data key or value");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -474,11 +426,9 @@ bool Kdbx3XmlReader::parseRoot()
|
||||||
}
|
}
|
||||||
|
|
||||||
groupElementFound = true;
|
groupElementFound = true;
|
||||||
}
|
} else if (m_xml.name() == "DeletedObjects") {
|
||||||
else if (m_xml.name() == "DeletedObjects") {
|
|
||||||
parseDeletedObjects();
|
parseDeletedObjects();
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
skipCurrentElement();
|
skipCurrentElement();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -500,99 +450,77 @@ Group* Kdbx3XmlReader::parseGroup()
|
||||||
if (uuid.isNull()) {
|
if (uuid.isNull()) {
|
||||||
if (m_strictMode) {
|
if (m_strictMode) {
|
||||||
raiseError("Null group uuid");
|
raiseError("Null group uuid");
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
group->setUuid(Uuid::random());
|
group->setUuid(Uuid::random());
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
group->setUuid(uuid);
|
group->setUuid(uuid);
|
||||||
}
|
}
|
||||||
}
|
} else if (m_xml.name() == "Name") {
|
||||||
else if (m_xml.name() == "Name") {
|
|
||||||
group->setName(readString());
|
group->setName(readString());
|
||||||
}
|
} else if (m_xml.name() == "Notes") {
|
||||||
else if (m_xml.name() == "Notes") {
|
|
||||||
group->setNotes(readString());
|
group->setNotes(readString());
|
||||||
}
|
} else if (m_xml.name() == "IconID") {
|
||||||
else if (m_xml.name() == "IconID") {
|
|
||||||
int iconId = readNumber();
|
int iconId = readNumber();
|
||||||
if (iconId < 0) {
|
if (iconId < 0) {
|
||||||
if (m_strictMode) {
|
if (m_strictMode) {
|
||||||
raiseError("Invalid group icon number");
|
raiseError("Invalid group icon number");
|
||||||
}
|
}
|
||||||
iconId = 0;
|
iconId = 0;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
if (iconId >= DatabaseIcons::IconCount) {
|
if (iconId >= DatabaseIcons::IconCount) {
|
||||||
qWarning("Kdbx3XmlReader::parseGroup: icon id \"%d\" not supported", iconId);
|
qWarning("Kdbx3XmlReader::parseGroup: icon id \"%d\" not supported", iconId);
|
||||||
}
|
}
|
||||||
group->setIcon(iconId);
|
group->setIcon(iconId);
|
||||||
}
|
}
|
||||||
}
|
} else if (m_xml.name() == "CustomIconUUID") {
|
||||||
else if (m_xml.name() == "CustomIconUUID") {
|
|
||||||
Uuid uuid = readUuid();
|
Uuid uuid = readUuid();
|
||||||
if (!uuid.isNull()) {
|
if (!uuid.isNull()) {
|
||||||
group->setIcon(uuid);
|
group->setIcon(uuid);
|
||||||
}
|
}
|
||||||
}
|
} else if (m_xml.name() == "Times") {
|
||||||
else if (m_xml.name() == "Times") {
|
|
||||||
group->setTimeInfo(parseTimes());
|
group->setTimeInfo(parseTimes());
|
||||||
}
|
} else if (m_xml.name() == "IsExpanded") {
|
||||||
else if (m_xml.name() == "IsExpanded") {
|
|
||||||
group->setExpanded(readBool());
|
group->setExpanded(readBool());
|
||||||
}
|
} else if (m_xml.name() == "DefaultAutoTypeSequence") {
|
||||||
else if (m_xml.name() == "DefaultAutoTypeSequence") {
|
|
||||||
group->setDefaultAutoTypeSequence(readString());
|
group->setDefaultAutoTypeSequence(readString());
|
||||||
}
|
} else if (m_xml.name() == "EnableAutoType") {
|
||||||
else if (m_xml.name() == "EnableAutoType") {
|
|
||||||
QString str = readString();
|
QString str = readString();
|
||||||
|
|
||||||
if (str.compare("null", Qt::CaseInsensitive) == 0) {
|
if (str.compare("null", Qt::CaseInsensitive) == 0) {
|
||||||
group->setAutoTypeEnabled(Group::Inherit);
|
group->setAutoTypeEnabled(Group::Inherit);
|
||||||
}
|
} else if (str.compare("true", Qt::CaseInsensitive) == 0) {
|
||||||
else if (str.compare("true", Qt::CaseInsensitive) == 0) {
|
|
||||||
group->setAutoTypeEnabled(Group::Enable);
|
group->setAutoTypeEnabled(Group::Enable);
|
||||||
}
|
} else if (str.compare("false", Qt::CaseInsensitive) == 0) {
|
||||||
else if (str.compare("false", Qt::CaseInsensitive) == 0) {
|
|
||||||
group->setAutoTypeEnabled(Group::Disable);
|
group->setAutoTypeEnabled(Group::Disable);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
raiseError("Invalid EnableAutoType value");
|
raiseError("Invalid EnableAutoType value");
|
||||||
}
|
}
|
||||||
}
|
} else if (m_xml.name() == "EnableSearching") {
|
||||||
else if (m_xml.name() == "EnableSearching") {
|
|
||||||
QString str = readString();
|
QString str = readString();
|
||||||
|
|
||||||
if (str.compare("null", Qt::CaseInsensitive) == 0) {
|
if (str.compare("null", Qt::CaseInsensitive) == 0) {
|
||||||
group->setSearchingEnabled(Group::Inherit);
|
group->setSearchingEnabled(Group::Inherit);
|
||||||
}
|
} else if (str.compare("true", Qt::CaseInsensitive) == 0) {
|
||||||
else if (str.compare("true", Qt::CaseInsensitive) == 0) {
|
|
||||||
group->setSearchingEnabled(Group::Enable);
|
group->setSearchingEnabled(Group::Enable);
|
||||||
}
|
} else if (str.compare("false", Qt::CaseInsensitive) == 0) {
|
||||||
else if (str.compare("false", Qt::CaseInsensitive) == 0) {
|
|
||||||
group->setSearchingEnabled(Group::Disable);
|
group->setSearchingEnabled(Group::Disable);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
raiseError("Invalid EnableSearching value");
|
raiseError("Invalid EnableSearching value");
|
||||||
}
|
}
|
||||||
}
|
} else if (m_xml.name() == "LastTopVisibleEntry") {
|
||||||
else if (m_xml.name() == "LastTopVisibleEntry") {
|
|
||||||
group->setLastTopVisibleEntry(getEntry(readUuid()));
|
group->setLastTopVisibleEntry(getEntry(readUuid()));
|
||||||
}
|
} else if (m_xml.name() == "Group") {
|
||||||
else if (m_xml.name() == "Group") {
|
|
||||||
Group* newGroup = parseGroup();
|
Group* newGroup = parseGroup();
|
||||||
if (newGroup) {
|
if (newGroup) {
|
||||||
children.append(newGroup);
|
children.append(newGroup);
|
||||||
}
|
}
|
||||||
}
|
} else if (m_xml.name() == "Entry") {
|
||||||
else if (m_xml.name() == "Entry") {
|
|
||||||
Entry* newEntry = parseEntry(false);
|
Entry* newEntry = parseEntry(false);
|
||||||
if (newEntry) {
|
if (newEntry) {
|
||||||
entries.append(newEntry);
|
entries.append(newEntry);
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
skipCurrentElement();
|
skipCurrentElement();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -607,8 +535,7 @@ Group* Kdbx3XmlReader::parseGroup()
|
||||||
group->copyDataFrom(tmpGroup);
|
group->copyDataFrom(tmpGroup);
|
||||||
group->setUpdateTimeinfo(false);
|
group->setUpdateTimeinfo(false);
|
||||||
delete tmpGroup;
|
delete tmpGroup;
|
||||||
}
|
} else if (!hasError()) {
|
||||||
else if (!hasError()) {
|
|
||||||
raiseError("No group uuid found");
|
raiseError("No group uuid found");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -630,8 +557,7 @@ void Kdbx3XmlReader::parseDeletedObjects()
|
||||||
while (!m_xml.error() && m_xml.readNextStartElement()) {
|
while (!m_xml.error() && m_xml.readNextStartElement()) {
|
||||||
if (m_xml.name() == "DeletedObject") {
|
if (m_xml.name() == "DeletedObject") {
|
||||||
parseDeletedObject();
|
parseDeletedObject();
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
skipCurrentElement();
|
skipCurrentElement();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -650,23 +576,19 @@ void Kdbx3XmlReader::parseDeletedObject()
|
||||||
if (m_strictMode) {
|
if (m_strictMode) {
|
||||||
raiseError("Null DeleteObject uuid");
|
raiseError("Null DeleteObject uuid");
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
delObj.uuid = uuid;
|
delObj.uuid = uuid;
|
||||||
}
|
}
|
||||||
}
|
} else if (m_xml.name() == "DeletionTime") {
|
||||||
else if (m_xml.name() == "DeletionTime") {
|
|
||||||
delObj.deletionTime = readDateTime();
|
delObj.deletionTime = readDateTime();
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
skipCurrentElement();
|
skipCurrentElement();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!delObj.uuid.isNull() && !delObj.deletionTime.isNull()) {
|
if (!delObj.uuid.isNull() && !delObj.deletionTime.isNull()) {
|
||||||
m_db->addDeletedObject(delObj);
|
m_db->addDeletedObject(delObj);
|
||||||
}
|
} else if (m_strictMode) {
|
||||||
else if (m_strictMode) {
|
|
||||||
raiseError("Missing DeletedObject uuid or time");
|
raiseError("Missing DeletedObject uuid or time");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -686,69 +608,53 @@ Entry* Kdbx3XmlReader::parseEntry(bool history)
|
||||||
if (uuid.isNull()) {
|
if (uuid.isNull()) {
|
||||||
if (m_strictMode) {
|
if (m_strictMode) {
|
||||||
raiseError("Null entry uuid");
|
raiseError("Null entry uuid");
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
entry->setUuid(Uuid::random());
|
entry->setUuid(Uuid::random());
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
entry->setUuid(uuid);
|
entry->setUuid(uuid);
|
||||||
}
|
}
|
||||||
}
|
} else if (m_xml.name() == "IconID") {
|
||||||
else if (m_xml.name() == "IconID") {
|
|
||||||
int iconId = readNumber();
|
int iconId = readNumber();
|
||||||
if (iconId < 0) {
|
if (iconId < 0) {
|
||||||
if (m_strictMode) {
|
if (m_strictMode) {
|
||||||
raiseError("Invalid entry icon number");
|
raiseError("Invalid entry icon number");
|
||||||
}
|
}
|
||||||
iconId = 0;
|
iconId = 0;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
entry->setIcon(iconId);
|
entry->setIcon(iconId);
|
||||||
}
|
}
|
||||||
}
|
} else if (m_xml.name() == "CustomIconUUID") {
|
||||||
else if (m_xml.name() == "CustomIconUUID") {
|
|
||||||
Uuid uuid = readUuid();
|
Uuid uuid = readUuid();
|
||||||
if (!uuid.isNull()) {
|
if (!uuid.isNull()) {
|
||||||
entry->setIcon(uuid);
|
entry->setIcon(uuid);
|
||||||
}
|
}
|
||||||
}
|
} else if (m_xml.name() == "ForegroundColor") {
|
||||||
else if (m_xml.name() == "ForegroundColor") {
|
|
||||||
entry->setForegroundColor(readColor());
|
entry->setForegroundColor(readColor());
|
||||||
}
|
} else if (m_xml.name() == "BackgroundColor") {
|
||||||
else if (m_xml.name() == "BackgroundColor") {
|
|
||||||
entry->setBackgroundColor(readColor());
|
entry->setBackgroundColor(readColor());
|
||||||
}
|
} else if (m_xml.name() == "OverrideURL") {
|
||||||
else if (m_xml.name() == "OverrideURL") {
|
|
||||||
entry->setOverrideUrl(readString());
|
entry->setOverrideUrl(readString());
|
||||||
}
|
} else if (m_xml.name() == "Tags") {
|
||||||
else if (m_xml.name() == "Tags") {
|
|
||||||
entry->setTags(readString());
|
entry->setTags(readString());
|
||||||
}
|
} else if (m_xml.name() == "Times") {
|
||||||
else if (m_xml.name() == "Times") {
|
|
||||||
entry->setTimeInfo(parseTimes());
|
entry->setTimeInfo(parseTimes());
|
||||||
}
|
} else if (m_xml.name() == "String") {
|
||||||
else if (m_xml.name() == "String") {
|
|
||||||
parseEntryString(entry);
|
parseEntryString(entry);
|
||||||
}
|
} else if (m_xml.name() == "Binary") {
|
||||||
else if (m_xml.name() == "Binary") {
|
|
||||||
QPair<QString, QString> ref = parseEntryBinary(entry);
|
QPair<QString, QString> ref = parseEntryBinary(entry);
|
||||||
if (!ref.first.isNull() && !ref.second.isNull()) {
|
if (!ref.first.isNull() && !ref.second.isNull()) {
|
||||||
binaryRefs.append(ref);
|
binaryRefs.append(ref);
|
||||||
}
|
}
|
||||||
}
|
} else if (m_xml.name() == "AutoType") {
|
||||||
else if (m_xml.name() == "AutoType") {
|
|
||||||
parseAutoType(entry);
|
parseAutoType(entry);
|
||||||
}
|
} else if (m_xml.name() == "History") {
|
||||||
else if (m_xml.name() == "History") {
|
|
||||||
if (history) {
|
if (history) {
|
||||||
raiseError("History element in history entry");
|
raiseError("History element in history entry");
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
historyItems = parseEntryHistory();
|
historyItems = parseEntryHistory();
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
skipCurrentElement();
|
skipCurrentElement();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -760,8 +666,7 @@ Entry* Kdbx3XmlReader::parseEntry(bool history)
|
||||||
if (!entry->uuid().isNull()) {
|
if (!entry->uuid().isNull()) {
|
||||||
if (history) {
|
if (history) {
|
||||||
entry->setUpdateTimeinfo(false);
|
entry->setUpdateTimeinfo(false);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
Entry* tmpEntry = entry;
|
Entry* tmpEntry = entry;
|
||||||
|
|
||||||
entry = getEntry(tmpEntry->uuid());
|
entry = getEntry(tmpEntry->uuid());
|
||||||
|
@ -770,8 +675,7 @@ Entry* Kdbx3XmlReader::parseEntry(bool history)
|
||||||
|
|
||||||
delete tmpEntry;
|
delete tmpEntry;
|
||||||
}
|
}
|
||||||
}
|
} else if (!hasError()) {
|
||||||
else if (!hasError()) {
|
|
||||||
raiseError("No entry uuid found");
|
raiseError("No entry uuid found");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -807,8 +711,7 @@ void Kdbx3XmlReader::parseEntryString(Entry* entry)
|
||||||
if (m_xml.name() == "Key") {
|
if (m_xml.name() == "Key") {
|
||||||
key = readString();
|
key = readString();
|
||||||
keySet = true;
|
keySet = true;
|
||||||
}
|
} else if (m_xml.name() == "Value") {
|
||||||
else if (m_xml.name() == "Value") {
|
|
||||||
QXmlStreamAttributes attr = m_xml.attributes();
|
QXmlStreamAttributes attr = m_xml.attributes();
|
||||||
value = readString();
|
value = readString();
|
||||||
|
|
||||||
|
@ -823,20 +726,17 @@ void Kdbx3XmlReader::parseEntryString(Entry* entry)
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
value.clear();
|
value.clear();
|
||||||
raiseError(m_randomStream->errorString());
|
raiseError(m_randomStream->errorString());
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
value = QString::fromUtf8(plaintext);
|
value = QString::fromUtf8(plaintext);
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
raiseError("Unable to decrypt entry string");
|
raiseError("Unable to decrypt entry string");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protect = isProtected || protectInMemory;
|
protect = isProtected || protectInMemory;
|
||||||
valueSet = true;
|
valueSet = true;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
skipCurrentElement();
|
skipCurrentElement();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -845,12 +745,10 @@ void Kdbx3XmlReader::parseEntryString(Entry* entry)
|
||||||
// the default attributes are always there so additionally check if it's empty
|
// the default attributes are always there so additionally check if it's empty
|
||||||
if (entry->attributes()->hasKey(key) && !entry->attributes()->value(key).isEmpty()) {
|
if (entry->attributes()->hasKey(key) && !entry->attributes()->value(key).isEmpty()) {
|
||||||
raiseError("Duplicate custom attribute found");
|
raiseError("Duplicate custom attribute found");
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
entry->attributes()->set(key, value, protect);
|
entry->attributes()->set(key, value, protect);
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
raiseError("Entry string key or value missing");
|
raiseError("Entry string key or value missing");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -870,15 +768,13 @@ QPair<QString, QString> Kdbx3XmlReader::parseEntryBinary(Entry* entry)
|
||||||
if (m_xml.name() == "Key") {
|
if (m_xml.name() == "Key") {
|
||||||
key = readString();
|
key = readString();
|
||||||
keySet = true;
|
keySet = true;
|
||||||
}
|
} else if (m_xml.name() == "Value") {
|
||||||
else if (m_xml.name() == "Value") {
|
|
||||||
QXmlStreamAttributes attr = m_xml.attributes();
|
QXmlStreamAttributes attr = m_xml.attributes();
|
||||||
|
|
||||||
if (attr.hasAttribute("Ref")) {
|
if (attr.hasAttribute("Ref")) {
|
||||||
poolRef = qMakePair(attr.value("Ref").toString(), key);
|
poolRef = qMakePair(attr.value("Ref").toString(), key);
|
||||||
m_xml.skipCurrentElement();
|
m_xml.skipCurrentElement();
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
// format compatibility
|
// format compatibility
|
||||||
value = readBinary();
|
value = readBinary();
|
||||||
bool isProtected = attr.hasAttribute("Protected")
|
bool isProtected = attr.hasAttribute("Protected")
|
||||||
|
@ -892,8 +788,7 @@ QPair<QString, QString> Kdbx3XmlReader::parseEntryBinary(Entry* entry)
|
||||||
}
|
}
|
||||||
|
|
||||||
valueSet = true;
|
valueSet = true;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
skipCurrentElement();
|
skipCurrentElement();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -901,12 +796,10 @@ QPair<QString, QString> Kdbx3XmlReader::parseEntryBinary(Entry* entry)
|
||||||
if (keySet && valueSet) {
|
if (keySet && valueSet) {
|
||||||
if (entry->attachments()->hasKey(key)) {
|
if (entry->attachments()->hasKey(key)) {
|
||||||
raiseError("Duplicate attachment found");
|
raiseError("Duplicate attachment found");
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
entry->attachments()->set(key, value);
|
entry->attachments()->set(key, value);
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
raiseError("Entry binary key or value missing");
|
raiseError("Entry binary key or value missing");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -920,17 +813,13 @@ void Kdbx3XmlReader::parseAutoType(Entry* entry)
|
||||||
while (!m_xml.error() && m_xml.readNextStartElement()) {
|
while (!m_xml.error() && m_xml.readNextStartElement()) {
|
||||||
if (m_xml.name() == "Enabled") {
|
if (m_xml.name() == "Enabled") {
|
||||||
entry->setAutoTypeEnabled(readBool());
|
entry->setAutoTypeEnabled(readBool());
|
||||||
}
|
} else if (m_xml.name() == "DataTransferObfuscation") {
|
||||||
else if (m_xml.name() == "DataTransferObfuscation") {
|
|
||||||
entry->setAutoTypeObfuscation(readNumber());
|
entry->setAutoTypeObfuscation(readNumber());
|
||||||
}
|
} else if (m_xml.name() == "DefaultSequence") {
|
||||||
else if (m_xml.name() == "DefaultSequence") {
|
|
||||||
entry->setDefaultAutoTypeSequence(readString());
|
entry->setDefaultAutoTypeSequence(readString());
|
||||||
}
|
} else if (m_xml.name() == "Association") {
|
||||||
else if (m_xml.name() == "Association") {
|
|
||||||
parseAutoTypeAssoc(entry);
|
parseAutoTypeAssoc(entry);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
skipCurrentElement();
|
skipCurrentElement();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -948,20 +837,17 @@ void Kdbx3XmlReader::parseAutoTypeAssoc(Entry* entry)
|
||||||
if (m_xml.name() == "Window") {
|
if (m_xml.name() == "Window") {
|
||||||
assoc.window = readString();
|
assoc.window = readString();
|
||||||
windowSet = true;
|
windowSet = true;
|
||||||
}
|
} else if (m_xml.name() == "KeystrokeSequence") {
|
||||||
else if (m_xml.name() == "KeystrokeSequence") {
|
|
||||||
assoc.sequence = readString();
|
assoc.sequence = readString();
|
||||||
sequenceSet = true;
|
sequenceSet = true;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
skipCurrentElement();
|
skipCurrentElement();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (windowSet && sequenceSet) {
|
if (windowSet && sequenceSet) {
|
||||||
entry->autoTypeAssociations()->add(assoc);
|
entry->autoTypeAssociations()->add(assoc);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
raiseError("Auto-type association window or sequence missing");
|
raiseError("Auto-type association window or sequence missing");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -975,8 +861,7 @@ QList<Entry*> Kdbx3XmlReader::parseEntryHistory()
|
||||||
while (!m_xml.error() && m_xml.readNextStartElement()) {
|
while (!m_xml.error() && m_xml.readNextStartElement()) {
|
||||||
if (m_xml.name() == "Entry") {
|
if (m_xml.name() == "Entry") {
|
||||||
historyItems.append(parseEntry(true));
|
historyItems.append(parseEntry(true));
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
skipCurrentElement();
|
skipCurrentElement();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -992,26 +877,19 @@ TimeInfo Kdbx3XmlReader::parseTimes()
|
||||||
while (!m_xml.error() && m_xml.readNextStartElement()) {
|
while (!m_xml.error() && m_xml.readNextStartElement()) {
|
||||||
if (m_xml.name() == "LastModificationTime") {
|
if (m_xml.name() == "LastModificationTime") {
|
||||||
timeInfo.setLastModificationTime(readDateTime());
|
timeInfo.setLastModificationTime(readDateTime());
|
||||||
}
|
} else if (m_xml.name() == "CreationTime") {
|
||||||
else if (m_xml.name() == "CreationTime") {
|
|
||||||
timeInfo.setCreationTime(readDateTime());
|
timeInfo.setCreationTime(readDateTime());
|
||||||
}
|
} else if (m_xml.name() == "LastAccessTime") {
|
||||||
else if (m_xml.name() == "LastAccessTime") {
|
|
||||||
timeInfo.setLastAccessTime(readDateTime());
|
timeInfo.setLastAccessTime(readDateTime());
|
||||||
}
|
} else if (m_xml.name() == "ExpiryTime") {
|
||||||
else if (m_xml.name() == "ExpiryTime") {
|
|
||||||
timeInfo.setExpiryTime(readDateTime());
|
timeInfo.setExpiryTime(readDateTime());
|
||||||
}
|
} else if (m_xml.name() == "Expires") {
|
||||||
else if (m_xml.name() == "Expires") {
|
|
||||||
timeInfo.setExpires(readBool());
|
timeInfo.setExpires(readBool());
|
||||||
}
|
} else if (m_xml.name() == "UsageCount") {
|
||||||
else if (m_xml.name() == "UsageCount") {
|
|
||||||
timeInfo.setUsageCount(readNumber());
|
timeInfo.setUsageCount(readNumber());
|
||||||
}
|
} else if (m_xml.name() == "LocationChanged") {
|
||||||
else if (m_xml.name() == "LocationChanged") {
|
|
||||||
timeInfo.setLocationChanged(readDateTime());
|
timeInfo.setLocationChanged(readDateTime());
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
skipCurrentElement();
|
skipCurrentElement();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1030,14 +908,11 @@ bool Kdbx3XmlReader::readBool()
|
||||||
|
|
||||||
if (str.compare("True", Qt::CaseInsensitive) == 0) {
|
if (str.compare("True", Qt::CaseInsensitive) == 0) {
|
||||||
return true;
|
return true;
|
||||||
}
|
} else if (str.compare("False", Qt::CaseInsensitive) == 0) {
|
||||||
else if (str.compare("False", Qt::CaseInsensitive) == 0) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
} else if (str.length() == 0) {
|
||||||
else if (str.length() == 0) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
raiseError("Invalid bool value");
|
raiseError("Invalid bool value");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1051,8 +926,7 @@ QDateTime Kdbx3XmlReader::readDateTime()
|
||||||
if (!dt.isValid()) {
|
if (!dt.isValid()) {
|
||||||
if (m_strictMode) {
|
if (m_strictMode) {
|
||||||
raiseError("Invalid date time value");
|
raiseError("Invalid date time value");
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
dt = QDateTime::currentDateTimeUtc();
|
dt = QDateTime::currentDateTimeUtc();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1089,11 +963,9 @@ QColor Kdbx3XmlReader::readColor()
|
||||||
|
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
color.setRed(rgbPart);
|
color.setRed(rgbPart);
|
||||||
}
|
} else if (i == 1) {
|
||||||
else if (i == 1) {
|
|
||||||
color.setGreen(rgbPart);
|
color.setGreen(rgbPart);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
color.setBlue(rgbPart);
|
color.setBlue(rgbPart);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1116,14 +988,12 @@ Uuid Kdbx3XmlReader::readUuid()
|
||||||
QByteArray uuidBin = readBinary();
|
QByteArray uuidBin = readBinary();
|
||||||
if (uuidBin.isEmpty()) {
|
if (uuidBin.isEmpty()) {
|
||||||
return Uuid();
|
return Uuid();
|
||||||
}
|
} else if (uuidBin.length() != Uuid::Length) {
|
||||||
else if (uuidBin.length() != Uuid::Length) {
|
|
||||||
if (m_strictMode) {
|
if (m_strictMode) {
|
||||||
raiseError("Invalid uuid value");
|
raiseError("Invalid uuid value");
|
||||||
}
|
}
|
||||||
return Uuid();
|
return Uuid();
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
return Uuid(uuidBin);
|
return Uuid(uuidBin);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1159,8 +1029,7 @@ Group* Kdbx3XmlReader::getGroup(const Uuid& uuid)
|
||||||
|
|
||||||
if (m_groups.contains(uuid)) {
|
if (m_groups.contains(uuid)) {
|
||||||
return m_groups.value(uuid);
|
return m_groups.value(uuid);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
Group* group = new Group();
|
Group* group = new Group();
|
||||||
group->setUpdateTimeinfo(false);
|
group->setUpdateTimeinfo(false);
|
||||||
group->setUuid(uuid);
|
group->setUuid(uuid);
|
||||||
|
@ -1178,8 +1047,7 @@ Entry* Kdbx3XmlReader::getEntry(const Uuid& uuid)
|
||||||
|
|
||||||
if (m_entries.contains(uuid)) {
|
if (m_entries.contains(uuid)) {
|
||||||
return m_entries.value(uuid);
|
return m_entries.value(uuid);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
Entry* entry = new Entry();
|
Entry* entry = new Entry();
|
||||||
entry->setUpdateTimeinfo(false);
|
entry->setUpdateTimeinfo(false);
|
||||||
entry->setUuid(uuid);
|
entry->setUuid(uuid);
|
||||||
|
|
|
@ -202,8 +202,7 @@ void Kdbx3XmlWriter::writeBinaries()
|
||||||
|
|
||||||
buffer.seek(0);
|
buffer.seek(0);
|
||||||
data = buffer.readAll();
|
data = buffer.readAll();
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
data = i.key();
|
data = i.key();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -367,13 +366,11 @@ void Kdbx3XmlWriter::writeEntry(const Entry* entry)
|
||||||
raiseError(m_randomStream->errorString());
|
raiseError(m_randomStream->errorString());
|
||||||
}
|
}
|
||||||
value = QString::fromLatin1(rawData.toBase64());
|
value = QString::fromLatin1(rawData.toBase64());
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
m_xml.writeAttribute("ProtectInMemory", "True");
|
m_xml.writeAttribute("ProtectInMemory", "True");
|
||||||
value = entry->attributes()->value(key);
|
value = entry->attributes()->value(key);
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
value = entry->attributes()->value(key);
|
value = entry->attributes()->value(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -449,8 +446,7 @@ void Kdbx3XmlWriter::writeString(const QString& qualifiedName, const QString& st
|
||||||
{
|
{
|
||||||
if (string.isEmpty()) {
|
if (string.isEmpty()) {
|
||||||
m_xml.writeEmptyElement(qualifiedName);
|
m_xml.writeEmptyElement(qualifiedName);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
m_xml.writeTextElement(qualifiedName, stripInvalidXml10Chars(string));
|
m_xml.writeTextElement(qualifiedName, stripInvalidXml10Chars(string));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -464,8 +460,7 @@ void Kdbx3XmlWriter::writeBool(const QString& qualifiedName, bool b)
|
||||||
{
|
{
|
||||||
if (b) {
|
if (b) {
|
||||||
writeString(qualifiedName, "True");
|
writeString(qualifiedName, "True");
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
writeString(qualifiedName, "False");
|
writeString(qualifiedName, "False");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -494,8 +489,7 @@ void Kdbx3XmlWriter::writeUuid(const QString& qualifiedName, const Group* group)
|
||||||
{
|
{
|
||||||
if (group) {
|
if (group) {
|
||||||
writeUuid(qualifiedName, group->uuid());
|
writeUuid(qualifiedName, group->uuid());
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
writeUuid(qualifiedName, Uuid());
|
writeUuid(qualifiedName, Uuid());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -504,8 +498,7 @@ void Kdbx3XmlWriter::writeUuid(const QString& qualifiedName, const Entry* entry)
|
||||||
{
|
{
|
||||||
if (entry) {
|
if (entry) {
|
||||||
writeUuid(qualifiedName, entry->uuid());
|
writeUuid(qualifiedName, entry->uuid());
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
writeUuid(qualifiedName, Uuid());
|
writeUuid(qualifiedName, Uuid());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -534,11 +527,9 @@ void Kdbx3XmlWriter::writeTriState(const QString& qualifiedName, Group::TriState
|
||||||
|
|
||||||
if (triState == Group::Inherit) {
|
if (triState == Group::Inherit) {
|
||||||
value = "null";
|
value = "null";
|
||||||
}
|
} else if (triState == Group::Enable) {
|
||||||
else if (triState == Group::Enable) {
|
|
||||||
value = "true";
|
value = "true";
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
value = "false";
|
value = "false";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -564,8 +555,7 @@ QString Kdbx3XmlWriter::stripInvalidXml10Chars(QString str)
|
||||||
if (ch.isLowSurrogate() && i != 0 && str.at(i - 1).isHighSurrogate()) {
|
if (ch.isLowSurrogate() && i != 0 && str.at(i - 1).isHighSurrogate()) {
|
||||||
// keep valid surrogate pair
|
// keep valid surrogate pair
|
||||||
i--;
|
i--;
|
||||||
}
|
} else if ((uc < 0x20 && uc != 0x09 && uc != 0x0A && uc != 0x0D) // control characters
|
||||||
else if ((uc < 0x20 && uc != 0x09 && uc != 0x0A && uc != 0x0D) // control characters
|
|
||||||
|| (uc >= 0x7F && uc <= 0x84) // control characters, valid but discouraged by XML
|
|| (uc >= 0x7F && uc <= 0x84) // control characters, valid but discouraged by XML
|
||||||
|| (uc >= 0x86 && uc <= 0x9F) // control characters, valid but discouraged by XML
|
|| (uc >= 0x86 && uc <= 0x9F) // control characters, valid but discouraged by XML
|
||||||
|| (uc > 0xFFFD) // noncharacter
|
|| (uc > 0xFFFD) // noncharacter
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2017 KeePassXC Team
|
* Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -94,8 +94,7 @@ qint64 HmacBlockStream::readData(char* data, qint64 maxSize)
|
||||||
{
|
{
|
||||||
if (m_error) {
|
if (m_error) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
} else if (m_eof) {
|
||||||
else if (m_eof) {
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,8 +106,7 @@ qint64 HmacBlockStream::readData(char* data, qint64 maxSize)
|
||||||
if (!readHashedBlock()) {
|
if (!readHashedBlock()) {
|
||||||
if (m_error) {
|
if (m_error) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
return maxSize - bytesRemaining;
|
return maxSize - bytesRemaining;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -204,8 +202,7 @@ qint64 HmacBlockStream::writeData(const char* data, qint64 maxSize)
|
||||||
if (!writeHashedBlock()) {
|
if (!writeHashedBlock()) {
|
||||||
if (m_error) {
|
if (m_error) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
return maxSize - bytesRemaining;
|
return maxSize - bytesRemaining;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -249,11 +246,13 @@ bool HmacBlockStream::writeHashedBlock()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray HmacBlockStream::getCurrentHmacKey() const {
|
QByteArray HmacBlockStream::getCurrentHmacKey() const
|
||||||
|
{
|
||||||
return getHmacKey(m_blockIndex, m_key);
|
return getHmacKey(m_blockIndex, m_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray HmacBlockStream::getHmacKey(quint64 blockIndex, QByteArray key) {
|
QByteArray HmacBlockStream::getHmacKey(quint64 blockIndex, QByteArray key)
|
||||||
|
{
|
||||||
Q_ASSERT(key.size() == 64);
|
Q_ASSERT(key.size() == 64);
|
||||||
QByteArray indexBytes = Endian::sizedIntToBytes<quint64>(blockIndex, ByteOrder);
|
QByteArray indexBytes = Endian::sizedIntToBytes<quint64>(blockIndex, ByteOrder);
|
||||||
CryptoHash hasher(CryptoHash::Sha512);
|
CryptoHash hasher(CryptoHash::Sha512);
|
||||||
|
@ -262,6 +261,7 @@ QByteArray HmacBlockStream::getHmacKey(quint64 blockIndex, QByteArray key) {
|
||||||
return hasher.result();
|
return hasher.result();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HmacBlockStream::atEnd() const {
|
bool HmacBlockStream::atEnd() const
|
||||||
|
{
|
||||||
return m_eof;
|
return m_eof;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2017 KeePassXC Team
|
* Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue