mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2024-10-01 01:26:01 -04:00
Implement reading encrypted kdbx files.
This commit is contained in:
parent
bb6ae3a014
commit
9f282928e8
@ -19,6 +19,7 @@ configure_file( config-keepassx.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-keepa
|
||||
|
||||
set(keepassx_SOURCES
|
||||
core/Database.cpp
|
||||
core/Endian.cpp
|
||||
core/Entry.cpp
|
||||
core/Group.cpp
|
||||
core/Metadata.cpp
|
||||
@ -28,6 +29,7 @@ set(keepassx_SOURCES
|
||||
crypto/CryptoHash.cpp
|
||||
crypto/Random.cpp
|
||||
crypto/SymmetricCipher.cpp
|
||||
format/KeePass2Reader.cpp
|
||||
format/KeePass2XmlReader.cpp
|
||||
format/KeePass2XmlWriter.cpp
|
||||
gui/DatabaseWidget.cpp
|
||||
@ -35,6 +37,11 @@ set(keepassx_SOURCES
|
||||
gui/EntryView.cpp
|
||||
gui/GroupModel.cpp
|
||||
gui/GroupView.cpp
|
||||
keys/CompositeKey.cpp
|
||||
keys/PasswordKey.cpp
|
||||
streams/HashedBlockStream.cpp
|
||||
streams/LayeredStream.cpp
|
||||
streams/SymmetricCipherStream.cpp
|
||||
)
|
||||
|
||||
automoc4_add_library( keepassx_core STATIC ${keepassx_SOURCES} )
|
||||
|
134
src/core/Endian.cpp
Normal file
134
src/core/Endian.cpp
Normal file
@ -0,0 +1,134 @@
|
||||
/*
|
||||
* 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 "Endian.h"
|
||||
|
||||
#include <QtCore/QtEndian>
|
||||
#include <QtCore/QIODevice>
|
||||
|
||||
namespace Endian
|
||||
{
|
||||
|
||||
qint16 bytesToInt16(const QByteArray& ba, QSysInfo::Endian byteOrder)
|
||||
{
|
||||
Q_ASSERT(ba.size() == 2);
|
||||
|
||||
if (byteOrder == QSysInfo::LittleEndian) {
|
||||
return qFromLittleEndian<qint16>(reinterpret_cast<const uchar*>(ba.constData()));
|
||||
}
|
||||
else {
|
||||
return qFromBigEndian<qint16>(reinterpret_cast<const uchar*>(ba.constData()));
|
||||
}
|
||||
}
|
||||
|
||||
qint32 bytesToInt32(const QByteArray& ba, QSysInfo::Endian byteOrder)
|
||||
{
|
||||
Q_ASSERT(ba.size() == 4);
|
||||
|
||||
if (byteOrder == QSysInfo::LittleEndian) {
|
||||
return qFromLittleEndian<qint32>(reinterpret_cast<const uchar*>(ba.constData()));
|
||||
}
|
||||
else {
|
||||
return qFromBigEndian<qint32>(reinterpret_cast<const uchar*>(ba.constData()));
|
||||
}
|
||||
}
|
||||
|
||||
qint64 bytesToInt64(const QByteArray& ba, QSysInfo::Endian byteOrder)
|
||||
{
|
||||
Q_ASSERT(ba.size() == 8);
|
||||
|
||||
if (byteOrder == QSysInfo::LittleEndian) {
|
||||
return qFromLittleEndian<qint64>(reinterpret_cast<const uchar*>(ba.constData()));
|
||||
}
|
||||
else {
|
||||
return qFromBigEndian<qint64>(reinterpret_cast<const uchar*>(ba.constData()));
|
||||
}
|
||||
}
|
||||
|
||||
quint16 bytesToUInt16(const QByteArray& ba, QSysInfo::Endian byteOrder)
|
||||
{
|
||||
return bytesToInt16(ba, byteOrder);
|
||||
}
|
||||
|
||||
quint32 bytesToUInt32(const QByteArray& ba, QSysInfo::Endian byteOrder)
|
||||
{
|
||||
return bytesToInt32(ba, byteOrder);
|
||||
}
|
||||
|
||||
quint64 bytesToUInt64(const QByteArray& ba, QSysInfo::Endian byteOrder)
|
||||
{
|
||||
return bytesToInt64(ba, byteOrder);
|
||||
}
|
||||
|
||||
qint16 readInt16(QIODevice* device, QSysInfo::Endian byteOrder, bool* ok)
|
||||
{
|
||||
QByteArray ba = device->read(2);
|
||||
|
||||
if (ba.size() != 2) {
|
||||
*ok = false;
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
*ok = true;
|
||||
return bytesToUInt16(ba, byteOrder);
|
||||
}
|
||||
}
|
||||
|
||||
qint32 readInt32(QIODevice* device, QSysInfo::Endian byteOrder, bool* ok)
|
||||
{
|
||||
QByteArray ba = device->read(4);
|
||||
|
||||
if (ba.size() != 4) {
|
||||
*ok = false;
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
*ok = true;
|
||||
return bytesToUInt32(ba, byteOrder);
|
||||
}
|
||||
}
|
||||
|
||||
qint64 readInt64(QIODevice* device, QSysInfo::Endian byteOrder, bool* ok)
|
||||
{
|
||||
QByteArray ba = device->read(8);
|
||||
|
||||
if (ba.size() != 8) {
|
||||
*ok = false;
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
*ok = true;
|
||||
return bytesToUInt64(ba, byteOrder);
|
||||
}
|
||||
}
|
||||
|
||||
quint16 readUInt16(QIODevice* device, QSysInfo::Endian byteOrder, bool* ok)
|
||||
{
|
||||
return readInt16(device, byteOrder, ok);
|
||||
}
|
||||
|
||||
quint32 readUInt32(QIODevice* device, QSysInfo::Endian byteOrder, bool* ok)
|
||||
{
|
||||
return readInt32(device, byteOrder, ok);
|
||||
}
|
||||
|
||||
quint64 readUInt64(QIODevice* device, QSysInfo::Endian byteOrder, bool* ok)
|
||||
{
|
||||
return readInt64(device, byteOrder, ok);
|
||||
}
|
||||
|
||||
} // namespace Endian
|
43
src/core/Endian.h
Normal file
43
src/core/Endian.h
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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_ENDIAN_H
|
||||
#define KEEPASSX_ENDIAN_H
|
||||
|
||||
#include <QtCore/QByteArray>
|
||||
#include <QtCore/QSysInfo>
|
||||
|
||||
class QIODevice;
|
||||
|
||||
namespace Endian
|
||||
{
|
||||
qint16 bytesToInt16(const QByteArray& ba, QSysInfo::Endian byteOrder);
|
||||
quint16 bytesToUInt16(const QByteArray& ba, QSysInfo::Endian byteOrder);
|
||||
qint32 bytesToInt32(const QByteArray& ba, QSysInfo::Endian byteOrder);
|
||||
quint32 bytesToUInt32(const QByteArray& ba, QSysInfo::Endian byteOrder);
|
||||
qint64 bytesToInt64(const QByteArray& ba, QSysInfo::Endian byteOrder);
|
||||
quint64 bytesToUInt64(const QByteArray& ba, QSysInfo::Endian byteOrder);
|
||||
|
||||
qint16 readInt16(QIODevice* device, QSysInfo::Endian byteOrder, bool* ok);
|
||||
quint16 readUInt16(QIODevice* device, QSysInfo::Endian byteOrder, bool* ok);
|
||||
qint32 readInt32(QIODevice* device, QSysInfo::Endian byteOrder, bool* ok);
|
||||
quint32 readUInt32(QIODevice* device, QSysInfo::Endian byteOrder, bool* ok);
|
||||
qint64 readInt64(QIODevice* device, QSysInfo::Endian byteOrder, bool* ok);
|
||||
quint64 readUInt64(QIODevice* device, QSysInfo::Endian byteOrder, bool* ok);
|
||||
};
|
||||
|
||||
#endif // KEEPASSX_ENDIAN_H
|
@ -1,34 +0,0 @@
|
||||
/*
|
||||
* 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_DATABASEREADER_H
|
||||
#define KEEPASSX_DATABASEREADER_H
|
||||
|
||||
#include <QtCore/QString>
|
||||
|
||||
class Database;
|
||||
class QIODevice;
|
||||
|
||||
class DatabaseReader
|
||||
{
|
||||
public:
|
||||
virtual Database* readDatabase(QIODevice* device) = 0;
|
||||
virtual bool error() = 0;
|
||||
virtual QString errorString() = 0;
|
||||
};
|
||||
|
||||
#endif // KEEPASSX_DATABASEREADER_H
|
@ -1,32 +0,0 @@
|
||||
/*
|
||||
* 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_DATABASEWRITER_H
|
||||
#define KEEPASSX_DATABASEWRITER_H
|
||||
|
||||
#include <QtCore/QString>
|
||||
|
||||
class Database;
|
||||
class QIODevice;
|
||||
|
||||
class DatabaseWriter
|
||||
{
|
||||
public:
|
||||
virtual void writeDatabase(QIODevice* device, Database* db) = 0;
|
||||
};
|
||||
|
||||
#endif // KEEPASSX_DATABASEWRITER_H
|
53
src/format/KeePass2.h
Normal file
53
src/format/KeePass2.h
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* 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_KEEPASS2_H
|
||||
#define KEEPASSX_KEEPASS2_H
|
||||
|
||||
#include <QtCore/QtGlobal>
|
||||
|
||||
namespace KeePass2
|
||||
{
|
||||
const quint32 SIGNATURE_1 = 0x9AA2D903;
|
||||
const quint32 SIGNATURE_2 = 0xB54BFB67;
|
||||
const quint32 FILE_VERSION = 0x00020000;
|
||||
const quint32 FILE_VERSION_CRITICAL_MASK = 0xFFFF0000;
|
||||
|
||||
enum HeaderFieldID
|
||||
{
|
||||
EndOfHeader = 0,
|
||||
Comment = 1,
|
||||
CipherID = 2,
|
||||
CompressionFlags = 3,
|
||||
MasterSeed = 4,
|
||||
TransformSeed = 5,
|
||||
TransformRounds = 6,
|
||||
EncryptionIV = 7,
|
||||
ProtectedStreamKey = 8,
|
||||
StreamStartBytes = 9,
|
||||
InnerRandomStreamID = 10
|
||||
};
|
||||
|
||||
enum CompressionAlgorithm
|
||||
{
|
||||
CompressionNone = 0,
|
||||
CompressionGZip = 1,
|
||||
CompressionCount = 2
|
||||
};
|
||||
}
|
||||
|
||||
#endif // KEEPASSX_KEEPASS2_H
|
273
src/format/KeePass2Reader.cpp
Normal file
273
src/format/KeePass2Reader.cpp
Normal file
@ -0,0 +1,273 @@
|
||||
/*
|
||||
* 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 "KeePass2Reader.h"
|
||||
|
||||
#include <QtCore/QBuffer>
|
||||
#include <QtCore/QFile>
|
||||
#include <QtCore/QIODevice>
|
||||
|
||||
#include "KeePass2.h"
|
||||
#include "KeePass2XmlReader.h"
|
||||
#include "crypto/CryptoHash.h"
|
||||
#include "streams/HashedBlockStream.h"
|
||||
#include "streams/SymmetricCipherStream.h"
|
||||
|
||||
const QSysInfo::Endian KeePass2Reader::BYTEORDER = QSysInfo::LittleEndian;
|
||||
|
||||
Database* KeePass2Reader::readDatabase(QIODevice* device, const CompositeKey& key)
|
||||
{
|
||||
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);
|
||||
if (!ok || signature1 != KeePass2::SIGNATURE_1) {
|
||||
raiseError("1");
|
||||
return 0;
|
||||
}
|
||||
|
||||
quint32 signature2 = Endian::readUInt32(m_device, 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 expectedVersion = KeePass2::FILE_VERSION & KeePass2::FILE_VERSION_CRITICAL_MASK;
|
||||
// TODO do we support old Kdbx versions?
|
||||
if (!ok || (version != expectedVersion)) {
|
||||
raiseError("3");
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (readHeaderField() && !error()) {
|
||||
}
|
||||
|
||||
CryptoHash hash(CryptoHash::Sha256);
|
||||
hash.addData(m_masterSeed);
|
||||
hash.addData(key.transform(m_transformSeed, m_transformRounds));
|
||||
QByteArray finalKey = hash.result();
|
||||
|
||||
SymmetricCipherStream cipherStream(device, SymmetricCipher::Aes256, SymmetricCipher::Cbc, SymmetricCipher::Decrypt, finalKey, m_encryptionIV);
|
||||
cipherStream.open(QIODevice::ReadOnly);
|
||||
|
||||
QByteArray realStart = cipherStream.read(32);
|
||||
|
||||
if (realStart != m_streamStartBytes) {
|
||||
raiseError("4");
|
||||
}
|
||||
|
||||
HashedBlockStream hashedStream(&cipherStream);
|
||||
hashedStream.open(QIODevice::ReadOnly);
|
||||
|
||||
KeePass2XmlReader xmlReader;
|
||||
Database* db = xmlReader.readDatabase(&hashedStream);
|
||||
return db;
|
||||
}
|
||||
|
||||
Database* KeePass2Reader::readDatabase(const QString& filename, const CompositeKey& key)
|
||||
{
|
||||
QFile file(filename);
|
||||
file.open(QFile::ReadOnly);
|
||||
Database* db = readDatabase(&file, key);
|
||||
// TODO check for QFile errors
|
||||
return db;
|
||||
}
|
||||
|
||||
bool KeePass2Reader::error()
|
||||
{
|
||||
return m_error;
|
||||
}
|
||||
|
||||
QString KeePass2Reader::errorString()
|
||||
{
|
||||
// TODO
|
||||
return QString();
|
||||
}
|
||||
|
||||
void KeePass2Reader::raiseError(const QString& str)
|
||||
{
|
||||
// TODO
|
||||
qWarning("KeePass2Reader error: %s", qPrintable(str));
|
||||
m_error = true;
|
||||
}
|
||||
|
||||
bool KeePass2Reader::readHeaderField()
|
||||
{
|
||||
QByteArray fieldIDArray = m_device->read(1);
|
||||
if (fieldIDArray.size() != 1) {
|
||||
raiseError("");
|
||||
return false;
|
||||
}
|
||||
quint8 fieldID = fieldIDArray.at(0);
|
||||
|
||||
bool ok;
|
||||
quint16 fieldLen = Endian::readUInt16(m_device, BYTEORDER, &ok);
|
||||
if (!ok) {
|
||||
raiseError("");
|
||||
return false;
|
||||
}
|
||||
|
||||
QByteArray fieldData;
|
||||
if (fieldLen != 0) {
|
||||
fieldData = m_device->read(fieldLen);
|
||||
if (fieldData.size() != fieldLen) {
|
||||
raiseError("");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
switch (fieldID) {
|
||||
case KeePass2::EndOfHeader:
|
||||
m_headerEnd = true;
|
||||
break;
|
||||
|
||||
case KeePass2::CipherID:
|
||||
setCipher(fieldData);
|
||||
break;
|
||||
|
||||
case KeePass2::CompressionFlags:
|
||||
setCompressionFlags(fieldData);
|
||||
break;
|
||||
|
||||
case KeePass2::MasterSeed:
|
||||
setMasterSeed(fieldData);
|
||||
break;
|
||||
|
||||
case KeePass2::TransformSeed:
|
||||
setTransformSeed(fieldData);
|
||||
break;
|
||||
|
||||
case KeePass2::TransformRounds:
|
||||
setTansformRounds(fieldData);
|
||||
break;
|
||||
|
||||
case KeePass2::EncryptionIV:
|
||||
setEncryptionIV(fieldData);
|
||||
break;
|
||||
|
||||
case KeePass2::ProtectedStreamKey:
|
||||
setProtectedStreamKey(fieldData);
|
||||
break;
|
||||
|
||||
case KeePass2::StreamStartBytes:
|
||||
setStreamStartBytes(fieldData);
|
||||
break;
|
||||
|
||||
case KeePass2::InnerRandomStreamID:
|
||||
setInnerRandomStreamID(fieldData);
|
||||
break;
|
||||
|
||||
default:
|
||||
qWarning("Unknown header field read: id=%d", fieldID);
|
||||
break;
|
||||
}
|
||||
|
||||
return !m_headerEnd;
|
||||
}
|
||||
|
||||
void KeePass2Reader::setCipher(const QByteArray& data)
|
||||
{
|
||||
if (data.size() != Uuid::LENGTH) {
|
||||
raiseError("");
|
||||
}
|
||||
else {
|
||||
m_cipher = Uuid(data);
|
||||
}
|
||||
}
|
||||
|
||||
void KeePass2Reader::setCompressionFlags(const QByteArray& data)
|
||||
{
|
||||
if (data.size() != 4) {
|
||||
raiseError("");
|
||||
}
|
||||
else {
|
||||
quint32 id = Endian::bytesToUInt32(data, BYTEORDER);
|
||||
|
||||
if (id >= KeePass2::CompressionCount) {
|
||||
raiseError("");
|
||||
}
|
||||
else {
|
||||
m_compression = id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KeePass2Reader::setMasterSeed(const QByteArray& data)
|
||||
{
|
||||
if (data.size() != 32) {
|
||||
raiseError("");
|
||||
}
|
||||
else {
|
||||
m_masterSeed = data;
|
||||
}
|
||||
}
|
||||
|
||||
void KeePass2Reader::setTransformSeed(const QByteArray& data)
|
||||
{
|
||||
if (data.size() != 32) {
|
||||
raiseError("");
|
||||
}
|
||||
else {
|
||||
m_transformSeed = data;
|
||||
}
|
||||
}
|
||||
|
||||
void KeePass2Reader::setTansformRounds(const QByteArray& data)
|
||||
{
|
||||
if (data.size() != 8) {
|
||||
raiseError("");
|
||||
}
|
||||
else {
|
||||
m_transformRounds = Endian::bytesToUInt64(data, BYTEORDER);
|
||||
}
|
||||
}
|
||||
|
||||
void KeePass2Reader::setEncryptionIV(const QByteArray& data)
|
||||
{
|
||||
if (data.size() != 16) {
|
||||
raiseError("");
|
||||
}
|
||||
else {
|
||||
m_encryptionIV = data;
|
||||
}
|
||||
}
|
||||
|
||||
void KeePass2Reader::setProtectedStreamKey(const QByteArray& data)
|
||||
{
|
||||
// TODO ignore?
|
||||
}
|
||||
|
||||
void KeePass2Reader::setStreamStartBytes(const QByteArray& data)
|
||||
{
|
||||
if (data.size() != 32) {
|
||||
raiseError("");
|
||||
}
|
||||
else {
|
||||
m_streamStartBytes = data;
|
||||
}
|
||||
}
|
||||
|
||||
void KeePass2Reader::setInnerRandomStreamID(const QByteArray& data)
|
||||
{
|
||||
// TODO ignore?
|
||||
}
|
70
src/format/KeePass2Reader.h
Normal file
70
src/format/KeePass2Reader.h
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* 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_KEEPASS2READER_H
|
||||
#define KEEPASSX_KEEPASS2READER_H
|
||||
|
||||
#include <QtCore/QCoreApplication>
|
||||
|
||||
#include "core/Endian.h"
|
||||
#include "core/Uuid.h"
|
||||
#include "keys/CompositeKey.h"
|
||||
|
||||
class Database;
|
||||
|
||||
class KeePass2Reader
|
||||
{
|
||||
Q_DECLARE_TR_FUNCTIONS(KeePass2Reader);
|
||||
|
||||
public:
|
||||
Database* readDatabase(QIODevice* device, const CompositeKey& key);
|
||||
Database* readDatabase(const QString& filename, const CompositeKey& key);
|
||||
bool error();
|
||||
QString errorString();
|
||||
|
||||
private:
|
||||
void raiseError(const QString& str);
|
||||
|
||||
bool readHeaderField();
|
||||
|
||||
void setCipher(const QByteArray& data);
|
||||
void setCompressionFlags(const QByteArray& data);
|
||||
void setMasterSeed(const QByteArray& data);
|
||||
void setTransformSeed(const QByteArray& data);
|
||||
void setTansformRounds(const QByteArray& data);
|
||||
void setEncryptionIV(const QByteArray& data);
|
||||
void setProtectedStreamKey(const QByteArray& data);
|
||||
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;
|
||||
int m_compression;
|
||||
QByteArray m_masterSeed;
|
||||
QByteArray m_transformSeed;
|
||||
quint64 m_transformRounds;
|
||||
QByteArray m_encryptionIV;
|
||||
QByteArray m_streamStartBytes;
|
||||
};
|
||||
|
||||
#endif // KEEPASSX_KEEPASS2READER_H
|
@ -57,7 +57,7 @@ Database* KeePass2XmlReader::readDatabase(QIODevice* device)
|
||||
Database* KeePass2XmlReader::readDatabase(const QString& filename)
|
||||
{
|
||||
QFile file(filename);
|
||||
file.open(QIODevice::ReadOnly | QIODevice::Text);
|
||||
file.open(QIODevice::ReadOnly);
|
||||
return readDatabase(&file);
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,6 @@
|
||||
#include <QtCore/QXmlStreamReader>
|
||||
#include <QtGui/QColor>
|
||||
|
||||
#include "DatabaseReader.h"
|
||||
#include "core/TimeInfo.h"
|
||||
#include "core/Uuid.h"
|
||||
|
||||
@ -32,7 +31,7 @@ class Entry;
|
||||
class Group;
|
||||
class Metadata;
|
||||
|
||||
class KeePass2XmlReader : public DatabaseReader
|
||||
class KeePass2XmlReader
|
||||
{
|
||||
Q_DECLARE_TR_FUNCTIONS(KeePass2XmlReader);
|
||||
|
||||
|
@ -23,7 +23,6 @@
|
||||
#include <QtGui/QColor>
|
||||
#include <QtGui/QImage>
|
||||
|
||||
#include "DatabaseWriter.h"
|
||||
#include "core/Database.h"
|
||||
#include "core/Entry.h"
|
||||
#include "core/TimeInfo.h"
|
||||
@ -32,7 +31,7 @@
|
||||
class Group;
|
||||
class Metadata;
|
||||
|
||||
class KeePass2XmlWriter : public DatabaseWriter
|
||||
class KeePass2XmlWriter
|
||||
{
|
||||
public:
|
||||
KeePass2XmlWriter();
|
||||
|
113
src/keys/CompositeKey.cpp
Normal file
113
src/keys/CompositeKey.cpp
Normal file
@ -0,0 +1,113 @@
|
||||
/*
|
||||
* 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 "CompositeKey.h"
|
||||
|
||||
#include <QtCore/QThread>
|
||||
|
||||
#include "crypto/CryptoHash.h"
|
||||
#include "crypto/SymmetricCipher.h"
|
||||
|
||||
class KeyTransformation : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
KeyTransformation(const QByteArray& key, const QByteArray& seed, int rounds);
|
||||
QByteArray result();
|
||||
|
||||
protected:
|
||||
void run();
|
||||
|
||||
private:
|
||||
QByteArray m_key;
|
||||
QByteArray m_seed;
|
||||
int m_rounds;
|
||||
QByteArray m_result;
|
||||
};
|
||||
|
||||
CompositeKey::~CompositeKey()
|
||||
{
|
||||
qDeleteAll(m_keys);
|
||||
}
|
||||
|
||||
CompositeKey* CompositeKey::clone() const
|
||||
{
|
||||
return new CompositeKey(*this);
|
||||
}
|
||||
|
||||
|
||||
QByteArray CompositeKey::rawKey() const
|
||||
{
|
||||
CryptoHash cryptoHash(CryptoHash::Sha256);
|
||||
|
||||
Q_FOREACH (Key* key, m_keys) {
|
||||
cryptoHash.addData(key->rawKey());
|
||||
}
|
||||
|
||||
return cryptoHash.result();
|
||||
}
|
||||
|
||||
QByteArray CompositeKey::transform(const QByteArray& seed, int rounds) const
|
||||
{
|
||||
QByteArray key = rawKey();
|
||||
|
||||
KeyTransformation* transform1 = new KeyTransformation(key.left(16), seed, rounds);
|
||||
KeyTransformation* transform2 = new KeyTransformation(key.right(16), seed, rounds);
|
||||
|
||||
transform1->start();
|
||||
transform2->start();
|
||||
|
||||
transform1->wait();
|
||||
transform2->wait();
|
||||
|
||||
QByteArray transformed;
|
||||
transformed.append(transform1->result());
|
||||
transformed.append(transform2->result());
|
||||
|
||||
return CryptoHash::hash(transformed, CryptoHash::Sha256);
|
||||
}
|
||||
|
||||
void CompositeKey::addKey(const Key& key)
|
||||
{
|
||||
m_keys.append(key.clone());
|
||||
}
|
||||
|
||||
KeyTransformation::KeyTransformation(const QByteArray& key, const QByteArray& seed, int rounds)
|
||||
: m_key(key)
|
||||
, m_seed(seed)
|
||||
, m_rounds(rounds)
|
||||
, m_result(key)
|
||||
{
|
||||
}
|
||||
|
||||
void KeyTransformation::run()
|
||||
{
|
||||
QByteArray iv(16, 0);
|
||||
SymmetricCipher cipher(SymmetricCipher::Aes256, SymmetricCipher::Ecb, SymmetricCipher::Encrypt, m_seed, iv);
|
||||
|
||||
for (int i=0; i<m_rounds; i++) {
|
||||
cipher.processInPlace(m_result);
|
||||
}
|
||||
}
|
||||
|
||||
QByteArray KeyTransformation::result()
|
||||
{
|
||||
return m_result;
|
||||
}
|
||||
|
||||
#include "KeyTransformation.moc"
|
39
src/keys/CompositeKey.h
Normal file
39
src/keys/CompositeKey.h
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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_COMPOSITEKEY_H
|
||||
#define KEEPASSX_COMPOSITEKEY_H
|
||||
|
||||
#include <QtCore/QList>
|
||||
|
||||
#include "Key.h"
|
||||
|
||||
class CompositeKey : public Key
|
||||
{
|
||||
public:
|
||||
~CompositeKey();
|
||||
CompositeKey* clone() const;
|
||||
|
||||
QByteArray rawKey() const;
|
||||
QByteArray transform(const QByteArray& seed, int rounds) const;
|
||||
void addKey(const Key& key);
|
||||
|
||||
private:
|
||||
QList<Key*> m_keys;
|
||||
};
|
||||
|
||||
#endif // KEEPASSX_COMPOSITEKEY_H
|
30
src/keys/Key.h
Normal file
30
src/keys/Key.h
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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_KEY_H
|
||||
#define KEEPASSX_KEY_H
|
||||
|
||||
#include <QtCore/QByteArray>
|
||||
|
||||
class Key
|
||||
{
|
||||
public:
|
||||
virtual QByteArray rawKey() const = 0;
|
||||
virtual Key* clone() const = 0;
|
||||
};
|
||||
|
||||
#endif // KEEPASSX_KEY_H
|
35
src/keys/PasswordKey.cpp
Normal file
35
src/keys/PasswordKey.cpp
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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 "PasswordKey.h"
|
||||
|
||||
#include "crypto/CryptoHash.h"
|
||||
|
||||
QByteArray PasswordKey::rawKey() const
|
||||
{
|
||||
return m_key;
|
||||
}
|
||||
|
||||
void PasswordKey::setPassword(const QString& password)
|
||||
{
|
||||
m_key = CryptoHash::hash(password.toUtf8(), CryptoHash::Sha256);
|
||||
}
|
||||
|
||||
PasswordKey* PasswordKey::clone() const
|
||||
{
|
||||
return new PasswordKey(*this);
|
||||
}
|
36
src/keys/PasswordKey.h
Normal file
36
src/keys/PasswordKey.h
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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_PASSWORDKEY_H
|
||||
#define KEEPASSX_PASSWORDKEY_H
|
||||
|
||||
#include <QtCore/QString>
|
||||
|
||||
#include "Key.h"
|
||||
|
||||
class PasswordKey : public Key
|
||||
{
|
||||
public:
|
||||
QByteArray rawKey() const;
|
||||
void setPassword(const QString& password);
|
||||
PasswordKey* clone() const;
|
||||
|
||||
private:
|
||||
QByteArray m_key;
|
||||
};
|
||||
|
||||
#endif // KEEPASSX_PASSWORDKEY_H
|
145
src/streams/HashedBlockStream.cpp
Normal file
145
src/streams/HashedBlockStream.cpp
Normal file
@ -0,0 +1,145 @@
|
||||
/*
|
||||
* 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 "HashedBlockStream.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "crypto/CryptoHash.h"
|
||||
|
||||
const QSysInfo::Endian HashedBlockStream::BYTEORDER = QSysInfo::LittleEndian;
|
||||
|
||||
HashedBlockStream::HashedBlockStream(QIODevice* baseDevice)
|
||||
: LayeredStream(baseDevice)
|
||||
, m_blockSize(1024*1024)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
HashedBlockStream::HashedBlockStream(QIODevice* baseDevice, qint32 blockSize)
|
||||
: LayeredStream(baseDevice)
|
||||
, m_blockSize(blockSize)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
void HashedBlockStream::init()
|
||||
{
|
||||
m_bufferPos = 0;
|
||||
m_blockIndex = 0;
|
||||
m_eof = false;
|
||||
}
|
||||
|
||||
void HashedBlockStream::close()
|
||||
{
|
||||
LayeredStream::close();
|
||||
}
|
||||
|
||||
qint64 HashedBlockStream::readData(char* data, qint64 maxSize)
|
||||
{
|
||||
if (m_eof) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
qint64 bytesRemaining = maxSize;
|
||||
qint64 offset = 0;
|
||||
|
||||
while (bytesRemaining > 0) {
|
||||
if (m_bufferPos == m_buffer.size()) {
|
||||
if (!readHashedBlock()) {
|
||||
return maxSize - bytesRemaining;
|
||||
}
|
||||
}
|
||||
|
||||
int bytesToCopy = qMin(bytesRemaining, static_cast<qint64>(m_buffer.size() - m_bufferPos));
|
||||
|
||||
memcpy(data + offset, m_buffer.constData() + m_bufferPos, bytesToCopy);
|
||||
|
||||
offset += bytesToCopy;
|
||||
m_bufferPos += bytesToCopy;
|
||||
bytesRemaining -= bytesToCopy;
|
||||
}
|
||||
|
||||
return maxSize;
|
||||
}
|
||||
|
||||
bool HashedBlockStream::readHashedBlock()
|
||||
{
|
||||
bool ok;
|
||||
|
||||
quint32 index = Endian::readUInt32(m_baseDevice, BYTEORDER, &ok);
|
||||
if (!ok || index != m_blockIndex) {
|
||||
// TODO error
|
||||
Q_ASSERT(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
QByteArray hash = m_baseDevice->read(32);
|
||||
if (hash.size() != 32) {
|
||||
// TODO error
|
||||
Q_ASSERT(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_blockSize = Endian::readInt32(m_baseDevice, BYTEORDER, &ok);
|
||||
if (!ok || m_blockSize < 0) {
|
||||
// TODO error
|
||||
Q_ASSERT(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_blockSize == 0) {
|
||||
if (hash.count(static_cast<char>(0)) != 32) {
|
||||
// TODO error
|
||||
Q_ASSERT(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_eof = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_buffer = m_baseDevice->read(m_blockSize);
|
||||
if (m_buffer.size() != m_blockSize) {
|
||||
// TODO error
|
||||
Q_ASSERT(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (hash != CryptoHash::hash(m_buffer, CryptoHash::Sha256)) {
|
||||
// TODO error
|
||||
Q_ASSERT(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_bufferPos = 0;
|
||||
m_blockIndex++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
qint64 HashedBlockStream::writeData(const char* data, qint64 maxSize)
|
||||
{
|
||||
// TODO implement
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool HashedBlockStream::writeHashedBlock()
|
||||
{
|
||||
// TODO implement
|
||||
return false;
|
||||
}
|
52
src/streams/HashedBlockStream.h
Normal file
52
src/streams/HashedBlockStream.h
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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_HASHEDBLOCKSTREAM_H
|
||||
#define KEEPASSX_HASHEDBLOCKSTREAM_H
|
||||
|
||||
#include "LayeredStream.h"
|
||||
#include "core/Endian.h"
|
||||
#include "crypto/CryptoHash.h"
|
||||
|
||||
class HashedBlockStream : public LayeredStream
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit HashedBlockStream(QIODevice* baseDevice);
|
||||
HashedBlockStream(QIODevice* baseDevice, qint32 blockSize);
|
||||
|
||||
void close();
|
||||
|
||||
protected:
|
||||
qint64 readData(char* data, qint64 maxSize);
|
||||
qint64 writeData(const char* data, qint64 maxSize);
|
||||
|
||||
private:
|
||||
void init();
|
||||
bool readHashedBlock();
|
||||
bool writeHashedBlock();
|
||||
|
||||
static const QSysInfo::Endian BYTEORDER;
|
||||
qint32 m_blockSize;
|
||||
QByteArray m_buffer;
|
||||
int m_bufferPos;
|
||||
quint32 m_blockIndex;
|
||||
bool m_eof;
|
||||
};
|
||||
|
||||
#endif // KEEPASSX_HASHEDBLOCKSTREAM_H
|
72
src/streams/LayeredStream.cpp
Normal file
72
src/streams/LayeredStream.cpp
Normal file
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* 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 "LayeredStream.h"
|
||||
|
||||
LayeredStream::LayeredStream(QIODevice* baseDevice)
|
||||
: QIODevice(baseDevice)
|
||||
, m_baseDevice(baseDevice)
|
||||
{
|
||||
connect(baseDevice, SIGNAL(aboutToClose()), SLOT(closeStream()));
|
||||
}
|
||||
|
||||
bool LayeredStream::isSequential() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
QString LayeredStream::errorString() const
|
||||
{
|
||||
return m_baseDevice->errorString();
|
||||
}
|
||||
|
||||
bool LayeredStream::open(QIODevice::OpenMode mode)
|
||||
{
|
||||
// filter out all other modes
|
||||
mode &= QIODevice::ReadWrite;
|
||||
|
||||
if (mode == QIODevice::ReadWrite) {
|
||||
qWarning("Reading and writing at the same time is not supported.");
|
||||
return false;
|
||||
}
|
||||
else if (openMode() & mode) {
|
||||
return true;
|
||||
}
|
||||
else if (!(m_baseDevice->openMode() & mode)) {
|
||||
qWarning("Base device is not opened correctly.");
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
setOpenMode(mode | QIODevice::Unbuffered);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
qint64 LayeredStream::readData(char* data, qint64 maxSize)
|
||||
{
|
||||
return m_baseDevice->read(data, maxSize);
|
||||
}
|
||||
|
||||
qint64 LayeredStream::writeData(const char* data, qint64 maxSize)
|
||||
{
|
||||
return m_baseDevice->write(data, maxSize);
|
||||
}
|
||||
|
||||
void LayeredStream::closeStream()
|
||||
{
|
||||
close();
|
||||
}
|
44
src/streams/LayeredStream.h
Normal file
44
src/streams/LayeredStream.h
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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_LAYEREDSTREAM_H
|
||||
#define KEEPASSX_LAYEREDSTREAM_H
|
||||
|
||||
#include <QtCore/QIODevice>
|
||||
|
||||
class LayeredStream : public QIODevice
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit LayeredStream(QIODevice* baseDevice);
|
||||
|
||||
bool isSequential() const;
|
||||
virtual QString errorString() const;
|
||||
bool open(QIODevice::OpenMode mode);
|
||||
|
||||
protected:
|
||||
qint64 readData(char* data, qint64 maxSize);
|
||||
qint64 writeData(const char* data, qint64 maxSize);
|
||||
|
||||
QIODevice* m_baseDevice;
|
||||
|
||||
private Q_SLOTS:
|
||||
void closeStream();
|
||||
};
|
||||
|
||||
#endif // KEEPASSX_LAYEREDSTREAM_H
|
92
src/streams/SymmetricCipherStream.cpp
Normal file
92
src/streams/SymmetricCipherStream.cpp
Normal file
@ -0,0 +1,92 @@
|
||||
/*
|
||||
* 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 "SymmetricCipherStream.h"
|
||||
|
||||
SymmetricCipherStream::SymmetricCipherStream(QIODevice* baseDevice, SymmetricCipher::Algorithm algo, SymmetricCipher::Mode mode,
|
||||
SymmetricCipher::Direction direction, const QByteArray& key, const QByteArray& iv)
|
||||
: LayeredStream(baseDevice)
|
||||
, m_bufferPos(0)
|
||||
, m_eof(false)
|
||||
{
|
||||
m_cipher = new SymmetricCipher(algo, mode, direction, key, iv);
|
||||
}
|
||||
|
||||
bool SymmetricCipherStream::reset()
|
||||
{
|
||||
m_buffer.clear();
|
||||
m_bufferPos = 0;
|
||||
m_cipher->reset();
|
||||
return true;
|
||||
}
|
||||
|
||||
qint64 SymmetricCipherStream::readData(char* data, qint64 maxSize)
|
||||
{
|
||||
// TODO m_eof is probably wrong and should be removed
|
||||
if (m_eof) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
qint64 bytesRemaining = maxSize;
|
||||
qint64 offset = 0;
|
||||
|
||||
while (bytesRemaining > 0) {
|
||||
if (m_bufferPos == m_buffer.size()) {
|
||||
if (!readBlock()) {
|
||||
return maxSize - bytesRemaining;
|
||||
}
|
||||
}
|
||||
|
||||
int bytesToCopy = qMin(bytesRemaining, static_cast<qint64>(m_buffer.size() - m_bufferPos));
|
||||
|
||||
memcpy(data + offset, m_buffer.constData() + m_bufferPos, bytesToCopy);
|
||||
|
||||
offset += bytesToCopy;
|
||||
m_bufferPos += bytesToCopy;
|
||||
bytesRemaining -= bytesToCopy;
|
||||
}
|
||||
|
||||
return maxSize;
|
||||
}
|
||||
|
||||
bool SymmetricCipherStream::readBlock()
|
||||
{
|
||||
m_buffer = m_baseDevice->read(m_cipher->blockSize());
|
||||
|
||||
if (m_buffer.size() != m_cipher->blockSize()) {
|
||||
m_eof = true;
|
||||
// TODO check if m_buffer.size()!=0
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
m_cipher->processInPlace(m_buffer);
|
||||
m_bufferPos = 0;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
qint64 SymmetricCipherStream::writeData(const char* data, qint64 maxSize)
|
||||
{
|
||||
// TODO implement
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool SymmetricCipherStream::writeBlock()
|
||||
{
|
||||
// TODO implement
|
||||
return false;
|
||||
}
|
49
src/streams/SymmetricCipherStream.h
Normal file
49
src/streams/SymmetricCipherStream.h
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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_SYMMETRICCIPHERSTREAM_H
|
||||
#define KEEPASSX_SYMMETRICCIPHERSTREAM_H
|
||||
|
||||
#include <QtCore/QByteArray>
|
||||
|
||||
#include "LayeredStream.h"
|
||||
#include "crypto/SymmetricCipher.h"
|
||||
|
||||
class SymmetricCipherStream : public LayeredStream
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SymmetricCipherStream(QIODevice* baseDevice, SymmetricCipher::Algorithm algo, SymmetricCipher::Mode mode,
|
||||
SymmetricCipher::Direction direction, const QByteArray& key, const QByteArray& iv);
|
||||
bool reset();
|
||||
|
||||
protected:
|
||||
qint64 readData(char* data, qint64 maxSize);
|
||||
qint64 writeData(const char* data, qint64 maxSize);
|
||||
|
||||
private:
|
||||
bool readBlock();
|
||||
bool writeBlock();
|
||||
|
||||
SymmetricCipher* m_cipher;
|
||||
QByteArray m_buffer;
|
||||
int m_bufferPos;
|
||||
bool m_eof;
|
||||
};
|
||||
|
||||
#endif // KEEPASSX_SYMMETRICCIPHERSTREAM_H
|
Loading…
Reference in New Issue
Block a user