diff options
author | madmaxoft@gmail.com <madmaxoft@gmail.com@0a769ca7-a7f5-676a-18bf-c427514a06d6> | 2012-08-30 23:06:13 +0200 |
---|---|---|
committer | madmaxoft@gmail.com <madmaxoft@gmail.com@0a769ca7-a7f5-676a-18bf-c427514a06d6> | 2012-08-30 23:06:13 +0200 |
commit | 539364846a89987ac2679988653f50332cb91d26 (patch) | |
tree | f1695473c1f493a19c5fbdb70f7f1faccf99d7f3 /source | |
parent | Updated to V6 - "Stop" and "Progress report" functionality (diff) | |
download | cuberite-539364846a89987ac2679988653f50332cb91d26.tar cuberite-539364846a89987ac2679988653f50332cb91d26.tar.gz cuberite-539364846a89987ac2679988653f50332cb91d26.tar.bz2 cuberite-539364846a89987ac2679988653f50332cb91d26.tar.lz cuberite-539364846a89987ac2679988653f50332cb91d26.tar.xz cuberite-539364846a89987ac2679988653f50332cb91d26.tar.zst cuberite-539364846a89987ac2679988653f50332cb91d26.zip |
Diffstat (limited to 'source')
-rw-r--r-- | source/Protocol132.cpp | 200 | ||||
-rw-r--r-- | source/Protocol132.h | 23 | ||||
-rw-r--r-- | source/ProtocolRecognizer.cpp | 3 | ||||
-rw-r--r-- | source/cServer.cpp | 18 | ||||
-rw-r--r-- | source/cServer.h | 10 |
5 files changed, 248 insertions, 6 deletions
diff --git a/source/Protocol132.cpp b/source/Protocol132.cpp index faff57004..2a4a830c6 100644 --- a/source/Protocol132.cpp +++ b/source/Protocol132.cpp @@ -5,6 +5,10 @@ #include "Globals.h"
#include "Protocol132.h"
+#include "cRoot.h"
+#include "cServer.h"
+#include "cClientHandle.h"
+#include "CryptoPP/osrng.h"
@@ -28,11 +32,24 @@ typedef unsigned char Byte; +using namespace CryptoPP;
+
+
+
+
+
+const int MAX_ENC_LEN = 512; // Maximum size of the encrypted message; should be 128, but who knows...
+
+
+
+
+
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cProtocol132:
cProtocol132::cProtocol132(cClientHandle * a_Client) :
- super(a_Client)
+ super(a_Client),
+ m_IsEncrypted(false)
{
}
@@ -42,8 +59,36 @@ cProtocol132::cProtocol132(cClientHandle * a_Client) : void cProtocol132::DataReceived(const char * a_Data, int a_Size)
{
- // TODO: Protocol decryption
- super::DataReceived(a_Data, a_Size);
+ if (m_IsEncrypted)
+ {
+ byte Decrypted[512];
+ while (a_Size > 0)
+ {
+ int NumBytes = (a_Size > sizeof(Decrypted)) ? sizeof(Decrypted) : a_Size;
+ m_Decryptor.ProcessData(Decrypted, (byte *)a_Data, NumBytes);
+ super::DataReceived((const char *)Decrypted, NumBytes);
+ a_Size -= NumBytes;
+ a_Data += NumBytes;
+ }
+ }
+ else
+ {
+ super::DataReceived(a_Data, a_Size);
+ }
+}
+
+
+
+
+
+int cProtocol132::ParsePacket(unsigned char a_PacketType)
+{
+ switch (a_PacketType)
+ {
+ default: return super::ParsePacket(a_PacketType); // off-load previously known packets into cProtocol125
+ case 0xcd: return ParseClientStatuses();
+ case 0xfc: return ParseEncryptionKeyResponse();
+ }
}
@@ -55,11 +100,158 @@ int cProtocol132::ParseHandshake(void) HANDLE_PACKET_READ(ReadByte, Byte, ProtocolVersion);
HANDLE_PACKET_READ(ReadBEUTF16String16, AString, Username);
HANDLE_PACKET_READ(ReadBEUTF16String16, AString, ServerHost);
- HANDLE_PACKET_READ(ReadBEInt, int, ServerPort);
+ HANDLE_PACKET_READ(ReadBEInt, int, ServerPort);
m_Username = Username;
+
+ AString key;
+ CryptoPP::StringSink sink(key); // GCC won't allow inline instantiation in the following line, damned temporary refs
+ cRoot::Get()->GetServer()->GetPublicKey().Save(sink);
+
+ // Send a 0xFD Encryption Key Request http://wiki.vg/Protocol#Encryption_Key_Request_.280xFD.29
+ WriteByte((char)0xfd);
+ WriteString("MCServer");
+ WriteShort((short)key.size());
+ SendData(key.data(), key.size());
+ WriteShort(4);
+ WriteInt((int)this); // Using 'this' as the cryptographic nonce, so that we don't have to generate one each time :)
+ return PARSE_OK;
+}
+
+
+
+
+
+int cProtocol132::ParseLogin(void)
+{
+ // Login packet not used in 1.3.2
+ return PARSE_ERROR;
+}
+
+
+
+
+
+int cProtocol132::ParseClientStatuses(void)
+{
+ HANDLE_PACKET_READ(ReadByte, byte, Status);
+
+ // DEBUG:
+ // Kick the client, we don't have all the packets yet and sending wrong packets makes the client freeze
+ // m_Client->Kick("I don't speak your language (yet)");
+
+ // TODO:
+ // m_Client->HandleLogin(39, m_Username);
+
return PARSE_OK;
}
+
+int cProtocol132::ParseEncryptionKeyResponse(void)
+{
+ HANDLE_PACKET_READ(ReadBEShort, short, EncKeyLength);
+ AString EncKey;
+ if (!m_ReceivedData.ReadString(EncKey, EncKeyLength))
+ {
+ return PARSE_INCOMPLETE;
+ }
+ HANDLE_PACKET_READ(ReadBEShort, short, EncNonceLength);
+ AString EncNonce;
+ if (!m_ReceivedData.ReadString(EncNonce, EncNonceLength))
+ {
+ return PARSE_INCOMPLETE;
+ }
+ if ((EncKeyLength > MAX_ENC_LEN) || (EncNonceLength > MAX_ENC_LEN))
+ {
+ LOGD("Too long encryption");
+ m_Client->Kick("Hacked client");
+ return PARSE_OK;
+ }
+
+ HandleEncryptionKeyResponse(EncKey, EncNonce);
+ return PARSE_OK;
+}
+
+
+
+
+
+void cProtocol132::SendData(const char * a_Data, int a_Size)
+{
+ if (m_IsEncrypted)
+ {
+ byte Encrypted[1024]; // Larger buffer, we may be sending lots of data (chunks)
+ while (a_Size > 0)
+ {
+ int NumBytes = (a_Size > sizeof(Encrypted)) ? sizeof(Encrypted) : a_Size;
+ m_Encryptor.ProcessData(Encrypted, (byte *)a_Data, NumBytes);
+ super::SendData((const char *)Encrypted, NumBytes);
+ a_Size -= NumBytes;
+ a_Data += NumBytes;
+ }
+ }
+ else
+ {
+ super::SendData(a_Data, a_Size);
+ }
+}
+
+
+
+
+
+void cProtocol132::HandleEncryptionKeyResponse(const AString & a_EncKey, const AString & a_EncNonce)
+{
+ // Decrypt EncNonce using privkey
+ RSAES<PKCS1v15>::Decryptor rsaDecryptor(cRoot::Get()->GetServer()->GetPrivateKey());
+ AutoSeededRandomPool rng;
+ byte DecryptedNonce[MAX_ENC_LEN];
+ DecodingResult res = rsaDecryptor.Decrypt(rng, (const byte *)a_EncNonce.data(), a_EncNonce.size(), DecryptedNonce);
+ if (!res.isValidCoding || (res.messageLength != 4))
+ {
+ LOGD("Bad nonce length");
+ m_Client->Kick("Hacked client");
+ return;
+ }
+ if (ntohl(*((int *)DecryptedNonce)) != (unsigned)this)
+ {
+ LOGD("Bad nonce value");
+ m_Client->Kick("Hacked client");
+ return;
+ }
+
+ // Decrypt the symmetric encryption key using privkey:
+ byte DecryptedKey[MAX_ENC_LEN];
+ res = rsaDecryptor.Decrypt(rng, (const byte *)a_EncKey.data(), a_EncKey.size(), DecryptedKey);
+ if (!res.isValidCoding || (res.messageLength != 16))
+ {
+ LOGD("Bad key length");
+ m_Client->Kick("Hacked client");
+ return;
+ }
+
+ // Send encryption key response:
+ WriteByte((char)0xfc);
+ WriteShort(0);
+ WriteShort(0);
+
+ StartEncryption(DecryptedKey);
+ return;
+}
+
+
+
+
+
+void cProtocol132::StartEncryption(const byte * a_Key)
+{
+ m_Encryptor.SetKey(a_Key, 16, MakeParameters(Name::IV(), ConstByteArrayParameter(a_Key, 16))(Name::FeedbackSize(), 1));
+ m_Decryptor.SetKey(a_Key, 16, MakeParameters(Name::IV(), ConstByteArrayParameter(a_Key, 16))(Name::FeedbackSize(), 1));
+ m_IsEncrypted = true;
+}
+
+
+
+
diff --git a/source/Protocol132.h b/source/Protocol132.h index af3e78ecc..a0e16b585 100644 --- a/source/Protocol132.h +++ b/source/Protocol132.h @@ -10,6 +10,8 @@ #pragma once
#include "Protocol125.h"
+#include "CryptoPP/modes.h"
+#include "CryptoPP/aes.h"
@@ -26,8 +28,29 @@ public: /// Called when client sends some data:
virtual void DataReceived(const char * a_Data, int a_Size) override;
+ /// Handling of the additional packets:
+ virtual int ParsePacket(unsigned char a_PacketType) override;
+
// Modified packets:
virtual int ParseHandshake(void) override;
+ virtual int ParseLogin (void) override;
+
+ // New packets:
+ virtual int ParseClientStatuses (void);
+ virtual int ParseEncryptionKeyResponse(void);
+
+ virtual void SendData(const char * a_Data, int a_Size);
+
+protected:
+ bool m_IsEncrypted;
+ CryptoPP::CFB_Mode<CryptoPP::AES>::Decryption m_Decryptor; // ((byte*)sDecryptedSharedSecret.c_str(),(unsigned int)16, IV, 1);
+ CryptoPP::CFB_Mode<CryptoPP::AES>::Encryption m_Encryptor;
+
+ /// Decrypts the key and nonce, checks nonce, starts the symmetric encryption
+ void HandleEncryptionKeyResponse(const AString & a_EncKey, const AString & a_EncNonce);
+
+ /// Starts the symmetric encryption with the specified key
+ void StartEncryption(const byte * a_Key);
} ;
diff --git a/source/ProtocolRecognizer.cpp b/source/ProtocolRecognizer.cpp index af917b7de..d0a3f4637 100644 --- a/source/ProtocolRecognizer.cpp +++ b/source/ProtocolRecognizer.cpp @@ -43,7 +43,6 @@ void cProtocolRecognizer::DataReceived(const char * a_Data, int a_Size) {
return;
}
- LOGD("ProtocolRecognizer at %p recognized protocol %p", this, m_Protocol);
// The protocol has just been recognized, dump the whole m_Buffer contents into it for parsing:
AString Dump;
@@ -491,7 +490,7 @@ bool cProtocolRecognizer::TryRecognizeProtocol(void) {
return false;
}
- if (ch == 0x39)
+ if (ch == 39)
{
m_Protocol = new cProtocol132(m_Client);
return true;
diff --git a/source/cServer.cpp b/source/cServer.cpp index 330a69873..157de2388 100644 --- a/source/cServer.cpp +++ b/source/cServer.cpp @@ -241,6 +241,8 @@ bool cServer::InitServer( int a_Port ) m_NotifyWriteThread.Start(this); + PrepareKeys(); + return true; } @@ -283,6 +285,22 @@ cServer::~cServer() +void cServer::PrepareKeys(void) +{ + // TODO: Save and load key for persistence across sessions + // But generating the key takes only a moment, do we even need that? + + LOG("Generating protocol encryption keypair..."); + CryptoPP::AutoSeededRandomPool rng; + m_PrivateKey.GenerateRandomWithKeySize(rng, 1024); + CryptoPP::RSA::PublicKey pk(m_PrivateKey); + m_PublicKey = pk; +} + + + + + void cServer::BroadcastChat(const AString & a_Message, const cClientHandle * a_Exclude) { cCSLock Lock(m_CSClients); diff --git a/source/cServer.h b/source/cServer.h index a97bcbd7a..7baaa0d6a 100644 --- a/source/cServer.h +++ b/source/cServer.h @@ -12,6 +12,8 @@ #define CSERVER_H_INCLUDED #include "cSocketThreads.h" +#include "CryptoPP/rsa.h" +#include "CryptoPP/osrng.h" @@ -66,6 +68,9 @@ public: //tolua_export void RemoveClient(const cSocket * a_Socket); // Removes the socket from m_SocketThreads + CryptoPP::RSA::PrivateKey & GetPrivateKey(void) { return m_PrivateKey; } + CryptoPP::RSA::PublicKey & GetPublicKey (void) { return m_PublicKey; } + private: friend class cRoot; // so cRoot can create and destroy cServer @@ -114,10 +119,15 @@ private: int m_iServerPort; bool m_bRestarting; + + CryptoPP::RSA::PrivateKey m_PrivateKey; + CryptoPP::RSA::PublicKey m_PublicKey; cServer(); ~cServer(); + /// Loads, or generates, if missing, RSA keys for protocol encryption + void PrepareKeys(void); }; //tolua_export |