Fix coding style and GUI test

This commit is contained in:
Janek Bevendorff 2018-01-06 17:06:51 +01:00 committed by Jonathan White
parent 54fb0d9bd3
commit ccfd7a065c
No known key found for this signature in database
GPG Key ID: 440FC65F2E0C6E01
28 changed files with 426 additions and 379 deletions

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
@ -33,7 +33,7 @@
Argon2Kdf::Argon2Kdf() Argon2Kdf::Argon2Kdf()
: Kdf::Kdf(KeePass2::KDF_ARGON2) : Kdf::Kdf(KeePass2::KDF_ARGON2)
, m_version(0x13) , m_version(0x13)
, m_memory(1<<16) , m_memory(1 << 16)
, m_parallelism(2) , m_parallelism(2)
{ {
m_rounds = 1; m_rounds = 1;
@ -63,7 +63,7 @@ quint64 Argon2Kdf::memory() const
bool Argon2Kdf::setMemory(quint64 kibibytes) bool Argon2Kdf::setMemory(quint64 kibibytes)
{ {
// MIN=8KB; MAX=2,147,483,648KB // MIN=8KB; MAX=2,147,483,648KB
if (kibibytes >= 8 && kibibytes < (1ULL<<32)) { if (kibibytes >= 8 && kibibytes < (1ULL << 32)) {
m_memory = kibibytes; m_memory = kibibytes;
return true; return true;
} }
@ -79,7 +79,7 @@ quint32 Argon2Kdf::parallelism() const
bool Argon2Kdf::setParallelism(quint32 threads) bool Argon2Kdf::setParallelism(quint32 threads)
{ {
// MIN=1; MAX=16,777,215 // MIN=1; MAX=16,777,215
if (threads >= 1 && threads < (1<<24)) { if (threads >= 1 && threads < (1 << 24)) {
m_parallelism = threads; m_parallelism = threads;
return true; return true;
} }

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

@ -1,4 +1,5 @@
/* /*
* Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
* Copyright (C) 2010 Felix Geyer <debfx@fobos.de> * Copyright (C) 2010 Felix Geyer <debfx@fobos.de>
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
@ -161,7 +162,7 @@ Database* Kdbx3Reader::readDatabase(QIODevice* device, const CompositeKey& key,
xmlDevice = ioCompressor.data(); xmlDevice = ioCompressor.data();
} }
KeePass2RandomStream randomStream(KeePass2::Salsa20); KeePass2RandomStream randomStream(KeePass2::ProtectedStreamAlgo::Salsa20);
if (!randomStream.init(m_protectedStreamKey)) { if (!randomStream.init(m_protectedStreamKey)) {
raiseError(randomStream.errorString()); raiseError(randomStream.errorString());
return nullptr; return nullptr;
@ -208,10 +209,10 @@ bool Kdbx3Reader::readHeaderField()
raiseError("Invalid header id size"); raiseError("Invalid header id size");
return false; return false;
} }
quint8 fieldID = fieldIDArray.at(0); char fieldID = fieldIDArray.at(0);
bool ok; bool ok;
quint16 fieldLen = Endian::readSizedInt<quint16>(m_headerStream, KeePass2::BYTEORDER, &ok); auto fieldLen = Endian::readSizedInt<quint16>(m_headerStream, KeePass2::BYTEORDER, &ok);
if (!ok) { if (!ok) {
raiseError("Invalid header field length"); raiseError("Invalid header field length");
return false; return false;
@ -226,44 +227,44 @@ bool Kdbx3Reader::readHeaderField()
} }
} }
switch (fieldID) { switch (static_cast<KeePass2::HeaderFieldID>(fieldID)) {
case KeePass2::EndOfHeader: case KeePass2::HeaderFieldID::EndOfHeader:
m_headerEnd = true; m_headerEnd = true;
break; break;
case KeePass2::CipherID: case KeePass2::HeaderFieldID::CipherID:
setCipher(fieldData); setCipher(fieldData);
break; break;
case KeePass2::CompressionFlags: case KeePass2::HeaderFieldID::CompressionFlags:
setCompressionFlags(fieldData); setCompressionFlags(fieldData);
break; break;
case KeePass2::MasterSeed: case KeePass2::HeaderFieldID::MasterSeed:
setMasterSeed(fieldData); setMasterSeed(fieldData);
break; break;
case KeePass2::TransformSeed: case KeePass2::HeaderFieldID::TransformSeed:
setTransformSeed(fieldData); setTransformSeed(fieldData);
break; break;
case KeePass2::TransformRounds: case KeePass2::HeaderFieldID::TransformRounds:
setTransformRounds(fieldData); setTransformRounds(fieldData);
break; break;
case KeePass2::EncryptionIV: case KeePass2::HeaderFieldID::EncryptionIV:
setEncryptionIV(fieldData); setEncryptionIV(fieldData);
break; break;
case KeePass2::ProtectedStreamKey: case KeePass2::HeaderFieldID::ProtectedStreamKey:
setProtectedStreamKey(fieldData); setProtectedStreamKey(fieldData);
break; break;
case KeePass2::StreamStartBytes: case KeePass2::HeaderFieldID::StreamStartBytes:
setStreamStartBytes(fieldData); setStreamStartBytes(fieldData);
break; break;
case KeePass2::InnerRandomStreamID: case KeePass2::HeaderFieldID::InnerRandomStreamID:
setInnerRandomStreamID(fieldData); setInnerRandomStreamID(fieldData);
break; break;
@ -279,39 +280,40 @@ void Kdbx3Reader::setCipher(const QByteArray& data)
{ {
if (data.size() != Uuid::Length) { if (data.size() != Uuid::Length) {
raiseError("Invalid cipher uuid length"); raiseError("Invalid cipher uuid length");
} else { return;
Uuid uuid(data);
if (SymmetricCipher::cipherToAlgorithm(uuid) == SymmetricCipher::InvalidAlgorithm) {
raiseError("Unsupported cipher");
} else {
m_db->setCipher(uuid);
}
} }
Uuid uuid(data);
if (SymmetricCipher::cipherToAlgorithm(uuid) == SymmetricCipher::InvalidAlgorithm) {
raiseError("Unsupported cipher");
return;
}
m_db->setCipher(uuid);
} }
void Kdbx3Reader::setCompressionFlags(const QByteArray& data) 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 { return;
quint32 id = Endian::bytesToSizedInt<quint32>(data, KeePass2::BYTEORDER);
if (id > Database::CompressionAlgorithmMax) {
raiseError("Unsupported compression algorithm");
} else {
m_db->setCompressionAlgo(static_cast<Database::CompressionAlgorithm>(id));
}
} }
auto id = Endian::bytesToSizedInt<quint32>(data, KeePass2::BYTEORDER);
if (id > Database::CompressionAlgorithmMax) {
raiseError("Unsupported compression algorithm");
return;
}
m_db->setCompressionAlgo(static_cast<Database::CompressionAlgorithm>(id));
} }
void Kdbx3Reader::setMasterSeed(const QByteArray& data) 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 { return;
m_masterSeed = data;
} }
m_masterSeed = data;
} }
void Kdbx3Reader::setTransformSeed(const QByteArray& data) void Kdbx3Reader::setTransformSeed(const QByteArray& data)
@ -355,22 +357,23 @@ 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 { return;
m_streamStartBytes = data;
} }
m_streamStartBytes = data;
} }
void Kdbx3Reader::setInnerRandomStreamID(const QByteArray& data) void Kdbx3Reader::setInnerRandomStreamID(const QByteArray& data)
{ {
if (data.size() != 4) { if (data.size() != 4) {
raiseError("Invalid random stream id size"); raiseError("Invalid random stream id size");
} else { return;
quint32 id = Endian::bytesToSizedInt<quint32>(data, KeePass2::BYTEORDER);
KeePass2::ProtectedStreamAlgo irsAlgo = KeePass2::idToProtectedStreamAlgo(id);
if (irsAlgo == KeePass2::InvalidProtectedStreamAlgo || irsAlgo == KeePass2::ArcFourVariant) {
raiseError("Invalid inner random stream cipher");
} else {
m_irsAlgo = irsAlgo;
}
} }
quint32 id = Endian::bytesToSizedInt<quint32>(data, KeePass2::BYTEORDER);
KeePass2::ProtectedStreamAlgo irsAlgo = KeePass2::idToProtectedStreamAlgo(id);
if (irsAlgo == KeePass2::ProtectedStreamAlgo::InvalidProtectedStreamAlgo ||
irsAlgo == KeePass2::ProtectedStreamAlgo::ArcFourVariant) {
raiseError("Invalid inner random stream cipher");
return;
}
m_irsAlgo = irsAlgo;
} }

View File

@ -1,4 +1,5 @@
/* /*
* Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
* Copyright (C) 2010 Felix Geyer <debfx@fobos.de> * Copyright (C) 2010 Felix Geyer <debfx@fobos.de>
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify

View File

@ -1,4 +1,5 @@
/* /*
* Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
* Copyright (C) 2010 Felix Geyer <debfx@fobos.de> * Copyright (C) 2010 Felix Geyer <debfx@fobos.de>
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
@ -32,9 +33,6 @@
#include "streams/QtIOCompressor" #include "streams/QtIOCompressor"
#include "streams/SymmetricCipherStream.h" #include "streams/SymmetricCipherStream.h"
#define CHECK_RETURN(x) if (!(x)) return;
#define CHECK_RETURN_FALSE(x) if (!(x)) return false;
Kdbx3Writer::Kdbx3Writer() Kdbx3Writer::Kdbx3Writer()
: m_device(0) : m_device(0)
{ {
@ -51,7 +49,7 @@ bool Kdbx3Writer::writeDatabase(QIODevice* device, Database* db)
QByteArray startBytes = randomGen()->randomArray(32); QByteArray startBytes = randomGen()->randomArray(32);
QByteArray endOfHeader = "\r\n\r\n"; QByteArray endOfHeader = "\r\n\r\n";
if (db->challengeMasterSeed(masterSeed) == false) { if (!db->challengeMasterSeed(masterSeed)) {
raiseError(tr("Unable to issue challenge-response.")); raiseError(tr("Unable to issue challenge-response."));
return false; return false;
} }
@ -76,23 +74,23 @@ bool Kdbx3Writer::writeDatabase(QIODevice* device, Database* db)
CHECK_RETURN_FALSE(writeData(Endian::sizedIntToBytes<qint32>(KeePass2::SIGNATURE_2, KeePass2::BYTEORDER))); CHECK_RETURN_FALSE(writeData(Endian::sizedIntToBytes<qint32>(KeePass2::SIGNATURE_2, KeePass2::BYTEORDER)));
CHECK_RETURN_FALSE(writeData(Endian::sizedIntToBytes<qint32>(KeePass2::FILE_VERSION_3, KeePass2::BYTEORDER))); CHECK_RETURN_FALSE(writeData(Endian::sizedIntToBytes<qint32>(KeePass2::FILE_VERSION_3, KeePass2::BYTEORDER)));
CHECK_RETURN_FALSE(writeHeaderField(KeePass2::CipherID, db->cipher().toByteArray())); CHECK_RETURN_FALSE(writeHeaderField(KeePass2::HeaderFieldID::CipherID, db->cipher().toByteArray()));
CHECK_RETURN_FALSE(writeHeaderField(KeePass2::CompressionFlags, CHECK_RETURN_FALSE(writeHeaderField(KeePass2::HeaderFieldID::CompressionFlags,
Endian::sizedIntToBytes<qint32>(db->compressionAlgo(), Endian::sizedIntToBytes<qint32>(db->compressionAlgo(),
KeePass2::BYTEORDER))); KeePass2::BYTEORDER)));
auto kdf = db->kdf(); auto kdf = db->kdf();
CHECK_RETURN_FALSE(writeHeaderField(KeePass2::MasterSeed, masterSeed)); CHECK_RETURN_FALSE(writeHeaderField(KeePass2::HeaderFieldID::MasterSeed, masterSeed));
CHECK_RETURN_FALSE(writeHeaderField(KeePass2::TransformSeed, kdf->seed())); CHECK_RETURN_FALSE(writeHeaderField(KeePass2::HeaderFieldID::TransformSeed, kdf->seed()));
CHECK_RETURN_FALSE(writeHeaderField(KeePass2::TransformRounds, CHECK_RETURN_FALSE(writeHeaderField(KeePass2::HeaderFieldID::TransformRounds,
Endian::sizedIntToBytes<qint64>(kdf->rounds(), Endian::sizedIntToBytes<qint64>(kdf->rounds(),
KeePass2::BYTEORDER))); KeePass2::BYTEORDER)));
CHECK_RETURN_FALSE(writeHeaderField(KeePass2::EncryptionIV, encryptionIV)); CHECK_RETURN_FALSE(writeHeaderField(KeePass2::HeaderFieldID::EncryptionIV, encryptionIV));
CHECK_RETURN_FALSE(writeHeaderField(KeePass2::ProtectedStreamKey, protectedStreamKey)); CHECK_RETURN_FALSE(writeHeaderField(KeePass2::HeaderFieldID::ProtectedStreamKey, protectedStreamKey));
CHECK_RETURN_FALSE(writeHeaderField(KeePass2::StreamStartBytes, startBytes)); CHECK_RETURN_FALSE(writeHeaderField(KeePass2::HeaderFieldID::StreamStartBytes, startBytes));
CHECK_RETURN_FALSE(writeHeaderField(KeePass2::InnerRandomStreamID, CHECK_RETURN_FALSE(writeHeaderField(KeePass2::HeaderFieldID::InnerRandomStreamID,
Endian::sizedIntToBytes<qint32>(KeePass2::Salsa20, Endian::sizedIntToBytes<qint32>(static_cast<qint32>(KeePass2::ProtectedStreamAlgo::Salsa20),
KeePass2::BYTEORDER))); KeePass2::BYTEORDER)));
CHECK_RETURN_FALSE(writeHeaderField(KeePass2::EndOfHeader, endOfHeader)); CHECK_RETURN_FALSE(writeHeaderField(KeePass2::HeaderFieldID::EndOfHeader, endOfHeader));
header.close(); header.close();
m_device = device; m_device = device;
@ -130,7 +128,7 @@ bool Kdbx3Writer::writeDatabase(QIODevice* device, Database* db)
m_device = ioCompressor.data(); m_device = ioCompressor.data();
} }
KeePass2RandomStream randomStream(KeePass2::Salsa20); KeePass2RandomStream randomStream(KeePass2::ProtectedStreamAlgo::Salsa20);
if (!randomStream.init(protectedStreamKey)) { if (!randomStream.init(protectedStreamKey)) {
raiseError(randomStream.errorString()); raiseError(randomStream.errorString());
return false; return false;
@ -175,7 +173,7 @@ bool Kdbx3Writer::writeHeaderField(KeePass2::HeaderFieldID fieldId, const QByteA
Q_ASSERT(data.size() <= 65535); Q_ASSERT(data.size() <= 65535);
QByteArray fieldIdArr; QByteArray fieldIdArr;
fieldIdArr[0] = fieldId; fieldIdArr[0] = static_cast<char>(fieldId);
CHECK_RETURN_FALSE(writeData(fieldIdArr)); CHECK_RETURN_FALSE(writeData(fieldIdArr));
CHECK_RETURN_FALSE(writeData(Endian::sizedIntToBytes<qint16>(static_cast<quint16>(data.size()), CHECK_RETURN_FALSE(writeData(Endian::sizedIntToBytes<qint16>(static_cast<quint16>(data.size()),
KeePass2::BYTEORDER))); KeePass2::BYTEORDER)));

View File

@ -1,4 +1,5 @@
/* /*
* Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
* Copyright (C) 2010 Felix Geyer <debfx@fobos.de> * Copyright (C) 2010 Felix Geyer <debfx@fobos.de>
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify

View File

@ -1,4 +1,5 @@
/* /*
* Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
* Copyright (C) 2010 Felix Geyer <debfx@fobos.de> * Copyright (C) 2010 Felix Geyer <debfx@fobos.de>
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify

View File

@ -1,4 +1,5 @@
/* /*
* Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
* Copyright (C) 2010 Felix Geyer <debfx@fobos.de> * Copyright (C) 2010 Felix Geyer <debfx@fobos.de>
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify

View File

@ -1,4 +1,5 @@
/* /*
* Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
* Copyright (C) 2010 Felix Geyer <debfx@fobos.de> * Copyright (C) 2010 Felix Geyer <debfx@fobos.de>
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
@ -458,11 +459,7 @@ void Kdbx3XmlWriter::writeNumber(const QString& qualifiedName, int number)
void Kdbx3XmlWriter::writeBool(const QString& qualifiedName, bool b) void Kdbx3XmlWriter::writeBool(const QString& qualifiedName, bool b)
{ {
if (b) { writeString(qualifiedName, b ? "True" : "False");
writeString(qualifiedName, "True");
} else {
writeString(qualifiedName, "False");
}
} }
void Kdbx3XmlWriter::writeDateTime(const QString& qualifiedName, const QDateTime& dateTime) void Kdbx3XmlWriter::writeDateTime(const QString& qualifiedName, const QDateTime& dateTime)
@ -487,20 +484,12 @@ void Kdbx3XmlWriter::writeUuid(const QString& qualifiedName, const Uuid& uuid)
void Kdbx3XmlWriter::writeUuid(const QString& qualifiedName, const Group* group) void Kdbx3XmlWriter::writeUuid(const QString& qualifiedName, const Group* group)
{ {
if (group) { writeUuid(qualifiedName, group ? group->uuid() : Uuid());
writeUuid(qualifiedName, group->uuid());
} else {
writeUuid(qualifiedName, Uuid());
}
} }
void Kdbx3XmlWriter::writeUuid(const QString& qualifiedName, const Entry* entry) void Kdbx3XmlWriter::writeUuid(const QString& qualifiedName, const Entry* entry)
{ {
if (entry) { writeUuid(qualifiedName, entry ? entry->uuid() : Uuid());
writeUuid(qualifiedName, entry->uuid());
} else {
writeUuid(qualifiedName, Uuid());
}
} }
void Kdbx3XmlWriter::writeBinary(const QString& qualifiedName, const QByteArray& ba) void Kdbx3XmlWriter::writeBinary(const QString& qualifiedName, const QByteArray& ba)

View File

@ -1,4 +1,5 @@
/* /*
* Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
* Copyright (C) 2010 Felix Geyer <debfx@fobos.de> * Copyright (C) 2010 Felix Geyer <debfx@fobos.de>
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2010 Felix Geyer <debfx@fobos.de> * 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
@ -72,8 +72,7 @@ Database* Kdbx4Reader::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;
} }
@ -203,9 +202,7 @@ Database* Kdbx4Reader::readDatabase(QIODevice* device, const CompositeKey& key,
if (keepDatabase) { if (keepDatabase) {
return db.take(); return db.take();
} }
else { return nullptr;
return nullptr;
}
} }
return db.take(); return db.take();
@ -218,10 +215,10 @@ bool Kdbx4Reader::readHeaderField(QIODevice* device)
raiseError("Invalid header id size"); raiseError("Invalid header id size");
return false; return false;
} }
quint8 fieldID = fieldIDArray.at(0); char fieldID = fieldIDArray.at(0);
bool ok; bool ok;
quint32 fieldLen = Endian::readSizedInt<quint32>(device, KeePass2::BYTEORDER, &ok); auto fieldLen = Endian::readSizedInt<quint32>(device, KeePass2::BYTEORDER, &ok);
if (!ok) { if (!ok) {
raiseError("Invalid header field length"); raiseError("Invalid header field length");
return false; return false;
@ -236,27 +233,27 @@ bool Kdbx4Reader::readHeaderField(QIODevice* device)
} }
} }
switch (fieldID) { switch (static_cast<KeePass2::HeaderFieldID>(fieldID)) {
case KeePass2::EndOfHeader: case KeePass2::HeaderFieldID::EndOfHeader:
return false; return false;
case KeePass2::CipherID: case KeePass2::HeaderFieldID::CipherID:
setCipher(fieldData); setCipher(fieldData);
break; break;
case KeePass2::CompressionFlags: case KeePass2::HeaderFieldID::CompressionFlags:
setCompressionFlags(fieldData); setCompressionFlags(fieldData);
break; break;
case KeePass2::MasterSeed: case KeePass2::HeaderFieldID::MasterSeed:
setMasterSeed(fieldData); setMasterSeed(fieldData);
break; break;
case KeePass2::EncryptionIV: case KeePass2::HeaderFieldID::EncryptionIV:
setEncryptionIV(fieldData); setEncryptionIV(fieldData);
break; break;
case KeePass2::KdfParameters: { case KeePass2::HeaderFieldID::KdfParameters: {
QBuffer bufIoDevice(&fieldData); QBuffer bufIoDevice(&fieldData);
if (!bufIoDevice.open(QIODevice::ReadOnly)) { if (!bufIoDevice.open(QIODevice::ReadOnly)) {
raiseError("Failed to open buffer for KDF parameters in header"); raiseError("Failed to open buffer for KDF parameters in header");
@ -264,7 +261,7 @@ bool Kdbx4Reader::readHeaderField(QIODevice* device)
} }
QVariantMap kdfParams = readVariantMap(&bufIoDevice); QVariantMap kdfParams = readVariantMap(&bufIoDevice);
QSharedPointer<Kdf> kdf = KeePass2::kdfFromParameters(kdfParams); QSharedPointer<Kdf> kdf = KeePass2::kdfFromParameters(kdfParams);
if (kdf == nullptr) { if (!kdf) {
raiseError("Invalid KDF parameters"); raiseError("Invalid KDF parameters");
return false; return false;
} }
@ -272,15 +269,15 @@ bool Kdbx4Reader::readHeaderField(QIODevice* device)
break; break;
} }
case KeePass2::PublicCustomData: case KeePass2::HeaderFieldID::PublicCustomData:
m_db->setPublicCustomData(fieldData); m_db->setPublicCustomData(fieldData);
break; break;
case KeePass2::ProtectedStreamKey: case KeePass2::HeaderFieldID::ProtectedStreamKey:
case KeePass2::TransformRounds: case KeePass2::HeaderFieldID::TransformRounds:
case KeePass2::TransformSeed: case KeePass2::HeaderFieldID::TransformSeed:
case KeePass2::StreamStartBytes: case KeePass2::HeaderFieldID::StreamStartBytes:
case KeePass2::InnerRandomStreamID: case KeePass2::HeaderFieldID::InnerRandomStreamID:
raiseError("Legacy header fields found in KDBX4 file."); raiseError("Legacy header fields found in KDBX4 file.");
return false; return false;
@ -456,39 +453,39 @@ void Kdbx4Reader::setCipher(const QByteArray& data)
{ {
if (data.size() != Uuid::Length) { if (data.size() != Uuid::Length) {
raiseError("Invalid cipher uuid length"); raiseError("Invalid cipher uuid length");
} else { return;
Uuid uuid(data);
if (SymmetricCipher::cipherToAlgorithm(uuid) == SymmetricCipher::InvalidAlgorithm) {
raiseError("Unsupported cipher");
} else {
m_db->setCipher(uuid);
}
} }
Uuid uuid(data);
if (SymmetricCipher::cipherToAlgorithm(uuid) == SymmetricCipher::InvalidAlgorithm) {
raiseError("Unsupported cipher");
return;
}
m_db->setCipher(uuid);
} }
void Kdbx4Reader::setCompressionFlags(const QByteArray& data) void Kdbx4Reader::setCompressionFlags(const QByteArray& data)
{ {
if (data.size() != 4) { if (data.size() != 4) {
raiseError("Invalid compression flags length"); raiseError("Invalid compression flags length");
} else { return;
quint32 id = Endian::bytesToSizedInt<quint32>(data, KeePass2::BYTEORDER);
if (id > Database::CompressionAlgorithmMax) {
raiseError("Unsupported compression algorithm");
} else {
m_db->setCompressionAlgo(static_cast<Database::CompressionAlgorithm>(id));
}
} }
auto id = Endian::bytesToSizedInt<quint32>(data, KeePass2::BYTEORDER);
if (id > Database::CompressionAlgorithmMax) {
raiseError("Unsupported compression algorithm");
return;
}
m_db->setCompressionAlgo(static_cast<Database::CompressionAlgorithm>(id));
} }
void Kdbx4Reader::setMasterSeed(const QByteArray& data) void Kdbx4Reader::setMasterSeed(const QByteArray& data)
{ {
if (data.size() != 32) { if (data.size() != 32) {
raiseError("Invalid master seed size"); raiseError("Invalid master seed size");
} else { return;
m_masterSeed = data;
} }
m_masterSeed = data;
} }
void Kdbx4Reader::setEncryptionIV(const QByteArray& data) void Kdbx4Reader::setEncryptionIV(const QByteArray& data)
@ -505,15 +502,15 @@ void Kdbx4Reader::setInnerRandomStreamID(const QByteArray& data)
{ {
if (data.size() != 4) { if (data.size() != 4) {
raiseError("Invalid random stream id size"); raiseError("Invalid random stream id size");
} else { return;
quint32 id = Endian::bytesToSizedInt<quint32>(data, KeePass2::BYTEORDER);
KeePass2::ProtectedStreamAlgo irsAlgo = KeePass2::idToProtectedStreamAlgo(id);
if (irsAlgo == KeePass2::InvalidProtectedStreamAlgo || irsAlgo == KeePass2::ArcFourVariant) {
raiseError("Invalid inner random stream cipher");
} else {
m_irsAlgo = irsAlgo;
}
} }
auto id = Endian::bytesToSizedInt<quint32>(data, KeePass2::BYTEORDER);
KeePass2::ProtectedStreamAlgo irsAlgo = KeePass2::idToProtectedStreamAlgo(id);
if (irsAlgo == KeePass2::ProtectedStreamAlgo::InvalidProtectedStreamAlgo || irsAlgo == KeePass2::ProtectedStreamAlgo::ArcFourVariant) {
raiseError("Invalid inner random stream cipher");
return;
}
m_irsAlgo = irsAlgo;
} }
QHash<QString, QByteArray> Kdbx4Reader::binaryPool() QHash<QString, QByteArray> Kdbx4Reader::binaryPool()

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2010 Felix Geyer <debfx@fobos.de> * 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

@ -1,5 +1,4 @@
/* /*
* Copyright (C) 2010 Felix Geyer <debfx@fobos.de>
* Copyright (C) 2017 KeePassXC Team <team@keepassxc.org> * 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
@ -34,8 +33,6 @@
#include "streams/QtIOCompressor" #include "streams/QtIOCompressor"
#include "streams/SymmetricCipherStream.h" #include "streams/SymmetricCipherStream.h"
#define CHECK_RETURN_FALSE(x) if (!(x)) return false;
Kdbx4Writer::Kdbx4Writer() Kdbx4Writer::Kdbx4Writer()
: m_device(nullptr) : m_device(nullptr)
{ {
@ -63,7 +60,7 @@ bool Kdbx4Writer::writeDatabase(QIODevice* device, Database* db)
QByteArray startBytes; QByteArray startBytes;
QByteArray endOfHeader = "\r\n\r\n"; QByteArray endOfHeader = "\r\n\r\n";
if (db->challengeMasterSeed(masterSeed) == false) { if (!db->challengeMasterSeed(masterSeed)) {
raiseError(tr("Unable to issue challenge-response.")); raiseError(tr("Unable to issue challenge-response."));
return false; return false;
} }
@ -88,12 +85,12 @@ bool Kdbx4Writer::writeDatabase(QIODevice* device, Database* db)
CHECK_RETURN_FALSE(writeData(Endian::sizedIntToBytes(KeePass2::SIGNATURE_1, KeePass2::BYTEORDER))); CHECK_RETURN_FALSE(writeData(Endian::sizedIntToBytes(KeePass2::SIGNATURE_1, KeePass2::BYTEORDER)));
CHECK_RETURN_FALSE(writeData(Endian::sizedIntToBytes(KeePass2::SIGNATURE_2, KeePass2::BYTEORDER))); CHECK_RETURN_FALSE(writeData(Endian::sizedIntToBytes(KeePass2::SIGNATURE_2, KeePass2::BYTEORDER)));
CHECK_RETURN_FALSE(writeData(Endian::sizedIntToBytes(KeePass2::FILE_VERSION_4, KeePass2::BYTEORDER))); CHECK_RETURN_FALSE(writeData(Endian::sizedIntToBytes(KeePass2::FILE_VERSION_4, KeePass2::BYTEORDER)));
CHECK_RETURN_FALSE(writeHeaderField(KeePass2::CipherID, db->cipher().toByteArray())); CHECK_RETURN_FALSE(writeHeaderField(KeePass2::HeaderFieldID::CipherID, db->cipher().toByteArray()));
CHECK_RETURN_FALSE(writeHeaderField(KeePass2::CompressionFlags, CHECK_RETURN_FALSE(writeHeaderField(KeePass2::HeaderFieldID::CompressionFlags,
Endian::sizedIntToBytes(static_cast<int>(db->compressionAlgo()), Endian::sizedIntToBytes(static_cast<int>(db->compressionAlgo()),
KeePass2::BYTEORDER))); KeePass2::BYTEORDER)));
CHECK_RETURN_FALSE(writeHeaderField(KeePass2::MasterSeed, masterSeed)); CHECK_RETURN_FALSE(writeHeaderField(KeePass2::HeaderFieldID::MasterSeed, masterSeed));
CHECK_RETURN_FALSE(writeHeaderField(KeePass2::EncryptionIV, encryptionIV)); CHECK_RETURN_FALSE(writeHeaderField(KeePass2::HeaderFieldID::EncryptionIV, encryptionIV));
// Convert current Kdf to basic parameters // Convert current Kdf to basic parameters
QVariantMap kdfParams = KeePass2::kdfToParameters(db->kdf()); QVariantMap kdfParams = KeePass2::kdfToParameters(db->kdf());
@ -104,12 +101,12 @@ bool Kdbx4Writer::writeDatabase(QIODevice* device, Database* db)
return false; return false;
} }
QByteArray publicCustomData = db->publicCustomData(); QByteArray publicCustomData = db->publicCustomData();
CHECK_RETURN_FALSE(writeHeaderField(KeePass2::KdfParameters, kdfParamBytes)); CHECK_RETURN_FALSE(writeHeaderField(KeePass2::HeaderFieldID::KdfParameters, kdfParamBytes));
if (!publicCustomData.isEmpty()) { if (!publicCustomData.isEmpty()) {
CHECK_RETURN_FALSE(writeHeaderField(KeePass2::PublicCustomData, publicCustomData)); CHECK_RETURN_FALSE(writeHeaderField(KeePass2::HeaderFieldID::PublicCustomData, publicCustomData));
} }
CHECK_RETURN_FALSE(writeHeaderField(KeePass2::EndOfHeader, endOfHeader)); CHECK_RETURN_FALSE(writeHeaderField(KeePass2::HeaderFieldID::EndOfHeader, endOfHeader));
header.close(); header.close();
m_device = device; m_device = device;
headerData = header.data(); headerData = header.data();
@ -161,7 +158,7 @@ bool Kdbx4Writer::writeDatabase(QIODevice* device, Database* db)
QHash<QByteArray, int> idMap; QHash<QByteArray, int> idMap;
CHECK_RETURN_FALSE(writeInnerHeaderField(KeePass2::InnerHeaderFieldID::InnerRandomStreamID, CHECK_RETURN_FALSE(writeInnerHeaderField(KeePass2::InnerHeaderFieldID::InnerRandomStreamID,
Endian::sizedIntToBytes(static_cast<int>(KeePass2::ChaCha20), Endian::sizedIntToBytes(static_cast<int>(KeePass2::ProtectedStreamAlgo::ChaCha20),
KeePass2::BYTEORDER))); KeePass2::BYTEORDER)));
CHECK_RETURN_FALSE(writeInnerHeaderField(KeePass2::InnerHeaderFieldID::InnerRandomStreamKey, CHECK_RETURN_FALSE(writeInnerHeaderField(KeePass2::InnerHeaderFieldID::InnerRandomStreamKey,
protectedStreamKey)); protectedStreamKey));
@ -180,7 +177,7 @@ bool Kdbx4Writer::writeDatabase(QIODevice* device, Database* db)
} }
CHECK_RETURN_FALSE(writeInnerHeaderField(KeePass2::InnerHeaderFieldID::End, QByteArray())); CHECK_RETURN_FALSE(writeInnerHeaderField(KeePass2::InnerHeaderFieldID::End, QByteArray()));
KeePass2RandomStream randomStream(KeePass2::ChaCha20); KeePass2RandomStream randomStream(KeePass2::ProtectedStreamAlgo::ChaCha20);
if (!randomStream.init(protectedStreamKey)) { if (!randomStream.init(protectedStreamKey)) {
raiseError(randomStream.errorString()); raiseError(randomStream.errorString());
return false; return false;
@ -217,15 +214,13 @@ bool Kdbx4Writer::writeData(const QByteArray& data)
raiseError(m_device->errorString()); raiseError(m_device->errorString());
return false; return false;
} }
else { return true;
return true;
}
} }
bool Kdbx4Writer::writeHeaderField(KeePass2::HeaderFieldID fieldId, const QByteArray& data) bool Kdbx4Writer::writeHeaderField(KeePass2::HeaderFieldID fieldId, const QByteArray& data)
{ {
QByteArray fieldIdArr; QByteArray fieldIdArr;
fieldIdArr[0] = fieldId; fieldIdArr[0] = static_cast<char>(fieldId);
CHECK_RETURN_FALSE(writeData(fieldIdArr)); CHECK_RETURN_FALSE(writeData(fieldIdArr));
CHECK_RETURN_FALSE(writeData(Endian::sizedIntToBytes(static_cast<quint32>(data.size()), KeePass2::BYTEORDER))); CHECK_RETURN_FALSE(writeData(Endian::sizedIntToBytes(static_cast<quint32>(data.size()), KeePass2::BYTEORDER)));
CHECK_RETURN_FALSE(writeData(data)); CHECK_RETURN_FALSE(writeData(data));
@ -264,47 +259,46 @@ bool Kdbx4Writer::serializeVariantMap(const QVariantMap& p, QByteArray& o)
bool ok; bool ok;
QList<QString> keys = p.keys(); QList<QString> keys = p.keys();
for (int i = 0; i < keys.size(); ++i) { for (const auto& k : keys) {
QString k = keys.at(i);
KeePass2::VariantMapFieldType fieldType; KeePass2::VariantMapFieldType fieldType;
QByteArray data; QByteArray data;
QVariant v = p.value(k); QVariant v = p.value(k);
switch (static_cast<QMetaType::Type>(v.type())) { switch (static_cast<QMetaType::Type>(v.type())) {
case QMetaType::Type::Int: case QMetaType::Type::Int:
fieldType = KeePass2::VariantMapFieldType::Int32; fieldType = KeePass2::VariantMapFieldType::Int32;
data = Endian::sizedIntToBytes(v.toInt(&ok), KeePass2::BYTEORDER); data = Endian::sizedIntToBytes(v.toInt(&ok), KeePass2::BYTEORDER);
CHECK_RETURN_FALSE(ok); CHECK_RETURN_FALSE(ok);
break; break;
case QMetaType::Type::UInt: case QMetaType::Type::UInt:
fieldType = KeePass2::VariantMapFieldType::UInt32; fieldType = KeePass2::VariantMapFieldType::UInt32;
data = Endian::sizedIntToBytes(v.toUInt(&ok), KeePass2::BYTEORDER); data = Endian::sizedIntToBytes(v.toUInt(&ok), KeePass2::BYTEORDER);
CHECK_RETURN_FALSE(ok); CHECK_RETURN_FALSE(ok);
break; break;
case QMetaType::Type::LongLong: case QMetaType::Type::LongLong:
fieldType = KeePass2::VariantMapFieldType::Int64; fieldType = KeePass2::VariantMapFieldType::Int64;
data = Endian::sizedIntToBytes(v.toLongLong(&ok), KeePass2::BYTEORDER); data = Endian::sizedIntToBytes(v.toLongLong(&ok), KeePass2::BYTEORDER);
CHECK_RETURN_FALSE(ok); CHECK_RETURN_FALSE(ok);
break; break;
case QMetaType::Type::ULongLong: case QMetaType::Type::ULongLong:
fieldType = KeePass2::VariantMapFieldType::UInt64; fieldType = KeePass2::VariantMapFieldType::UInt64;
data = Endian::sizedIntToBytes(v.toULongLong(&ok), KeePass2::BYTEORDER); data = Endian::sizedIntToBytes(v.toULongLong(&ok), KeePass2::BYTEORDER);
CHECK_RETURN_FALSE(ok); CHECK_RETURN_FALSE(ok);
break; break;
case QMetaType::Type::QString: case QMetaType::Type::QString:
fieldType = KeePass2::VariantMapFieldType::String; fieldType = KeePass2::VariantMapFieldType::String;
data = v.toString().toUtf8(); data = v.toString().toUtf8();
break; break;
case QMetaType::Type::Bool: case QMetaType::Type::Bool:
fieldType = KeePass2::VariantMapFieldType::Bool; fieldType = KeePass2::VariantMapFieldType::Bool;
data = QByteArray(1, (v.toBool() ? '\1' : '\0')); data = QByteArray(1, static_cast<char>(v.toBool() ? '\1' : '\0'));
break; break;
case QMetaType::Type::QByteArray: case QMetaType::Type::QByteArray:
fieldType = KeePass2::VariantMapFieldType::ByteArray; fieldType = KeePass2::VariantMapFieldType::ByteArray;
data = v.toByteArray(); data = v.toByteArray();
break; break;
default: default:
qWarning("Unknown object type %d in QVariantMap", v.type()); qWarning("Unknown object type %d in QVariantMap", v.type());
return false; return false;
} }
QByteArray typeBytes; QByteArray typeBytes;
typeBytes[0] = static_cast<char>(fieldType); typeBytes[0] = static_cast<char>(fieldType);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2010 Felix Geyer <debfx@fobos.de> * 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

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2010 Felix Geyer <debfx@fobos.de> * 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
@ -19,12 +19,9 @@
#include <QBuffer> #include <QBuffer>
#include <QFile> #include <QFile>
#include <QRegularExpression>
#include "core/Endian.h" #include "core/Endian.h"
#include "core/Database.h"
#include "core/DatabaseIcons.h" #include "core/DatabaseIcons.h"
#include "core/Group.h"
#include "core/Metadata.h" #include "core/Metadata.h"
#include "core/Tools.h" #include "core/Tools.h"
#include "format/KeePass2RandomStream.h" #include "format/KeePass2RandomStream.h"
@ -68,30 +65,32 @@ void Kdbx4XmlReader::readDatabase(QIODevice* device, Database* db, KeePass2Rando
m_randomStream = randomStream; m_randomStream = randomStream;
m_headerHash.clear(); m_headerHash.clear();
m_tmpParent = new Group(); m_tmpParent.reset(new Group());
bool rootGroupParsed = false; bool rootGroupParsed = false;
if (!m_xml.hasError() && m_xml.readNextStartElement()) { if (m_xml.hasError()) {
if (m_xml.name() == "KeePassFile") { raiseError(QString("XML parsing failure: %1").arg(m_xml.error()));
rootGroupParsed = parseKeePassFile(); return;
}
} }
if (!m_xml.hasError() && !rootGroupParsed) { if (m_xml.readNextStartElement() && m_xml.name() == "KeePassFile") {
rootGroupParsed = parseKeePassFile();
}
if (!rootGroupParsed) {
raiseError("No root group"); raiseError("No root group");
return;
} }
if (!m_xml.hasError()) { if (!m_tmpParent->children().isEmpty()) {
if (!m_tmpParent->children().isEmpty()) { qWarning("Kdbx4XmlReader::readDatabase: found %d invalid group reference(s)",
qWarning("Kdbx4XmlReader::readDatabase: found %d invalid group reference(s)", m_tmpParent->children().size());
m_tmpParent->children().size()); }
}
if (!m_tmpParent->entries().isEmpty()) { if (!m_tmpParent->entries().isEmpty()) {
qWarning("Kdbx4XmlReader::readDatabase: found %d invalid entry reference(s)", qWarning("Kdbx4XmlReader::readDatabase: found %d invalid entry reference(s)",
m_tmpParent->children().size()); m_tmpParent->children().size());
}
} }
const QSet<QString> poolKeys = m_binaryPool.keys().toSet(); const QSet<QString> poolKeys = m_binaryPool.keys().toSet();
@ -100,13 +99,11 @@ void Kdbx4XmlReader::readDatabase(QIODevice* device, Database* db, KeePass2Rando
const QSet<QString> unusedKeys = poolKeys - entryKeys; const QSet<QString> unusedKeys = poolKeys - entryKeys;
if (!unmappedKeys.isEmpty()) { if (!unmappedKeys.isEmpty()) {
raiseError("Unmapped keys left."); qWarning("Unmapped keys left.");
} }
if (!m_xml.hasError()) { for (const QString& key : unusedKeys) {
for (const QString& key : unusedKeys) { qWarning("Kdbx4XmlReader::readDatabase: found unused key \"%s\"", qPrintable(key));
qWarning("Kdbx4XmlReader::readDatabase: found unused key \"%s\"", qPrintable(key));
}
} }
QHash<QString, QPair<Entry*, QString> >::const_iterator i; QHash<QString, QPair<Entry*, QString> >::const_iterator i;
@ -131,13 +128,11 @@ void Kdbx4XmlReader::readDatabase(QIODevice* device, Database* db, KeePass2Rando
histEntry->setUpdateTimeinfo(true); histEntry->setUpdateTimeinfo(true);
} }
} }
delete m_tmpParent;
} }
Database* Kdbx4XmlReader::readDatabase(QIODevice* device) Database* Kdbx4XmlReader::readDatabase(QIODevice* device)
{ {
Database* db = new Database(); auto db = new Database();
readDatabase(device, db); readDatabase(device, db);
return db; return db;
} }
@ -158,14 +153,16 @@ QString Kdbx4XmlReader::errorString()
{ {
if (m_error) { if (m_error) {
return m_errorStr; return m_errorStr;
} else if (m_xml.hasError()) { }
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 {
return QString();
} }
return QString();
} }
void Kdbx4XmlReader::raiseError(const QString& errorMessage) void Kdbx4XmlReader::raiseError(const QString& errorMessage)
@ -189,17 +186,21 @@ bool Kdbx4XmlReader::parseKeePassFile()
while (!m_xml.hasError() && m_xml.readNextStartElement()) { while (!m_xml.hasError() && m_xml.readNextStartElement()) {
if (m_xml.name() == "Meta") { if (m_xml.name() == "Meta") {
parseMeta(); parseMeta();
} else if (m_xml.name() == "Root") { continue;
}
if (m_xml.name() == "Root") {
if (rootElementFound) { if (rootElementFound) {
rootParsedSuccessfully = false; rootParsedSuccessfully = false;
raiseError("Multiple root elements"); qWarning("Multiple root elements");
} else { } else {
rootParsedSuccessfully = parseRoot(); rootParsedSuccessfully = parseRoot();
rootElementFound = true; rootElementFound = true;
} }
} else { continue;
skipCurrentElement();
} }
skipCurrentElement();
} }
return rootParsedSuccessfully; return rootParsedSuccessfully;
@ -259,14 +260,14 @@ void Kdbx4XmlReader::parseMeta()
if (value >= -1) { if (value >= -1) {
m_meta->setHistoryMaxItems(value); m_meta->setHistoryMaxItems(value);
} else { } else {
raiseError("HistoryMaxItems invalid number"); qWarning("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"); qWarning("HistoryMaxSize invalid number");
} }
} else if (m_xml.name() == "Binaries") { } else if (m_xml.name() == "Binaries") {
parseBinaries(); parseBinaries();
@ -337,9 +338,10 @@ void Kdbx4XmlReader::parseIcon()
if (uuidSet && iconSet) { if (uuidSet && iconSet) {
m_meta->addCustomIcon(uuid, icon); m_meta->addCustomIcon(uuid, icon);
} else { return;
raiseError("Missing icon uuid or data");
} }
raiseError("Missing icon uuid or data");
} }
void Kdbx4XmlReader::parseBinaries() void Kdbx4XmlReader::parseBinaries()
@ -347,27 +349,28 @@ void Kdbx4XmlReader::parseBinaries()
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "Binaries"); Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "Binaries");
while (!m_xml.hasError() && m_xml.readNextStartElement()) { while (!m_xml.hasError() && m_xml.readNextStartElement()) {
if (m_xml.name() == "Binary") { if (m_xml.name() != "Binary") {
QXmlStreamAttributes attr = m_xml.attributes();
QString id = attr.value("ID").toString();
QByteArray data;
if (attr.value("Compressed").compare(QLatin1String("True"), Qt::CaseInsensitive) == 0) {
data = readCompressedBinary();
} else {
data = readBinary();
}
if (m_binaryPool.contains(id)) {
qWarning("Kdbx4XmlReader::parseBinaries: overwriting binary item \"%s\"",
qPrintable(id));
}
m_binaryPool.insert(id, data);
} else {
skipCurrentElement(); skipCurrentElement();
continue;
} }
QXmlStreamAttributes attr = m_xml.attributes();
QString id = attr.value("ID").toString();
QByteArray data;
if (attr.value("Compressed").compare(QLatin1String("True"), Qt::CaseInsensitive) == 0) {
data = readCompressedBinary();
} else {
data = readBinary();
}
if (m_binaryPool.contains(id)) {
qWarning("Kdbx4XmlReader::parseBinaries: overwriting binary item \"%s\"",
qPrintable(id));
}
m_binaryPool.insert(id, data);
} }
} }
@ -378,9 +381,9 @@ void Kdbx4XmlReader::parseCustomData()
while (!m_xml.hasError() && m_xml.readNextStartElement()) { while (!m_xml.hasError() && m_xml.readNextStartElement()) {
if (m_xml.name() == "Item") { if (m_xml.name() == "Item") {
parseCustomDataItem(); parseCustomDataItem();
} else { continue;
skipCurrentElement();
} }
skipCurrentElement();
} }
} }
@ -407,9 +410,10 @@ void Kdbx4XmlReader::parseCustomDataItem()
if (keySet && valueSet) { if (keySet && valueSet) {
m_meta->addCustomField(key, value); m_meta->addCustomField(key, value);
} else { return;
raiseError("Missing custom data key or value");
} }
raiseError("Missing custom data key or value");
} }
bool Kdbx4XmlReader::parseRoot() bool Kdbx4XmlReader::parseRoot()
@ -450,7 +454,7 @@ Group* Kdbx4XmlReader::parseGroup()
{ {
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "Group"); Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "Group");
Group* group = new Group(); auto group = new Group();
group->setUpdateTimeinfo(false); group->setUpdateTimeinfo(false);
QList<Group*> children; QList<Group*> children;
QList<Entry*> entries; QList<Entry*> entries;
@ -466,11 +470,17 @@ Group* Kdbx4XmlReader::parseGroup()
} else { } else {
group->setUuid(uuid); group->setUuid(uuid);
} }
} else if (m_xml.name() == "Name") { continue;
}
if (m_xml.name() == "Name") {
group->setName(readString()); group->setName(readString());
} else if (m_xml.name() == "Notes") { continue;
}
if (m_xml.name() == "Notes") {
group->setNotes(readString()); group->setNotes(readString());
} else if (m_xml.name() == "IconID") { continue;
}
if (m_xml.name() == "IconID") {
int iconId = readNumber(); int iconId = readNumber();
if (iconId < 0) { if (iconId < 0) {
if (m_strictMode) { if (m_strictMode) {
@ -483,18 +493,28 @@ Group* Kdbx4XmlReader::parseGroup()
} }
group->setIcon(iconId); group->setIcon(iconId);
} else if (m_xml.name() == "CustomIconUUID") { continue;
}
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") { continue;
}
if (m_xml.name() == "Times") {
group->setTimeInfo(parseTimes()); group->setTimeInfo(parseTimes());
} else if (m_xml.name() == "IsExpanded") { continue;
}
if (m_xml.name() == "IsExpanded") {
group->setExpanded(readBool()); group->setExpanded(readBool());
} else if (m_xml.name() == "DefaultAutoTypeSequence") { continue;
}
if (m_xml.name() == "DefaultAutoTypeSequence") {
group->setDefaultAutoTypeSequence(readString()); group->setDefaultAutoTypeSequence(readString());
} else if (m_xml.name() == "EnableAutoType") { continue;
}
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) {
@ -506,7 +526,9 @@ Group* Kdbx4XmlReader::parseGroup()
} else { } else {
raiseError("Invalid EnableAutoType value"); raiseError("Invalid EnableAutoType value");
} }
} else if (m_xml.name() == "EnableSearching") { continue;
}
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) {
@ -518,21 +540,28 @@ Group* Kdbx4XmlReader::parseGroup()
} else { } else {
raiseError("Invalid EnableSearching value"); raiseError("Invalid EnableSearching value");
} }
} else if (m_xml.name() == "LastTopVisibleEntry") { continue;
}
if (m_xml.name() == "LastTopVisibleEntry") {
group->setLastTopVisibleEntry(getEntry(readUuid())); group->setLastTopVisibleEntry(getEntry(readUuid()));
} else if (m_xml.name() == "Group") { continue;
}
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") { continue;
}
if (m_xml.name() == "Entry") {
Entry* newEntry = parseEntry(false); Entry* newEntry = parseEntry(false);
if (newEntry) { if (newEntry) {
entries.append(newEntry); entries.append(newEntry);
} }
} else { continue;
skipCurrentElement();
} }
skipCurrentElement();
} }
if (group->uuid().isNull() && !m_strictMode) { if (group->uuid().isNull() && !m_strictMode) {
@ -577,7 +606,7 @@ void Kdbx4XmlReader::parseDeletedObject()
{ {
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "DeletedObject"); Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "DeletedObject");
DeletedObject delObj; DeletedObject delObj{};
while (!m_xml.hasError() && m_xml.readNextStartElement()) { while (!m_xml.hasError() && m_xml.readNextStartElement()) {
if (m_xml.name() == "UUID") { if (m_xml.name() == "UUID") {
@ -586,19 +615,24 @@ void Kdbx4XmlReader::parseDeletedObject()
if (m_strictMode) { if (m_strictMode) {
raiseError("Null DeleteObject uuid"); raiseError("Null DeleteObject uuid");
} }
} else { continue;
delObj.uuid = uuid;
} }
} else if (m_xml.name() == "DeletionTime") { delObj.uuid = uuid;
delObj.deletionTime = readDateTime(); continue;
} else {
skipCurrentElement();
} }
if (m_xml.name() == "DeletionTime") {
delObj.deletionTime = readDateTime();
continue;
}
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) { return;
}
if (m_strictMode) {
raiseError("Missing DeletedObject uuid or time"); raiseError("Missing DeletedObject uuid or time");
} }
} }
@ -607,7 +641,7 @@ Entry* Kdbx4XmlReader::parseEntry(bool history)
{ {
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "Entry"); Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "Entry");
Entry* entry = new Entry(); auto entry = new Entry();
entry->setUpdateTimeinfo(false); entry->setUpdateTimeinfo(false);
QList<Entry*> historyItems; QList<Entry*> historyItems;
QList<StringPair> binaryRefs; QList<StringPair> binaryRefs;
@ -624,7 +658,9 @@ Entry* Kdbx4XmlReader::parseEntry(bool history)
} else { } else {
entry->setUuid(uuid); entry->setUuid(uuid);
} }
} else if (m_xml.name() == "IconID") { continue;
}
if (m_xml.name() == "IconID") {
int iconId = readNumber(); int iconId = readNumber();
if (iconId < 0) { if (iconId < 0) {
if (m_strictMode) { if (m_strictMode) {
@ -633,39 +669,59 @@ Entry* Kdbx4XmlReader::parseEntry(bool history)
iconId = 0; iconId = 0;
} }
entry->setIcon(iconId); entry->setIcon(iconId);
} else if (m_xml.name() == "CustomIconUUID") { continue;
}
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") { continue;
}if (m_xml.name() == "ForegroundColor") {
entry->setForegroundColor(readColor()); entry->setForegroundColor(readColor());
} else if (m_xml.name() == "BackgroundColor") { continue;
}
if (m_xml.name() == "BackgroundColor") {
entry->setBackgroundColor(readColor()); entry->setBackgroundColor(readColor());
} else if (m_xml.name() == "OverrideURL") { continue;
}
if (m_xml.name() == "OverrideURL") {
entry->setOverrideUrl(readString()); entry->setOverrideUrl(readString());
} else if (m_xml.name() == "Tags") { continue;
}
if (m_xml.name() == "Tags") {
entry->setTags(readString()); entry->setTags(readString());
} else if (m_xml.name() == "Times") { continue;
}
if (m_xml.name() == "Times") {
entry->setTimeInfo(parseTimes()); entry->setTimeInfo(parseTimes());
} else if (m_xml.name() == "String") { continue;
}
if (m_xml.name() == "String") {
parseEntryString(entry); parseEntryString(entry);
} else if (m_xml.name() == "Binary") { continue;
}
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") { continue;
}
if (m_xml.name() == "AutoType") {
parseAutoType(entry); parseAutoType(entry);
} else if (m_xml.name() == "History") { continue;
}
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 { continue;
skipCurrentElement();
} }
skipCurrentElement();
} }
if (entry->uuid().isNull() && !m_strictMode) { if (entry->uuid().isNull() && !m_strictMode) {
@ -720,7 +776,10 @@ void Kdbx4XmlReader::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") { continue;
}
if (m_xml.name() == "Value") {
QXmlStreamAttributes attr = m_xml.attributes(); QXmlStreamAttributes attr = m_xml.attributes();
value = readString(); value = readString();
@ -740,26 +799,29 @@ void Kdbx4XmlReader::parseEntryString(Entry* entry)
} }
} else { } else {
raiseError("Unable to decrypt entry string"); raiseError("Unable to decrypt entry string");
continue;
} }
} }
protect = isProtected || protectInMemory; protect = isProtected || protectInMemory;
valueSet = true; valueSet = true;
} else { continue;
skipCurrentElement();
} }
skipCurrentElement();
} }
if (keySet && valueSet) { if (keySet && valueSet) {
// 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 { return;
entry->attributes()->set(key, value, protect);
} }
} else { entry->attributes()->set(key, value, protect);
raiseError("Entry string key or value missing"); return;
} }
raiseError("Entry string key or value missing");
} }
QPair<QString, QString> Kdbx4XmlReader::parseEntryBinary(Entry* entry) QPair<QString, QString> Kdbx4XmlReader::parseEntryBinary(Entry* entry)
@ -777,7 +839,9 @@ QPair<QString, QString> Kdbx4XmlReader::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") { continue;
}
if (m_xml.name() == "Value") {
QXmlStreamAttributes attr = m_xml.attributes(); QXmlStreamAttributes attr = m_xml.attributes();
if (attr.hasAttribute("Ref")) { if (attr.hasAttribute("Ref")) {
@ -797,9 +861,9 @@ QPair<QString, QString> Kdbx4XmlReader::parseEntryBinary(Entry* entry)
} }
valueSet = true; valueSet = true;
} else { continue;
skipCurrentElement();
} }
skipCurrentElement();
} }
if (keySet && valueSet) { if (keySet && valueSet) {
@ -856,9 +920,9 @@ void Kdbx4XmlReader::parseAutoTypeAssoc(Entry* entry)
if (windowSet && sequenceSet) { if (windowSet && sequenceSet) {
entry->autoTypeAssociations()->add(assoc); entry->autoTypeAssociations()->add(assoc);
} else { return;
raiseError("Auto-type association window or sequence missing");
} }
raiseError("Auto-type association window or sequence missing");
} }
QList<Entry*> Kdbx4XmlReader::parseEntryHistory() QList<Entry*> Kdbx4XmlReader::parseEntryHistory()
@ -917,14 +981,15 @@ bool Kdbx4XmlReader::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) { }
return false; if (str.compare("False", Qt::CaseInsensitive) == 0) {
} else if (str.length() == 0) {
return false;
} else {
raiseError("Invalid bool value");
return false; return false;
} }
if (str.length() == 0) {
return false;
}
raiseError("Invalid bool value");
return false;
} }
QDateTime Kdbx4XmlReader::readDateTime() QDateTime Kdbx4XmlReader::readDateTime()
@ -936,18 +1001,18 @@ QDateTime Kdbx4XmlReader::readDateTime()
QByteArray secsBytes = QByteArray::fromBase64(str.toUtf8()).leftJustified(8, '\0', true).left(8); QByteArray secsBytes = QByteArray::fromBase64(str.toUtf8()).leftJustified(8, '\0', true).left(8);
qint64 secs = Endian::bytesToSizedInt<quint64>(secsBytes, KeePass2::BYTEORDER); qint64 secs = Endian::bytesToSizedInt<quint64>(secsBytes, KeePass2::BYTEORDER);
return QDateTime(QDate(1, 1, 1), QTime(0, 0, 0, 0), Qt::UTC).addSecs(secs); return QDateTime(QDate(1, 1, 1), QTime(0, 0, 0, 0), Qt::UTC).addSecs(secs);
} else {
QDateTime dt = QDateTime::fromString(str, Qt::ISODate);
if (dt.isValid()) {
return dt;
} else {
if (m_strictMode) {
raiseError("Invalid date time value");
}
return QDateTime::currentDateTimeUtc();
}
} }
QDateTime dt = QDateTime::fromString(str, Qt::ISODate);
if (dt.isValid()) {
return dt;
}
if (m_strictMode) {
raiseError("Invalid date time value");
}
return QDateTime::currentDateTimeUtc();
} }
QColor Kdbx4XmlReader::readColor() QColor Kdbx4XmlReader::readColor()
@ -955,26 +1020,26 @@ QColor Kdbx4XmlReader::readColor()
QString colorStr = readString(); QString colorStr = readString();
if (colorStr.isEmpty()) { if (colorStr.isEmpty()) {
return QColor(); return {};
} }
if (colorStr.length() != 7 || colorStr[0] != '#') { if (colorStr.length() != 7 || colorStr[0] != '#') {
if (m_strictMode) { if (m_strictMode) {
raiseError("Invalid color value"); raiseError("Invalid color value");
} }
return QColor(); return {};
} }
QColor color; QColor color;
for (int i = 0; i <= 2; i++) { for (int i = 0; i <= 2; ++i) {
QString rgbPartStr = colorStr.mid(1 + 2*i, 2); QString rgbPartStr = colorStr.mid(1 + 2 * i, 2);
bool ok; bool ok;
int rgbPart = rgbPartStr.toInt(&ok, 16); int rgbPart = rgbPartStr.toInt(&ok, 16);
if (!ok || rgbPart > 255) { if (!ok || rgbPart > 255) {
if (m_strictMode) { if (m_strictMode) {
raiseError("Invalid color rgb part"); raiseError("Invalid color rgb part");
} }
return QColor(); return {};
} }
if (i == 0) { if (i == 0) {
@ -1003,15 +1068,15 @@ Uuid Kdbx4XmlReader::readUuid()
{ {
QByteArray uuidBin = readBinary(); QByteArray uuidBin = readBinary();
if (uuidBin.isEmpty()) { if (uuidBin.isEmpty()) {
return Uuid(); return {};
} else if (uuidBin.length() != Uuid::Length) { }
if (uuidBin.length() != Uuid::Length) {
if (m_strictMode) { if (m_strictMode) {
raiseError("Invalid uuid value"); raiseError("Invalid uuid value");
} }
return Uuid(); return {};
} else {
return Uuid(uuidBin);
} }
return Uuid(uuidBin);
} }
QByteArray Kdbx4XmlReader::readBinary() QByteArray Kdbx4XmlReader::readBinary()
@ -1045,14 +1110,14 @@ Group* Kdbx4XmlReader::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 {
Group* group = new Group();
group->setUpdateTimeinfo(false);
group->setUuid(uuid);
group->setParent(m_tmpParent);
m_groups.insert(uuid, group);
return group;
} }
auto group = new Group();
group->setUpdateTimeinfo(false);
group->setUuid(uuid);
group->setParent(m_tmpParent.data());
m_groups.insert(uuid, group);
return group;
} }
Entry* Kdbx4XmlReader::getEntry(const Uuid& uuid) Entry* Kdbx4XmlReader::getEntry(const Uuid& uuid)
@ -1063,14 +1128,14 @@ Entry* Kdbx4XmlReader::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 {
Entry* entry = new Entry();
entry->setUpdateTimeinfo(false);
entry->setUuid(uuid);
entry->setGroup(m_tmpParent);
m_entries.insert(uuid, entry);
return entry;
} }
auto entry = new Entry();
entry->setUpdateTimeinfo(false);
entry->setUuid(uuid);
entry->setGroup(m_tmpParent.data());
m_entries.insert(uuid, entry);
return entry;
} }
void Kdbx4XmlReader::skipCurrentElement() void Kdbx4XmlReader::skipCurrentElement()

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2010 Felix Geyer <debfx@fobos.de> * 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
@ -27,10 +27,10 @@
#include "core/TimeInfo.h" #include "core/TimeInfo.h"
#include "core/Uuid.h" #include "core/Uuid.h"
#include "core/Group.h"
class Database; class Database;
class Entry; class Entry;
class Group;
class KeePass2RandomStream; class KeePass2RandomStream;
class Metadata; class Metadata;
@ -88,7 +88,7 @@ private:
KeePass2RandomStream* m_randomStream; KeePass2RandomStream* m_randomStream;
Database* m_db; Database* m_db;
Metadata* m_meta; Metadata* m_meta;
Group* m_tmpParent; QScopedPointer<Group> m_tmpParent;
QHash<Uuid, Group*> m_groups; QHash<Uuid, Group*> m_groups;
QHash<Uuid, Entry*> m_entries; QHash<Uuid, Entry*> m_entries;
QHash<QString, QByteArray> m_binaryPool; QHash<QString, QByteArray> m_binaryPool;

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2010 Felix Geyer <debfx@fobos.de> * 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

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2010 Felix Geyer <debfx@fobos.de> * 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

@ -89,7 +89,8 @@ QSharedPointer<Kdf> KeePass2::uuidToKdf(const Uuid& uuid)
{ {
if (uuid == KDF_AES) { if (uuid == KDF_AES) {
return QSharedPointer<AesKdf>::create(); return QSharedPointer<AesKdf>::create();
} else if (uuid == KDF_ARGON2) { }
if (uuid == KDF_ARGON2) {
return QSharedPointer<Argon2Kdf>::create(); return QSharedPointer<Argon2Kdf>::create();
} }
@ -100,13 +101,13 @@ QSharedPointer<Kdf> KeePass2::uuidToKdf(const Uuid& uuid)
KeePass2::ProtectedStreamAlgo KeePass2::idToProtectedStreamAlgo(quint32 id) KeePass2::ProtectedStreamAlgo KeePass2::idToProtectedStreamAlgo(quint32 id)
{ {
switch (id) { switch (id) {
case static_cast<quint32>(KeePass2::ArcFourVariant): case static_cast<quint32>(KeePass2::ProtectedStreamAlgo::ArcFourVariant):
return KeePass2::ArcFourVariant; return KeePass2::ProtectedStreamAlgo::ArcFourVariant;
case static_cast<quint32>(KeePass2::Salsa20): case static_cast<quint32>(KeePass2::ProtectedStreamAlgo::Salsa20):
return KeePass2::Salsa20; return KeePass2::ProtectedStreamAlgo::Salsa20;
case static_cast<quint32>(KeePass2::ChaCha20): case static_cast<quint32>(KeePass2::ProtectedStreamAlgo::ChaCha20):
return KeePass2::ChaCha20; return KeePass2::ProtectedStreamAlgo::ChaCha20;
default: default:
return KeePass2::InvalidProtectedStreamAlgo; return KeePass2::ProtectedStreamAlgo::InvalidProtectedStreamAlgo;
} }
} }

View File

@ -65,7 +65,7 @@ namespace KeePass2
extern const QList<QPair<Uuid, QString>> CIPHERS; extern const QList<QPair<Uuid, QString>> CIPHERS;
extern const QList<QPair<Uuid, QString>> KDFS; extern const QList<QPair<Uuid, QString>> KDFS;
enum HeaderFieldID enum class HeaderFieldID
{ {
EndOfHeader = 0, EndOfHeader = 0,
Comment = 1, Comment = 1,
@ -90,7 +90,7 @@ namespace KeePass2
Binary = 3 Binary = 3
}; };
enum ProtectedStreamAlgo enum class ProtectedStreamAlgo
{ {
ArcFourVariant = 1, ArcFourVariant = 1,
Salsa20 = 2, Salsa20 = 2,

View File

@ -123,9 +123,9 @@ bool KeePass2RandomStream::loadBlock()
SymmetricCipher::Algorithm KeePass2RandomStream::mapAlgo(KeePass2::ProtectedStreamAlgo algo) { SymmetricCipher::Algorithm KeePass2RandomStream::mapAlgo(KeePass2::ProtectedStreamAlgo algo) {
switch (algo) { switch (algo) {
case KeePass2::ChaCha20: case KeePass2::ProtectedStreamAlgo::ChaCha20:
return SymmetricCipher::ChaCha20; return SymmetricCipher::ChaCha20;
case KeePass2::Salsa20: case KeePass2::ProtectedStreamAlgo::Salsa20:
return SymmetricCipher::Salsa20; return SymmetricCipher::Salsa20;
default: default:
return SymmetricCipher::InvalidAlgorithm; return SymmetricCipher::InvalidAlgorithm;

View File

@ -30,7 +30,7 @@
BaseKeePass2Reader::BaseKeePass2Reader() BaseKeePass2Reader::BaseKeePass2Reader()
: m_error(false) : m_error(false)
, m_saveXml(false) , m_saveXml(false)
, m_irsAlgo(KeePass2::InvalidProtectedStreamAlgo) , m_irsAlgo(KeePass2::ProtectedStreamAlgo::InvalidProtectedStreamAlgo)
{ {
m_errorStr.clear(); m_errorStr.clear();
m_xmlData.clear(); m_xmlData.clear();

View File

@ -27,6 +27,8 @@
#include "core/Database.h" #include "core/Database.h"
#include "format/KeePass2.h" #include "format/KeePass2.h"
#define CHECK_RETURN_FALSE(x) if (!(x)) return false;
class BaseKeePass2Writer class BaseKeePass2Writer
{ {
public: public:

View File

@ -134,7 +134,7 @@ void DatabaseSettingsWidget::save()
{ {
// first perform safety check for KDF rounds // first perform safety check for KDF rounds
auto kdf = KeePass2::uuidToKdf(Uuid(m_uiEncryption->kdfComboBox->currentData().toByteArray())); auto kdf = KeePass2::uuidToKdf(Uuid(m_uiEncryption->kdfComboBox->currentData().toByteArray()));
if (kdf->uuid() == KeePass2::KDF_ARGON2 and m_uiEncryption->transformRoundsSpinBox->value() > 1000) { if (kdf->uuid() == KeePass2::KDF_ARGON2 && m_uiEncryption->transformRoundsSpinBox->value() > 1000) {
QMessageBox warning; QMessageBox warning;
warning.setIcon(QMessageBox::Warning); warning.setIcon(QMessageBox::Warning);
warning.setWindowTitle(tr("Number of rounds too high")); warning.setWindowTitle(tr("Number of rounds too high"));
@ -147,7 +147,7 @@ void DatabaseSettingsWidget::save()
if (warning.clickedButton() != ok) { if (warning.clickedButton() != ok) {
return; return;
} }
} else if (kdf->uuid() == KeePass2::KDF_AES and m_uiEncryption->transformRoundsSpinBox->value() < 100000) { } else if (kdf->uuid() == KeePass2::KDF_AES && m_uiEncryption->transformRoundsSpinBox->value() < 100000) {
QMessageBox warning; QMessageBox warning;
warning.setIcon(QMessageBox::Warning); warning.setIcon(QMessageBox::Warning);
warning.setWindowTitle(tr("Number of rounds too low")); warning.setWindowTitle(tr("Number of rounds too low"));

View File

@ -57,10 +57,8 @@ bool HmacBlockStream::reset()
// Write final block(s) only if device is writable and we haven't // Write final block(s) only if device is writable and we haven't
// already written a final block. // already written a final block.
if (isWritable() && (!m_buffer.isEmpty() || m_blockIndex != 0)) { if (isWritable() && (!m_buffer.isEmpty() || m_blockIndex != 0)) {
if (!m_buffer.isEmpty()) { if (!m_buffer.isEmpty() && !writeHashedBlock()) {
if (!writeHashedBlock()) { return false;
return false;
}
} }
// write empty final block // write empty final block
@ -106,15 +104,14 @@ qint64 HmacBlockStream::readData(char* data, qint64 maxSize)
if (!readHashedBlock()) { if (!readHashedBlock()) {
if (m_error) { if (m_error) {
return -1; return -1;
} else {
return maxSize - bytesRemaining;
} }
return maxSize - bytesRemaining;
} }
} }
int bytesToCopy = qMin(bytesRemaining, static_cast<qint64>(m_buffer.size() - m_bufferPos)); qint64 bytesToCopy = qMin(bytesRemaining, static_cast<qint64>(m_buffer.size() - m_bufferPos));
memcpy(data + offset, m_buffer.constData() + m_bufferPos, bytesToCopy); memcpy(data + offset, m_buffer.constData() + m_bufferPos, static_cast<size_t>(bytesToCopy));
offset += bytesToCopy; offset += bytesToCopy;
m_bufferPos += bytesToCopy; m_bufferPos += bytesToCopy;
@ -142,7 +139,7 @@ bool HmacBlockStream::readHashedBlock()
setErrorString("Invalid block size size."); setErrorString("Invalid block size size.");
return false; return false;
} }
qint32 blockSize = Endian::bytesToSizedInt<qint32>(blockSizeBytes, ByteOrder); auto blockSize = Endian::bytesToSizedInt<qint32>(blockSizeBytes, ByteOrder);
if (blockSize < 0) { if (blockSize < 0) {
m_error = true; m_error = true;
setErrorString("Invalid block size."); setErrorString("Invalid block size.");
@ -169,7 +166,7 @@ bool HmacBlockStream::readHashedBlock()
} }
m_bufferPos = 0; m_bufferPos = 0;
m_blockIndex++; ++m_blockIndex;
if (blockSize == 0) { if (blockSize == 0) {
m_eof = true; m_eof = true;
@ -191,21 +188,18 @@ qint64 HmacBlockStream::writeData(const char* data, qint64 maxSize)
qint64 offset = 0; qint64 offset = 0;
while (bytesRemaining > 0) { while (bytesRemaining > 0) {
int bytesToCopy = qMin(bytesRemaining, static_cast<qint64>(m_blockSize - m_buffer.size())); qint64 bytesToCopy = qMin(bytesRemaining, static_cast<qint64>(m_blockSize - m_buffer.size()));
m_buffer.append(data + offset, bytesToCopy); m_buffer.append(data + offset, static_cast<int>(bytesToCopy));
offset += bytesToCopy; offset += bytesToCopy;
bytesRemaining -= bytesToCopy; bytesRemaining -= bytesToCopy;
if (m_buffer.size() == m_blockSize) { if (m_buffer.size() == m_blockSize && !writeHashedBlock()) {
if (!writeHashedBlock()) { if (m_error) {
if (m_error) { return -1;
return -1;
} else {
return maxSize - bytesRemaining;
}
} }
return maxSize - bytesRemaining;
} }
} }
@ -242,7 +236,7 @@ bool HmacBlockStream::writeHashedBlock()
m_buffer.clear(); m_buffer.clear();
} }
m_blockIndex++; ++m_blockIndex;
return true; return true;
} }

View File

@ -252,7 +252,6 @@ bool SymmetricCipherStream::writeBlock(bool lastBlock)
int SymmetricCipherStream::blockSize() const { int SymmetricCipherStream::blockSize() const {
if (m_streamCipher) { if (m_streamCipher) {
return 1024; return 1024;
} else {
return m_cipher->blockSize();
} }
return m_cipher->blockSize();
} }

View File

@ -58,7 +58,7 @@ void TestKeePass2RandomStream::test()
} }
KeePass2RandomStream randomStream(KeePass2::Salsa20); KeePass2RandomStream randomStream(KeePass2::ProtectedStreamAlgo::Salsa20);
bool ok; bool ok;
QVERIFY(randomStream.init(key)); QVERIFY(randomStream.init(key));
QByteArray randomStreamData; QByteArray randomStreamData;

View File

@ -900,11 +900,11 @@ void TestGui::testDatabaseSettings()
QWidget* dbSettingsWidget = m_dbWidget->findChild<QWidget*>("databaseSettingsWidget"); QWidget* dbSettingsWidget = m_dbWidget->findChild<QWidget*>("databaseSettingsWidget");
QSpinBox* transformRoundsSpinBox = dbSettingsWidget->findChild<QSpinBox*>("transformRoundsSpinBox"); QSpinBox* transformRoundsSpinBox = dbSettingsWidget->findChild<QSpinBox*>("transformRoundsSpinBox");
QVERIFY(transformRoundsSpinBox != nullptr); QVERIFY(transformRoundsSpinBox != nullptr);
transformRoundsSpinBox->setValue(100); transformRoundsSpinBox->setValue(123456);
QTest::keyClick(transformRoundsSpinBox, Qt::Key_Enter); QTest::keyClick(transformRoundsSpinBox, Qt::Key_Enter);
// wait for modified timer // wait for modified timer
QTRY_COMPARE(m_tabWidget->tabText(m_tabWidget->currentIndex()), QString("Save*")); QTRY_COMPARE(m_tabWidget->tabText(m_tabWidget->currentIndex()), QString("Save*"));
QCOMPARE(m_db->kdf()->rounds(), Q_UINT64_C(100)); QCOMPARE(m_db->kdf()->rounds(), Q_UINT64_C(123456));
triggerAction("actionDatabaseSave"); triggerAction("actionDatabaseSave");
QCOMPARE(m_tabWidget->tabText(m_tabWidget->currentIndex()), QString("Save")); QCOMPARE(m_tabWidget->tabText(m_tabWidget->currentIndex()), QString("Save"));