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

github.com/keepassxreboot/keepassxc.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/format/KeePass1Reader.cpp63
-rw-r--r--src/format/KeePass1Reader.h2
-rw-r--r--src/format/KeePass2Reader.cpp47
-rw-r--r--src/format/KeePass2Reader.h2
-rw-r--r--src/format/KeePass2Writer.cpp18
-rw-r--r--src/format/KeePass2Writer.h3
-rw-r--r--src/format/KeePass2XmlReader.cpp119
-rw-r--r--src/format/KeePass2XmlReader.h4
-rw-r--r--src/streams/HashedBlockStream.cpp4
-rw-r--r--tests/TestKeePass1Reader.cpp2
-rw-r--r--tests/TestKeePass2Writer.cpp2
11 files changed, 165 insertions, 101 deletions
diff --git a/src/format/KeePass1Reader.cpp b/src/format/KeePass1Reader.cpp
index 1390d2021..926399293 100644
--- a/src/format/KeePass1Reader.cpp
+++ b/src/format/KeePass1Reader.cpp
@@ -56,6 +56,9 @@ KeePass1Reader::KeePass1Reader()
Database* KeePass1Reader::readDatabase(QIODevice* device, const QString& password,
QIODevice* keyfileDevice)
{
+ m_error = false;
+ m_errorStr.clear();
+
QByteArray keyfileData;
FileKey newFileKey;
@@ -63,13 +66,16 @@ Database* KeePass1Reader::readDatabase(QIODevice* device, const QString& passwor
keyfileData = readKeyfile(keyfileDevice);
if (keyfileData.isEmpty()) {
+ raiseError(tr("Unable to read keyfile.").append("\n").append(keyfileDevice->errorString()));
return Q_NULLPTR;
}
if (!keyfileDevice->seek(0)) {
+ raiseError(tr("Unable to read keyfile.").append("\n").append(keyfileDevice->errorString()));
return Q_NULLPTR;
}
if (!newFileKey.load(keyfileDevice)) {
+ raiseError(tr("Unable to read keyfile.").append("\n").append(keyfileDevice->errorString()));
return Q_NULLPTR;
}
}
@@ -79,8 +85,6 @@ Database* KeePass1Reader::readDatabase(QIODevice* device, const QString& passwor
m_db = db.data();
m_tmpParent = tmpParent.data();
m_device = device;
- m_error = false;
- m_errorStr = QString();
bool ok;
@@ -111,43 +115,43 @@ Database* KeePass1Reader::readDatabase(QIODevice* device, const QString& passwor
m_masterSeed = m_device->read(16);
if (m_masterSeed.size() != 16) {
- // TODO: error
+ raiseError("Unable to read master seed");
return Q_NULLPTR;
}
m_encryptionIV = m_device->read(16);
if (m_encryptionIV.size() != 16) {
- // TODO: error
+ raiseError("Unable to read encryption IV");
return Q_NULLPTR;
}
quint32 numGroups = Endian::readUInt32(m_device, KeePass1::BYTEORDER, &ok);
if (!ok) {
- // TODO: error
+ raiseError("Invalid number of groups");
return Q_NULLPTR;
}
quint32 numEntries = Endian::readUInt32(m_device, KeePass1::BYTEORDER, &ok);
if (!ok) {
- // TODO: error
+ raiseError("Invalid number of entries");
return Q_NULLPTR;
}
m_contentHashHeader = m_device->read(32);
if (m_contentHashHeader.size() != 32) {
- // TODO: error
+ raiseError("Invalid content hash size");
return Q_NULLPTR;
}
m_transformSeed = m_device->read(32);
if (m_transformSeed.size() != 32) {
- // TODO: error
+ raiseError("Invalid transform seed size");
return Q_NULLPTR;
}
m_transformRounds = Endian::readUInt32(m_device, KeePass1::BYTEORDER, &ok);
if (!ok) {
- // TODO: error
+ raiseError("Invalid number of transform rounds");
return Q_NULLPTR;
}
m_db->setTransformRounds(m_transformRounds);
@@ -157,7 +161,7 @@ Database* KeePass1Reader::readDatabase(QIODevice* device, const QString& passwor
QScopedPointer<SymmetricCipherStream> cipherStream(testKeys(password, keyfileData, contentPos));
if (!cipherStream) {
- // TODO: error
+ raiseError("Unable to create cipher stream");
return Q_NULLPTR;
}
@@ -180,6 +184,7 @@ Database* KeePass1Reader::readDatabase(QIODevice* device, const QString& passwor
}
if (!constructGroupTree(groups)) {
+ raiseError("Unable to construct group tree");
return Q_NULLPTR;
}
@@ -337,7 +342,12 @@ SymmetricCipherStream* KeePass1Reader::testKeys(const QString& password, const Q
cipherStream->reset();
cipherStream->close();
if (!m_device->seek(contentPos)) {
- // TODO: error
+ QString msg = "unable to seek to content position";
+ if (!m_device->errorString().isEmpty()) {
+ msg.append("\n").append(m_device->errorString());
+ }
+ raiseError(msg);
+
return Q_NULLPTR;
}
cipherStream->open(QIODevice::ReadOnly);
@@ -402,17 +412,19 @@ Group* KeePass1Reader::readGroup(QIODevice* cipherStream)
do {
quint16 fieldType = Endian::readUInt16(cipherStream, KeePass1::BYTEORDER, &ok);
if (!ok) {
+ raiseError("Invalid group field type number");
return Q_NULLPTR;
}
int fieldSize = static_cast<int>(Endian::readUInt32(cipherStream, KeePass1::BYTEORDER, &ok));
if (!ok) {
+ raiseError("Invalid group field size");
return Q_NULLPTR;
}
QByteArray fieldData = cipherStream->read(fieldSize);
if (fieldData.size() != fieldSize) {
- // TODO: error
+ raiseError("Read group field data doesn't match size");
return Q_NULLPTR;
}
@@ -422,6 +434,7 @@ Group* KeePass1Reader::readGroup(QIODevice* cipherStream)
break;
case 0x0001:
if (fieldSize != 4) {
+ raiseError("Incorrect group id field size");
return Q_NULLPTR;
}
groupId = Endian::bytesToUInt32(fieldData, KeePass1::BYTEORDER);
@@ -433,6 +446,7 @@ Group* KeePass1Reader::readGroup(QIODevice* cipherStream)
case 0x0003:
{
if (fieldSize != 5) {
+ raiseError("Incorrect group creation time field size");
return Q_NULLPTR;
}
QDateTime dateTime = dateFromPackedStruct(fieldData);
@@ -444,6 +458,7 @@ Group* KeePass1Reader::readGroup(QIODevice* cipherStream)
case 0x0004:
{
if (fieldSize != 5) {
+ raiseError("Incorrect group modification time field size");
return Q_NULLPTR;
}
QDateTime dateTime = dateFromPackedStruct(fieldData);
@@ -455,7 +470,7 @@ Group* KeePass1Reader::readGroup(QIODevice* cipherStream)
case 0x0005:
{
if (fieldSize != 5) {
- return Q_NULLPTR;
+ raiseError("Incorrect group access time field size");
}
QDateTime dateTime = dateFromPackedStruct(fieldData);
if (dateTime.isValid()) {
@@ -466,7 +481,7 @@ Group* KeePass1Reader::readGroup(QIODevice* cipherStream)
case 0x0006:
{
if (fieldSize != 5) {
- return Q_NULLPTR;
+ raiseError("Incorrect group expiry time field size");
}
QDateTime dateTime = dateFromPackedStruct(fieldData);
if (dateTime.isValid()) {
@@ -478,6 +493,7 @@ Group* KeePass1Reader::readGroup(QIODevice* cipherStream)
case 0x0007:
{
if (fieldSize != 4) {
+ raiseError("Incorrect group icon field size");
return Q_NULLPTR;
}
quint32 iconNumber = Endian::bytesToUInt32(fieldData, KeePass1::BYTEORDER);
@@ -487,6 +503,7 @@ Group* KeePass1Reader::readGroup(QIODevice* cipherStream)
case 0x0008:
{
if (fieldSize != 2) {
+ raiseError("Incorrect group level field size");
return Q_NULLPTR;
}
groupLevel = Endian::bytesToUInt16(fieldData, KeePass1::BYTEORDER);
@@ -501,11 +518,13 @@ Group* KeePass1Reader::readGroup(QIODevice* cipherStream)
break;
default:
// invalid field
+ raiseError("Invalid group field type");
return Q_NULLPTR;
}
} while (!reachedEnd);
if (!groupIdSet || !groupLevelSet) {
+ raiseError("Missing group id or level");
return Q_NULLPTR;
}
@@ -531,17 +550,19 @@ Entry* KeePass1Reader::readEntry(QIODevice* cipherStream)
do {
quint16 fieldType = Endian::readUInt16(cipherStream, KeePass1::BYTEORDER, &ok);
if (!ok) {
+ raiseError("Missing entry field type number");
return Q_NULLPTR;
}
int fieldSize = static_cast<int>(Endian::readUInt32(cipherStream, KeePass1::BYTEORDER, &ok));
if (!ok) {
+ raiseError("Invalid entry field size");
return Q_NULLPTR;
}
QByteArray fieldData = cipherStream->read(fieldSize);
if (fieldData.size() != fieldSize) {
- // TODO: error
+ raiseError("Read entry field data doesn't match size");
return Q_NULLPTR;
}
@@ -551,6 +572,7 @@ Entry* KeePass1Reader::readEntry(QIODevice* cipherStream)
break;
case 0x0001:
if (fieldSize != 16) {
+ raiseError("Invalid entry uuid field size");
return Q_NULLPTR;
}
m_entryUuids.insert(fieldData, entry.data());
@@ -558,6 +580,7 @@ Entry* KeePass1Reader::readEntry(QIODevice* cipherStream)
case 0x0002:
{
if (fieldSize != 4) {
+ raiseError("Invalid entry group id field size");
return Q_NULLPTR;
}
quint32 groupId = Endian::bytesToUInt32(fieldData, KeePass1::BYTEORDER);
@@ -567,6 +590,7 @@ Entry* KeePass1Reader::readEntry(QIODevice* cipherStream)
case 0x0003:
{
if (fieldSize != 4) {
+ raiseError("Invalid entry icon field size");
return Q_NULLPTR;
}
quint32 iconNumber = Endian::bytesToUInt32(fieldData, KeePass1::BYTEORDER);
@@ -591,6 +615,7 @@ Entry* KeePass1Reader::readEntry(QIODevice* cipherStream)
case 0x0009:
{
if (fieldSize != 5) {
+ raiseError("Invalid entry creation time field size");
return Q_NULLPTR;
}
QDateTime dateTime = dateFromPackedStruct(fieldData);
@@ -602,6 +627,7 @@ Entry* KeePass1Reader::readEntry(QIODevice* cipherStream)
case 0x000A:
{
if (fieldSize != 5) {
+ raiseError("Invalid entry modification time field size");
return Q_NULLPTR;
}
QDateTime dateTime = dateFromPackedStruct(fieldData);
@@ -613,6 +639,7 @@ Entry* KeePass1Reader::readEntry(QIODevice* cipherStream)
case 0x000B:
{
if (fieldSize != 5) {
+ raiseError("Invalid entry creation time field size");
return Q_NULLPTR;
}
QDateTime dateTime = dateFromPackedStruct(fieldData);
@@ -624,6 +651,7 @@ Entry* KeePass1Reader::readEntry(QIODevice* cipherStream)
case 0x000C:
{
if (fieldSize != 5) {
+ raiseError("Invalid entry expiry time field size");
return Q_NULLPTR;
}
QDateTime dateTime = dateFromPackedStruct(fieldData);
@@ -646,6 +674,7 @@ Entry* KeePass1Reader::readEntry(QIODevice* cipherStream)
break;
default:
// invalid field
+ raiseError("Invalid entry field type");
return Q_NULLPTR;
}
} while (!reachedEnd);
@@ -870,10 +899,10 @@ bool KeePass1Reader::parseCustomIcons4(const QByteArray& data)
return true;
}
-void KeePass1Reader::raiseError(const QString& str)
+void KeePass1Reader::raiseError(const QString& errorMessage)
{
m_error = true;
- m_errorStr = str;
+ m_errorStr = errorMessage;
}
QDateTime KeePass1Reader::dateFromPackedStruct(const QByteArray& data)
diff --git a/src/format/KeePass1Reader.h b/src/format/KeePass1Reader.h
index 208bd4b52..056a21504 100644
--- a/src/format/KeePass1Reader.h
+++ b/src/format/KeePass1Reader.h
@@ -62,7 +62,7 @@ private:
void parseMetaStream(const Entry* entry);
bool parseGroupTreeState(const QByteArray& data);
bool parseCustomIcons4(const QByteArray& data);
- void raiseError(const QString& str);
+ void raiseError(const QString& errorMessage);
static QByteArray readKeyfile(QIODevice* device);
static QDateTime dateFromPackedStruct(const QByteArray& data);
static bool isMetaStream(const Entry* entry);
diff --git a/src/format/KeePass2Reader.cpp b/src/format/KeePass2Reader.cpp
index 3eb3fe977..91482316c 100644
--- a/src/format/KeePass2Reader.cpp
+++ b/src/format/KeePass2Reader.cpp
@@ -33,8 +33,9 @@
#include "streams/SymmetricCipherStream.h"
KeePass2Reader::KeePass2Reader()
+ : m_error(false)
+ , m_saveXml(false)
{
- m_saveXml = false;
}
Database* KeePass2Reader::readDatabase(QIODevice* device, const CompositeKey& key)
@@ -43,7 +44,7 @@ Database* KeePass2Reader::readDatabase(QIODevice* device, const CompositeKey& ke
m_db = db.data();
m_device = device;
m_error = false;
- m_errorStr = QString();
+ m_errorStr.clear();
m_headerEnd = false;
m_xmlData.clear();
m_masterSeed.clear();
@@ -83,11 +84,15 @@ Database* KeePass2Reader::readDatabase(QIODevice* device, const CompositeKey& ke
headerStream.close();
+ if (hasError()) {
+ return Q_NULLPTR;
+ }
+
// check if all required headers were present
if (m_masterSeed.isEmpty() || m_transformSeed.isEmpty() || m_encryptionIV.isEmpty()
|| m_streamStartBytes.isEmpty() || m_protectedStreamKey.isEmpty()
|| m_db->cipher().isNull()) {
- raiseError("");
+ raiseError("missing database headers");
return Q_NULLPTR;
}
@@ -149,7 +154,7 @@ Database* KeePass2Reader::readDatabase(QIODevice* device, const CompositeKey& ke
if (!xmlReader.headerHash().isEmpty()) {
QByteArray headerHash = CryptoHash::hash(headerStream.storedData(), CryptoHash::Sha256);
if (headerHash != xmlReader.headerHash()) {
- raiseError("");
+ raiseError("Head doesn't match hash");
return Q_NULLPTR;
}
}
@@ -195,17 +200,17 @@ QByteArray KeePass2Reader::xmlData()
return m_xmlData;
}
-void KeePass2Reader::raiseError(const QString& str)
+void KeePass2Reader::raiseError(const QString& errorMessage)
{
m_error = true;
- m_errorStr = str;
+ m_errorStr = errorMessage;
}
bool KeePass2Reader::readHeaderField()
{
QByteArray fieldIDArray = m_headerStream->read(1);
if (fieldIDArray.size() != 1) {
- raiseError("");
+ raiseError("Invalid header id size");
return false;
}
quint8 fieldID = fieldIDArray.at(0);
@@ -213,7 +218,7 @@ bool KeePass2Reader::readHeaderField()
bool ok;
quint16 fieldLen = Endian::readUInt16(m_headerStream, KeePass2::BYTEORDER, &ok);
if (!ok) {
- raiseError("");
+ raiseError("Invalid header field length");
return false;
}
@@ -221,7 +226,7 @@ bool KeePass2Reader::readHeaderField()
if (fieldLen != 0) {
fieldData = m_headerStream->read(fieldLen);
if (fieldData.size() != fieldLen) {
- raiseError("");
+ raiseError("Invalid header data length");
return false;
}
}
@@ -278,13 +283,13 @@ bool KeePass2Reader::readHeaderField()
void KeePass2Reader::setCipher(const QByteArray& data)
{
if (data.size() != Uuid::Length) {
- raiseError("");
+ raiseError("Invalid cipher uuid length");
}
else {
Uuid uuid(data);
if (uuid != KeePass2::CIPHER_AES) {
- raiseError("");
+ raiseError("Unsupported cipher");
}
else {
m_db->setCipher(uuid);
@@ -295,13 +300,13 @@ void KeePass2Reader::setCipher(const QByteArray& data)
void KeePass2Reader::setCompressionFlags(const QByteArray& data)
{
if (data.size() != 4) {
- raiseError("");
+ raiseError("Invalid compression flags length");
}
else {
quint32 id = Endian::bytesToUInt32(data, KeePass2::BYTEORDER);
if (id > Database::CompressionAlgorithmMax) {
- raiseError("");
+ raiseError("Unsupported compression algorithm");
}
else {
m_db->setCompressionAlgo(static_cast<Database::CompressionAlgorithm>(id));
@@ -312,7 +317,7 @@ void KeePass2Reader::setCompressionFlags(const QByteArray& data)
void KeePass2Reader::setMasterSeed(const QByteArray& data)
{
if (data.size() != 32) {
- raiseError("");
+ raiseError("Invalid master seed size");
}
else {
m_masterSeed = data;
@@ -322,7 +327,7 @@ void KeePass2Reader::setMasterSeed(const QByteArray& data)
void KeePass2Reader::setTransformSeed(const QByteArray& data)
{
if (data.size() != 32) {
- raiseError("");
+ raiseError("Invalid transform seed size");
}
else {
m_transformSeed = data;
@@ -332,7 +337,7 @@ void KeePass2Reader::setTransformSeed(const QByteArray& data)
void KeePass2Reader::setTansformRounds(const QByteArray& data)
{
if (data.size() != 8) {
- raiseError("");
+ raiseError("Invalid transform rounds size");
}
else {
m_db->setTransformRounds(Endian::bytesToUInt64(data, KeePass2::BYTEORDER));
@@ -342,7 +347,7 @@ void KeePass2Reader::setTansformRounds(const QByteArray& data)
void KeePass2Reader::setEncryptionIV(const QByteArray& data)
{
if (data.size() != 16) {
- raiseError("");
+ raiseError("Invalid encryption iv size");
}
else {
m_encryptionIV = data;
@@ -352,7 +357,7 @@ void KeePass2Reader::setEncryptionIV(const QByteArray& data)
void KeePass2Reader::setProtectedStreamKey(const QByteArray& data)
{
if (data.size() != 32) {
- raiseError("");
+ raiseError("Invalid stream key size");
}
else {
m_protectedStreamKey = data;
@@ -362,7 +367,7 @@ void KeePass2Reader::setProtectedStreamKey(const QByteArray& data)
void KeePass2Reader::setStreamStartBytes(const QByteArray& data)
{
if (data.size() != 32) {
- raiseError("");
+ raiseError("Invalid start bytes size");
}
else {
m_streamStartBytes = data;
@@ -372,13 +377,13 @@ void KeePass2Reader::setStreamStartBytes(const QByteArray& data)
void KeePass2Reader::setInnerRandomStreamID(const QByteArray& data)
{
if (data.size() != 4) {
- raiseError("");
+ raiseError("Invalid random stream id size");
}
else {
quint32 id = Endian::bytesToUInt32(data, KeePass2::BYTEORDER);
if (id != KeePass2::Salsa20) {
- raiseError("");
+ raiseError("Unsupported random stream algorithm");
}
}
}
diff --git a/src/format/KeePass2Reader.h b/src/format/KeePass2Reader.h
index 4b38de570..8af87adeb 100644
--- a/src/format/KeePass2Reader.h
+++ b/src/format/KeePass2Reader.h
@@ -39,7 +39,7 @@ public:
QByteArray xmlData();
private:
- void raiseError(const QString& str);
+ void raiseError(const QString& errorMessage);
bool readHeaderField();
diff --git a/src/format/KeePass2Writer.cpp b/src/format/KeePass2Writer.cpp
index 91ad84159..2a6b4eb9a 100644
--- a/src/format/KeePass2Writer.cpp
+++ b/src/format/KeePass2Writer.cpp
@@ -43,7 +43,7 @@ KeePass2Writer::KeePass2Writer()
void KeePass2Writer::writeDatabase(QIODevice* device, Database* db)
{
m_error = false;
- m_errorStr = QString();
+ m_errorStr.clear();
QByteArray masterSeed = Random::randomArray(32);
QByteArray encryptionIV = Random::randomArray(16);
@@ -117,8 +117,7 @@ void KeePass2Writer::writeDatabase(QIODevice* device, Database* db)
bool KeePass2Writer::writeData(const QByteArray& data)
{
if (m_device->write(data) != data.size()) {
- m_error = true;
- m_errorStr = m_device->errorString();
+ raiseError(m_device->errorString());
return false;
}
else {
@@ -143,11 +142,14 @@ bool KeePass2Writer::writeHeaderField(KeePass2::HeaderFieldID fieldId, const QBy
void KeePass2Writer::writeDatabase(const QString& filename, Database* db)
{
QFile file(filename);
- file.open(QIODevice::WriteOnly|QIODevice::Truncate);
+ if (!file.open(QIODevice::WriteOnly|QIODevice::Truncate)) {
+ raiseError(file.errorString());
+ return;
+ }
writeDatabase(&file, db);
}
-bool KeePass2Writer::error()
+bool KeePass2Writer::hasError()
{
return m_error;
}
@@ -156,3 +158,9 @@ QString KeePass2Writer::errorString()
{
return m_errorStr;
}
+
+void KeePass2Writer::raiseError(const QString& errorMessage)
+{
+ m_error = true;
+ m_errorStr = errorMessage;
+}
diff --git a/src/format/KeePass2Writer.h b/src/format/KeePass2Writer.h
index 1d9dde419..1b3436dc6 100644
--- a/src/format/KeePass2Writer.h
+++ b/src/format/KeePass2Writer.h
@@ -30,12 +30,13 @@ public:
KeePass2Writer();
void writeDatabase(QIODevice* device, Database* db);
void writeDatabase(const QString& filename, Database* db);
- bool error();
+ bool hasError();
QString errorString();
private:
bool writeData(const QByteArray& data);
bool writeHeaderField(KeePass2::HeaderFieldID fieldId, const QByteArray& data);
+ void raiseError(const QString& errorMessage);
QIODevice* m_device;
bool m_error;
diff --git a/src/format/KeePass2XmlReader.cpp b/src/format/KeePass2XmlReader.cpp
index df62daf50..ecf5c0484 100644
--- a/src/format/KeePass2XmlReader.cpp
+++ b/src/format/KeePass2XmlReader.cpp
@@ -34,11 +34,15 @@ KeePass2XmlReader::KeePass2XmlReader()
: m_randomStream(Q_NULLPTR)
, m_db(Q_NULLPTR)
, m_meta(Q_NULLPTR)
+ , m_error(false)
{
}
void KeePass2XmlReader::readDatabase(QIODevice* device, Database* db, KeePass2RandomStream* randomStream)
{
+ m_error = false;
+ m_errorStr.clear();
+
m_xml.clear();
m_xml.setDevice(device);
@@ -60,7 +64,7 @@ void KeePass2XmlReader::readDatabase(QIODevice* device, Database* db, KeePass2Ra
}
if (!m_xml.error() && !rootGroupParsed) {
- raiseError(28);
+ raiseError("No root group");
}
if (!m_xml.error()) {
@@ -81,7 +85,7 @@ void KeePass2XmlReader::readDatabase(QIODevice* device, Database* db, KeePass2Ra
QSet<QString> unusedKeys = poolKeys - entryKeys;
if (!unmappedKeys.isEmpty()) {
- raiseError(17);
+ raiseError("Unmapped keys left.");
}
if (!m_xml.error()) {
@@ -131,15 +135,29 @@ Database* KeePass2XmlReader::readDatabase(const QString& filename)
bool KeePass2XmlReader::hasError()
{
- return m_xml.hasError();
+ return m_error || m_xml.hasError();
}
QString KeePass2XmlReader::errorString()
{
- return QString("%1\nLine %2, column %3")
- .arg(m_xml.errorString())
- .arg(m_xml.lineNumber())
- .arg(m_xml.columnNumber());
+ if (m_error) {
+ return m_errorStr;
+ }
+ else if (m_xml.hasError()) {
+ return QString("XML error:\n%1\nLine %2, column %3")
+ .arg(m_xml.errorString())
+ .arg(m_xml.lineNumber())
+ .arg(m_xml.columnNumber());
+ }
+ else {
+ return QString();
+ }
+}
+
+void KeePass2XmlReader::raiseError(const QString& errorMessage)
+{
+ m_error = true;
+ m_errorStr = errorMessage;
}
QByteArray KeePass2XmlReader::headerHash()
@@ -161,7 +179,7 @@ bool KeePass2XmlReader::parseKeePassFile()
else if (m_xml.name() == "Root") {
if (rootElementFound) {
rootParsedSuccesfully = false;
- raiseError(29);
+ raiseError("Multiple root elements");
}
else {
rootParsedSuccesfully = parseRoot();
@@ -253,7 +271,7 @@ void KeePass2XmlReader::parseMeta()
m_meta->setHistoryMaxItems(value);
}
else {
- raiseError(18);
+ raiseError("HistoryMaxItems invalid number");
}
}
else if (m_xml.name() == "HistoryMaxSize") {
@@ -262,7 +280,7 @@ void KeePass2XmlReader::parseMeta()
m_meta->setHistoryMaxSize(value);
}
else {
- raiseError(19);
+ raiseError("HistoryMaxSize invalid number");
}
}
else if (m_xml.name() == "Binaries") {
@@ -347,7 +365,7 @@ void KeePass2XmlReader::parseIcon()
m_meta->addCustomIcon(uuid, icon);
}
else {
- raiseError(20);
+ raiseError("Missing icon uuid or data");
}
}
@@ -423,7 +441,7 @@ void KeePass2XmlReader::parseCustomDataItem()
m_meta->addCustomField(key, value);
}
else {
- raiseError(21);
+ raiseError("Missing custom data key or value");
}
}
@@ -438,7 +456,7 @@ bool KeePass2XmlReader::parseRoot()
if (m_xml.name() == "Group") {
if (groupElementFound) {
groupParsedSuccesfully = false;
- raiseError(30);
+ raiseError("Multiple group elements");
continue;
}
@@ -475,7 +493,7 @@ Group* KeePass2XmlReader::parseGroup()
if (m_xml.name() == "UUID") {
Uuid uuid = readUuid();
if (uuid.isNull()) {
- raiseError(1);
+ raiseError("Null group uuid");
}
else {
group->setUuid(uuid);
@@ -490,7 +508,7 @@ Group* KeePass2XmlReader::parseGroup()
else if (m_xml.name() == "IconID") {
int iconId = readNumber();
if (iconId < 0) {
- raiseError(2);
+ raiseError("Invalid group icon number");
}
else {
if (iconId >= DatabaseIcons::IconCount) {
@@ -527,7 +545,7 @@ Group* KeePass2XmlReader::parseGroup()
group->setAutoTypeEnabled(Group::Disable);
}
else {
- raiseError(3);
+ raiseError("Invalid EnableAutoType value");
}
}
else if (m_xml.name() == "EnableSearching") {
@@ -543,7 +561,7 @@ Group* KeePass2XmlReader::parseGroup()
group->setSearchingEnabled(Group::Disable);
}
else {
- raiseError(4);
+ raiseError("Invalid EnableSearching value");
}
}
else if (m_xml.name() == "LastTopVisibleEntry") {
@@ -573,8 +591,8 @@ Group* KeePass2XmlReader::parseGroup()
group->setUpdateTimeinfo(false);
delete tmpGroup;
}
- else {
- raiseError(22);
+ else if (!hasError()) {
+ raiseError("No group uuid found");
}
Q_FOREACH (Group* child, children) {
@@ -612,7 +630,7 @@ void KeePass2XmlReader::parseDeletedObject()
if (m_xml.name() == "UUID") {
Uuid uuid = readUuid();
if (uuid.isNull()) {
- raiseError(5);
+ raiseError("Null DeleteObject uuid");
}
else {
delObj.uuid = uuid;
@@ -630,7 +648,7 @@ void KeePass2XmlReader::parseDeletedObject()
m_db->addDeletedObject(delObj);
}
else {
- raiseError(23);
+ raiseError("Missing DeletedObject uuid or time");
}
}
@@ -647,7 +665,7 @@ Entry* KeePass2XmlReader::parseEntry(bool history)
if (m_xml.name() == "UUID") {
Uuid uuid = readUuid();
if (uuid.isNull()) {
- raiseError(6);
+ raiseError("Null entry uuid");
}
else {
entry->setUuid(uuid);
@@ -656,7 +674,7 @@ Entry* KeePass2XmlReader::parseEntry(bool history)
else if (m_xml.name() == "IconID") {
int iconId = readNumber();
if (iconId < 0) {
- raiseError(7);
+ raiseError("Invalud entry icon number");
}
else {
entry->setIcon(iconId);
@@ -697,7 +715,7 @@ Entry* KeePass2XmlReader::parseEntry(bool history)
}
else if (m_xml.name() == "History") {
if (history) {
- raiseError(8);
+ raiseError("History element in history entry");
}
else {
historyItems = parseEntryHistory();
@@ -708,20 +726,22 @@ Entry* KeePass2XmlReader::parseEntry(bool history)
}
}
- if (entry->uuid().isNull()) {
- raiseError(24);
- }
- else if (history) {
- entry->setUpdateTimeinfo(false);
- }
- else {
- Entry* tmpEntry = entry;
+ if (!entry->uuid().isNull()) {
+ if (history) {
+ entry->setUpdateTimeinfo(false);
+ }
+ else {
+ Entry* tmpEntry = entry;
- entry = getEntry(tmpEntry->uuid());
- entry->copyDataFrom(tmpEntry);
- entry->setUpdateTimeinfo(false);
+ entry = getEntry(tmpEntry->uuid());
+ entry->copyDataFrom(tmpEntry);
+ entry->setUpdateTimeinfo(false);
- delete tmpEntry;
+ delete tmpEntry;
+ }
+ }
+ else if (!hasError()) {
+ raiseError("No entry uuid found");
}
Q_FOREACH (Entry* historyItem, historyItems) {
@@ -762,7 +782,7 @@ void KeePass2XmlReader::parseEntryString(Entry* entry)
value = QString::fromUtf8(m_randomStream->process(QByteArray::fromBase64(value.toAscii())));
}
else {
- raiseError(9);
+ raiseError("Unable to decrypt entry string");
}
}
@@ -778,7 +798,7 @@ void KeePass2XmlReader::parseEntryString(Entry* entry)
entry->attributes()->set(key, value, protect);
}
else {
- raiseError(25);
+ raiseError("Entry string key or value missing");
}
}
@@ -827,7 +847,7 @@ QPair<QString, QString> KeePass2XmlReader::parseEntryBinary(Entry* entry)
entry->attachments()->set(key, value);
}
else {
- raiseError(26);
+ raiseError("Entry binary key or value missing");
}
return poolRef;
@@ -882,7 +902,7 @@ void KeePass2XmlReader::parseAutoTypeAssoc(Entry* entry)
entry->autoTypeAssociations()->add(assoc);
}
else {
- raiseError(27);
+ raiseError("Auto-type association window or sequence missing");
}
}
@@ -955,7 +975,7 @@ bool KeePass2XmlReader::readBool()
return false;
}
else {
- raiseError(10);
+ raiseError("Invalid bool value");
return false;
}
}
@@ -966,7 +986,7 @@ QDateTime KeePass2XmlReader::readDateTime()
QDateTime dt = QDateTime::fromString(str, Qt::ISODate);
if (!dt.isValid()) {
- raiseError(11);
+ raiseError("Invalid date time value");
}
return dt;
@@ -981,7 +1001,7 @@ QColor KeePass2XmlReader::readColor()
}
if (colorStr.length() != 7 || colorStr[0] != '#') {
- raiseError(12);
+ raiseError("Invalid color value");
return QColor();
}
@@ -991,7 +1011,7 @@ QColor KeePass2XmlReader::readColor()
bool ok;
int rgbPart = rgbPartStr.toInt(&ok, 16);
if (!ok || rgbPart > 255) {
- raiseError(13);
+ raiseError("Invalid color rgb part");
return QColor();
}
@@ -1014,7 +1034,7 @@ int KeePass2XmlReader::readNumber()
bool ok;
int result = readString().toInt(&ok);
if (!ok) {
- raiseError(14);
+ raiseError("Invalid number value");
}
return result;
}
@@ -1023,7 +1043,7 @@ Uuid KeePass2XmlReader::readUuid()
{
QByteArray uuidBin = readBinary();
if (uuidBin.length() != Uuid::Length) {
- raiseError(15);
+ raiseError("Invalid uuid value");
return Uuid();
}
else {
@@ -1049,7 +1069,7 @@ QByteArray KeePass2XmlReader::readCompressedBinary()
QByteArray result;
if (!Tools::readAllFromDevice(&compressor, result)) {
- raiseError(16);
+ raiseError("Unable to decompress binary");
}
return result;
}
@@ -1092,11 +1112,6 @@ Entry* KeePass2XmlReader::getEntry(const Uuid& uuid)
}
}
-void KeePass2XmlReader::raiseError(int internalNumber)
-{
- m_xml.raiseError(tr("Invalid database file (error no %1).").arg(QString::number(internalNumber)));
-}
-
void KeePass2XmlReader::skipCurrentElement()
{
qWarning("KeePass2XmlReader::skipCurrentElement: skip element \"%s\"", qPrintable(m_xml.name().toString()));
diff --git a/src/format/KeePass2XmlReader.h b/src/format/KeePass2XmlReader.h
index bfae0fd97..1eb41898b 100644
--- a/src/format/KeePass2XmlReader.h
+++ b/src/format/KeePass2XmlReader.h
@@ -80,7 +80,7 @@ private:
Group* getGroup(const Uuid& uuid);
Entry* getEntry(const Uuid& uuid);
- void raiseError(int internalNumber);
+ void raiseError(const QString& errorMessage);
void skipCurrentElement();
QXmlStreamReader m_xml;
@@ -93,6 +93,8 @@ private:
QHash<QString, QByteArray> m_binaryPool;
QHash<QString, QPair<Entry*, QString> > m_binaryMap;
QByteArray m_headerHash;
+ bool m_error;
+ QString m_errorStr;
};
#endif // KEEPASSX_KEEPASS2XMLREADER_H
diff --git a/src/streams/HashedBlockStream.cpp b/src/streams/HashedBlockStream.cpp
index 1085242c7..39e16de2e 100644
--- a/src/streams/HashedBlockStream.cpp
+++ b/src/streams/HashedBlockStream.cpp
@@ -129,18 +129,21 @@ bool HashedBlockStream::readHashedBlock()
quint32 index = Endian::readUInt32(m_baseDevice, ByteOrder, &ok);
if (!ok || index != m_blockIndex) {
m_error = true;
+ setErrorString("Invalid block index.");
return false;
}
QByteArray hash = m_baseDevice->read(32);
if (hash.size() != 32) {
m_error = true;
+ setErrorString("Invalid hash size.");
return false;
}
m_blockSize = Endian::readInt32(m_baseDevice, ByteOrder, &ok);
if (!ok || m_blockSize < 0) {
m_error = true;
+ setErrorString("Invalid block size.");
return false;
}
@@ -157,6 +160,7 @@ bool HashedBlockStream::readHashedBlock()
m_buffer = m_baseDevice->read(m_blockSize);
if (m_buffer.size() != m_blockSize) {
m_error = true;
+ setErrorString("Block too short.");
return false;
}
diff --git a/tests/TestKeePass1Reader.cpp b/tests/TestKeePass1Reader.cpp
index 79764817f..2bcd72c7a 100644
--- a/tests/TestKeePass1Reader.cpp
+++ b/tests/TestKeePass1Reader.cpp
@@ -273,7 +273,7 @@ void TestKeePass1Reader::reopenDatabase(Database* db, const QString& password, c
KeePass2Writer writer;
writer.writeDatabase(&buffer, db);
- QVERIFY(!writer.error());
+ QVERIFY(!writer.hasError());
QVERIFY(buffer.seek(0));
CompositeKey key;
diff --git a/tests/TestKeePass2Writer.cpp b/tests/TestKeePass2Writer.cpp
index cf9ed15c0..233634883 100644
--- a/tests/TestKeePass2Writer.cpp
+++ b/tests/TestKeePass2Writer.cpp
@@ -61,7 +61,7 @@ void TestKeePass2Writer::initTestCase()
KeePass2Writer writer;
writer.writeDatabase(&buffer, m_dbOrg);
- QVERIFY(!writer.error());
+ QVERIFY(!writer.hasError());
buffer.seek(0);
KeePass2Reader reader;
m_dbTest = reader.readDatabase(&buffer, key);