mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2024-12-29 09:16:29 -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();
|
return QString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool KdbxXmlReader::isTrueValue(const QStringRef& value)
|
||||||
|
{
|
||||||
|
return value.compare(QLatin1String("true"), Qt::CaseInsensitive) == 0
|
||||||
|
|| value == "1";
|
||||||
|
}
|
||||||
|
|
||||||
void KdbxXmlReader::raiseError(const QString& errorMessage)
|
void KdbxXmlReader::raiseError(const QString& errorMessage)
|
||||||
{
|
{
|
||||||
m_error = true;
|
m_error = true;
|
||||||
@ -378,15 +384,9 @@ void KdbxXmlReader::parseBinaries()
|
|||||||
}
|
}
|
||||||
|
|
||||||
QXmlStreamAttributes attr = m_xml.attributes();
|
QXmlStreamAttributes attr = m_xml.attributes();
|
||||||
|
|
||||||
QString id = attr.value("ID").toString();
|
QString id = attr.value("ID").toString();
|
||||||
|
QByteArray data = isTrueValue(attr.value("Compressed"))
|
||||||
QByteArray data;
|
? readCompressedBinary() : readBinary();
|
||||||
if (attr.value("Compressed").compare(QLatin1String("True"), Qt::CaseInsensitive) == 0) {
|
|
||||||
data = readCompressedBinary();
|
|
||||||
} else {
|
|
||||||
data = readBinary();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_binaryPool.contains(id)) {
|
if (m_binaryPool.contains(id)) {
|
||||||
qWarning("KdbxXmlReader::parseBinaries: overwriting binary item \"%s\"",
|
qWarning("KdbxXmlReader::parseBinaries: overwriting binary item \"%s\"",
|
||||||
@ -812,28 +812,9 @@ void KdbxXmlReader::parseEntryString(Entry* entry)
|
|||||||
|
|
||||||
if (m_xml.name() == "Value") {
|
if (m_xml.name() == "Value") {
|
||||||
QXmlStreamAttributes attr = m_xml.attributes();
|
QXmlStreamAttributes attr = m_xml.attributes();
|
||||||
value = readString();
|
bool isProtected;
|
||||||
|
bool protectInMemory;
|
||||||
bool isProtected = attr.value("Protected") == "True";
|
value = readString(isProtected, protectInMemory);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protect = isProtected || protectInMemory;
|
protect = isProtected || protectInMemory;
|
||||||
valueSet = true;
|
valueSet = true;
|
||||||
continue;
|
continue;
|
||||||
@ -881,14 +862,6 @@ QPair<QString, QString> KdbxXmlReader::parseEntryBinary(Entry* entry)
|
|||||||
} else {
|
} else {
|
||||||
// format compatibility
|
// format compatibility
|
||||||
value = readBinary();
|
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;
|
valueSet = true;
|
||||||
@ -1003,17 +976,43 @@ TimeInfo KdbxXmlReader::parseTimes()
|
|||||||
|
|
||||||
QString KdbxXmlReader::readString()
|
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()
|
bool KdbxXmlReader::readBool()
|
||||||
{
|
{
|
||||||
QString str = readString();
|
QString str = readString();
|
||||||
|
|
||||||
if (str.compare("True", Qt::CaseInsensitive) == 0) {
|
if (str.compare("true", Qt::CaseInsensitive) == 0) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (str.compare("False", Qt::CaseInsensitive) == 0) {
|
if (str.compare("false", Qt::CaseInsensitive) == 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (str.length() == 0) {
|
if (str.length() == 0) {
|
||||||
@ -1112,7 +1111,24 @@ Uuid KdbxXmlReader::readUuid()
|
|||||||
|
|
||||||
QByteArray KdbxXmlReader::readBinary()
|
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()
|
QByteArray KdbxXmlReader::readCompressedBinary()
|
||||||
|
@ -81,6 +81,7 @@ protected:
|
|||||||
virtual TimeInfo parseTimes();
|
virtual TimeInfo parseTimes();
|
||||||
|
|
||||||
virtual QString readString();
|
virtual QString readString();
|
||||||
|
virtual QString readString(bool& isProtected, bool& protectInMemory);
|
||||||
virtual bool readBool();
|
virtual bool readBool();
|
||||||
virtual QDateTime readDateTime();
|
virtual QDateTime readDateTime();
|
||||||
virtual QColor readColor();
|
virtual QColor readColor();
|
||||||
@ -94,6 +95,7 @@ protected:
|
|||||||
virtual Group* getGroup(const Uuid& uuid);
|
virtual Group* getGroup(const Uuid& uuid);
|
||||||
virtual Entry* getEntry(const Uuid& uuid);
|
virtual Entry* getEntry(const Uuid& uuid);
|
||||||
|
|
||||||
|
virtual bool isTrueValue(const QStringRef& value);
|
||||||
virtual void raiseError(const QString& errorMessage);
|
virtual void raiseError(const QString& errorMessage);
|
||||||
|
|
||||||
const quint32 m_kdbxVersion;
|
const quint32 m_kdbxVersion;
|
||||||
|
Loading…
Reference in New Issue
Block a user