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
path: root/src
diff options
context:
space:
mode:
authorFelix Geyer <debfx@fobos.de>2010-09-25 14:41:00 +0400
committerFelix Geyer <debfx@fobos.de>2010-09-25 14:41:00 +0400
commite3da80fcc61476a931564cac98ea56186dabacce (patch)
tree20e201ce4a68b12045645c016b77c09951909a17 /src
parenta9ac4bbf41aa1d7f4f25f45ea5cc237894e1fb56 (diff)
Add KeePass2Writer.
Support attributes MasterKeyChanged, MasterKeyChangeRec, MasterKeyChangeForce and Tags. Close streams in the dtor.
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/core/Database.cpp58
-rw-r--r--src/core/Database.h25
-rw-r--r--src/core/Entry.cpp10
-rw-r--r--src/core/Entry.h3
-rw-r--r--src/core/Metadata.cpp30
-rw-r--r--src/core/Metadata.h10
-rw-r--r--src/format/KeePass2.h13
-rw-r--r--src/format/KeePass2Reader.cpp46
-rw-r--r--src/format/KeePass2Reader.h8
-rw-r--r--src/format/KeePass2Writer.cpp132
-rw-r--r--src/format/KeePass2Writer.h46
-rw-r--r--src/format/KeePass2XmlReader.cpp23
-rw-r--r--src/format/KeePass2XmlReader.h1
-rw-r--r--src/format/KeePass2XmlWriter.cpp10
-rw-r--r--src/streams/HashedBlockStream.cpp5
-rw-r--r--src/streams/HashedBlockStream.h1
-rw-r--r--src/streams/LayeredStream.cpp5
-rw-r--r--src/streams/LayeredStream.h1
-rw-r--r--src/streams/SymmetricCipherStream.cpp5
-rw-r--r--src/streams/SymmetricCipherStream.h1
-rw-r--r--src/streams/qtiocompressor.cpp2
22 files changed, 397 insertions, 39 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 367696c3e..aa8fc04ca 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -31,6 +31,7 @@ set(keepassx_SOURCES
crypto/Random.cpp
crypto/SymmetricCipher.cpp
format/KeePass2Reader.cpp
+ format/KeePass2Writer.cpp
format/KeePass2XmlReader.cpp
format/KeePass2XmlWriter.cpp
gui/DatabaseWidget.cpp
diff --git a/src/core/Database.cpp b/src/core/Database.cpp
index fcb5eab83..88c12e0ed 100644
--- a/src/core/Database.cpp
+++ b/src/core/Database.cpp
@@ -102,3 +102,61 @@ void Database::addDeletedObject(const DeletedObject& delObj)
{
m_deletedObjects.append(delObj);
}
+
+Uuid Database::cipher() const
+{
+ return m_cipher;
+}
+
+Database::CompressionAlgorithm Database::compressionAlgo() const
+{
+ return m_compressionAlgo;
+}
+
+QByteArray Database::transformSeed() const
+{
+ return m_transformSeed;
+}
+
+quint64 Database::transformRounds() const
+{
+ return m_transformRounds;
+}
+
+QByteArray Database::transformedMasterKey() const
+{
+ return m_transformedMasterKey;
+}
+
+void Database::setCipher(const Uuid& cipher)
+{
+ Q_ASSERT(!cipher.isNull());
+
+ m_cipher = cipher;
+}
+
+void Database::setCompressionAlgo(Database::CompressionAlgorithm algo)
+{
+ Q_ASSERT(static_cast<quint32>(algo) <= CompressionAlgorithmMax);
+
+ m_compressionAlgo = algo;
+}
+
+void Database::setTransformSeed(const QByteArray& seed)
+{
+ Q_ASSERT(seed.size() == 32);
+
+ m_transformSeed = seed;
+}
+
+void Database::setTransformRounds(quint64 rounds)
+{
+ m_transformRounds = rounds;
+}
+
+void Database::setTransformedMasterKey(QByteArray& key)
+{
+ Q_ASSERT(key.size() == 32);
+
+ m_transformedMasterKey = key;
+}
diff --git a/src/core/Database.h b/src/core/Database.h
index 486b8178c..5ec296e20 100644
--- a/src/core/Database.h
+++ b/src/core/Database.h
@@ -36,6 +36,13 @@ class Database : public QObject
Q_OBJECT
public:
+ enum CompressionAlgorithm
+ {
+ CompressionNone = 0,
+ CompressionGZip = 1
+ };
+ static const quint32 CompressionAlgorithmMax = CompressionGZip;
+
Database();
Group* rootGroup();
const Group* rootGroup() const;
@@ -47,6 +54,18 @@ public:
QList<DeletedObject> deletedObjects();
void addDeletedObject(const DeletedObject& delObj);
+ Uuid cipher() const;
+ Database::CompressionAlgorithm compressionAlgo() const;
+ QByteArray transformSeed() const;
+ quint64 transformRounds() const;
+ QByteArray transformedMasterKey() const;
+
+ void setCipher(const Uuid& cipher);
+ void setCompressionAlgo(Database::CompressionAlgorithm algo);
+ void setTransformSeed(const QByteArray& seed);
+ void setTransformRounds(quint64 rounds);
+ void setTransformedMasterKey(QByteArray& key);
+
Q_SIGNALS:
void groupDataChanged(Group* group);
void groupAboutToAdd(Group* group, int index);
@@ -61,6 +80,12 @@ private:
Metadata* m_metadata;
Group* m_rootGroup;
QList<DeletedObject> m_deletedObjects;
+
+ Uuid m_cipher;
+ CompressionAlgorithm m_compressionAlgo;
+ QByteArray m_transformSeed;
+ quint64 m_transformRounds;
+ QByteArray m_transformedMasterKey;
};
#endif // KEEPASSX_DATABASE_H
diff --git a/src/core/Entry.cpp b/src/core/Entry.cpp
index 783b824fb..9416262da 100644
--- a/src/core/Entry.cpp
+++ b/src/core/Entry.cpp
@@ -74,6 +74,11 @@ QString Entry::overrideUrl() const
return m_overrideUrl;
}
+QString Entry::tags() const
+{
+ return m_tags;
+}
+
TimeInfo Entry::timeInfo() const
{
return m_timeInfo;
@@ -172,6 +177,11 @@ void Entry::setOverrideUrl(const QString& url)
m_overrideUrl = url;
}
+void Entry::setTags(const QString& tags)
+{
+ m_tags = tags;
+}
+
void Entry::setTimeInfo(const TimeInfo& timeInfo)
{
m_timeInfo = timeInfo;
diff --git a/src/core/Entry.h b/src/core/Entry.h
index 5147fbcf9..b14a3fdf3 100644
--- a/src/core/Entry.h
+++ b/src/core/Entry.h
@@ -49,6 +49,7 @@ public:
QColor foregroundColor() const;
QColor backgroundColor() const;
QString overrideUrl() const;
+ QString tags() const;
TimeInfo timeInfo() const;
bool autoTypeEnabled() const;
int autoTypeObfuscation() const;
@@ -68,6 +69,7 @@ public:
void setForegroundColor(const QColor& color);
void setBackgroundColor(const QColor& color);
void setOverrideUrl(const QString& url);
+ void setTags(const QString& tags);
void setTimeInfo(const TimeInfo& timeInfo);
void setAutoTypeEnabled(bool enable);
void setAutoTypeObfuscation(int obfuscation);
@@ -98,6 +100,7 @@ private:
QColor m_foregroundColor;
QColor m_backgroundColor;
QString m_overrideUrl;
+ QString m_tags;
TimeInfo m_timeInfo;
bool m_autoTypeEnabled;
int m_autoTypeObfuscation;
diff --git a/src/core/Metadata.cpp b/src/core/Metadata.cpp
index 284ff6bc7..3dd38bd19 100644
--- a/src/core/Metadata.cpp
+++ b/src/core/Metadata.cpp
@@ -145,6 +145,21 @@ const Group* Metadata::lastTopVisibleGroup() const
return m_lastTopVisibleGroup;
}
+QDateTime Metadata::masterKeyChanged() const
+{
+ return m_masterKeyChanged;
+}
+
+int Metadata::masterKeyChangeRec() const
+{
+ return m_masterKeyChangeRec;
+}
+
+int Metadata::masterKeyChangeForce() const
+{
+ return m_masterKeyChangeForce;
+}
+
QHash<QString, QString> Metadata::customFields() const
{
return m_customFields;
@@ -271,6 +286,21 @@ void Metadata::setLastTopVisibleGroup(Group* group)
m_lastTopVisibleGroup = group;
}
+void Metadata::setMasterKeyChanged(const QDateTime& value)
+{
+ m_masterKeyChanged = value;
+}
+
+void Metadata::setMasterKeyChangeRec(int value)
+{
+ m_masterKeyChangeRec = value;
+}
+
+void Metadata::setMasterKeyChangeForce(int value)
+{
+ m_masterKeyChangeForce = value;
+}
+
void Metadata::addCustomField(const QString& key, const QString& value)
{
Q_ASSERT(!m_customFields.contains(key));
diff --git a/src/core/Metadata.h b/src/core/Metadata.h
index f49a4f9ff..00484cf52 100644
--- a/src/core/Metadata.h
+++ b/src/core/Metadata.h
@@ -57,6 +57,9 @@ public:
QDateTime entryTemplatesGroupChanged() const;
const Group* lastSelectedGroup() const;
const Group* lastTopVisibleGroup() const;
+ QDateTime masterKeyChanged() const;
+ int masterKeyChangeRec() const;
+ int masterKeyChangeForce() const;
QHash<QString, QString> customFields() const;
void setGenerator(const QString& value);
@@ -82,6 +85,9 @@ public:
void setEntryTemplatesGroupChanged(const QDateTime& value);
void setLastSelectedGroup(Group* group);
void setLastTopVisibleGroup(Group* group);
+ void setMasterKeyChanged(const QDateTime& value);
+ void setMasterKeyChangeRec(int value);
+ void setMasterKeyChangeForce(int value);
void addCustomField(const QString& key, const QString& value);
void removeCustomField(const QString& key);
@@ -112,6 +118,10 @@ private:
Group* m_lastSelectedGroup;
Group* m_lastTopVisibleGroup;
+ QDateTime m_masterKeyChanged;
+ int m_masterKeyChangeRec;
+ int m_masterKeyChangeForce;
+
QHash<QString, QString> m_customFields;
};
diff --git a/src/format/KeePass2.h b/src/format/KeePass2.h
index 0785a4eac..ecf7921b1 100644
--- a/src/format/KeePass2.h
+++ b/src/format/KeePass2.h
@@ -20,6 +20,8 @@
#include <QtCore/QtGlobal>
+#include "core/Uuid.h"
+
namespace KeePass2
{
const quint32 SIGNATURE_1 = 0x9AA2D903;
@@ -27,6 +29,10 @@ namespace KeePass2
const quint32 FILE_VERSION = 0x00020000;
const quint32 FILE_VERSION_CRITICAL_MASK = 0xFFFF0000;
+ const QSysInfo::Endian BYTEORDER = QSysInfo::LittleEndian;
+
+ const Uuid CIPHER_AES = Uuid(QByteArray::fromHex("31c1f2e6bf714350be5805216afc5aff"));
+
enum HeaderFieldID
{
EndOfHeader = 0,
@@ -41,13 +47,6 @@ namespace KeePass2
StreamStartBytes = 9,
InnerRandomStreamID = 10
};
-
- enum CompressionAlgorithm
- {
- CompressionNone = 0,
- CompressionGZip = 1,
- CompressionCount = 2
- };
}
#endif // KEEPASSX_KEEPASS2_H
diff --git a/src/format/KeePass2Reader.cpp b/src/format/KeePass2Reader.cpp
index 13df6b97d..f26fa188b 100644
--- a/src/format/KeePass2Reader.cpp
+++ b/src/format/KeePass2Reader.cpp
@@ -21,37 +21,37 @@
#include <QtCore/QFile>
#include <QtCore/QIODevice>
-#include "KeePass2XmlReader.h"
+#include "core/Database.h"
#include "crypto/CryptoHash.h"
+#include "format/KeePass2.h"
+#include "format/KeePass2XmlReader.h"
#include "streams/HashedBlockStream.h"
#include "streams/QtIOCompressor"
#include "streams/SymmetricCipherStream.h"
-const QSysInfo::Endian KeePass2Reader::BYTEORDER = QSysInfo::LittleEndian;
-
Database* KeePass2Reader::readDatabase(QIODevice* device, const CompositeKey& key)
{
+ m_db = new Database();
m_device = device;
m_error = false;
m_errorStr = QString();
m_headerEnd = false;
- m_cipher = Uuid();
bool ok;
- quint32 signature1 = Endian::readUInt32(m_device, BYTEORDER, &ok);
+ quint32 signature1 = Endian::readUInt32(m_device, KeePass2::BYTEORDER, &ok);
if (!ok || signature1 != KeePass2::SIGNATURE_1) {
raiseError("1");
return 0;
}
- quint32 signature2 = Endian::readUInt32(m_device, BYTEORDER, &ok);
+ quint32 signature2 = Endian::readUInt32(m_device, KeePass2::BYTEORDER, &ok);
if (!ok || signature2 != KeePass2::SIGNATURE_2) {
raiseError("2");
return 0;
}
- quint32 version = Endian::readUInt32(m_device, BYTEORDER, &ok) & KeePass2::FILE_VERSION_CRITICAL_MASK;
+ quint32 version = Endian::readUInt32(m_device, KeePass2::BYTEORDER, &ok) & KeePass2::FILE_VERSION_CRITICAL_MASK;
quint32 expectedVersion = KeePass2::FILE_VERSION & KeePass2::FILE_VERSION_CRITICAL_MASK;
// TODO do we support old Kdbx versions?
if (!ok || (version != expectedVersion)) {
@@ -62,9 +62,12 @@ Database* KeePass2Reader::readDatabase(QIODevice* device, const CompositeKey& ke
while (readHeaderField() && !error()) {
}
+ QByteArray transformedMasterKey = key.transform(m_db->transformSeed(), m_db->transformRounds());
+ m_db->setTransformedMasterKey(transformedMasterKey);
+
CryptoHash hash(CryptoHash::Sha256);
hash.addData(m_masterSeed);
- hash.addData(key.transform(m_transformSeed, m_transformRounds));
+ hash.addData(transformedMasterKey);
QByteArray finalKey = hash.result();
SymmetricCipherStream cipherStream(device, SymmetricCipher::Aes256, SymmetricCipher::Cbc, SymmetricCipher::Decrypt, finalKey, m_encryptionIV);
@@ -83,7 +86,7 @@ Database* KeePass2Reader::readDatabase(QIODevice* device, const CompositeKey& ke
QIODevice* xmlDevice;
QScopedPointer<QtIOCompressor> ioCompressor;
- if (m_compression == KeePass2::CompressionNone) {
+ if (m_db->compressionAlgo() == Database::CompressionNone) {
xmlDevice = &hashedStream;
}
else {
@@ -94,9 +97,9 @@ Database* KeePass2Reader::readDatabase(QIODevice* device, const CompositeKey& ke
}
KeePass2XmlReader xmlReader;
- Database* db = xmlReader.readDatabase(xmlDevice);
+ xmlReader.readDatabase(xmlDevice, m_db);
// TODO forward error messages from xmlReader
- return db;
+ return m_db;
}
Database* KeePass2Reader::readDatabase(const QString& filename, const CompositeKey& key)
@@ -136,7 +139,7 @@ bool KeePass2Reader::readHeaderField()
quint8 fieldID = fieldIDArray.at(0);
bool ok;
- quint16 fieldLen = Endian::readUInt16(m_device, BYTEORDER, &ok);
+ quint16 fieldLen = Endian::readUInt16(m_device, KeePass2::BYTEORDER, &ok);
if (!ok) {
raiseError("");
return false;
@@ -206,7 +209,14 @@ void KeePass2Reader::setCipher(const QByteArray& data)
raiseError("");
}
else {
- m_cipher = Uuid(data);
+ Uuid uuid(data);
+
+ if (uuid != KeePass2::CIPHER_AES) {
+ raiseError("");
+ }
+ else {
+ m_db->setCipher(uuid);
+ }
}
}
@@ -216,13 +226,13 @@ void KeePass2Reader::setCompressionFlags(const QByteArray& data)
raiseError("");
}
else {
- quint32 id = Endian::bytesToUInt32(data, BYTEORDER);
+ quint32 id = Endian::bytesToUInt32(data, KeePass2::BYTEORDER);
- if (id >= KeePass2::CompressionCount) {
+ if (id > Database::CompressionAlgorithmMax) {
raiseError("");
}
else {
- m_compression = static_cast<KeePass2::CompressionAlgorithm>(id);
+ m_db->setCompressionAlgo(static_cast<Database::CompressionAlgorithm>(id));
}
}
}
@@ -243,7 +253,7 @@ void KeePass2Reader::setTransformSeed(const QByteArray& data)
raiseError("");
}
else {
- m_transformSeed = data;
+ m_db->setTransformSeed(data);
}
}
@@ -253,7 +263,7 @@ void KeePass2Reader::setTansformRounds(const QByteArray& data)
raiseError("");
}
else {
- m_transformRounds = Endian::bytesToUInt64(data, BYTEORDER);
+ m_db->setTransformRounds(Endian::bytesToUInt64(data, KeePass2::BYTEORDER));
}
}
diff --git a/src/format/KeePass2Reader.h b/src/format/KeePass2Reader.h
index e839fcaa8..9730d9538 100644
--- a/src/format/KeePass2Reader.h
+++ b/src/format/KeePass2Reader.h
@@ -23,7 +23,6 @@
#include "core/Endian.h"
#include "core/Uuid.h"
#include "keys/CompositeKey.h"
-#include "format/KeePass2.h"
class Database;
@@ -52,18 +51,13 @@ private:
void setStreamStartBytes(const QByteArray& data);
void setInnerRandomStreamID(const QByteArray& data);
- static const QSysInfo::Endian BYTEORDER;
-
QIODevice* m_device;
bool m_error;
QString m_errorStr;
bool m_headerEnd;
- Uuid m_cipher;
- KeePass2::CompressionAlgorithm m_compression;
+ Database* m_db;
QByteArray m_masterSeed;
- QByteArray m_transformSeed;
- quint64 m_transformRounds;
QByteArray m_encryptionIV;
QByteArray m_streamStartBytes;
};
diff --git a/src/format/KeePass2Writer.cpp b/src/format/KeePass2Writer.cpp
new file mode 100644
index 000000000..115c143a5
--- /dev/null
+++ b/src/format/KeePass2Writer.cpp
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2010 Felix Geyer <debfx@fobos.de>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 or (at your option)
+ * version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "KeePass2Writer.h"
+
+#include <QtCore/QFile>
+
+#include "core/Database.h"
+#include "core/Endian.h"
+#include "crypto/CryptoHash.h"
+#include "crypto/Random.h"
+#include "format/KeePass2XmlWriter.h"
+#include "streams/HashedBlockStream.h"
+#include "streams/QtIOCompressor"
+#include "streams/SymmetricCipherStream.h"
+
+#define CHECK_RETURN(x) if (!(x)) return;
+#define CHECK_RETURN_FALSE(x) if (!(x)) return false;
+
+KeePass2Writer::KeePass2Writer()
+ : m_error(false)
+{
+}
+
+void KeePass2Writer::writeDatabase(QIODevice* device, Database* db)
+{
+ m_error = false;
+ m_errorStr = QString();
+
+ m_device = device;
+
+ QByteArray masterSeed = Random::randomArray(32);
+ QByteArray encryptionIV = Random::randomArray(16);
+ QByteArray startBytes = Random::randomArray(32);
+ QByteArray endOfHeader = "\r\n\r\n";
+
+ CryptoHash hash(CryptoHash::Sha256);
+ hash.addData(masterSeed);
+ hash.addData(db->transformedMasterKey());
+ QByteArray finalKey = hash.result();
+
+
+ CHECK_RETURN(writeData(Endian::int32ToBytes(KeePass2::SIGNATURE_1, KeePass2::BYTEORDER)));
+ CHECK_RETURN(writeData(Endian::int32ToBytes(KeePass2::SIGNATURE_2, KeePass2::BYTEORDER)));
+ CHECK_RETURN(writeData(Endian::int32ToBytes(KeePass2::FILE_VERSION, KeePass2::BYTEORDER)));
+
+ CHECK_RETURN(writeHeaderField(KeePass2::CipherID, db->cipher().toByteArray()));
+ CHECK_RETURN(writeHeaderField(KeePass2::CompressionFlags, Endian::int32ToBytes(db->compressionAlgo(), KeePass2::BYTEORDER)));
+ CHECK_RETURN(writeHeaderField(KeePass2::MasterSeed, masterSeed));
+ CHECK_RETURN(writeHeaderField(KeePass2::TransformSeed, db->transformSeed()));
+ CHECK_RETURN(writeHeaderField(KeePass2::TransformRounds, Endian::int64ToBytes(db->transformRounds(), KeePass2::BYTEORDER)));
+ CHECK_RETURN(writeHeaderField(KeePass2::EncryptionIV, encryptionIV));
+ CHECK_RETURN(writeHeaderField(KeePass2::StreamStartBytes, startBytes));
+ CHECK_RETURN(writeHeaderField(KeePass2::EndOfHeader, endOfHeader));
+
+ SymmetricCipherStream cipherStream(device, SymmetricCipher::Aes256, SymmetricCipher::Cbc, SymmetricCipher::Encrypt, finalKey, encryptionIV);
+ cipherStream.open(QIODevice::WriteOnly);
+ m_device = &cipherStream;
+ CHECK_RETURN(writeData(startBytes));
+
+ HashedBlockStream hashedStream(&cipherStream);
+ hashedStream.open(QIODevice::WriteOnly);
+
+ QScopedPointer<QtIOCompressor> ioCompressor;
+
+ if (db->compressionAlgo() == Database::CompressionNone) {
+ m_device = &hashedStream;
+ }
+ else {
+ ioCompressor.reset(new QtIOCompressor(&hashedStream));
+ ioCompressor->setStreamFormat(QtIOCompressor::GzipFormat);
+ ioCompressor->open(QIODevice::WriteOnly);
+ m_device = ioCompressor.data();
+ }
+
+ KeePass2XmlWriter xmlWriter;
+ xmlWriter.writeDatabase(m_device, db);
+}
+
+bool KeePass2Writer::writeData(const QByteArray& data)
+{
+ if (m_device->write(data) != data.size()) {
+ m_error = true;
+ m_errorStr = m_device->errorString();
+ return false;
+ }
+ else {
+ return true;
+ }
+}
+
+bool KeePass2Writer::writeHeaderField(KeePass2::HeaderFieldID fieldId, const QByteArray& data)
+{
+ QByteArray fieldIdArr;
+ fieldIdArr[0] = fieldId;
+ CHECK_RETURN_FALSE(writeData(fieldIdArr));
+ CHECK_RETURN_FALSE(writeData(Endian::int16ToBytes(data.size(), KeePass2::BYTEORDER)));
+ CHECK_RETURN_FALSE(writeData(data));
+
+ return true;
+}
+
+void KeePass2Writer::writeDatabase(const QString& filename, Database* db)
+{
+ QFile file(filename);
+ file.open(QIODevice::WriteOnly|QIODevice::Truncate);
+ writeDatabase(&file, db);
+}
+
+bool KeePass2Writer::error()
+{
+ return m_error;
+}
+
+QString KeePass2Writer::errorString()
+{
+ return m_errorStr;
+}
diff --git a/src/format/KeePass2Writer.h b/src/format/KeePass2Writer.h
new file mode 100644
index 000000000..2477468d4
--- /dev/null
+++ b/src/format/KeePass2Writer.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2010 Felix Geyer <debfx@fobos.de>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 or (at your option)
+ * version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef KEEPASSX_KEEPASS2WRITER_H
+#define KEEPASSX_KEEPASS2WRITER_H
+
+#include <QtCore/QIODevice>
+
+#include "format/KeePass2.h"
+#include "keys/CompositeKey.h"
+
+class Database;
+
+class KeePass2Writer
+{
+public:
+ KeePass2Writer();
+ void writeDatabase(QIODevice* device, Database* db);
+ void writeDatabase(const QString& filename, Database* db);
+ bool error();
+ QString errorString();
+
+private:
+ bool writeData(const QByteArray& data);
+ bool writeHeaderField(KeePass2::HeaderFieldID fieldId, const QByteArray& data);
+
+ QIODevice* m_device;
+ bool m_error;
+ QString m_errorStr;
+};
+
+#endif // KEEPASSX_KEEPASS2WRITER_H
diff --git a/src/format/KeePass2XmlReader.cpp b/src/format/KeePass2XmlReader.cpp
index 605dc93aa..62a4e81e7 100644
--- a/src/format/KeePass2XmlReader.cpp
+++ b/src/format/KeePass2XmlReader.cpp
@@ -29,11 +29,11 @@ KeePass2XmlReader::KeePass2XmlReader()
{
}
-Database* KeePass2XmlReader::readDatabase(QIODevice* device)
+void KeePass2XmlReader::readDatabase(QIODevice* device, Database* db)
{
m_xml.setDevice(device);
- m_db = new Database();
+ m_db = db;
m_meta = m_db->metadata();
m_tmpParent = new Group();
@@ -50,8 +50,13 @@ Database* KeePass2XmlReader::readDatabase(QIODevice* device)
}
delete m_tmpParent;
+}
- return m_db;
+Database* KeePass2XmlReader::readDatabase(QIODevice* device)
+{
+ Database* db = new Database();
+ readDatabase(device, db);
+ return db;
}
Database* KeePass2XmlReader::readDatabase(const QString& filename)
@@ -120,6 +125,15 @@ void KeePass2XmlReader::parseMeta()
else if (m_xml.name() == "MaintenanceHistoryDays") {
m_meta->setMaintenanceHistoryDays(readNumber());
}
+ else if (m_xml.name() == "MasterKeyChanged") {
+ m_meta->setMasterKeyChanged(readDateTime());
+ }
+ else if (m_xml.name() == "MasterKeyChangeRec") {
+ m_meta->setMasterKeyChangeRec(readNumber());
+ }
+ else if (m_xml.name() == "MasterKeyChangeForce") {
+ m_meta->setMasterKeyChangeForce(readNumber());
+ }
else if (m_xml.name() == "MemoryProtection") {
parseMemoryProtection();
}
@@ -461,6 +475,9 @@ Entry* KeePass2XmlReader::parseEntry(bool history)
else if (m_xml.name() == "OverrideURL") {
entry->setOverrideUrl(readString());
}
+ else if (m_xml.name() == "Tags") {
+ entry->setTags(readString());
+ }
else if (m_xml.name() == "Times") {
entry->setTimeInfo(parseTimes());
}
diff --git a/src/format/KeePass2XmlReader.h b/src/format/KeePass2XmlReader.h
index f6c4d8993..da6b17c36 100644
--- a/src/format/KeePass2XmlReader.h
+++ b/src/format/KeePass2XmlReader.h
@@ -38,6 +38,7 @@ class KeePass2XmlReader
public:
KeePass2XmlReader();
Database* readDatabase(QIODevice* device);
+ void readDatabase(QIODevice* device, Database* db);
Database* readDatabase(const QString& filename);
bool error();
QString errorString();
diff --git a/src/format/KeePass2XmlWriter.cpp b/src/format/KeePass2XmlWriter.cpp
index d3b2a612a..77a7d8adb 100644
--- a/src/format/KeePass2XmlWriter.cpp
+++ b/src/format/KeePass2XmlWriter.cpp
@@ -53,7 +53,7 @@ void KeePass2XmlWriter::writeDatabase(QIODevice* device, Database* db)
void KeePass2XmlWriter::writeDatabase(const QString& filename, Database* db)
{
QFile file(filename);
- file.open(QIODevice::WriteOnly);
+ file.open(QIODevice::WriteOnly|QIODevice::Truncate);
writeDatabase(&file, db);
}
@@ -69,6 +69,9 @@ void KeePass2XmlWriter::writeMetadata()
writeString("DefaultUserName", m_meta->defaultUserName());
writeDateTime("DefaultUserNameChanged", m_meta->defaultUserNameChanged());
writeNumber("MaintenanceHistoryDays", m_meta->maintenanceHistoryDays());
+ writeDateTime("MasterKeyChanged", m_meta->masterKeyChanged());
+ writeNumber("MasterKeyChangeRec", m_meta->masterKeyChangeRec());
+ writeNumber("MasterKeyChangeForce", m_meta->masterKeyChangeForce());
writeMemoryProtection();
writeCustomIcons();
writeBool("RecycleBinEnabled", m_meta->recycleBinEnabled());
@@ -263,16 +266,17 @@ void KeePass2XmlWriter::writeEntry(const Entry* entry)
writeColor("ForegroundColor", entry->foregroundColor());
writeColor("BackgroundColor", entry->backgroundColor());
writeString("OverrideURL", entry->overrideUrl());
+ writeString("Tags", entry->tags());
writeTimes(entry->timeInfo());
- Q_FOREACH (const QString& key, entry->attributes()) {
+ Q_FOREACH (const QString& key, entry->attributes().keys()) {
m_xml.writeStartElement("String");
writeString("Key", key);
writeString("Value", entry->attributes().value(key));
m_xml.writeEndElement();
}
- Q_FOREACH (const QString& key, entry->attachments()) {
+ Q_FOREACH (const QString& key, entry->attachments().keys()) {
m_xml.writeStartElement("Binary");
writeString("Key", key);
writeBinary("Value", entry->attachments().value(key));
diff --git a/src/streams/HashedBlockStream.cpp b/src/streams/HashedBlockStream.cpp
index c0f97764a..3ad35e30a 100644
--- a/src/streams/HashedBlockStream.cpp
+++ b/src/streams/HashedBlockStream.cpp
@@ -38,6 +38,11 @@ HashedBlockStream::HashedBlockStream(QIODevice* baseDevice, qint32 blockSize)
init();
}
+HashedBlockStream::~HashedBlockStream()
+{
+ close();
+}
+
void HashedBlockStream::init()
{
m_buffer.clear();
diff --git a/src/streams/HashedBlockStream.h b/src/streams/HashedBlockStream.h
index 3aa23bf22..fc20ce14f 100644
--- a/src/streams/HashedBlockStream.h
+++ b/src/streams/HashedBlockStream.h
@@ -29,6 +29,7 @@ class HashedBlockStream : public LayeredStream
public:
explicit HashedBlockStream(QIODevice* baseDevice);
HashedBlockStream(QIODevice* baseDevice, qint32 blockSize);
+ ~HashedBlockStream();
bool reset();
void close();
diff --git a/src/streams/LayeredStream.cpp b/src/streams/LayeredStream.cpp
index d0078085c..b71eb228a 100644
--- a/src/streams/LayeredStream.cpp
+++ b/src/streams/LayeredStream.cpp
@@ -24,6 +24,11 @@ LayeredStream::LayeredStream(QIODevice* baseDevice)
connect(baseDevice, SIGNAL(aboutToClose()), SLOT(closeStream()));
}
+LayeredStream::~LayeredStream()
+{
+ close();
+}
+
bool LayeredStream::isSequential() const
{
return true;
diff --git a/src/streams/LayeredStream.h b/src/streams/LayeredStream.h
index 86e9d1a6b..0c008ae93 100644
--- a/src/streams/LayeredStream.h
+++ b/src/streams/LayeredStream.h
@@ -26,6 +26,7 @@ class LayeredStream : public QIODevice
public:
explicit LayeredStream(QIODevice* baseDevice);
+ virtual ~LayeredStream();
bool isSequential() const;
virtual QString errorString() const;
diff --git a/src/streams/SymmetricCipherStream.cpp b/src/streams/SymmetricCipherStream.cpp
index fd7354727..edfbc0b74 100644
--- a/src/streams/SymmetricCipherStream.cpp
+++ b/src/streams/SymmetricCipherStream.cpp
@@ -28,6 +28,11 @@ SymmetricCipherStream::SymmetricCipherStream(QIODevice* baseDevice, SymmetricCip
m_cipher = new SymmetricCipher(algo, mode, direction, key, iv);
}
+SymmetricCipherStream::~SymmetricCipherStream()
+{
+ close();
+}
+
bool SymmetricCipherStream::reset()
{
if (isWritable()) {
diff --git a/src/streams/SymmetricCipherStream.h b/src/streams/SymmetricCipherStream.h
index 90bfc7257..186bd1200 100644
--- a/src/streams/SymmetricCipherStream.h
+++ b/src/streams/SymmetricCipherStream.h
@@ -30,6 +30,7 @@ class SymmetricCipherStream : public LayeredStream
public:
SymmetricCipherStream(QIODevice* baseDevice, SymmetricCipher::Algorithm algo, SymmetricCipher::Mode mode,
SymmetricCipher::Direction direction, const QByteArray& key, const QByteArray& iv);
+ ~SymmetricCipherStream();
bool reset();
void close();
diff --git a/src/streams/qtiocompressor.cpp b/src/streams/qtiocompressor.cpp
index 0de5dff4d..569596302 100644
--- a/src/streams/qtiocompressor.cpp
+++ b/src/streams/qtiocompressor.cpp
@@ -45,7 +45,7 @@
****************************************************************************/
#include "qtiocompressor.h"
-#include "zlib.h"
+#include <zlib.h>
#include <QtCore/QDebug>
typedef Bytef ZlibByte;