2010-09-13 21:24:36 +00:00
|
|
|
/*
|
|
|
|
|
* 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"
|
|
|
|
|
|
2018-03-31 20:01:30 +00:00
|
|
|
SymmetricCipherStream::SymmetricCipherStream(QIODevice* baseDevice,
|
|
|
|
|
SymmetricCipher::Algorithm algo,
|
|
|
|
|
SymmetricCipher::Mode mode,
|
|
|
|
|
SymmetricCipher::Direction direction)
|
2010-11-21 22:11:16 +00:00
|
|
|
: LayeredStream(baseDevice)
|
2015-05-09 17:47:53 +00:00
|
|
|
, m_cipher(new SymmetricCipher(algo, mode, direction))
|
2010-11-21 22:11:16 +00:00
|
|
|
, m_bufferPos(0)
|
|
|
|
|
, m_bufferFilling(false)
|
|
|
|
|
, m_error(false)
|
2017-11-12 13:02:23 +00:00
|
|
|
, m_isInitialized(false)
|
2015-07-20 19:02:57 +00:00
|
|
|
, m_dataWritten(false)
|
2019-02-18 13:26:56 +00:00
|
|
|
, m_streamCipher(false)
|
2010-09-13 21:24:36 +00:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2010-09-25 10:41:00 +00:00
|
|
|
SymmetricCipherStream::~SymmetricCipherStream()
|
|
|
|
|
{
|
|
|
|
|
close();
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-09 17:47:53 +00:00
|
|
|
bool SymmetricCipherStream::init(const QByteArray& key, const QByteArray& iv)
|
|
|
|
|
{
|
2017-11-12 13:02:23 +00:00
|
|
|
m_isInitialized = m_cipher->init(key, iv);
|
|
|
|
|
if (!m_isInitialized) {
|
2015-05-09 17:47:53 +00:00
|
|
|
setErrorString(m_cipher->errorString());
|
|
|
|
|
}
|
2017-11-12 13:02:23 +00:00
|
|
|
m_streamCipher = m_cipher->blockSize() == 1;
|
|
|
|
|
return m_isInitialized;
|
2015-05-09 17:47:53 +00:00
|
|
|
}
|
|
|
|
|
|
2015-07-20 19:02:57 +00:00
|
|
|
void SymmetricCipherStream::resetInternalState()
|
|
|
|
|
{
|
|
|
|
|
m_buffer.clear();
|
|
|
|
|
m_bufferPos = 0;
|
|
|
|
|
m_bufferFilling = false;
|
|
|
|
|
m_error = false;
|
|
|
|
|
m_dataWritten = false;
|
|
|
|
|
m_cipher->reset();
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-09 17:47:53 +00:00
|
|
|
bool SymmetricCipherStream::open(QIODevice::OpenMode mode)
|
|
|
|
|
{
|
2017-11-12 13:02:23 +00:00
|
|
|
return m_isInitialized && LayeredStream::open(mode);
|
2015-05-09 17:47:53 +00:00
|
|
|
}
|
|
|
|
|
|
2010-09-13 21:24:36 +00:00
|
|
|
bool SymmetricCipherStream::reset()
|
|
|
|
|
{
|
2015-07-20 19:02:57 +00:00
|
|
|
if (isWritable() && m_dataWritten) {
|
2012-05-08 19:33:21 +00:00
|
|
|
if (!writeBlock(true)) {
|
2010-09-18 15:13:28 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-20 19:02:57 +00:00
|
|
|
resetInternalState();
|
2010-09-18 15:13:28 +00:00
|
|
|
|
2010-09-13 21:24:36 +00:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2010-09-16 16:20:46 +00:00
|
|
|
void SymmetricCipherStream::close()
|
2010-09-13 21:24:36 +00:00
|
|
|
{
|
2015-07-20 19:02:57 +00:00
|
|
|
if (isWritable() && m_dataWritten) {
|
2012-05-08 19:33:21 +00:00
|
|
|
writeBlock(true);
|
2010-09-13 21:24:36 +00:00
|
|
|
}
|
|
|
|
|
|
2015-07-20 19:02:57 +00:00
|
|
|
resetInternalState();
|
|
|
|
|
|
2010-09-16 16:20:46 +00:00
|
|
|
LayeredStream::close();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
qint64 SymmetricCipherStream::readData(char* data, qint64 maxSize)
|
|
|
|
|
{
|
|
|
|
|
Q_ASSERT(maxSize >= 0);
|
|
|
|
|
|
2012-05-08 19:33:21 +00:00
|
|
|
if (m_error) {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2010-09-13 21:24:36 +00:00
|
|
|
qint64 bytesRemaining = maxSize;
|
|
|
|
|
qint64 offset = 0;
|
|
|
|
|
|
|
|
|
|
while (bytesRemaining > 0) {
|
2010-09-16 16:20:46 +00:00
|
|
|
if ((m_bufferPos == m_buffer.size()) || m_bufferFilling) {
|
2010-09-13 21:24:36 +00:00
|
|
|
if (!readBlock()) {
|
2012-05-08 19:33:21 +00:00
|
|
|
if (m_error) {
|
|
|
|
|
return -1;
|
2018-03-31 20:01:30 +00:00
|
|
|
} else {
|
2012-05-08 19:33:21 +00:00
|
|
|
return maxSize - bytesRemaining;
|
|
|
|
|
}
|
2010-09-13 21:24:36 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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()
|
|
|
|
|
{
|
2015-07-20 17:54:18 +00:00
|
|
|
QByteArray newData;
|
|
|
|
|
|
2010-09-16 16:20:46 +00:00
|
|
|
if (m_bufferFilling) {
|
2017-11-12 13:02:23 +00:00
|
|
|
newData.resize(blockSize() - m_buffer.size());
|
2018-03-31 20:01:30 +00:00
|
|
|
} else {
|
2015-07-20 17:54:18 +00:00
|
|
|
m_buffer.clear();
|
2017-11-12 13:02:23 +00:00
|
|
|
newData.resize(blockSize());
|
2015-07-20 17:54:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int readResult = m_baseDevice->read(newData.data(), newData.size());
|
|
|
|
|
|
|
|
|
|
if (readResult == -1) {
|
|
|
|
|
m_error = true;
|
|
|
|
|
setErrorString(m_baseDevice->errorString());
|
|
|
|
|
return false;
|
2017-11-12 13:02:23 +00:00
|
|
|
} else {
|
2015-07-20 17:54:18 +00:00
|
|
|
m_buffer.append(newData.left(readResult));
|
2010-09-16 16:20:46 +00:00
|
|
|
}
|
2010-09-13 21:24:36 +00:00
|
|
|
|
2017-11-12 13:02:23 +00:00
|
|
|
if (!m_streamCipher && m_buffer.size() != blockSize()) {
|
2010-09-16 16:20:46 +00:00
|
|
|
m_bufferFilling = true;
|
2010-09-13 21:24:36 +00:00
|
|
|
return false;
|
2018-03-31 20:01:30 +00:00
|
|
|
} else {
|
2015-05-09 17:47:53 +00:00
|
|
|
if (!m_cipher->processInPlace(m_buffer)) {
|
|
|
|
|
m_error = true;
|
|
|
|
|
setErrorString(m_cipher->errorString());
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2010-09-13 21:24:36 +00:00
|
|
|
m_bufferPos = 0;
|
2010-09-16 16:20:46 +00:00
|
|
|
m_bufferFilling = false;
|
2012-05-08 19:33:21 +00:00
|
|
|
|
|
|
|
|
if (m_baseDevice->atEnd()) {
|
2017-11-12 13:02:23 +00:00
|
|
|
if (!m_streamCipher) {
|
|
|
|
|
// PKCS7 padding
|
|
|
|
|
quint8 padLength = m_buffer.at(m_buffer.size() - 1);
|
|
|
|
|
|
|
|
|
|
if (padLength == blockSize()) {
|
|
|
|
|
Q_ASSERT(m_buffer == QByteArray(blockSize(), blockSize()));
|
|
|
|
|
// full block with just padding: discard
|
|
|
|
|
m_buffer.clear();
|
|
|
|
|
return false;
|
|
|
|
|
} else if (padLength > blockSize()) {
|
|
|
|
|
// invalid padding
|
|
|
|
|
m_error = true;
|
|
|
|
|
setErrorString("Invalid padding.");
|
|
|
|
|
return false;
|
|
|
|
|
} else {
|
|
|
|
|
Q_ASSERT(m_buffer.right(padLength) == QByteArray(padLength, padLength));
|
|
|
|
|
// resize buffer to strip padding
|
|
|
|
|
m_buffer.resize(blockSize() - padLength);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
return m_buffer.size() > 0;
|
2012-05-08 19:33:21 +00:00
|
|
|
}
|
2018-03-31 20:01:30 +00:00
|
|
|
} else {
|
2012-05-08 19:33:21 +00:00
|
|
|
return true;
|
|
|
|
|
}
|
2010-09-13 21:24:36 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
qint64 SymmetricCipherStream::writeData(const char* data, qint64 maxSize)
|
|
|
|
|
{
|
2010-09-16 16:20:46 +00:00
|
|
|
Q_ASSERT(maxSize >= 0);
|
|
|
|
|
|
|
|
|
|
if (m_error) {
|
2012-05-08 19:33:21 +00:00
|
|
|
return -1;
|
2010-09-16 16:20:46 +00:00
|
|
|
}
|
|
|
|
|
|
2015-07-20 19:02:57 +00:00
|
|
|
m_dataWritten = true;
|
2010-09-16 16:20:46 +00:00
|
|
|
qint64 bytesRemaining = maxSize;
|
|
|
|
|
qint64 offset = 0;
|
|
|
|
|
|
|
|
|
|
while (bytesRemaining > 0) {
|
2017-11-12 13:02:23 +00:00
|
|
|
int bytesToCopy = qMin(bytesRemaining, static_cast<qint64>(blockSize() - m_buffer.size()));
|
2010-09-16 16:20:46 +00:00
|
|
|
|
|
|
|
|
m_buffer.append(data + offset, bytesToCopy);
|
|
|
|
|
|
|
|
|
|
offset += bytesToCopy;
|
|
|
|
|
bytesRemaining -= bytesToCopy;
|
|
|
|
|
|
2017-11-12 13:02:23 +00:00
|
|
|
if (m_buffer.size() == blockSize()) {
|
2012-05-08 19:33:21 +00:00
|
|
|
if (!writeBlock(false)) {
|
2010-09-16 16:20:46 +00:00
|
|
|
if (m_error) {
|
|
|
|
|
return -1;
|
2018-03-31 20:01:30 +00:00
|
|
|
} else {
|
2010-09-16 16:20:46 +00:00
|
|
|
return maxSize - bytesRemaining;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return maxSize;
|
2010-09-13 21:24:36 +00:00
|
|
|
}
|
|
|
|
|
|
2012-05-08 19:33:21 +00:00
|
|
|
bool SymmetricCipherStream::writeBlock(bool lastBlock)
|
2010-09-13 21:24:36 +00:00
|
|
|
{
|
2017-11-12 13:02:23 +00:00
|
|
|
Q_ASSERT(m_streamCipher || lastBlock || (m_buffer.size() == blockSize()));
|
2015-07-20 19:02:57 +00:00
|
|
|
|
2017-11-12 13:02:23 +00:00
|
|
|
if (lastBlock && !m_streamCipher) {
|
2010-09-18 15:13:28 +00:00
|
|
|
// PKCS7 padding
|
2017-11-12 13:02:23 +00:00
|
|
|
int padLen = blockSize() - m_buffer.size();
|
2012-05-08 19:33:21 +00:00
|
|
|
for (int i = 0; i < padLen; i++) {
|
2010-09-16 16:20:46 +00:00
|
|
|
m_buffer.append(static_cast<char>(padLen));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-09 17:47:53 +00:00
|
|
|
if (!m_cipher->processInPlace(m_buffer)) {
|
|
|
|
|
m_error = true;
|
|
|
|
|
setErrorString(m_cipher->errorString());
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2010-09-16 16:20:46 +00:00
|
|
|
|
|
|
|
|
if (m_baseDevice->write(m_buffer) != m_buffer.size()) {
|
|
|
|
|
m_error = true;
|
2015-07-20 17:53:17 +00:00
|
|
|
setErrorString(m_baseDevice->errorString());
|
2010-09-16 16:20:46 +00:00
|
|
|
return false;
|
2018-03-31 20:01:30 +00:00
|
|
|
} else {
|
2010-09-16 16:20:46 +00:00
|
|
|
m_buffer.clear();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2010-09-13 21:24:36 +00:00
|
|
|
}
|
2017-11-12 13:02:23 +00:00
|
|
|
|
2018-03-31 20:01:30 +00:00
|
|
|
int SymmetricCipherStream::blockSize() const
|
|
|
|
|
{
|
2017-11-12 13:02:23 +00:00
|
|
|
if (m_streamCipher) {
|
|
|
|
|
return 1024;
|
|
|
|
|
}
|
2018-01-06 16:06:51 +00:00
|
|
|
return m_cipher->blockSize();
|
2017-11-12 13:02:23 +00:00
|
|
|
}
|