mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2024-10-01 01:26:01 -04:00
Add KeePass2Writer.
Support attributes MasterKeyChanged, MasterKeyChangeRec, MasterKeyChangeForce and Tags. Close streams in the dtor.
This commit is contained in:
parent
a9ac4bbf41
commit
e3da80fcc6
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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));
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
132
src/format/KeePass2Writer.cpp
Normal file
132
src/format/KeePass2Writer.cpp
Normal file
@ -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;
|
||||
}
|
46
src/format/KeePass2Writer.h
Normal file
46
src/format/KeePass2Writer.h
Normal file
@ -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
|
@ -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());
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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));
|
||||
|
@ -38,6 +38,11 @@ HashedBlockStream::HashedBlockStream(QIODevice* baseDevice, qint32 blockSize)
|
||||
init();
|
||||
}
|
||||
|
||||
HashedBlockStream::~HashedBlockStream()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
void HashedBlockStream::init()
|
||||
{
|
||||
m_buffer.clear();
|
||||
|
@ -29,6 +29,7 @@ class HashedBlockStream : public LayeredStream
|
||||
public:
|
||||
explicit HashedBlockStream(QIODevice* baseDevice);
|
||||
HashedBlockStream(QIODevice* baseDevice, qint32 blockSize);
|
||||
~HashedBlockStream();
|
||||
|
||||
bool reset();
|
||||
void close();
|
||||
|
@ -24,6 +24,11 @@ LayeredStream::LayeredStream(QIODevice* baseDevice)
|
||||
connect(baseDevice, SIGNAL(aboutToClose()), SLOT(closeStream()));
|
||||
}
|
||||
|
||||
LayeredStream::~LayeredStream()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
bool LayeredStream::isSequential() const
|
||||
{
|
||||
return true;
|
||||
|
@ -26,6 +26,7 @@ class LayeredStream : public QIODevice
|
||||
|
||||
public:
|
||||
explicit LayeredStream(QIODevice* baseDevice);
|
||||
virtual ~LayeredStream();
|
||||
|
||||
bool isSequential() const;
|
||||
virtual QString errorString() const;
|
||||
|
@ -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()) {
|
||||
|
@ -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();
|
||||
|
||||
|
@ -45,7 +45,7 @@
|
||||
****************************************************************************/
|
||||
|
||||
#include "qtiocompressor.h"
|
||||
#include "zlib.h"
|
||||
#include <zlib.h>
|
||||
#include <QtCore/QDebug>
|
||||
|
||||
typedef Bytef ZlibByte;
|
||||
|
Loading…
Reference in New Issue
Block a user