Commit deeeb595 authored by Albert Vaca Cintora's avatar Albert Vaca Cintora

Implemented encryption in NetworkPackage using QCA2

Fixed some bugs in the pairing process state machine
Keys are now stored in base64 in KConfig (was storing non-allowed chars)
Updated NetworkPackage tests to include encryption
Increased networkpackage version 1 -> 2
parent 13589dfc
......@@ -18,4 +18,4 @@ add_subdirectory(kcm)
#add_subdirectory(kioslave)
add_subdirectory(plasmoid)
add_subdirectory(test)
add_subdirectory(tests)
add_subdirectory(plugins)
find_package (QJSON REQUIRED)
find_package (QCA2 REQUIRED)
include_directories(
${QJSON_INCLUDE_DIR}
${QCA2_INCLUDE_DIR}
......@@ -21,13 +26,8 @@ set(kded_kdeconnect_SRCS
device.cpp
)
add_subdirectory(plugins)
kde4_add_plugin(kded_kdeconnect ${kded_kdeconnect_SRCS})
find_package (QJSON REQUIRED)
find_package (QCA2 REQUIRED)
target_link_libraries(kded_kdeconnect
${KDE4_KDECORE_LIBS}
${KDE4_KDEUI_LIBS}
......
......@@ -57,10 +57,10 @@ Daemon::Daemon(QObject *parent, const QList<QVariant>&)
//http://delta.affinix.com/docs/qca/rsatest_8cpp-example.html
QCA::PrivateKey privateKey = QCA::KeyGenerator().createRSA(1024);
config->group("myself").writeEntry("privateKey", privateKey.toDER());
config->group("myself").writeEntry("privateKey", privateKey.toDER().toByteArray().toBase64());
QCA::PublicKey publicKey = privateKey.toPublicKey();
config->group("myself").writeEntry("publicKey", publicKey.toDER());
config->group("myself").writeEntry("publicKey", publicKey.toDER().toBase64());
//TODO: Store key in a PEM file instead (KStandardDirs::locate("appdata", "private.pem"))
}
......
......@@ -30,7 +30,7 @@ Device::Device(const QString& id)
m_deviceName = name;
const QByteArray& key = data.readEntry<QByteArray>("publicKey",QByteArray());
m_publicKey = QCA::RSAPublicKey::fromDER(key);
m_publicKey = QCA::RSAPublicKey::fromDER(QByteArray::fromBase64(key));
m_pairStatus = Device::Paired;
......@@ -57,12 +57,12 @@ Device::~Device()
}
bool Device::hasPlugin(const QString& name)
bool Device::hasPlugin(const QString& name) const
{
return m_plugins.contains(name);
}
QStringList Device::loadedPlugins()
QStringList Device::loadedPlugins() const
{
return m_plugins.keys();
}
......@@ -94,8 +94,8 @@ void Device::reloadPlugins()
} else {
KdeConnectPlugin* plugin = loader->instantiatePluginForDevice(pluginName, this);
connect(this, SIGNAL(receivedPackage(const NetworkPackage&)),
plugin, SLOT(receivePackage(const NetworkPackage&)));
connect(this, SIGNAL(receivedPackage(NetworkPackage)),
plugin, SLOT(receivePackage(NetworkPackage)));
newPluginMap[pluginName] = plugin;
}
......@@ -118,25 +118,16 @@ void Device::reloadPlugins()
}
//TODO
QSslKey myPrivateKey() {
KSharedConfigPtr config = KSharedConfig::openConfig("kdeconnectrc");
const QString& key = config->group("myself").readEntry<QString>("privateKey",QString());
QSslKey privateKey(key.toAscii(), QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey);
qDebug() << "Valid public key:" << !privateKey.isNull();
return privateKey;
}
void Device::requestPair()
{
if (m_pairStatus != NotPaired) {
if (m_pairStatus == Paired) {
Q_EMIT pairingFailed(i18n("Already paired"));
return;
}
if (m_pairStatus == Device::PairRequested) {
Q_EMIT pairingFailed(i18n("Pairing already requested for this device"));
return;
}
if (!isReachable()) {
Q_EMIT pairingFailed(i18n("Device not reachable"));
return;
......@@ -206,9 +197,10 @@ void Device::addLink(DeviceLink* link)
//the old one before this is called), so we do not have to worry about destroying old links.
//Actually, we should not destroy them or the provider will store an invalid ref!
connect(link, SIGNAL(receivedPackage(NetworkPackage)), this, SLOT(privateReceivedPackage(NetworkPackage)));
connect(link, SIGNAL(receivedPackage(NetworkPackage)),
this, SLOT(privateReceivedPackage(NetworkPackage)));
qSort(m_deviceLinks.begin(),m_deviceLinks.end(),lessThan);
qSort(m_deviceLinks.begin(), m_deviceLinks.end(), lessThan);
if (m_deviceLinks.size() == 1) {
reloadPlugins(); //Will load the plugins
......@@ -237,12 +229,12 @@ void Device::removeLink(DeviceLink* link)
}
}
bool Device::sendPackage(const NetworkPackage& np) const
bool Device::sendPackage(NetworkPackage& np)
{
//Maybe we could block here any package that is not an identity or a pairing package
if (isPaired()) {
np.encrypt(m_publicKey);
} else {
//Maybe we could block here any package that is not an identity or a pairing package to prevent sending non encrypted data
}
Q_FOREACH(DeviceLink* dl, m_deviceLinks) {
......@@ -256,21 +248,27 @@ bool Device::sendPackage(const NetworkPackage& np) const
void Device::privateReceivedPackage(const NetworkPackage& np)
{
if (np.type() == PACKAGE_TYPE_PAIR) {
qDebug() << "Pair package";
bool wantsPair = np.get<bool>("pair");
if (wantsPair == isPaired()) {
qDebug() << "Already" << (wantsPair? "paired":"unpaired");
if (m_pairStatus == Device::PairRequested) {
m_pairStatus = Device::NotPaired;
pairingTimer.stop();
Q_EMIT pairingFailed(i18n("Canceled by other peer"));
}
return;
}
KSharedConfigPtr config = KSharedConfig::openConfig("kdeconnectrc");
if (wantsPair) {
const QByteArray& key = np.get<QByteArray>("publicKey");
m_publicKey = QCA::RSAPublicKey::fromDER(QByteArray::fromBase64(key));
if (m_pairStatus == Device::PairRequested) { //We started pairing
qDebug() << "Pair answer";
......@@ -279,10 +277,10 @@ void Device::privateReceivedPackage(const NetworkPackage& np)
pairingTimer.stop();
//Store as trusted device
const QByteArray& key = np.get<QByteArray>("publicKey");
KSharedConfigPtr config = KSharedConfig::openConfig("kdeconnectrc");
config->group("devices").group(id()).writeEntry("publicKey",key);
config->group("devices").group(id()).writeEntry("name",name());
m_publicKey = QCA::RSAPublicKey::fromDER(key);
m_publicKey = QCA::RSAPublicKey::fromDER(QByteArray::fromBase64(key));
Q_EMIT pairingSuccesful();
......@@ -290,9 +288,6 @@ void Device::privateReceivedPackage(const NetworkPackage& np)
qDebug() << "Pair request";
const QByteArray& key = np.get<QByteArray>("publicKey");
m_publicKey = QCA::RSAPublicKey::fromDER(key);
KNotification* notification = new KNotification("pingReceived"); //KNotification::Persistent
notification->setPixmap(KIcon("dialog-information").pixmap(48, 48));
notification->setComponentData(KComponentData("kdeconnect", "kdeconnect"));
......@@ -309,10 +304,12 @@ void Device::privateReceivedPackage(const NetworkPackage& np)
qDebug() << "Unpair request";
if (m_pairStatus == PairRequested) {
m_pairStatus = Device::NotPaired;
pairingTimer.stop();
Q_EMIT pairingFailed(i18n("Canceled by other peer"));
} else if (m_pairStatus == Paired) {
unpair();
}
unpair();
}
......@@ -323,8 +320,26 @@ void Device::privateReceivedPackage(const NetworkPackage& np)
} else {
//Forward signal
Q_EMIT receivedPackage(np);
if (!np.isEncrypted()) {
//TODO: The other side doesn't know that we are already paired
qDebug() << "Warning: A paired device is sending an unencrypted package";
//Forward package
Q_EMIT receivedPackage(np);
} else {
//TODO: Do not read the key every time
KSharedConfigPtr config = KSharedConfig::openConfig("kdeconnectrc");
const QByteArray& key = config->group("myself").readEntry<QByteArray>("privateKey",QByteArray());
QCA::PrivateKey privateKey = QCA::PrivateKey::fromDER(QByteArray::fromBase64(key));
//Emit decrypted package
NetworkPackage decryptedNp("");
np.decrypt(privateKey, &decryptedNp);
Q_EMIT receivedPackage(decryptedNp);
}
}
......@@ -348,7 +363,7 @@ void Device::acceptPairing()
}
//Store as trusted device
config->group("devices").group(id()).writeEntry("publicKey", m_publicKey.toDER());
config->group("devices").group(id()).writeEntry("publicKey", m_publicKey.toDER().toBase64());
config->group("devices").group(id()).writeEntry("name", name());
reloadPlugins(); //This will load plugins
......
......@@ -71,14 +71,14 @@ public:
Q_SCRIPTABLE QStringList availableLinks() const;
Q_SCRIPTABLE bool isReachable() const { return !m_deviceLinks.empty(); }
Q_SCRIPTABLE QStringList loadedPlugins();
Q_SCRIPTABLE bool hasPlugin(const QString& name);
Q_SCRIPTABLE QStringList loadedPlugins() const;
Q_SCRIPTABLE bool hasPlugin(const QString& name) const;
//Send and receive
Q_SIGNALS:
void receivedPackage(const NetworkPackage& np);
void receivedPackage(const NetworkPackage& np) const;
public Q_SLOTS:
virtual bool sendPackage(const NetworkPackage& np) const;
virtual bool sendPackage(NetworkPackage& np);
//Dbus operations
public Q_SLOTS:
......@@ -110,6 +110,7 @@ private:
QMap<QString, KdeConnectPlugin*> m_plugins;
QTimer pairingTimer;
};
Q_DECLARE_METATYPE(Device*)
......
......@@ -39,10 +39,10 @@ public:
const QString& deviceId() { return mDeviceId; }
LinkProvider* provider() { return mLinkProvider; }
virtual bool sendPackage(const NetworkPackage& np) const = 0;
virtual bool sendPackage(const NetworkPackage& np) = 0;
signals:
void receivedPackage(const NetworkPackage& np) const;
Q_SIGNALS:
void receivedPackage(const NetworkPackage& np);
private:
QString mDeviceId;
......
......@@ -51,7 +51,7 @@ LanDeviceLink::LanDeviceLink(const QString& d, LinkProvider* a, QTcpSocket* sock
this, SLOT(dataReceived()));
}
bool LanDeviceLink::sendPackage(const NetworkPackage& np) const
bool LanDeviceLink::sendPackage(const NetworkPackage& np)
{
int written = mSocket->write(np.serialize());
return written != -1;
......
......@@ -38,7 +38,7 @@ class LanDeviceLink
public:
LanDeviceLink(const QString& d, LinkProvider* a, QTcpSocket* socket);
bool sendPackage(const NetworkPackage& np) const;
bool sendPackage(const NetworkPackage& np);
private Q_SLOTS:
void dataReceived();
......
......@@ -28,7 +28,7 @@ LoopbackDeviceLink::LoopbackDeviceLink(const QString& deviceId, LoopbackLinkProv
}
bool LoopbackDeviceLink::sendPackage(const NetworkPackage& toSend) const
bool LoopbackDeviceLink::sendPackage(const NetworkPackage& toSend)
{
NetworkPackage toReceive("");
NetworkPackage::unserialize(toSend.serialize(), &toReceive);
......
......@@ -18,8 +18,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ECHODEVICELINK_H
#define ECHODEVICELINK_H
#ifndef LOOPBACKDEVICELINK_H
#define LOOPBACKDEVICELINK_H
#include "devicelink.h"
class LoopbackLinkProvider;
......@@ -31,8 +32,8 @@ class LoopbackDeviceLink
public:
LoopbackDeviceLink(const QString& d, LoopbackLinkProvider* a);
bool sendPackage(const NetworkPackage& np) const;
bool sendPackage(const NetworkPackage& np);
};
#endif // ECHODEVICELINK_H
#endif
......@@ -55,7 +55,7 @@ Q_SIGNALS:
//NOTE: The provider will to destroy the DeviceLink when it's no longer accessible,
// and every user should listen to the destroyed signal to remove its references.
// That's the reason because there is no "onConnectionLost".
void onConnectionReceived(const NetworkPackage& identityPackage, DeviceLink*);
void onConnectionReceived(const NetworkPackage& identityPackage, DeviceLink*) const;
};
......
......@@ -32,15 +32,15 @@
#include <qjson/serializer.h>
#include <qjson/qobjecthelper.h>
#include "encryptednetworkpackage.h"
const static int CURRENT_PACKAGE_VERSION = 1;
const static int CURRENT_PACKAGE_VERSION = 2;
NetworkPackage::NetworkPackage(const QString& type)
{
mId = QDateTime::currentMSecsSinceEpoch();
mId = QString::number(QDateTime::currentMSecsSinceEpoch());
mType = type;
mBody = QVariantMap();
mVersion = CURRENT_PACKAGE_VERSION;
mEncrypted = false;
}
QByteArray NetworkPackage::serialize() const
......@@ -68,8 +68,8 @@ QByteArray NetworkPackage::serialize() const
void NetworkPackage::unserialize(const QByteArray& a, NetworkPackage* np)
{
qDebug() << "Unserialize:" << a;
qDebug() << "Unserialize: " << a;
//Json -> QVariant
QJson::Parser parser;
bool ok;
......@@ -80,11 +80,6 @@ void NetworkPackage::unserialize(const QByteArray& a, NetworkPackage* np)
}
//QVariant -> Object
//NetworkPackage np;
//QJSon json(a);
//np.mId = json["id"];
//np.mType = json["type"];
//np.mBody = json["body"];
QJson::QObjectHelper::qvariant2qobject(variant,np);
if (np->version() > CURRENT_PACKAGE_VERSION) {
......@@ -93,6 +88,34 @@ void NetworkPackage::unserialize(const QByteArray& a, NetworkPackage* np)
}
void NetworkPackage::encrypt (QCA::PublicKey& key)
{
qDebug() << key.toDER() << key.canEncrypt();
QByteArray serialized = serialize();
QByteArray data = key.encrypt(serialized, QCA::EME_PKCS1v15).toByteArray();
mId = QString::number(QDateTime::currentMSecsSinceEpoch());
mType = "kdeconnect.encrypted";
mBody = QVariantMap();
mBody["data"] = data.toBase64();
mVersion = CURRENT_PACKAGE_VERSION;
mEncrypted = true;
}
void NetworkPackage::decrypt (QCA::PrivateKey& key, NetworkPackage* out) const
{
QByteArray encryptedJson = QByteArray::fromBase64(get<QByteArray>("data"));
QCA::SecureArray decryptedJson;
key.decrypt(encryptedJson, &decryptedJson, QCA::EME_PKCS1v15);
unserialize(decryptedJson.toByteArray(), out);
}
void NetworkPackage::createIdentityPackage(NetworkPackage* np)
{
KSharedConfigPtr config = KSharedConfig::openConfig("kdeconnectrc");
......@@ -106,11 +129,4 @@ void NetworkPackage::createIdentityPackage(NetworkPackage* np)
//qDebug() << "createIdentityPackage" << np->serialize();
}
EncryptedNetworkPackage NetworkPackage::encrypt ( const QSslKey& key ) const
{
QByteArray serialized = serialize();
return EncryptedNetworkPackage();
}
......@@ -27,7 +27,7 @@
#include <QString>
#include <QVariant>
#include <QStringList>
#include <QSslKey>
#include <QtCrypto>
#include <qjson/parser.h>
......@@ -38,24 +38,29 @@ class EncryptedNetworkPackage;
class NetworkPackage : public QObject
{
Q_OBJECT
Q_PROPERTY( long id READ id WRITE setId )
Q_PROPERTY( QString id READ id WRITE setId )
Q_PROPERTY( QString type READ type WRITE setType )
Q_PROPERTY( QVariantMap body READ body WRITE setBody )
Q_PROPERTY( int version READ version WRITE setVersion )
Q_PROPERTY( bool isEncrypted READ isEncrypted WRITE setEncrypted )
public:
NetworkPackage(const QString& type);
static void unserialize(const QByteArray&, NetworkPackage*);
static void unserialize(const QByteArray& json, NetworkPackage* out);
QByteArray serialize() const;
void encrypt(QCA::PublicKey& key);
void decrypt(QCA::PrivateKey& key, NetworkPackage* out) const;
static void createIdentityPackage(NetworkPackage*);
long id() const { return mId; }
QString id() const { return mId; }
const QString& type() const { return mType; }
QVariantMap& body() { return mBody; }
int version() const { return mVersion; }
bool isEncrypted() const { return mEncrypted; }
//Get and set info from body. Note that id, type and version can not be accessed through these.
template<typename T> T get(const QString& key, const T& defaultValue = default_arg<T>::get()) const {
......@@ -65,16 +70,16 @@ public:
bool has(const QString& key) const { return mBody.contains(key); }
EncryptedNetworkPackage encrypt(const QSslKey& key) const;
private:
void setId(long id) { mId = id; }
void setId(QString id) { mId = id; }
void setType(const QString& t) { mType = t; }
void setBody(const QVariantMap& b) { mBody = b; }
void setVersion(int v) { mVersion = v; }
void setEncrypted(bool b) { mEncrypted = b; }
long mId;
QString mId;
QString mType;
bool mEncrypted;
QVariantMap mBody; //json in the Android side
int mVersion;
......
......@@ -2,6 +2,11 @@ find_package(KDE4 REQUIRED)
find_package(QJSON REQUIRED)
find_package(QCA2 REQUIRED)
include_directories(
${QJSON_INCLUDE_DIR}
${QCA2_INCLUDE_DIR}
)
include(KDE4Defaults)
include_directories(${KDE4_INCLUDES})
......
......@@ -2,6 +2,11 @@ find_package(KDE4 REQUIRED)
find_package(QJSON REQUIRED)
find_package(QCA2 REQUIRED)
include_directories(
${QJSON_INCLUDE_DIR}
${QCA2_INCLUDE_DIR}
)
include(KDE4Defaults)
include_directories(${KDE4_INCLUDES})
......
......@@ -2,6 +2,11 @@ find_package(KDE4 REQUIRED)
find_package(QJSON REQUIRED)
find_package(QCA2 REQUIRED)
include_directories(
${QJSON_INCLUDE_DIR}
${QCA2_INCLUDE_DIR}
)
include(KDE4Defaults)
include_directories(${KDE4_INCLUDES})
......
......@@ -49,6 +49,10 @@ public Q_SLOTS:
private:
Device* mDevice;
// The Initializer object sets things up, and also does cleanup when it goes out of scope
// Since the plugins use their own memory, they need their own initializer in order to send encrypted packages
QCA::Initializer init;
};
#endif
......@@ -2,6 +2,11 @@ find_package(KDE4 REQUIRED)
find_package(QJSON REQUIRED)
find_package(QCA2 REQUIRED)
include_directories(
${QJSON_INCLUDE_DIR}
${QCA2_INCLUDE_DIR}
)
include(KDE4Defaults)
include_directories(${KDE4_INCLUDES})
......
......@@ -2,6 +2,11 @@ find_package(KDE4 REQUIRED)
find_package(QJSON REQUIRED)
find_package(QCA2 REQUIRED)
include_directories(
${QJSON_INCLUDE_DIR}
${QCA2_INCLUDE_DIR}
)
include(KDE4Defaults)
include_directories(${KDE4_INCLUDES})
......
......@@ -2,6 +2,11 @@ find_package(KDE4 REQUIRED)
find_package(QJSON REQUIRED)
find_package(QCA2 REQUIRED)
include_directories(
${QJSON_INCLUDE_DIR}
${QCA2_INCLUDE_DIR}
)
include(KDE4Defaults)
include_directories(${KDE4_INCLUDES})
......
......@@ -2,6 +2,11 @@ find_package(KDE4 REQUIRED)
find_package(QJSON REQUIRED)
find_package(QCA2 REQUIRED)
include_directories(
${QJSON_INCLUDE_DIR}
${QCA2_INCLUDE_DIR}
)
include(KDE4Defaults)
include_directories(${KDE4_INCLUDES})
......
......@@ -2,6 +2,11 @@ find_package(KDE4 REQUIRED)
find_package(QJSON REQUIRED)
find_package(QCA2 REQUIRED)
include_directories(
${QJSON_INCLUDE_DIR}
${QCA2_INCLUDE_DIR}
)
include(KDE4Defaults)
include_directories(${KDE4_INCLUDES})
......
set(kded_kdeconnect_tests_SRCS
../daemon/networkpackage.cpp
backendtests.cpp
)
kde4_add_unit_test(kded_kdeconnect_tests ${kded_kdeconnect_tests_SRCS})
target_link_libraries(kded_kdeconnect_tests
${KDE4_KDECORE_LIBS}
${KDE4_KDEUI_LIBS}
kdnssd
qjson
${QT_QTTEST_LIBRARY}
${QT_QTNETWORK_LIBRARY}
)
add_test(kded_kdeconnect_tests ${CMAKE_CURRENT_BINARY_DIR}/kded_kdeconnect_tests)
set( EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR} )
find_package(QJSON REQUIRED)
find_package(QCA2 REQUIRED)
include_directories(
${QJSON_INCLUDE_DIR}
${QCA2_INCLUDE_DIR}
)
set(kdeconnect_tests_SRCS
../daemon/networkpackage.cpp
networkpackagetests.cpp
)
kde4_add_unit_test(kdeconnect_tests ${kdeconnect_tests_SRCS})
target_link_libraries(kdeconnect_tests
${KDE4_KDECORE_LIBS}
${KDE4_KDEUI_LIBS}
${QJSON_LIBRARIES}
${QCA2_LIBRARIES}
${QT_QTTEST_LIBRARY}
${QT_QTNETWORK_LIBRARY}
)
......@@ -18,21 +18,21 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "backendtests.h"
#include "networkpackagetests.h"
#include "../daemon/networkpackage.h"
#include <qtest_kde.h>
#include <QtTest>
QTEST_KDEMAIN(BackendTests, NoGUI);
QTEST_KDEMAIN(NetworkPackageTests, NoGUI);
void BackendTests::initTestCase()
void NetworkPackageTests::initTestCase()
{
// Called before the first testfunction is executed
}
void BackendTests::dummyTest()
void NetworkPackageTests::dummyTest()
{
QDate date;
date.setYMD( 1967, 3, 11 );
......@@ -41,7 +41,7 @@ void BackendTests::dummyTest()
QCOMPARE( QDate::longMonthName(date.month()), QString("March") );
}
void BackendTests::networkPackageTest()
void NetworkPackageTests::networkPackageTest()
{
NetworkPackage np("com.test");
......@@ -64,10 +64,10 @@ void BackendTests::networkPackageTest()
QCOMPARE( np.version(), np2.version() );
QCOMPARE( np.body(), np2.body() );
QByteArray json("{ \"id\": 123, \"type\": \"test\", \"body\": { \"testing\": true }, \"version\": 3 }");
QByteArray json("{ \"id\": \"123\", \"type\": \"test\", \"body\": { \"testing\": true }, \"version\": 3 }");
//qDebug() << json;
NetworkPackage::unserialize(json,&np2);
QCOMPARE( np2.id(), long(123) );
QCOMPARE( np2.id(), QString("123") );
QCOMPARE( np2.version(), 3 );
QCOMPARE( (np2.get<bool>("testing")), true );
QCOMPARE( (np2.get<bool>("not_testing")), false );
......@@ -78,22 +78,53 @@ void BackendTests::networkPackageTest()
//QtTest::ignoreMessage(QtDebugMsg, "Unserialization error: 1 \"syntax error, unexpected string\"");
//QCOMPARE( np2.version(), -1 );
}
void NetworkPackageTests::networkPackageEncryptionTest()
{
NetworkPackage original("com.test");
original.set("hello","hola");
NetworkPackage copy("");
NetworkPackage::unserialize(original.serialize(), &copy);
NetworkPackage decrypted("");
QCA::Initializer init;
QCA::PrivateKey privateKey = QCA::KeyGenerator().createRSA(1024);
QCA::PublicKey publicKey = privateKey.toPublicKey();
//Encrypt and decrypt np
QCOMPARE( original.isEncrypted(), false );
original.encrypt(publicKey);
QCOMPARE( original.isEncrypted(), true );
original.decrypt(privateKey, &decrypted);
QCOMPARE( original.isEncrypted(), true );
QCOMPARE( decrypted.isEncrypted(), false );
//np should be equal top np2
QCOMPARE( decrypted.id(), copy.id() );
QCOMPARE( decrypted.type(), copy.type() );
QCOMPARE( decrypted.version(), copy.version() );
QCOMPARE( decrypted.body(), copy.body() );