mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2025-07-27 08:45:18 -04:00
Implement reading encrypted kdbx files.
This commit is contained in:
parent
bb6ae3a014
commit
9f282928e8
22 changed files with 1290 additions and 71 deletions
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…
Add table
Add a link
Reference in a new issue