[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