[prev in list] [next in list] [prev in thread] [next in thread]
List: kde-commits
Subject: [KSecretService] 291840b: Add a QIODevice operating on a
From: Michael Leupold <lemma () confuego ! org>
Date: 2010-11-09 19:14:24
Message-ID: 20101109191424.B7B90A60D1 () git ! kde ! org
[Download RAW message or body]
A backend/tests/securebuffertest.h [License: LGPL]
A backend/tests/securebuffertest.cpp [License: LGPL]
A backend/securebuffer_p.h [License: LGPL]
A backend/securebuffer.h [License: LGPL]
A backend/securebuffer.cpp [License: LGPL]
commit 291840b3a4acc1537940eddcf7138a0d7cd7be1f
Author: Michael Leupold <lemma@confuego.org>
Date: Tue May 11 21:24:18 2010 +0000
Add a QIODevice operating on a QCA::SecureArray named SecureBuffer. Blatantly \
copy-pasted from QBuffer. Unit-test as well. Thank you Nokia.
CCMAIL: dario.freddi@collabora.co.uk
svn path=/trunk/playground/base/ksecretservice/; revision=1125638
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c048115..c140252 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -24,6 +24,7 @@ SET (ksecretservice_backend_SRCS
backend/temporarycollection.cpp
backend/temporarycollectionmanager.cpp
backend/temporaryitem.cpp
+ backend/securebuffer.cpp
)
KDE4_ADD_LIBRARY (ksecretservicebackend STATIC ${ksecretservice_backend_SRCS})
diff --git a/backend/securebuffer.cpp b/backend/securebuffer.cpp
new file mode 100644
index 0000000..d30f909
--- /dev/null
+++ b/backend/securebuffer.cpp
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2010 Michael Leupold <lemma@confuego.org>
+ *
+ * Large portions of the design and implementation have been copied
+ * from QBuffer (qbuffer.cpp):
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * All rights reserved.
+ * Contact: Nokia Corporation (qt-info@nokia.com)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include "securebuffer.h"
+#include "securebuffer_p.h"
+
+SecureBuffer::SecureBuffer(QObject *parent)
+ : QIODevice(parent), d(new SecureBufferPrivate(this))
+{
+ d->buf = &d->defaultBuf;
+ connect(d, SIGNAL(bytesWritten(qint64)), SIGNAL(bytesWritten(qint64)));
+ connect(d, SIGNAL(readyRead()), SIGNAL(readyRead()));
+}
+
+SecureBuffer::SecureBuffer(QCA::SecureArray *buf, QObject *parent)
+ : QIODevice(parent), d(new SecureBufferPrivate(this))
+{
+ d->buf = buf ? buf : &d->defaultBuf;
+ connect(d, SIGNAL(bytesWritten(qint64)), SIGNAL(bytesWritten(qint64)));
+ connect(d, SIGNAL(readyRead()), SIGNAL(readyRead()));
+}
+
+SecureBuffer::~SecureBuffer()
+{
+}
+
+QCA::SecureArray &SecureBuffer::buffer()
+{
+ return *d->buf;
+}
+
+const QCA::SecureArray &SecureBuffer::buffer() const
+{
+ return *d->buf;
+}
+
+void SecureBuffer::setBuffer(QCA::SecureArray *secureArray) const
+{
+ if (isOpen()) {
+ qWarning("SecureBuffer::setBuffer: Buffer is open");
+ return;
+ }
+ if (secureArray) {
+ d->buf = secureArray;
+ } else {
+ d->buf = &d->defaultBuf;
+ }
+ d->defaultBuf.clear();
+ d->ioIndex = 0;
+}
+
+bool SecureBuffer::open(QIODevice::OpenMode mode)
+{
+ // always operate in Unbuffered mode for security reasons.
+ mode |= QIODevice::Unbuffered;
+
+ if ((mode & QIODevice::Append) == Append) {
+ mode |= QIODevice::WriteOnly;
+ }
+ setOpenMode(mode);
+ if (!(isReadable() || isWritable())) {
+ qWarning("SecureBuffer::open: File access not specified");
+ return false;
+ }
+
+ if ((mode & QIODevice::Truncate) == QIODevice::Truncate) {
+ d->buf->clear();
+ }
+ if ((mode & QIODevice::Append) == QIODevice::Append) {
+ seek(d->buf->size());
+ } else {
+ seek(0);
+ }
+
+ return true;
+}
+
+void SecureBuffer::close()
+{
+ QIODevice::close();
+}
+
+qint64 SecureBuffer::size() const
+{
+ return qint64(d->buf->size());
+}
+
+qint64 SecureBuffer::pos() const
+{
+ return QIODevice::pos();
+}
+
+bool SecureBuffer::seek(qint64 pos)
+{
+ if (pos > d->buf->size() && isWritable()) {
+ if (seek(d->buf->size())) {
+ const qint64 gapSize = pos - d->buf->size();
+ if (write(QByteArray(gapSize, 0)) != gapSize) {
+ qWarning("SecureBuffer::seek: Unable to fill gap");
+ return false;
+ }
+ } else {
+ return false;
+ }
+ } else if (pos > d->buf->size() || pos < 0) {
+ qWarning("SecureBuffer::seek: Invalid pos: %d", int(pos));
+ return false;
+ }
+ d->ioIndex = int(pos);
+ return QIODevice::seek(pos);
+}
+
+bool SecureBuffer::atEnd() const
+{
+ return QIODevice::atEnd();
+}
+
+bool SecureBuffer::canReadLine() const
+{
+ if (!isOpen()) {
+ return false;
+ }
+
+ return ::memchr(d->buf->constData() + int(pos()), '\n', int(size())) != 0 || \
QIODevice::canReadLine(); +}
+
+void SecureBuffer::connectNotify(const char *signal)
+{
+ if (strcmp(signal + 1, "readyRead()") == 0 ||
+ strcmp(signal + 1, "bytesWritten(qint64)") == 0) {
+ d->signalConnectionCount++;
+ }
+}
+
+void SecureBuffer::disconnectNotify(const char *signal)
+{
+ if (!signal || strcmp(signal + 1, "readyRead()") == 0 ||
+ strcmp(signal + 1, "bytesWritten(qint64)") == 0) {
+ d->signalConnectionCount--;
+ }
+}
+
+qint64 SecureBuffer::readData(char *data, qint64 maxlen)
+{
+ if ((maxlen = qMin(maxlen, qint64(d->buf->size()) - d->ioIndex)) <= 0) {
+ return qint64(0);
+ }
+ memcpy(data, d->buf->constData() + d->ioIndex, maxlen);
+ d->ioIndex += int(maxlen);
+ return maxlen;
+}
+
+qint64 SecureBuffer::writeData(const char *data, qint64 len)
+{
+ int extraBytes = d->ioIndex + len - d->buf->size();
+ if (extraBytes > 0) { // exceeds current buffer size
+ int newSize = d->buf->size() + extraBytes;
+ d->buf->resize(newSize);
+ if (d->buf->size() != newSize) { // error resizing
+ qWarning("SecureBuffer::writeData: Memory allocation error");
+ return -1;
+ }
+ }
+
+ memcpy(d->buf->data() + d->ioIndex, (uchar *)data, int(len));
+ d->ioIndex += int(len);
+
+ d->writtenSinceLastEmit += len;
+ if (d->signalConnectionCount && !d->signalsEmitted && !signalsBlocked()) {
+ d->signalsEmitted = true;
+ QMetaObject::invokeMethod(d, "_q_emitSignals", Qt::QueuedConnection);
+ }
+
+ return len;
+}
+
+#include "securebuffer.moc"
+#include "securebuffer_p.moc"
diff --git a/backend/securebuffer.h b/backend/securebuffer.h
new file mode 100644
index 0000000..417d1f4
--- /dev/null
+++ b/backend/securebuffer.h
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2010 Michael Leupold <lemma@confuego.org>
+ *
+ * Large portions of the design and implementation have been copied
+ * from QBuffer (qbuffer.h):
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * All rights reserved.
+ * Contact: Nokia Corporation (qt-info@nokia.com)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef SECUREBUFFER_H
+#define SECUREBUFFER_H
+
+#include <QtCore/QIODevice>
+#include <QtCrypto/QtCrypto>
+
+class SecureBufferPrivate;
+
+/**
+ * SecureBuffer allows to access a QCA::SecureArray using the QIODevice
+ * interface.
+ */
+class SecureBuffer : public QIODevice
+{
+ Q_OBJECT
+
+public:
+ /**
+ Construct a new secure buffer with the given \a parent
+ allocating a new SecureArray as its internal storage.
+
+ \param parent the parent object of this SecureBuffer
+ */
+ explicit SecureBuffer(QObject *parent = 0);
+
+ /**
+ Construct a new secure buffer using \a buf as its internal
+ storage.
+
+ \param buf SecureArray to use as internal storage
+ \param parent the parent object of this SecureBuffer
+ */
+ SecureBuffer(QCA::SecureArray *buf, QObject *parent = 0);
+
+ /**
+ Destroys the secure buffer.
+ */
+ ~SecureBuffer();
+
+ /**
+ Returns a reference to the SecureBuffer's internal buffer.
+
+ \return a reference to the internal buffer
+ \sa setBuffer(), data()
+ */
+ QCA::SecureArray &buffer();
+
+ /**
+ Returns a constant reference to the SecureBuffer's internal
+ buffer.
+
+ \return a constant reference to the internal buffer
+ \sa setBuffer(), data()
+ */
+ const QCA::SecureArray &buffer() const;
+
+ /**
+ Make the SecureBuffer use the SecureArray pointed to by \a
+ secureArray as its internal storage. The SecureBuffer does
+ not take ownership of the SecureArray. The caller is responsible
+ that the SecureArray remains valid as long as the SecureBuffer
+ is not destroyed.
+
+ Does nothing if isOpen() is true.
+
+ If you write something into the buffer, \a secureArray will
+ be modified (size as well as contents).
+
+ \param secureArray the SecureArray to use as this buffer's
+ internal storage
+ */
+ void setBuffer(QCA::SecureArray *secureArray) const;
+
+ /**
+ Open the SecureBuffer and set its \a OpenMode to mode.
+
+ \param openMode the mode to open the SecureBuffer with
+ \return true if opening succeeded, false else
+ */
+ bool open(QIODevice::OpenMode mode);
+
+ /**
+ Closes the SecureBuffer.
+ */
+ void close();
+
+ /**
+ Returns the size of the underlying SecureArray.
+
+ \return the size of the internal buffer
+ */
+ qint64 size() const;
+
+ /**
+ Return the position the data is written to or read from.
+
+ \return the current position inside the internal buffer
+ */
+ qint64 pos() const;
+
+ /**
+ Set the current read/write position to \a pos.
+
+ \param pos the position to set
+ */
+ bool seek(qint64 pos);
+
+ /**
+ Check if the current position is at the end of the buffer.
+
+ \return true if the current position is at the end of the
+ internal buffer, false if it isn't
+ */
+ bool atEnd() const;
+
+ /**
+ Check if a complete line can be read from the buffer.
+
+ \return true if a complete line can be read from the buffer,
+ false if not
+ */
+ bool canReadLine() const;
+
+protected:
+ /**
+ Called when a connection is made to one of the buffer's signals.
+ */
+ void connectNotify(const char*);
+
+ /**
+ Called when a slot is disconnected from one of the buffer's signals.
+ */
+ void disconnectNotify(const char*);
+
+ /**
+ Read data from the buffer.
+
+ \param data array to store the data read into
+ \param maxlen maximum number of bytes to read
+ \return actual number of bytes read or -1 in case of an error
+ */
+ qint64 readData(char *data, qint64 maxlen);
+
+ /**
+ Write data into the buffer.
+
+ \param data array to read the data to be written from
+ \param len number of bytes to write
+ \return actual number of bytes written or -1 in case of an error
+ */
+ qint64 writeData(const char *data, qint64 len);
+
+private:
+ SecureBufferPrivate *d;
+
+ // TODO: does this work?
+ Q_DISABLE_COPY(SecureBuffer)
+};
+
+#endif
diff --git a/backend/securebuffer_p.h b/backend/securebuffer_p.h
new file mode 100644
index 0000000..1932ce5
--- /dev/null
+++ b/backend/securebuffer_p.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2010 Michael Leupold <lemma@confuego.org>
+ *
+ * Large portions of the design and implementation have been copied
+ * from QBuffer (qbuffer.h):
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * All rights reserved.
+ * Contact: Nokia Corporation (qt-info@nokia.com)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef SECUREBUFFER_PRIVATE_H
+#define SECUREBUFFER_PRIVATE_H
+
+#include <QtCore/QObject>
+
+class SecureBuffer;
+
+class SecureBufferPrivate : public QObject
+{
+ Q_OBJECT
+
+public:
+ SecureBufferPrivate(SecureBuffer *parent)
+ : q(parent), buf(0), ioIndex(0), writtenSinceLastEmit(0), \
signalConnectionCount(0), + signalsEmitted(false)
+ {}
+ ~SecureBufferPrivate() {}
+
+ SecureBuffer *q;
+
+ QCA::SecureArray *buf;
+ QCA::SecureArray defaultBuf;
+ int ioIndex;
+
+ qint64 writtenSinceLastEmit;
+ int signalConnectionCount;
+ bool signalsEmitted;
+
+public Q_SLOTS:
+ void _q_emitSignals() {
+ emit bytesWritten(writtenSinceLastEmit);
+ writtenSinceLastEmit = 0;
+ emit readyRead();
+ signalsEmitted = false;
+ }
+
+Q_SIGNALS:
+ void bytesWritten(qint64 len);
+ void readyRead();
+};
+
+#endif
diff --git a/backend/tests/CMakeLists.txt b/backend/tests/CMakeLists.txt
index 1d8a69c..be14404 100644
--- a/backend/tests/CMakeLists.txt
+++ b/backend/tests/CMakeLists.txt
@@ -4,3 +4,8 @@ KDE4_ADD_EXECUTABLE (ksecretservice_backend_test backendtest.cpp \
../../secrettoo TARGET_LINK_LIBRARIES (ksecretservice_backend_test \
ksecretservicebackend ${QT_QTTEST_LIBRARIES})
ADD_TEST (BackendItemCollectionHandlingTest ksecretservice_backend_test)
+
+KDE4_ADD_EXECUTABLE (securebuffer_test securebuffertest.cpp)
+TARGET_LINK_LIBRARIES (securebuffer_test ksecretservicebackend \
${QT_QTTEST_LIBRARIES}) +
+ADD_TEST (SecureBufferTest securebuffer_test)
diff --git a/backend/tests/securebuffertest.cpp b/backend/tests/securebuffertest.cpp
new file mode 100644
index 0000000..c9e1e22
--- /dev/null
+++ b/backend/tests/securebuffertest.cpp
@@ -0,0 +1,489 @@
+/*
+ * Copyright (C) 2010 Michael Leupold <lemma@confuego.org>
+ *
+ * Large portions of the design and implementation have been copied
+ * from the QBuffer unit-test (tst_qbuffer.cpp):
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * All rights reserved.
+ * Contact: Nokia Corporation (qt-info@nokia.com)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include "securebuffertest.h"
+
+#include <QtTest/QtTest>
+
+#include <securebuffer.h>
+
+SecureBufferTest::SecureBufferTest()
+{
+ qRegisterMetaType<QCA::SecureArray>();
+}
+
+// some status() tests, too
+void SecureBufferTest::readBlock()
+{
+// QTest::ignoreMessage(QtWarningMsg, "QIODevice::read: File not open");
+// QTest::ignoreMessage(QtWarningMsg, "QIODevice::read: Read operation not \
permitted"); +
+ const int arraySize = 10;
+ char a[arraySize];
+ SecureBuffer b;
+ QCOMPARE(b.read(a, arraySize), (qint64) -1); // not opened
+ QVERIFY(b.atEnd());
+
+ QCA::SecureArray ba;
+ ba.resize(arraySize);
+ b.setBuffer(&ba);
+ b.open(QIODevice::WriteOnly);
+ QTest::ignoreMessage(QtWarningMsg, "QIODevice::read: WriteOnly device");
+ QCOMPARE(b.read(a, arraySize), (qint64) -1); // no read access
+ b.close();
+
+ b.open(QIODevice::ReadOnly);
+ QCOMPARE(b.read(a, arraySize), (qint64) arraySize);
+ QVERIFY(b.atEnd());
+
+ // up to 3.0.x reading beyond the end was an error while ok
+ // this has been made consistent with other QIODevice sub classes in 3.1
+ QCOMPARE(b.read(a, 1), qint64(0));
+ QVERIFY(b.atEnd());
+
+ // read in two chunks
+ b.close();
+ b.open(QIODevice::ReadOnly);
+ QCOMPARE(b.read(a, arraySize/2), (qint64) arraySize/2);
+ QCOMPARE(b.read(a + arraySize/2, arraySize - arraySize/2),
+ (qint64)(arraySize - arraySize/2));
+ QVERIFY(b.atEnd());
+}
+
+void SecureBufferTest::readBlockPastEnd()
+{
+ QCA::SecureArray arr(4096 + 3616, 'd');
+ SecureBuffer buf(&arr);
+
+ buf.open(QIODevice::ReadOnly);
+ char dummy[4096];
+
+ buf.read(1);
+
+ QCOMPARE(buf.read(dummy, 4096), qint64(4096));
+ QCOMPARE(buf.read(dummy, 4096), qint64(3615));
+ QVERIFY(buf.atEnd());
+}
+
+void SecureBufferTest::writeBlock_data()
+{
+ QTest::addColumn<QString>("str");
+
+ QTest::newRow( "small_bytearray" ) << QString("Test");
+ QTest::newRow( "large_bytearray" ) << QString("Lorem ipsum dolor sit amet, \
consectetur adipisicing elit," + "sed do eiusmod tempor \
incididunt ut labore et dolore magna aliqua. Ut enim ad" + \
"minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea" + \
"commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit" + \
"esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat" + \
"non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." + \
"Lorem ipsum dolor sit amet, consectetur adipisicing elit," + \
"sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad" + \
"minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea" + \
"commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit" + \
"esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat" + \
"non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." + \
"Lorem ipsum dolor sit amet, consectetur adipisicing elit," + \
"sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad" + \
"minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea" + \
"commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit" + \
"esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat" + \
"non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." + \
"Lorem ipsum dolor sit amet, consectetur adipisicing elit," + \
"sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad" + \
"minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea" + \
"commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit" + \
"esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat" + \
"non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." + \
"Lorem ipsum dolor sit amet, consectetur adipisicing elit," + \
"sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad" + \
"minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea" + \
"commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit" + \
"esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat" + \
"non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." + \
"Lorem ipsum dolor sit amet, consectetur adipisicing elit," + \
"sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad" + \
"minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea" + \
"commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit" + \
"esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat" + \
"non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." + \
"Lorem ipsum dolor sit amet, consectetur adipisicing elit," + \
"sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad" + \
"minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea" + \
"commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit" + \
"esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat" + \
"non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." + \
"Lorem ipsum dolor sit amet, consectetur adipisicing elit," + \
"sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad" + \
"minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea" + \
"commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit" + \
"esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat" + \
"non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." + \
"Lorem ipsum dolor sit amet, consectetur adipisicing elit," + \
"sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad" + \
"minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea" + \
"commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit" + \
"esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat" + \
"non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." + \
"Lorem ipsum dolor sit amet, consectetur adipisicing elit," + \
"sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad" + \
"minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea" + \
"commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit" + \
"esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat" + \
"non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." + \
"Lorem ipsum dolor sit amet, consectetur adipisicing elit," + \
"sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad" + \
"minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea" + \
"commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit" + \
"esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat" + \
"non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." + \
"Lorem ipsum dolor sit amet, consectetur adipisicing elit," + \
"sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad" + \
"minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea" + \
"commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit" + \
"esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat" + \
"non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." + \
"Lorem ipsum dolor sit amet, consectetur adipisicing elit," + \
"sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad" + \
"minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea" + \
"commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit" + \
"esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat" + \
"non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." + \
"Lorem ipsum dolor sit amet, consectetur adipisicing elit," + \
"sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad" + \
"minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea" + \
"commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit" + \
"esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat" + \
"non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." + \
"Lorem ipsum dolor sit amet, consectetur adipisicing elit," + \
"sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad" + \
"minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea" + \
"commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit" + \
"esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat" + \
"non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."); +}
+
+void SecureBufferTest::writeBlock()
+{
+ QFETCH( QString, str );
+
+ QCA::SecureArray ba;
+ SecureBuffer buf( &ba );
+ buf.open(QIODevice::ReadWrite);
+ QByteArray data = str.toLatin1();
+ QCOMPARE(buf.write( data.constData(), data.size() ), qint64(data.size()));
+
+ QCOMPARE(buf.buffer(), QCA::SecureArray(data));
+}
+
+void SecureBufferTest::seek()
+{
+ SecureBuffer buffer;
+ buffer.open(QIODevice::WriteOnly);
+ QCOMPARE(buffer.size(), qint64(0));
+ QCOMPARE(buffer.pos(), qint64(0));
+ const qint64 pos = 10;
+ QVERIFY(buffer.seek(pos));
+ QCOMPARE(buffer.size(), pos);
+}
+
+void SecureBufferTest::seekTest_data()
+{
+ writeBlock_data();
+}
+
+#define DO_VALID_SEEK(position) { \
+ char c; \
+ QVERIFY(buf.seek(qint64(position))); \
+ QCOMPARE(buf.pos(), qint64(position)); \
+ QVERIFY(buf.getChar(&c)); \
+ QCOMPARE(QChar(c), str.at(qint64(position))); \
+}
+#define DO_INVALID_SEEK(position) { \
+ qint64 prev_pos = buf.pos(); \
+ QVERIFY(!buf.seek(qint64(position))); \
+ QCOMPARE(buf.pos(), prev_pos); /* position should not be changed */ \
\ +}
+
+void SecureBufferTest::seekTest()
+{
+ QFETCH(QString, str);
+
+ QCA::SecureArray ba;
+ SecureBuffer buf(&ba);
+#if 0
+ QCOMPARE(buf.pos(), qint64(-1));
+#endif
+ buf.open(QIODevice::ReadWrite);
+ QCOMPARE(buf.pos(), qint64(0));
+
+ QByteArray data = str.toLatin1();
+ QCOMPARE(buf.write( data.constData(), data.size() ), qint64(data.size()));
+
+ QTest::ignoreMessage(QtWarningMsg, "SecureBuffer::seek: Invalid pos: -1");
+ DO_INVALID_SEEK(-1);
+
+ DO_VALID_SEEK(0);
+ DO_VALID_SEEK(str.size() - 1);
+ QVERIFY(buf.atEnd());
+ DO_VALID_SEEK(str.size() / 2);
+
+ // Special case: valid to seek one position past the buffer.
+ // Its then legal to write, but not read.
+ {
+ char c = 'a';
+ QVERIFY(buf.seek(qint64(str.size())));
+ QCOMPARE(buf.read(&c, qint64(1)), qint64(0));
+ QCOMPARE(c, 'a');
+ QCOMPARE(buf.write(&c, qint64(1)), qint64(1));
+ }
+
+ // Special case 2: seeking to an arbitrary position beyond the buffer \
auto-expands it + // (see Task 184730)
+ {
+ char c;
+ const int offset = 1;
+ Q_ASSERT(offset > 0); // any positive integer will do
+ const qint64 pos = buf.size() + offset;
+ QVERIFY(buf.seek(pos));
+ QCOMPARE(buf.pos(), pos);
+ QVERIFY(!buf.getChar(&c));
+ QVERIFY(buf.seek(pos - 1));
+ QVERIFY(buf.getChar(&c));
+ QCOMPARE(c, buf.buffer().at(pos - 1));
+ QVERIFY(buf.seek(pos));
+ QVERIFY(buf.putChar(c));
+ }
+}
+
+void SecureBufferTest::read_rawdata()
+{
+ static const unsigned char mydata[] = {
+ 0x01, 0x00, 0x03, 0x84, 0x78, 0x9c, 0x3b, 0x76,
+ 0xec, 0x18, 0xc3, 0x31, 0x0a, 0xf1, 0xcc, 0x99,
+ 0x6d, 0x5b
+ };
+
+ QCA::SecureArray data = QByteArray::fromRawData((const char *)mydata, \
sizeof(mydata)); + SecureBuffer buffer(&data);
+ buffer.open(QIODevice::ReadOnly);
+ QDataStream in(&buffer);
+ quint8 ch;
+ for (int i = 0; i < (int)sizeof(mydata); ++i) {
+ QVERIFY(!buffer.atEnd());
+ in >> ch;
+ QVERIFY(ch == (quint8)mydata[i]);
+ }
+ QVERIFY(buffer.atEnd());
+}
+
+void SecureBufferTest::isSequential()
+{
+ SecureBuffer buf;
+ QVERIFY(!buf.isSequential());
+}
+
+void SecureBufferTest::signalTest_data()
+{
+ QTest::addColumn<QByteArray>("sample");
+
+ QTest::newRow("empty") << QByteArray();
+ QTest::newRow("size 1") << QByteArray("1");
+ QTest::newRow("size 2") << QByteArray("11");
+ QTest::newRow("size 100") << QByteArray(100, '1');
+}
+
+void SecureBufferTest::signalTest()
+{
+ QFETCH(QByteArray, sample);
+
+ totalBytesWritten = 0;
+
+ SecureBuffer buf;
+ buf.open(QIODevice::WriteOnly);
+
+ buf.buffer().resize(sample.size() * 10);
+ connect(&buf, SIGNAL(readyRead()), this, SLOT(readyReadSlot()));
+ connect(&buf, SIGNAL(bytesWritten(qint64)), this, \
SLOT(bytesWrittenSlot(qint64))); +
+ for (int i = 0; i < 10; ++i) {
+ gotReadyRead = false;
+ QCOMPARE(buf.write(sample), qint64(sample.size()));
+ if (sample.size() > 0) {
+ QTestEventLoop::instance().enterLoop(5);
+ if (QTestEventLoop::instance().timeout())
+ QFAIL("Timed out when waiting for readyRead()");
+ QCOMPARE(totalBytesWritten, qint64(sample.size() * (i + 1)));
+ QVERIFY(gotReadyRead);
+ } else {
+ QCOMPARE(totalBytesWritten, qint64(0));
+ QVERIFY(!gotReadyRead);
+ }
+ }
+}
+
+void SecureBufferTest::readyReadSlot()
+{
+ gotReadyRead = true;
+ QTestEventLoop::instance().exitLoop();
+}
+
+void SecureBufferTest::bytesWrittenSlot(qint64 written)
+{
+ totalBytesWritten += written;
+}
+
+void SecureBufferTest::isClosedAfterClose()
+{
+ SecureBuffer buffer;
+ buffer.open(SecureBuffer::ReadOnly);
+ QVERIFY(buffer.isOpen());
+ buffer.close();
+ QVERIFY(!buffer.isOpen());
+}
+
+void SecureBufferTest::readLine_data()
+{
+ QTest::addColumn<QCA::SecureArray>("src");
+ QTest::addColumn<int>("maxlen");
+ QTest::addColumn<QByteArray>("expected");
+
+ QTest::newRow("1") << QCA::SecureArray("line1\nline2\n") << 1024
+ << QByteArray("line1\n");
+ QTest::newRow("2") << QCA::SecureArray("hi there") << 1024
+ << QByteArray("hi there");
+ QTest::newRow("3") << QCA::SecureArray("l\n") << 3 << QByteArray("l\n");
+ QTest::newRow("4") << QCA::SecureArray("l\n") << 2 << QByteArray("l");
+}
+
+void SecureBufferTest::readLine()
+{
+ QFETCH(QCA::SecureArray, src);
+ QFETCH(int, maxlen);
+ QFETCH(QByteArray, expected);
+
+ SecureBuffer buf;
+ buf.setBuffer(&src);
+ char *result = new char[maxlen + 1];
+ result[maxlen] = '\0';
+
+ QVERIFY(buf.open(QIODevice::ReadOnly));
+
+ qint64 bytes_read = buf.readLine(result, maxlen);
+
+ QCOMPARE(bytes_read, qint64(expected.size()));
+ QCOMPARE(QByteArray(result), expected);
+
+ buf.close();
+ delete[] result;
+
+}
+
+void SecureBufferTest::canReadLine_data()
+{
+ QTest::addColumn<QCA::SecureArray>("src");
+ QTest::addColumn<bool>("expected");
+
+ QTest::newRow("1") << QCA::SecureArray("no newline") << false;
+ QTest::newRow("2") << QCA::SecureArray("two \n lines\n") << true;
+ QTest::newRow("3") << QCA::SecureArray("\n") << true;
+ QTest::newRow("4") << QCA::SecureArray() << false;
+}
+
+void SecureBufferTest::canReadLine()
+{
+ QFETCH(QCA::SecureArray, src);
+ QFETCH(bool, expected);
+
+ SecureBuffer buf;
+ buf.setBuffer(&src);
+ QVERIFY(!buf.canReadLine());
+ QVERIFY(buf.open(QIODevice::ReadOnly));
+ QCOMPARE(buf.canReadLine(), expected);
+}
+
+void SecureBufferTest::atEnd()
+{
+ SecureBuffer buffer;
+ buffer.open(SecureBuffer::Append);
+ buffer.write("heisann");
+ buffer.close();
+
+ buffer.open(SecureBuffer::ReadOnly);
+ buffer.seek(buffer.size());
+ char c;
+ QVERIFY(!buffer.getChar(&c));
+ QCOMPARE(buffer.read(&c, 1), qint64(0));
+}
+
+void SecureBufferTest::readLineBoundaries()
+{
+ QByteArray line = "This is a line\n";
+ SecureBuffer buffer;
+ buffer.open(QIODevice::ReadWrite);
+ while (buffer.size() < 16384)
+ buffer.write(line);
+
+/*
+ buffer.seek(0);
+ QFile out1("out1.txt");
+ out1.open(QFile::WriteOnly);
+ out1.write(buffer.readAll());
+ out1.close();
+*/
+ buffer.seek(0);
+
+ char c;
+ buffer.getChar(&c);
+ buffer.ungetChar(c);
+
+ QFile out2("out2.txt");
+ out2.open(QFile::WriteOnly);
+ while (!buffer.atEnd())
+ out2.write(buffer.readLine());
+
+ out2.close();
+ out2.remove();
+}
+
+void SecureBufferTest::writeAfterSecureArrayResize()
+{
+ SecureBuffer buffer;
+ QVERIFY(buffer.open(QIODevice::WriteOnly));
+
+ buffer.write(QByteArray().fill('a', 1000));
+ QCOMPARE(buffer.buffer().size(), 1000);
+
+ // resize the QByteArray behind SecureBuffer's back
+ buffer.buffer().clear();
+ buffer.seek(0);
+ QCOMPARE(buffer.buffer().size(), 0);
+
+ buffer.write(QByteArray().fill('b', 1000));
+ QCOMPARE(buffer.buffer().size(), 1000);
+}
+
+QTEST_MAIN(SecureBufferTest)
+
+#include "securebuffertest.moc"
diff --git a/backend/tests/securebuffertest.h b/backend/tests/securebuffertest.h
new file mode 100644
index 0000000..ed7c678
--- /dev/null
+++ b/backend/tests/securebuffertest.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2010 Michael Leupold <lemma@confuego.org>
+ *
+ * Large portions of the design and implementation have been copied
+ * from the QBuffer unit-test (tst_qbuffer.cpp):
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * All rights reserved.
+ * Contact: Nokia Corporation (qt-info@nokia.com)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef SECUREBUFFERTEST_H
+#define SECUREBUFFERTEST_H
+
+#include <QtCore/QObject>
+#include <QtCore/QMetaType>
+#include <QtCrypto/QtCrypto>
+
+Q_DECLARE_METATYPE(QCA::SecureArray)
+
+class SecureBufferTest : public QObject
+{
+ Q_OBJECT
+
+public:
+ SecureBufferTest();
+
+private slots:
+ void readBlock();
+ void readBlockPastEnd();
+ void writeBlock_data();
+ void writeBlock();
+ void seek();
+ void seekTest_data();
+ void seekTest();
+ void read_rawdata();
+ void isSequential();
+ void signalTest_data();
+ void signalTest();
+ void isClosedAfterClose();
+ void readLine_data();
+ void readLine();
+ void canReadLine_data();
+ void canReadLine();
+ void atEnd();
+ void readLineBoundaries();
+ void writeAfterSecureArrayResize();
+
+protected slots:
+ void readyReadSlot();
+ void bytesWrittenSlot(qint64 written);
+
+private:
+ qint64 totalBytesWritten;
+ bool gotReadyRead;
+
+ QCA::Initializer init;
+};
+
+#endif
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic