mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2025-05-10 02:25:38 -04:00
Add support for database format 3.01 (HeaderHash).
Add test for the format 3.00 and upgrade Compressed.kdbx, NonAscii.kdbx and ProtectedStrings.kdbx to 3.01. Add a test for an incorrect HeaderHash.
This commit is contained in:
parent
40ccd219f4
commit
18d3fe55f8
18 changed files with 185 additions and 16 deletions
|
@ -29,6 +29,7 @@
|
|||
#include "format/KeePass2XmlReader.h"
|
||||
#include "streams/HashedBlockStream.h"
|
||||
#include "streams/QtIOCompressor"
|
||||
#include "streams/StoreDataStream.h"
|
||||
#include "streams/SymmetricCipherStream.h"
|
||||
|
||||
KeePass2Reader::KeePass2Reader()
|
||||
|
@ -45,21 +46,26 @@ Database* KeePass2Reader::readDatabase(QIODevice* device, const CompositeKey& ke
|
|||
m_errorStr = QString();
|
||||
m_headerEnd = false;
|
||||
|
||||
StoreDataStream headerStream(m_device);
|
||||
headerStream.open(QIODevice::ReadOnly);
|
||||
m_headerStream = &headerStream;
|
||||
|
||||
bool ok;
|
||||
|
||||
quint32 signature1 = Endian::readUInt32(m_device, KeePass2::BYTEORDER, &ok);
|
||||
quint32 signature1 = Endian::readUInt32(m_headerStream, KeePass2::BYTEORDER, &ok);
|
||||
if (!ok || signature1 != KeePass2::SIGNATURE_1) {
|
||||
raiseError(tr("Not a KeePass database."));
|
||||
return Q_NULLPTR;
|
||||
}
|
||||
|
||||
quint32 signature2 = Endian::readUInt32(m_device, KeePass2::BYTEORDER, &ok);
|
||||
quint32 signature2 = Endian::readUInt32(m_headerStream, KeePass2::BYTEORDER, &ok);
|
||||
if (!ok || signature2 != KeePass2::SIGNATURE_2) {
|
||||
raiseError(tr("Not a KeePass database."));
|
||||
return Q_NULLPTR;
|
||||
}
|
||||
|
||||
quint32 version = Endian::readUInt32(m_device, KeePass2::BYTEORDER, &ok) & KeePass2::FILE_VERSION_CRITICAL_MASK;
|
||||
quint32 version = Endian::readUInt32(m_headerStream, KeePass2::BYTEORDER, &ok)
|
||||
& KeePass2::FILE_VERSION_CRITICAL_MASK;
|
||||
quint32 maxVersion = KeePass2::FILE_VERSION & KeePass2::FILE_VERSION_CRITICAL_MASK;
|
||||
if (!ok || (version < KeePass2::FILE_VERSION_MIN) || (version > maxVersion)) {
|
||||
raiseError(tr("Unsupported KeePass database version."));
|
||||
|
@ -69,6 +75,8 @@ Database* KeePass2Reader::readDatabase(QIODevice* device, const CompositeKey& ke
|
|||
while (readHeaderField() && !hasError()) {
|
||||
}
|
||||
|
||||
headerStream.close();
|
||||
|
||||
// TODO: check if all header fields have been parsed
|
||||
|
||||
m_db->setKey(key, m_transformSeed, false);
|
||||
|
@ -78,7 +86,7 @@ Database* KeePass2Reader::readDatabase(QIODevice* device, const CompositeKey& ke
|
|||
hash.addData(m_db->transformedMasterKey());
|
||||
QByteArray finalKey = hash.result();
|
||||
|
||||
SymmetricCipherStream cipherStream(device, SymmetricCipher::Aes256, SymmetricCipher::Cbc,
|
||||
SymmetricCipherStream cipherStream(m_device, SymmetricCipher::Aes256, SymmetricCipher::Cbc,
|
||||
SymmetricCipher::Decrypt, finalKey, m_encryptionIV);
|
||||
cipherStream.open(QIODevice::ReadOnly);
|
||||
|
||||
|
@ -124,6 +132,16 @@ Database* KeePass2Reader::readDatabase(QIODevice* device, const CompositeKey& ke
|
|||
return Q_NULLPTR;
|
||||
}
|
||||
|
||||
Q_ASSERT(version < 0x00030001 || !xmlReader.headerHash().isEmpty());
|
||||
|
||||
if (!xmlReader.headerHash().isEmpty()) {
|
||||
QByteArray headerHash = CryptoHash::hash(headerStream.storedData(), CryptoHash::Sha256);
|
||||
if (headerHash != xmlReader.headerHash()) {
|
||||
raiseError("");
|
||||
return Q_NULLPTR;
|
||||
}
|
||||
}
|
||||
|
||||
return db.take();
|
||||
}
|
||||
|
||||
|
@ -173,7 +191,7 @@ void KeePass2Reader::raiseError(const QString& str)
|
|||
|
||||
bool KeePass2Reader::readHeaderField()
|
||||
{
|
||||
QByteArray fieldIDArray = m_device->read(1);
|
||||
QByteArray fieldIDArray = m_headerStream->read(1);
|
||||
if (fieldIDArray.size() != 1) {
|
||||
raiseError("");
|
||||
return false;
|
||||
|
@ -181,7 +199,7 @@ bool KeePass2Reader::readHeaderField()
|
|||
quint8 fieldID = fieldIDArray.at(0);
|
||||
|
||||
bool ok;
|
||||
quint16 fieldLen = Endian::readUInt16(m_device, KeePass2::BYTEORDER, &ok);
|
||||
quint16 fieldLen = Endian::readUInt16(m_headerStream, KeePass2::BYTEORDER, &ok);
|
||||
if (!ok) {
|
||||
raiseError("");
|
||||
return false;
|
||||
|
@ -189,7 +207,7 @@ bool KeePass2Reader::readHeaderField()
|
|||
|
||||
QByteArray fieldData;
|
||||
if (fieldLen != 0) {
|
||||
fieldData = m_device->read(fieldLen);
|
||||
fieldData = m_headerStream->read(fieldLen);
|
||||
if (fieldData.size() != fieldLen) {
|
||||
raiseError("");
|
||||
return false;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue