Improve error messages for reading and wriiting databases.

Closes #7
This commit is contained in:
Felix Geyer 2013-06-30 14:43:02 +02:00
parent e1c82a4453
commit 5c84aa308d
11 changed files with 165 additions and 101 deletions

View File

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

View File

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

View File

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

View File

@ -39,7 +39,7 @@ public:
QByteArray xmlData();
private:
void raiseError(const QString& str);
void raiseError(const QString& errorMessage);
bool readHeaderField();

View File

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

View File

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

View File

@ -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")
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,10 +726,8 @@ Entry* KeePass2XmlReader::parseEntry(bool history)
}
}
if (entry->uuid().isNull()) {
raiseError(24);
}
else if (history) {
if (!entry->uuid().isNull()) {
if (history) {
entry->setUpdateTimeinfo(false);
}
else {
@ -723,6 +739,10 @@ Entry* KeePass2XmlReader::parseEntry(bool history)
delete tmpEntry;
}
}
else if (!hasError()) {
raiseError("No entry uuid found");
}
Q_FOREACH (Entry* historyItem, historyItems) {
entry->addHistoryItem(historyItem);
@ -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()));

View File

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

View File

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

View File

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

View File

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