mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2024-12-28 00:39:43 -05:00
KdbxXmlReader: Support Protected attribute on most nodes
Similar to KeePass2 most elements are checked for a Protected="True" attribute. Previously, files KDBX 3.1 files with protected Binary entries, as seen in the wild, could not be read (mangled passwords and file attachments).
This commit is contained in:
parent
084758908a
commit
4c9dcf5c98
@ -188,6 +188,12 @@ QString KdbxXmlReader::errorString() const
|
||||
return QString();
|
||||
}
|
||||
|
||||
bool KdbxXmlReader::isTrueValue(const QStringRef& value)
|
||||
{
|
||||
return value.compare(QLatin1String("true"), Qt::CaseInsensitive) == 0
|
||||
|| value == "1";
|
||||
}
|
||||
|
||||
void KdbxXmlReader::raiseError(const QString& errorMessage)
|
||||
{
|
||||
m_error = true;
|
||||
@ -378,15 +384,9 @@ void KdbxXmlReader::parseBinaries()
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
QByteArray data = isTrueValue(attr.value("Compressed"))
|
||||
? readCompressedBinary() : readBinary();
|
||||
|
||||
if (m_binaryPool.contains(id)) {
|
||||
qWarning("KdbxXmlReader::parseBinaries: overwriting binary item \"%s\"",
|
||||
@ -812,28 +812,9 @@ void KdbxXmlReader::parseEntryString(Entry* entry)
|
||||
|
||||
if (m_xml.name() == "Value") {
|
||||
QXmlStreamAttributes attr = m_xml.attributes();
|
||||
value = readString();
|
||||
|
||||
bool isProtected = attr.value("Protected") == "True";
|
||||
bool protectInMemory = attr.value("ProtectInMemory") == "True";
|
||||
|
||||
if (isProtected && !value.isEmpty()) {
|
||||
if (m_randomStream) {
|
||||
QByteArray ciphertext = QByteArray::fromBase64(value.toLatin1());
|
||||
bool ok;
|
||||
QByteArray plaintext = m_randomStream->process(ciphertext, &ok);
|
||||
if (!ok) {
|
||||
value.clear();
|
||||
raiseError(m_randomStream->errorString());
|
||||
} else {
|
||||
value = QString::fromUtf8(plaintext);
|
||||
}
|
||||
} else {
|
||||
raiseError(tr("Unable to decrypt entry string"));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
bool isProtected;
|
||||
bool protectInMemory;
|
||||
value = readString(isProtected, protectInMemory);
|
||||
protect = isProtected || protectInMemory;
|
||||
valueSet = true;
|
||||
continue;
|
||||
@ -881,14 +862,6 @@ QPair<QString, QString> KdbxXmlReader::parseEntryBinary(Entry* entry)
|
||||
} else {
|
||||
// format compatibility
|
||||
value = readBinary();
|
||||
bool isProtected = attr.hasAttribute("Protected")
|
||||
&& (attr.value("Protected") == "True");
|
||||
|
||||
if (isProtected && !value.isEmpty()) {
|
||||
if (!m_randomStream->processInPlace(value)) {
|
||||
raiseError(m_randomStream->errorString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
valueSet = true;
|
||||
@ -1003,17 +976,43 @@ TimeInfo KdbxXmlReader::parseTimes()
|
||||
|
||||
QString KdbxXmlReader::readString()
|
||||
{
|
||||
return m_xml.readElementText();
|
||||
bool isProtected;
|
||||
bool protectInMemory;
|
||||
|
||||
return readString(isProtected, protectInMemory);
|
||||
}
|
||||
|
||||
QString KdbxXmlReader::readString(bool& isProtected, bool& protectInMemory)
|
||||
{
|
||||
QXmlStreamAttributes attr = m_xml.attributes();
|
||||
isProtected = isTrueValue(attr.value("Protected"));
|
||||
protectInMemory = isTrueValue(attr.value("ProtectInMemory"));
|
||||
QString value = m_xml.readElementText();
|
||||
|
||||
if (isProtected && !value.isEmpty()) {
|
||||
QByteArray ciphertext = QByteArray::fromBase64(value.toLatin1());
|
||||
bool ok;
|
||||
QByteArray plaintext = m_randomStream->process(ciphertext, &ok);
|
||||
if (!ok) {
|
||||
value.clear();
|
||||
raiseError(m_randomStream->errorString());
|
||||
return value;
|
||||
}
|
||||
|
||||
value = QString::fromUtf8(plaintext);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
bool KdbxXmlReader::readBool()
|
||||
{
|
||||
QString str = readString();
|
||||
|
||||
if (str.compare("True", Qt::CaseInsensitive) == 0) {
|
||||
if (str.compare("true", Qt::CaseInsensitive) == 0) {
|
||||
return true;
|
||||
}
|
||||
if (str.compare("False", Qt::CaseInsensitive) == 0) {
|
||||
if (str.compare("false", Qt::CaseInsensitive) == 0) {
|
||||
return false;
|
||||
}
|
||||
if (str.length() == 0) {
|
||||
@ -1112,7 +1111,24 @@ Uuid KdbxXmlReader::readUuid()
|
||||
|
||||
QByteArray KdbxXmlReader::readBinary()
|
||||
{
|
||||
return QByteArray::fromBase64(readString().toLatin1());
|
||||
QXmlStreamAttributes attr = m_xml.attributes();
|
||||
bool isProtected = isTrueValue(attr.value("Protected"));
|
||||
QString value = m_xml.readElementText();
|
||||
QByteArray data = QByteArray::fromBase64(value.toLatin1());
|
||||
|
||||
if (isProtected && !data.isEmpty()) {
|
||||
bool ok;
|
||||
QByteArray plaintext = m_randomStream->process(data, &ok);
|
||||
if (!ok) {
|
||||
data.clear();
|
||||
raiseError(m_randomStream->errorString());
|
||||
return data;
|
||||
}
|
||||
|
||||
data = plaintext;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
QByteArray KdbxXmlReader::readCompressedBinary()
|
||||
|
@ -81,6 +81,7 @@ protected:
|
||||
virtual TimeInfo parseTimes();
|
||||
|
||||
virtual QString readString();
|
||||
virtual QString readString(bool& isProtected, bool& protectInMemory);
|
||||
virtual bool readBool();
|
||||
virtual QDateTime readDateTime();
|
||||
virtual QColor readColor();
|
||||
@ -94,6 +95,7 @@ protected:
|
||||
virtual Group* getGroup(const Uuid& uuid);
|
||||
virtual Entry* getEntry(const Uuid& uuid);
|
||||
|
||||
virtual bool isTrueValue(const QStringRef& value);
|
||||
virtual void raiseError(const QString& errorMessage);
|
||||
|
||||
const quint32 m_kdbxVersion;
|
||||
|
Loading…
Reference in New Issue
Block a user