diff options
author | Ben Boeckel <MathStuf@gmail.com> | 2008-11-01 01:08:10 +0000 |
---|---|---|
committer | Ben Boeckel <MathStuf@gmail.com> | 2008-11-01 01:08:10 +0000 |
commit | eda2022859e7cfde9197a34d9318a9ccec50d841 (patch) | |
tree | be51b862c06475932086c81cf43397008d773211 /signet | |
parent | ff3295a0ede441caef7a133d2f4f4a472b5b7cde (diff) | |
download | sigen-eda2022859e7cfde9197a34d9318a9ccec50d841.tar.gz sigen-eda2022859e7cfde9197a34d9318a9ccec50d841.tar.xz sigen-eda2022859e7cfde9197a34d9318a9ccec50d841.zip |
[FIX] Code for challenge-based login complete
[FIX] Protocol is getting started
[FIX] Removed the kdegames dependency until it's actually here
[FIX] Using QCA2 for hashing
git-svn-id: https://pokegen.svn.sourceforge.net/svnroot/pokegen/trunk@289 6ecfd1a5-f3ed-3746-8530-beee90d26b22
Diffstat (limited to 'signet')
-rw-r--r-- | signet/CMakeLists.txt | 13 | ||||
-rw-r--r-- | signet/ConnectionHandler.cpp | 91 | ||||
-rw-r--r-- | signet/ConnectionHandler.h | 22 | ||||
-rw-r--r-- | signet/Server.cpp | 10 | ||||
-rw-r--r-- | signet/Server.h | 2 | ||||
-rw-r--r-- | signet/protocol/ChallengeMediator.cpp | 135 | ||||
-rw-r--r-- | signet/protocol/ChallengeMediator.h | 74 | ||||
-rw-r--r-- | signet/protocol/Packet.cpp | 52 | ||||
-rw-r--r-- | signet/protocol/Packet.h | 62 | ||||
-rw-r--r-- | signet/protocol/PacketMaker.cpp | 35 | ||||
-rw-r--r-- | signet/protocol/PacketMaker.h | 57 |
11 files changed, 549 insertions, 4 deletions
diff --git a/signet/CMakeLists.txt b/signet/CMakeLists.txt index b9eba0b5..acdf5dc8 100644 --- a/signet/CMakeLists.txt +++ b/signet/CMakeLists.txt @@ -4,7 +4,13 @@ IF (NOT SIGEN_VERSION) MESSAGE(FATAL_ERROR "Sigen version is not defined") ENDIF (NOT SIGEN_VERSION) +SET(signet_PROTOCOL_HEADERS + protocol/ChallengeMediator.h + protocol/Packet.h + protocol/PacketMaker.h +) SET(signet_HEADERS + ${signet_PROTOCOL_HEADERS} Client.h ConnectionHandler.h Global.h @@ -12,7 +18,13 @@ SET(signet_HEADERS Server.h Table.h ) +SET(signet_PROTOCOL_SRCS + protocol/ChallengeMediator.cpp + protocol/Packet.cpp + protocol/PacketMaker.cpp +) SET(signet_SRCS + ${signet_PROTOCOL_SRCS} Client.cpp ConnectionHandler.cpp Room.cpp @@ -34,6 +46,7 @@ TARGET_LINK_LIBRARIES(signet ${QT_QTCORE_LIBRARY} ${QT_QTNETWORK_LIBRARY} ${KDE4_KDECORE_LIBRARY} + ${QCA2_LIBRARIES} ) INSTALL( diff --git a/signet/ConnectionHandler.cpp b/signet/ConnectionHandler.cpp index e72950cd..98c2420b 100644 --- a/signet/ConnectionHandler.cpp +++ b/signet/ConnectionHandler.cpp @@ -20,12 +20,103 @@ // Signet includes #include "Client.h" +#include "protocol/ChallengeMediator.h" + +// QCA includes +#include <QtCrypto/QtCrypto> + +// Qt includes +#include <QtCore/QUuid> +#include <QtNetwork/QHostAddress> +#include <QtNetwork/QTcpSocket> Signet::ConnectionHandler::ConnectionHandler(QObject* parent) : QObject(parent) { } +QByteArray Signet::ConnectionHandler::generateChallengeKey() +{ + return QUuid::createUuid().toString().toUtf8(); +} + +QByteArray Signet::ConnectionHandler::generateResponse(const QByteArray& key1, const QByteArray& key2, const QByteArray& secret) +{ + if (QCA::isSupported("sha256")) + { + QByteArray total; + total.append(key1); + total.append(key2); + total.append(secret); + QCA::Hash sha256("sha256"); + return sha256.hash(total).toByteArray(); + } + qFatal("SHA-256 is not supported"); + return QByteArray(); +} + +Signet::ConnectionHandler::ChallengeError Signet::ConnectionHandler::challenge(QTcpSocket* socket, const QByteArray& secret) +{ + QByteArray clientKey; + QByteArray serverKey; + QByteArray clientResponse; + QByteArray serverResponse; + QByteArray expectedServerResponse; + Protocol::ChallengeMediator mediator(socket, Protocol::ChallengeMediator::Client); + mediator.init(); + if (!mediator.getServerKey(&serverKey)) + return SocketError; + clientKey = generateChallengeKey(); + clientResponse = generateResponse(clientKey, serverKey, secret); + expectedServerResponse = generateResponse(serverKey, clientKey, secret); + mediator.clientResponse(clientKey, clientResponse); + if (!mediator.getServerResponse(&serverResponse)) + return SocketError; + if (mediator.state() != Protocol::ChallengeMediator::Accepted) + return ClientFailed; + if (serverResponse != expectedServerResponse) + { + mediator.notifyServerFail(); + return ServerFailed; + } + mediator.notifyServerAccept(); + return NoError; +} + +Signet::ConnectionHandler::ChallengeError Signet::ConnectionHandler::challenged(QTcpSocket* socket) +{ + QByteArray clientKey; + QByteArray serverKey; + QByteArray clientResponse; + QByteArray serverResponse; + QByteArray expectedClientResponse; + QByteArray secret = secretForHost(socket->peerAddress()); + Protocol::ChallengeMediator mediator(socket, Protocol::ChallengeMediator::Server); + serverKey = generateChallengeKey(); + mediator.serverKey(serverKey); + if (!mediator.getClientResponse(&clientKey, &clientResponse)) + return SocketError; + expectedClientResponse = generateResponse(clientKey, serverKey, secret); + if (clientResponse != expectedClientResponse) + { + mediator.notifyClientFail(); + return ClientFailed; + } + serverResponse = generateResponse(serverKey, clientKey, secret); + mediator.serverResponse(serverResponse); + if (!mediator.getClientAnswer()) + return SocketError; + if (mediator.state() != Protocol::ChallengeMediator::Accepted) + return ServerFailed; + return NoError; +} + +QByteArray Signet::ConnectionHandler::secretForHost(const QHostAddress& address) const +{ + Q_UNUSED(address) + return QByteArray(); +} + bool Signet::ConnectionHandler::addClient(Client* socket) { // TODO: Add the client diff --git a/signet/ConnectionHandler.h b/signet/ConnectionHandler.h index c845e6b5..9108a9a9 100644 --- a/signet/ConnectionHandler.h +++ b/signet/ConnectionHandler.h @@ -25,9 +25,12 @@ #include <QtCore/QMap> #include <QtCore/QObject> +// Forward declarations +class QHostAddress; +class QTcpSocket; + namespace Signet { -// Forward declarations class Client; class SIGNET_EXPORT ConnectionHandler : public QObject @@ -35,8 +38,23 @@ class SIGNET_EXPORT ConnectionHandler : public QObject Q_OBJECT public: + enum ChallengeError + { + NoError, + ClientFailed, + ServerFailed, + SocketError + }; + ConnectionHandler(QObject* parent); + static QByteArray generateChallengeKey(); + static QByteArray generateResponse(const QByteArray& key1, const QByteArray& key2, const QByteArray& secret); + static ChallengeError challenge(QTcpSocket* socket, const QByteArray& secret); + ChallengeError challenged(QTcpSocket* socket); + + virtual QByteArray secretForHost(const QHostAddress& address) const; + virtual QString type() const = 0; virtual QString name() const = 0; public slots: @@ -48,7 +66,7 @@ class SIGNET_EXPORT ConnectionHandler : public QObject protected slots: void sendData(Client* client, const QByteArray& data); private: - QList<Client*> m_sockets; + QList<Client*> m_clients; }; } diff --git a/signet/Server.cpp b/signet/Server.cpp index bd23faf5..422f2d45 100644 --- a/signet/Server.cpp +++ b/signet/Server.cpp @@ -62,6 +62,14 @@ void Signet::Server::hostFound() void Signet::Server::hostConnected() { qDebug("Master server connected"); + ChallengeError error = challenge(m_master, m_key); + if (error == NoError) + qDebug("Master server connected"); + else if (error != SocketError) + { + qCritical("Challenge negotiation failed: %s", (error == ClientFailed) ? "Client" : "Server"); + m_master->disconnectFromHost(); + } } void Signet::Server::hostDisconnected() @@ -96,7 +104,7 @@ void Signet::Server::loadConfiguration() m_masterPort = group.readEntry("Port", -1); if (m_masterPort < 0) qFatal("Invalid port for the master server: %d", m_masterPort); - m_key = group.readEntry("Key", ""); + m_key = group.readEntry("Key", QByteArray()); } else qFatal("Configuration does not contain a \"Master Server\" group"); diff --git a/signet/Server.h b/signet/Server.h index a8cb31ff..ee90455a 100644 --- a/signet/Server.h +++ b/signet/Server.h @@ -66,7 +66,7 @@ class SIGNET_EXPORT Server : public ConnectionHandler QHostAddress m_masterHost; int m_masterPort; - QUuid m_key; + QByteArray m_key; QMap<QString, Room*> m_rooms; }; diff --git a/signet/protocol/ChallengeMediator.cpp b/signet/protocol/ChallengeMediator.cpp new file mode 100644 index 00000000..c26b6ea4 --- /dev/null +++ b/signet/protocol/ChallengeMediator.cpp @@ -0,0 +1,135 @@ +/* + * Copyright 2008 Ben Boeckel <MathStuf@gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +// Header include +#include "ChallengeMediator.h" + +// Protocol includes +#include "PacketMaker.h" + +// Qt includes +#include <QtCore/QBuffer> +#include <QtNetwork/QTcpSocket> + +Signet::Protocol::ChallengeMediator::ChallengeMediator(QTcpSocket* socket, Side side) : + m_side(side), + m_state(Negotiating), + m_socket(socket) +{ +} + +void Signet::Protocol::ChallengeMediator::init() +{ + Q_ASSERT(m_side == Client); + PacketMaker::challengePacket(m_socket); +} + +void Signet::Protocol::ChallengeMediator::serverKey(const QByteArray& serverKey) +{ + Q_ASSERT(m_side == Server); + PacketMaker::wrap(m_socket, serverKey); +} + +bool Signet::Protocol::ChallengeMediator::getServerKey(QByteArray* serverKey) +{ + Q_ASSERT(m_side == Client); + QBuffer buffer(serverKey); + Packet packet = PacketMaker::unwrap(m_socket); + if (!packet.isValid()) + return false; + packet.dump(&buffer); + return true; +} + +void Signet::Protocol::ChallengeMediator::clientResponse(const QByteArray& clientKey, const QByteArray& clientResponse) +{ + Q_ASSERT(m_side == Client); + PacketMaker::wrap(m_socket, clientKey); + PacketMaker::wrap(m_socket, clientResponse); +} + +bool Signet::Protocol::ChallengeMediator::getClientResponse(QByteArray* clientKey, QByteArray* clientResponse) +{ + Q_ASSERT(m_side == Server); + QBuffer buffer(clientKey); + Packet packet = PacketMaker::unwrap(m_socket); + if (!packet.isValid()) + return false; + packet.dump(&buffer); + buffer.setBuffer(clientResponse); + packet = PacketMaker::unwrap(m_socket); + if (!packet.isValid()) + return false; + packet.dump(&buffer); + return true; +} + +void Signet::Protocol::ChallengeMediator::serverResponse(const QByteArray& serverResponse) +{ + Q_ASSERT(m_side == Server); + PacketMaker::wrap(m_socket, serverResponse); +} + +bool Signet::Protocol::ChallengeMediator::getServerResponse(QByteArray* serverResponse) +{ + Q_ASSERT(m_side == Client); + QBuffer buffer(serverResponse); + Packet packet = PacketMaker::unwrap(m_socket); + if (!packet.isValid()) + return false; + if (packet.type() == Packet::Denial) + m_state = Rejected; + else + packet.dump(&buffer); + return true; +} + +bool Signet::Protocol::ChallengeMediator::getClientAnswer() +{ + Q_ASSERT(m_side == Server); + Packet packet = PacketMaker::unwrap(m_socket); + if (!packet.isValid()) + return false; + if (packet.type() == Packet::Acceptance) + m_state = Accepted; + else + m_state = Rejected; + return true; +} + +Signet::Protocol::ChallengeMediator::State Signet::Protocol::ChallengeMediator::state() const +{ + return m_state; +} + +void Signet::Protocol::ChallengeMediator::notifyServerFail() +{ + Q_ASSERT(m_side == Client); + PacketMaker::deny(m_socket); +} + +void Signet::Protocol::ChallengeMediator::notifyServerAccept() +{ + Q_ASSERT(m_side == Client); + PacketMaker::accept(m_socket); +} + +void Signet::Protocol::ChallengeMediator::notifyClientFail() +{ + Q_ASSERT(m_side == Server); + PacketMaker::deny(m_socket); +} diff --git a/signet/protocol/ChallengeMediator.h b/signet/protocol/ChallengeMediator.h new file mode 100644 index 00000000..bc02245d --- /dev/null +++ b/signet/protocol/ChallengeMediator.h @@ -0,0 +1,74 @@ +/* + * Copyright 2008 Ben Boeckel <MathStuf@gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef SIGNET_PROTOCOL_CHALLENGEMEDIATOR +#define SIGNET_PROTOCOL_CHALLENGEMEDIATOR + +// Signet includes +#include "../Global.h" + +// Forward declarations +class QTcpSocket; + +namespace Signet +{ +namespace Protocol +{ +class SIGNET_EXPORT ChallengeMediator +{ + public: + enum Side + { + Client = 0, + Server = 1 + }; + enum State + { + Negotiating = 0, + Accepted = 1, + Rejected = 2 + }; + + ChallengeMediator(QTcpSocket* socket, Side side); + + void init(); + + void serverKey(const QByteArray& serverKey); + bool getServerKey(QByteArray* serverKey); + + void clientResponse(const QByteArray& clientKey, const QByteArray& clientResponse); + bool getClientResponse(QByteArray* clientKey, QByteArray* clientResponse); + + void serverResponse(const QByteArray& serverResponse); + bool getServerResponse(QByteArray* serverResponse); + + bool getClientAnswer(); + + State state() const; + + void notifyServerFail(); + void notifyServerAccept(); + void notifyClientFail(); + private: + const Side m_side; + State m_state; + QTcpSocket* m_socket; +}; +} +} + +#endif diff --git a/signet/protocol/Packet.cpp b/signet/protocol/Packet.cpp new file mode 100644 index 00000000..34e6d125 --- /dev/null +++ b/signet/protocol/Packet.cpp @@ -0,0 +1,52 @@ +/* + * Copyright 2008 Ben Boeckel <MathStuf@gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +// Header include +#include "Packet.h" + +// Qt include +#include <QtCore/QIODevice> + +Signet::Protocol::Packet::Packet(const Type type) : + m_type(type) +{ +} + +void Signet::Protocol::Packet::determineType() +{ +} + +Signet::Protocol::Packet::Type Signet::Protocol::Packet::type() const +{ + return m_type; +} + +bool Signet::Protocol::Packet::isValid() const +{ + return m_type == Invalid; +} + +void Signet::Protocol::Packet::write(const QByteArray& data) +{ + if ((m_type == RawData) || (m_type == Invalid)) + m_rawData.append(data); +} + +void Signet::Protocol::Packet::dump(QIODevice* device) const +{ + device->write(m_rawData); +} diff --git a/signet/protocol/Packet.h b/signet/protocol/Packet.h new file mode 100644 index 00000000..764ae26a --- /dev/null +++ b/signet/protocol/Packet.h @@ -0,0 +1,62 @@ +/* + * Copyright 2008 Ben Boeckel <MathStuf@gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef SIGNET_PROTOCOL_PACKET +#define SIGNET_PROTOCOL_PACKET + +// Signet includes +#include "../Global.h" + +// Qt includes +#include <QtCore/QByteArray> + +// Forward declarations +class QIODevice; + +namespace Signet +{ +namespace Protocol +{ +class SIGNET_EXPORT Packet +{ + public: + enum Type + { + Invalid = -1, + RawData = 0, + Acceptance = 1, + Denial = 2, + Challenge = 3 + }; + + Packet(const Type type = Invalid); + + void determineType(); + + Type type() const; + bool isValid() const; + + void write(const QByteArray& data); + void dump(QIODevice* device) const; + private: + Type m_type; + QByteArray m_rawData; +}; +} +} + +#endif diff --git a/signet/protocol/PacketMaker.cpp b/signet/protocol/PacketMaker.cpp new file mode 100644 index 00000000..f2a05d2b --- /dev/null +++ b/signet/protocol/PacketMaker.cpp @@ -0,0 +1,35 @@ +/* + * Copyright 2008 Ben Boeckel <MathStuf@gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +// Header include +#include "PacketMaker.h" + +void Signet::Protocol::PacketMaker::deny(QIODevice* device) +{ +} + +void Signet::Protocol::PacketMaker::accept(QIODevice* device) +{ +} + +void Signet::Protocol::PacketMaker::challengePacket(QIODevice* device) +{ +} + +Signet::Protocol::Packet Signet::Protocol::PacketMaker::unwrap(QIODevice* device) +{ +} diff --git a/signet/protocol/PacketMaker.h b/signet/protocol/PacketMaker.h new file mode 100644 index 00000000..877eef9b --- /dev/null +++ b/signet/protocol/PacketMaker.h @@ -0,0 +1,57 @@ +/* + * Copyright 2008 Ben Boeckel <MathStuf@gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef SIGNET_PROTOCOL_PACKETMAKER +#define SIGNET_PROTOCOL_PACKETMAKER + +// Protocol includes +#include "Packet.h" + +// Signet includes +#include "../Global.h" + +// Forward declarations +#include <QtCore/QIODevice> + +namespace Signet +{ +namespace Protocol +{ +class SIGNET_EXPORT PacketMaker +{ + public: + static void deny(QIODevice* device); + static void accept(QIODevice* device); + + static void challengePacket(QIODevice* device); + + template<typename T> static void wrap(QIODevice* device, const T& data); + + static Packet unwrap(QIODevice* device); +}; + +template<> inline void PacketMaker::wrap<QByteArray>(QIODevice* device, const QByteArray& data) +{ + Packet packet(Packet::RawData); + packet.write(data); + packet.dump(device); +} + +} +} + +#endif |