Reformat code, fix minor style issues, make kdf() getter const

This commit is contained in:
Janek Bevendorff 2017-12-16 17:36:33 +01:00 committed by Jonathan White
parent d1a19a1009
commit 0d6ca0945b
No known key found for this signature in database
GPG key ID: 440FC65F2E0C6E01
24 changed files with 324 additions and 473 deletions

View file

@ -485,7 +485,7 @@ QString Database::saveToFile(QString filePath)
} }
} }
Kdf* Database::kdf() { Kdf* Database::kdf() const {
return m_data.kdf; return m_data.kdf;
} }

View file

@ -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;

View file

@ -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);

View file

@ -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:

View file

@ -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;
} }

View file

@ -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

View file

@ -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);

View file

@ -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;
} }

View file

@ -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();
}; };

View file

@ -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);
} }

View file

@ -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;

View file

@ -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

View file

@ -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;
} }
} }

View file

@ -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;
} }
} }

View file

@ -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);

View file

@ -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

View file

@ -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;
} }

View file

@ -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