From 892385f3fc259c2464f8254e80d20ab684e9ff83 Mon Sep 17 00:00:00 2001 From: Albert Vaca Date: Mon, 2 Sep 2013 13:26:26 +0200 Subject: [PATCH] Simplified NetworkPackage format Now protocol version is only sent once (in the identity package) Removed "isEncrypted" bit, using type "kdeconnect.encrypted" instead. NetworkPackage's decrypt and unserialize return false when find problems Updated tests. --- kded/daemon.cpp | 2 +- kded/device.cpp | 24 ++++++++++++------ kded/linkproviders/lanlinkprovider.cpp | 8 +++--- kded/networkpackage.cpp | 35 +++++++++++--------------- kded/networkpackage.h | 32 ++++++++++------------- kded/networkpackagetypes.h | 1 + tests/networkpackagetests.cpp | 19 ++++++-------- 7 files changed, 57 insertions(+), 64 deletions(-) diff --git a/kded/daemon.cpp b/kded/daemon.cpp index b7f6cb443..873d1018c 100644 --- a/kded/daemon.cpp +++ b/kded/daemon.cpp @@ -152,7 +152,7 @@ void Daemon::onNewDeviceLink(const NetworkPackage& identityPackage, DeviceLink* } Q_EMIT deviceVisibilityChanged(id, true); - + } void Daemon::onDeviceReachableStatusChanged() diff --git a/kded/device.cpp b/kded/device.cpp index 7979ea647..4d2cf804e 100644 --- a/kded/device.cpp +++ b/kded/device.cpp @@ -44,6 +44,12 @@ Device::Device(const NetworkPackage& identityPackage, DeviceLink* dl) m_deviceId = identityPackage.get("deviceId"); m_deviceName = identityPackage.get("deviceName"); + int protocolVersion = identityPackage.get("protocolVersion"); + if (protocolVersion != NetworkPackage::ProtocolVersion) { + qDebug() << "WARNING: Device uses a different protocol version" << protocolVersion << "expected" << NetworkPackage::ProtocolVersion; + //TODO: Do something + } + addLink(dl); m_pairStatus = Device::Device::NotPaired; @@ -320,14 +326,7 @@ void Device::privateReceivedPackage(const NetworkPackage& np) } else { - 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 { + if (np.type() == PACKAGE_TYPE_ENCRYPTED) { //TODO: Do not read the key every time KSharedConfigPtr config = KSharedConfig::openConfig("kdeconnectrc"); @@ -338,6 +337,15 @@ void Device::privateReceivedPackage(const NetworkPackage& np) NetworkPackage decryptedNp(""); np.decrypt(privateKey, &decryptedNp); Q_EMIT receivedPackage(decryptedNp); + + } else { + + //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); + } diff --git a/kded/linkproviders/lanlinkprovider.cpp b/kded/linkproviders/lanlinkprovider.cpp index 862c72f2b..885605e01 100644 --- a/kded/linkproviders/lanlinkprovider.cpp +++ b/kded/linkproviders/lanlinkprovider.cpp @@ -76,9 +76,9 @@ void LanLinkProvider::newUdpConnection() mUdpServer->readDatagram(datagram.data(), datagram.size(), &sender, &senderPort); NetworkPackage* np = new NetworkPackage(""); - NetworkPackage::unserialize(datagram,np); + bool success = NetworkPackage::unserialize(datagram,np); - if (np->version() > 0 && np->type() == PACKAGE_TYPE_IDENTITY) { + if (success && np->type() == PACKAGE_TYPE_IDENTITY) { NetworkPackage np2(""); NetworkPackage::createIdentityPackage(&np2); @@ -206,9 +206,9 @@ void LanLinkProvider::dataReceived() qDebug() << "LanLinkProvider received reply:" << data; NetworkPackage np(""); - NetworkPackage::unserialize(data,&np); + bool success = NetworkPackage::unserialize(data,&np); - if (np.version() > 0 && np.type() == PACKAGE_TYPE_IDENTITY) { + if (success && np.type() == PACKAGE_TYPE_IDENTITY) { const QString& id = np.get("deviceId"); LanDeviceLink* dl = new LanDeviceLink(id, this, socket); diff --git a/kded/networkpackage.cpp b/kded/networkpackage.cpp index 9277ff88c..fec98dfbb 100644 --- a/kded/networkpackage.cpp +++ b/kded/networkpackage.cpp @@ -32,15 +32,11 @@ #include #include -const static int CURRENT_PACKAGE_VERSION = 2; - NetworkPackage::NetworkPackage(const QString& type) { mId = QString::number(QDateTime::currentMSecsSinceEpoch()); mType = type; mBody = QVariantMap(); - mVersion = CURRENT_PACKAGE_VERSION; - mEncrypted = false; } QByteArray NetworkPackage::serialize() const @@ -66,7 +62,7 @@ QByteArray NetworkPackage::serialize() const return json; } -void NetworkPackage::unserialize(const QByteArray& a, NetworkPackage* np) +bool NetworkPackage::unserialize(const QByteArray& a, NetworkPackage* np) { qDebug() << "Unserialize: " << a; @@ -76,15 +72,13 @@ void NetworkPackage::unserialize(const QByteArray& a, NetworkPackage* np) QVariantMap variant = parser.parse(a, &ok).toMap(); if (!ok) { qDebug() << "Unserialization error:" << parser.errorLine() << parser.errorString(); - np->setVersion(-1); + return false; } //QVariant -> Object QJson::QObjectHelper::qvariant2qobject(variant,np); - if (np->version() > CURRENT_PACKAGE_VERSION) { - qDebug() << "Warning: package version" << np->version() << "is greater than supported version" << CURRENT_PACKAGE_VERSION; - } + return true; } @@ -93,28 +87,26 @@ void NetworkPackage::encrypt (QCA::PublicKey& key) QByteArray serialized = serialize(); - int chunkSize = key.maximumEncryptSize(QCA::EME_PKCS1v15); + int chunkSize = key.maximumEncryptSize(NetworkPackage::EncryptionAlgorithm); QStringList chunks; while (!serialized.isEmpty()) { QByteArray chunk = serialized.left(chunkSize); serialized = serialized.mid(chunkSize); - QByteArray encryptedChunk = key.encrypt(chunk, QCA::EME_PKCS1v15).toByteArray(); + QByteArray encryptedChunk = key.encrypt(chunk, NetworkPackage::EncryptionAlgorithm).toByteArray(); chunks.append( encryptedChunk.toBase64() ); } qDebug() << chunks.size() << "chunks"; mId = QString::number(QDateTime::currentMSecsSinceEpoch()); - mType = "kdeconnect.encrypted"; + mType = PACKAGE_TYPE_ENCRYPTED; mBody = QVariantMap(); mBody["data"] = chunks; - mVersion = CURRENT_PACKAGE_VERSION; - mEncrypted = true; } -void NetworkPackage::decrypt (QCA::PrivateKey& key, NetworkPackage* out) const +bool NetworkPackage::decrypt (QCA::PrivateKey& key, NetworkPackage* out) const { const QStringList& chunks = mBody["data"].toStringList(); @@ -122,12 +114,16 @@ void NetworkPackage::decrypt (QCA::PrivateKey& key, NetworkPackage* out) const Q_FOREACH(const QString& chunk, chunks) { QByteArray encryptedChunk = QByteArray::fromBase64(chunk.toAscii()); QCA::SecureArray decryptedChunk; - key.decrypt(encryptedChunk, &decryptedChunk, QCA::EME_PKCS1v15); + bool success = key.decrypt(encryptedChunk, &decryptedChunk, NetworkPackage::EncryptionAlgorithm); + if (!success) { + return false; + } decryptedJson.append(decryptedChunk.toByteArray()); } - unserialize(decryptedJson, out); + return unserialize(decryptedJson, out); + } @@ -136,11 +132,10 @@ void NetworkPackage::createIdentityPackage(NetworkPackage* np) { KSharedConfigPtr config = KSharedConfig::openConfig("kdeconnectrc"); QString id = config->group("myself").readEntry("id",""); - np->mId = time(NULL); - np->mType = PACKAGE_TYPE_IDENTITY; - np->mVersion = CURRENT_PACKAGE_VERSION; + np->mId = QString::number(QDateTime::currentMSecsSinceEpoch()); np->set("deviceId", id); np->set("deviceName", QHostInfo::localHostName()); + np->set("protocolVersion", NetworkPackage::ProtocolVersion); //qDebug() << "createIdentityPackage" << np->serialize(); } diff --git a/kded/networkpackage.h b/kded/networkpackage.h index 6e5798b84..df297d8b8 100644 --- a/kded/networkpackage.h +++ b/kded/networkpackage.h @@ -41,47 +41,41 @@ class NetworkPackage : public QObject 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: + const static QCA::EncryptionAlgorithm EncryptionAlgorithm = QCA::EME_PKCS1v15; + const static int ProtocolVersion = 3; + NetworkPackage(const QString& type); - 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*); - QString id() const { return mId; } + QByteArray serialize() const; + static bool unserialize(const QByteArray& json, NetworkPackage* out); + + void encrypt(QCA::PublicKey& key); + bool decrypt(QCA::PrivateKey& key, NetworkPackage* out) const; + + const 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. + //Get and set info from body. Note that id and type can not be accessed through these. template T get(const QString& key, const T& defaultValue = default_arg::get()) const { return mBody.value(key,defaultValue).template value(); //Important note: Awesome template syntax is awesome } template void set(const QString& key, const T& value) { mBody[key] = QVariant(value); } - bool has(const QString& key) const { return mBody.contains(key); } private: - void setId(QString id) { mId = id; } + void setId(const 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; } QString mId; QString mType; - bool mEncrypted; - QVariantMap mBody; //json in the Android side - int mVersion; + QVariantMap mBody; }; diff --git a/kded/networkpackagetypes.h b/kded/networkpackagetypes.h index 618a9bf76..915f6c103 100644 --- a/kded/networkpackagetypes.h +++ b/kded/networkpackagetypes.h @@ -24,6 +24,7 @@ #define PACKAGE_TYPE_IDENTITY QString("kdeconnect.identity") #define PACKAGE_TYPE_PAIR QString("kdeconnect.pair") #define PACKAGE_TYPE_PING QString("kdeconnect.ping") +#define PACKAGE_TYPE_ENCRYPTED QString("kdeconnect.encrypted") #define PACKAGE_TYPE_NOTIFICATION QString("kdeconnect.notification") #define PACKAGE_TYPE_BATTERY QString("kdeconnect.battery") #define PACKAGE_TYPE_TELEPHONY QString("kdeconnect.telephony") diff --git a/tests/networkpackagetests.cpp b/tests/networkpackagetests.cpp index 4090f7d56..b2f3096f8 100644 --- a/tests/networkpackagetests.cpp +++ b/tests/networkpackagetests.cpp @@ -63,14 +63,12 @@ void NetworkPackageTests::networkPackageTest() QCOMPARE( np.id(), np2.id() ); QCOMPARE( np.type(), np2.type() ); - 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 } }"); //qDebug() << json; NetworkPackage::unserialize(json,&np2); QCOMPARE( np2.id(), QString("123") ); - QCOMPARE( np2.version(), 3 ); QCOMPARE( (np2.get("testing")), true ); QCOMPARE( (np2.get("not_testing")), false ); QCOMPARE( (np2.get("not_testing",true)), true ); @@ -78,8 +76,6 @@ void NetworkPackageTests::networkPackageTest() //NetworkPackage::unserialize("this is not json",&np2); //QtTest::ignoreMessage(QtSystemMsg, "json_parser - syntax error found, forcing abort, Line 1 Column 0"); //QtTest::ignoreMessage(QtDebugMsg, "Unserialization error: 1 \"syntax error, unexpected string\""); - //QCOMPARE( np2.version(), -1 ); - } @@ -100,27 +96,26 @@ void NetworkPackageTests::networkPackageEncryptionTest() //Encrypt and decrypt np - QCOMPARE( original.isEncrypted(), false ); + QCOMPARE( original.type(), QString("com.test") ); original.encrypt(publicKey); - QCOMPARE( original.isEncrypted(), true ); + QCOMPARE( original.type(), PACKAGE_TYPE_ENCRYPTED ); original.decrypt(privateKey, &decrypted); - QCOMPARE( original.isEncrypted(), true ); - QCOMPARE( decrypted.isEncrypted(), false ); + QCOMPARE( original.type(), PACKAGE_TYPE_ENCRYPTED ); + QCOMPARE( decrypted.type(), QString("com.test") ); //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() ); //Test for long package encryption that need multi-chunk encryption - QByteArray json = "{ \"body\" : { \"nowPlaying\" : \"A really long song name - A really long artist name\", \"player\" : \"A really long player name\" }, \"id\" : \"A really long package id\", \"isEncrypted\" : false, \"type\" : \"kdeconnect.a_really_long_package_type\", \"version\" : 2 }\n"; + QByteArray json = "{ \"body\" : { \"nowPlaying\" : \"A really long song name - A really long artist name\", \"player\" : \"A really long player name\", \"the_meaning_of_life_the_universe_and_everything\" : \"42\" }, \"id\" : \"A really long package id\", \"type\" : \"kdeconnect.a_really_really_long_package_type\" }\n"; qDebug() << "EME_PKCS1_OAEP maximumEncryptSize" << publicKey.maximumEncryptSize(QCA::EME_PKCS1_OAEP); qDebug() << "EME_PKCS1v15 maximumEncryptSize" << publicKey.maximumEncryptSize(QCA::EME_PKCS1v15); - QCOMPARE( json.size() > publicKey.maximumEncryptSize(QCA::EME_PKCS1v15), true ); + QCOMPARE( json.size() > publicKey.maximumEncryptSize(NetworkPackage::EncryptionAlgorithm), true ); NetworkPackage::unserialize(json, &original); original.encrypt(publicKey);