summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt3
-rw-r--r--src/Crypto.cpp435
-rw-r--r--src/Crypto.h169
-rw-r--r--src/Defines.h2
-rw-r--r--src/Globals.h3
-rw-r--r--src/LeakFinder.cpp11
-rw-r--r--src/Protocol/Protocol132.cpp149
-rw-r--r--src/Protocol/Protocol132.h16
-rw-r--r--src/Protocol/Protocol14x.cpp2
-rw-r--r--src/Protocol/Protocol17x.cpp8
-rw-r--r--src/Protocol/Protocol17x.h14
-rw-r--r--src/Protocol/ProtocolRecognizer.cpp2
-rw-r--r--src/Server.cpp12
-rw-r--r--src/Server.h14
14 files changed, 679 insertions, 161 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 75236ccb8..944150a44 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -4,6 +4,7 @@ project (MCServer)
include_directories (SYSTEM "${PROJECT_SOURCE_DIR}/../lib/")
include_directories (SYSTEM "${PROJECT_SOURCE_DIR}/../lib/jsoncpp/include")
+include_directories (SYSTEM "${PROJECT_SOURCE_DIR}/../lib/polarssl/include")
set(FOLDERS OSSupport HTTPServer Items Blocks Protocol Generating)
set(FOLDERS ${FOLDERS} WorldStorage Mobs Entities Simulator UI BlockEntities)
@@ -220,4 +221,4 @@ endif ()
if (WIN32)
target_link_libraries(${EXECUTABLE} expat tolualib ws2_32.lib Psapi.lib)
endif()
-target_link_libraries(${EXECUTABLE} md5 luaexpat iniFile jsoncpp cryptopp zlib lua sqlite)
+target_link_libraries(${EXECUTABLE} md5 luaexpat iniFile jsoncpp polarssl zlib lua sqlite)
diff --git a/src/Crypto.cpp b/src/Crypto.cpp
new file mode 100644
index 000000000..2045d0385
--- /dev/null
+++ b/src/Crypto.cpp
@@ -0,0 +1,435 @@
+
+// Crypto.cpp
+
+// Implements classes that wrap the cryptographic code library
+
+#include "Globals.h"
+#include "Crypto.h"
+
+#include "polarssl/pk.h"
+
+
+
+
+
+/*
+// Self-test the hash formatting for known values:
+// sha1(Notch) : 4ed1f46bbe04bc756bcb17c0c7ce3e4632f06a48
+// sha1(jeb_) : -7c9d5b0044c130109a5d7b5fb5c317c02b4e28c1
+// sha1(simon) : 88e16a1019277b15d58faf0541e11910eb756f6
+
+class Test
+{
+public:
+ Test(void)
+ {
+ AString DigestNotch, DigestJeb, DigestSimon;
+ Byte Digest[20];
+ cSHA1Checksum Checksum;
+ Checksum.Update((const Byte *)"Notch", 5);
+ Checksum.Finalize(Digest);
+ cSHA1Checksum::DigestToJava(Digest, DigestNotch);
+ Checksum.Restart();
+ Checksum.Update((const Byte *)"jeb_", 4);
+ Checksum.Finalize(Digest);
+ cSHA1Checksum::DigestToJava(Digest, DigestJeb);
+ Checksum.Restart();
+ Checksum.Update((const Byte *)"simon", 5);
+ Checksum.Finalize(Digest);
+ cSHA1Checksum::DigestToJava(Digest, DigestSimon);
+ printf("Notch: \"%s\"\n", DigestNotch.c_str());
+ printf("jeb_: \"%s\"\n", DigestJeb.c_str());
+ printf("simon: \"%s\"\n", DigestSimon.c_str());
+ assert(DigestNotch == "4ed1f46bbe04bc756bcb17c0c7ce3e4632f06a48");
+ assert(DigestJeb == "-7c9d5b0044c130109a5d7b5fb5c317c02b4e28c1");
+ assert(DigestSimon == "88e16a1019277b15d58faf0541e11910eb756f6");
+ }
+} test;
+*/
+
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cRSAPrivateKey:
+
+cRSAPrivateKey::cRSAPrivateKey(void)
+{
+ rsa_init(&m_Rsa, RSA_PKCS_V15, 0);
+ InitRnd();
+}
+
+
+
+
+
+cRSAPrivateKey::cRSAPrivateKey(const cRSAPrivateKey & a_Other)
+{
+ rsa_init(&m_Rsa, RSA_PKCS_V15, 0);
+ rsa_copy(&m_Rsa, &a_Other.m_Rsa);
+ InitRnd();
+}
+
+
+
+
+
+cRSAPrivateKey::~cRSAPrivateKey()
+{
+ entropy_free(&m_Entropy);
+ rsa_free(&m_Rsa);
+}
+
+
+
+
+
+void cRSAPrivateKey::InitRnd(void)
+{
+ entropy_init(&m_Entropy);
+ const unsigned char pers[] = "rsa_genkey";
+ ctr_drbg_init(&m_Ctr_drbg, entropy_func, &m_Entropy, pers, sizeof(pers) - 1);
+}
+
+
+
+
+
+bool cRSAPrivateKey::Generate(unsigned a_KeySizeBits)
+{
+ if (rsa_gen_key(&m_Rsa, ctr_drbg_random, &m_Ctr_drbg, a_KeySizeBits, 65537) != 0)
+ {
+ // Key generation failed
+ return false;
+ }
+
+ return true;
+}
+
+
+
+
+
+AString cRSAPrivateKey::GetPubKeyDER(void)
+{
+ class cPubKey
+ {
+ public:
+ cPubKey(rsa_context * a_Rsa) :
+ m_IsValid(false)
+ {
+ pk_init(&m_Key);
+ if (pk_init_ctx(&m_Key, pk_info_from_type(POLARSSL_PK_RSA)) != 0)
+ {
+ ASSERT(!"Cannot init PrivKey context");
+ return;
+ }
+ if (rsa_copy(pk_rsa(m_Key), a_Rsa) != 0)
+ {
+ ASSERT(!"Cannot copy PrivKey to PK context");
+ return;
+ }
+ m_IsValid = true;
+ }
+
+ ~cPubKey()
+ {
+ if (m_IsValid)
+ {
+ pk_free(&m_Key);
+ }
+ }
+
+ operator pk_context * (void) { return &m_Key; }
+
+ protected:
+ bool m_IsValid;
+ pk_context m_Key;
+ } PkCtx(&m_Rsa);
+
+ unsigned char buf[3000];
+ int res = pk_write_pubkey_der(PkCtx, buf, sizeof(buf));
+ if (res < 0)
+ {
+ return AString();
+ }
+ return AString((const char *)(buf + sizeof(buf) - res), (size_t)res);
+}
+
+
+
+
+
+int cRSAPrivateKey::Decrypt(const Byte * a_EncryptedData, size_t a_EncryptedLength, Byte * a_DecryptedData, size_t a_DecryptedMaxLength)
+{
+ if (a_EncryptedLength < m_Rsa.len)
+ {
+ LOGD("%s: Invalid a_EncryptedLength: got %u, exp at least %u",
+ __FUNCTION__, (unsigned)a_EncryptedLength, (unsigned)(m_Rsa.len)
+ );
+ ASSERT(!"Invalid a_DecryptedMaxLength!");
+ return -1;
+ }
+ if (a_DecryptedMaxLength < m_Rsa.len)
+ {
+ LOGD("%s: Invalid a_DecryptedMaxLength: got %u, exp at least %u",
+ __FUNCTION__, (unsigned)a_EncryptedLength, (unsigned)(m_Rsa.len)
+ );
+ ASSERT(!"Invalid a_DecryptedMaxLength!");
+ return -1;
+ }
+ size_t DecryptedLength;
+ int res = rsa_pkcs1_decrypt(
+ &m_Rsa, ctr_drbg_random, &m_Ctr_drbg, RSA_PRIVATE, &DecryptedLength,
+ a_EncryptedData, a_DecryptedData, a_DecryptedMaxLength
+ );
+ if (res != 0)
+ {
+ return -1;
+ }
+ return (int)DecryptedLength;
+}
+
+
+
+
+
+int cRSAPrivateKey::Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte * a_EncryptedData, size_t a_EncryptedMaxLength)
+{
+ if (a_EncryptedMaxLength < m_Rsa.len)
+ {
+ LOGD("%s: Invalid a_EncryptedMaxLength: got %u, exp at least %u",
+ __FUNCTION__, (unsigned)a_EncryptedMaxLength, (unsigned)(m_Rsa.len)
+ );
+ ASSERT(!"Invalid a_DecryptedMaxLength!");
+ return -1;
+ }
+ if (a_PlainLength < m_Rsa.len)
+ {
+ LOGD("%s: Invalid a_PlainLength: got %u, exp at least %u",
+ __FUNCTION__, (unsigned)a_PlainLength, (unsigned)(m_Rsa.len)
+ );
+ ASSERT(!"Invalid a_PlainLength!");
+ return -1;
+ }
+ size_t DecryptedLength;
+ int res = rsa_pkcs1_encrypt(
+ &m_Rsa, ctr_drbg_random, &m_Ctr_drbg, RSA_PUBLIC,
+ a_PlainLength, a_PlainData, a_EncryptedData
+ );
+ if (res != 0)
+ {
+ return -1;
+ }
+ return (int)DecryptedLength;
+}
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cAESCFBDecryptor:
+
+cAESCFBDecryptor::cAESCFBDecryptor(void) :
+ m_IsValid(false),
+ m_IVOffset(0)
+{
+}
+
+
+
+
+
+cAESCFBDecryptor::~cAESCFBDecryptor()
+{
+ // Clear the leftover in-memory data, so that they can't be accessed by a backdoor
+ memset(&m_Aes, 0, sizeof(m_Aes));
+}
+
+
+
+
+
+void cAESCFBDecryptor::Init(const Byte a_Key[16], const Byte a_IV[16])
+{
+ ASSERT(!IsValid()); // Cannot Init twice
+
+ memcpy(m_IV, a_IV, 16);
+ aes_setkey_enc(&m_Aes, a_Key, 128);
+ m_IsValid = true;
+}
+
+
+
+
+
+void cAESCFBDecryptor::ProcessData(Byte * a_DecryptedOut, const Byte * a_EncryptedIn, size_t a_Length)
+{
+ ASSERT(IsValid()); // Must Init() first
+
+ // PolarSSL doesn't support AES-CFB8, need to implement it manually:
+ for (size_t i = 0; i < a_Length; i++)
+ {
+ Byte Buffer[sizeof(m_IV)];
+ aes_crypt_ecb(&m_Aes, AES_ENCRYPT, m_IV, Buffer);
+ for (size_t idx = 0; idx < sizeof(m_IV) - 1; idx++)
+ {
+ m_IV[idx] = m_IV[idx + 1];
+ }
+ m_IV[sizeof(m_IV) - 1] = a_EncryptedIn[i];
+ a_DecryptedOut[i] = a_EncryptedIn[i] ^ Buffer[0];
+ }
+}
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cAESCFBEncryptor:
+
+cAESCFBEncryptor::cAESCFBEncryptor(void) :
+ m_IsValid(false),
+ m_IVOffset(0)
+{
+}
+
+
+
+
+
+cAESCFBEncryptor::~cAESCFBEncryptor()
+{
+ // Clear the leftover in-memory data, so that they can't be accessed by a backdoor
+ memset(&m_Aes, 0, sizeof(m_Aes));
+}
+
+
+
+
+
+void cAESCFBEncryptor::Init(const Byte a_Key[16], const Byte a_IV[16])
+{
+ ASSERT(!IsValid()); // Cannot Init twice
+ ASSERT(m_IVOffset == 0);
+
+ memcpy(m_IV, a_IV, 16);
+ aes_setkey_enc(&m_Aes, a_Key, 128);
+ m_IsValid = true;
+}
+
+
+
+
+
+void cAESCFBEncryptor::ProcessData(Byte * a_EncryptedOut, const Byte * a_PlainIn, size_t a_Length)
+{
+ ASSERT(IsValid()); // Must Init() first
+
+ // PolarSSL doesn't do AES-CFB8, so we need to implement it ourselves:
+ for (size_t i = 0; i < a_Length; i++)
+ {
+ Byte Buffer[sizeof(m_IV)];
+ aes_crypt_ecb(&m_Aes, AES_ENCRYPT, m_IV, Buffer);
+ for (size_t idx = 0; idx < sizeof(m_IV) - 1; idx++)
+ {
+ m_IV[idx] = m_IV[idx + 1];
+ }
+ a_EncryptedOut[i] = a_PlainIn[i] ^ Buffer[0];
+ m_IV[sizeof(m_IV) - 1] = a_EncryptedOut[i];
+ }
+}
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cSHA1Checksum:
+
+cSHA1Checksum::cSHA1Checksum(void) :
+ m_DoesAcceptInput(true)
+{
+ sha1_starts(&m_Sha1);
+}
+
+
+
+
+
+void cSHA1Checksum::Update(const Byte * a_Data, size_t a_Length)
+{
+ ASSERT(m_DoesAcceptInput); // Not Finalize()-d yet, or Restart()-ed
+
+ sha1_update(&m_Sha1, a_Data, a_Length);
+}
+
+
+
+
+
+void cSHA1Checksum::Finalize(cSHA1Checksum::Checksum & a_Output)
+{
+ ASSERT(m_DoesAcceptInput); // Not Finalize()-d yet, or Restart()-ed
+
+ sha1_finish(&m_Sha1, a_Output);
+ m_DoesAcceptInput = false;
+}
+
+
+
+
+
+void cSHA1Checksum::DigestToJava(const Checksum & a_Digest, AString & a_Out)
+{
+ Checksum Digest;
+ memcpy(Digest, a_Digest, sizeof(Digest));
+
+ bool IsNegative = (Digest[0] >= 0x80);
+ if (IsNegative)
+ {
+ // Two's complement:
+ bool carry = true; // Add one to the whole number
+ for (int i = 19; i >= 0; i--)
+ {
+ Digest[i] = ~Digest[i];
+ if (carry)
+ {
+ carry = (Digest[i] == 0xff);
+ Digest[i]++;
+ }
+ }
+ }
+ a_Out.clear();
+ a_Out.reserve(40);
+ for (int i = 0; i < 20; i++)
+ {
+ AppendPrintf(a_Out, "%02x", Digest[i]);
+ }
+ while ((a_Out.length() > 0) && (a_Out[0] == '0'))
+ {
+ a_Out.erase(0, 1);
+ }
+ if (IsNegative)
+ {
+ a_Out.insert(0, "-");
+ }
+}
+
+
+
+
+
+
+void cSHA1Checksum::Restart(void)
+{
+ sha1_starts(&m_Sha1);
+ m_DoesAcceptInput = true;
+}
+
+
+
+
diff --git a/src/Crypto.h b/src/Crypto.h
new file mode 100644
index 000000000..a97f34fbf
--- /dev/null
+++ b/src/Crypto.h
@@ -0,0 +1,169 @@
+
+// Crypto.h
+
+// Declares classes that wrap the cryptographic code library
+
+
+
+
+
+#pragma once
+
+#include "polarssl/rsa.h"
+#include "polarssl/aes.h"
+#include "polarssl/entropy.h"
+#include "polarssl/ctr_drbg.h"
+#include "polarssl/sha1.h"
+
+
+
+
+
+/** Encapsulates an RSA private key used in PKI cryptography */
+class cRSAPrivateKey
+{
+public:
+ /** Creates a new empty object, the key is not assigned */
+ cRSAPrivateKey(void);
+
+ /** Deep-copies the key from a_Other */
+ cRSAPrivateKey(const cRSAPrivateKey & a_Other);
+
+ ~cRSAPrivateKey();
+
+ /** Generates a new key within this object, with the specified size in bits.
+ Returns true on success, false on failure. */
+ bool Generate(unsigned a_KeySizeBits = 1024);
+
+ /** Returns the public key part encoded in ASN1 DER encoding */
+ AString GetPubKeyDER(void);
+
+ /** Decrypts the data using RSAES-PKCS#1 algorithm.
+ Both a_EncryptedData and a_DecryptedData must be at least <KeySizeBytes> bytes large.
+ Returns the number of bytes decrypted, or negative number for error. */
+ int Decrypt(const Byte * a_EncryptedData, size_t a_EncryptedLength, Byte * a_DecryptedData, size_t a_DecryptedMaxLength);
+
+ /** Encrypts the data using RSAES-PKCS#1 algorithm.
+ Both a_EncryptedData and a_DecryptedData must be at least <KeySizeBytes> bytes large.
+ Returns the number of bytes decrypted, or negative number for error. */
+ int Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte * a_EncryptedData, size_t a_EncryptedMaxLength);
+
+protected:
+ rsa_context m_Rsa;
+ entropy_context m_Entropy;
+ ctr_drbg_context m_Ctr_drbg;
+
+ /** Initializes the m_Entropy and m_Ctr_drbg contexts
+ Common part of this object's construction, called from all constructors. */
+ void InitRnd(void);
+} ;
+
+
+
+
+
+/** Decrypts data using the AES / CFB (128) algorithm */
+class cAESCFBDecryptor
+{
+public:
+ Byte test;
+
+ cAESCFBDecryptor(void);
+ ~cAESCFBDecryptor();
+
+ /** Initializes the decryptor with the specified Key / IV */
+ void Init(const Byte a_Key[16], const Byte a_IV[16]);
+
+ /** Decrypts a_Length bytes of the encrypted data; produces a_Length output bytes */
+ void ProcessData(Byte * a_DecryptedOut, const Byte * a_EncryptedIn, size_t a_Length);
+
+ /** Returns true if the object has been initialized with the Key / IV */
+ bool IsValid(void) const { return m_IsValid; }
+
+protected:
+ aes_context m_Aes;
+
+ /** The InitialVector, used by the CFB mode decryption */
+ Byte m_IV[16];
+
+ /** Current offset in the m_IV, used by the CFB mode decryption */
+ size_t m_IVOffset;
+
+ /** Indicates whether the object has been initialized with the Key / IV */
+ bool m_IsValid;
+} ;
+
+
+
+
+
+/** Encrypts data using the AES / CFB (128) algorithm */
+class cAESCFBEncryptor
+{
+public:
+ Byte test;
+
+ cAESCFBEncryptor(void);
+ ~cAESCFBEncryptor();
+
+ /** Initializes the decryptor with the specified Key / IV */
+ void Init(const Byte a_Key[16], const Byte a_IV[16]);
+
+ /** Encrypts a_Length bytes of the plain data; produces a_Length output bytes */
+ void ProcessData(Byte * a_EncryptedOut, const Byte * a_PlainIn, size_t a_Length);
+
+ /** Returns true if the object has been initialized with the Key / IV */
+ bool IsValid(void) const { return m_IsValid; }
+
+protected:
+ aes_context m_Aes;
+
+ /** The InitialVector, used by the CFB mode encryption */
+ Byte m_IV[16];
+
+ /** Current offset in the m_IV, used by the CFB mode encryption */
+ size_t m_IVOffset;
+
+ /** Indicates whether the object has been initialized with the Key / IV */
+ bool m_IsValid;
+} ;
+
+
+
+
+
+/** Calculates a SHA1 checksum for data stream */
+class cSHA1Checksum
+{
+public:
+ typedef Byte Checksum[20]; // The type used for storing the checksum
+
+ cSHA1Checksum(void);
+
+ /** Adds the specified data to the checksum */
+ void Update(const Byte * a_Data, size_t a_Length);
+
+ /** Calculates and returns the final checksum */
+ void Finalize(Checksum & a_Output);
+
+ /** Returns true if the object is accepts more input data, false if Finalize()-d (need to Restart()) */
+ bool DoesAcceptInput(void) const { return m_DoesAcceptInput; }
+
+ /** Converts a raw 160-bit SHA1 digest into a Java Hex representation
+ According to http://wiki.vg/wiki/index.php?title=Protocol_Encryption&oldid=2802
+ */
+ static void DigestToJava(const Checksum & a_Digest, AString & a_JavaOut);
+
+ /** Clears the current context and start a new checksum calculation */
+ void Restart(void);
+
+protected:
+ /** True if the object is accepts more input data, false if Finalize()-d (need to Restart()) */
+ bool m_DoesAcceptInput;
+
+ sha1_context m_Sha1;
+} ;
+
+
+
+
diff --git a/src/Defines.h b/src/Defines.h
index 7a86f499e..0dcc3214a 100644
--- a/src/Defines.h
+++ b/src/Defines.h
@@ -5,8 +5,6 @@
-typedef unsigned char Byte;
-
/// List of slot numbers, used for inventory-painting
typedef std::vector<int> cSlotNums;
diff --git a/src/Globals.h b/src/Globals.h
index d2080b8eb..7e53da80e 100644
--- a/src/Globals.h
+++ b/src/Globals.h
@@ -91,6 +91,9 @@ typedef unsigned long long UInt64;
typedef unsigned int UInt32;
typedef unsigned short UInt16;
+typedef unsigned char Byte;
+
+
diff --git a/src/LeakFinder.cpp b/src/LeakFinder.cpp
index 9d7f185ba..42a5afe56 100644
--- a/src/LeakFinder.cpp
+++ b/src/LeakFinder.cpp
@@ -862,8 +862,10 @@ static int MyAllocHook(int nAllocType, void *pvData,
{
// RequestID was found
size_t temp = g_CurrentMemUsage;
- g_CurrentMemUsage -= nSize ;
- g_pCRTTable->Remove(lRequest);
+ if (g_pCRTTable->Remove(lRequest))
+ {
+ g_CurrentMemUsage -= nSize;
+ }
if (g_CurrentMemUsage > temp)
{
printf("********************************************\n");
@@ -896,8 +898,11 @@ static int MyAllocHook(int nAllocType, void *pvData,
// Try to find the RequestID in the Hash-Table, mark it that it was freed
lReallocRequest = pHead->lRequest;
size_t temp = g_CurrentMemUsage;
- g_CurrentMemUsage -= pHead->nDataSize;
bRet = g_pCRTTable->Remove(lReallocRequest);
+ if (bRet)
+ {
+ g_CurrentMemUsage -= pHead->nDataSize;
+ }
if (g_CurrentMemUsage > temp)
{
printf("********************************************\n");
diff --git a/src/Protocol/Protocol132.cpp b/src/Protocol/Protocol132.cpp
index b4ca37d37..f5fd95c7e 100644
--- a/src/Protocol/Protocol132.cpp
+++ b/src/Protocol/Protocol132.cpp
@@ -28,13 +28,14 @@
#pragma warning(disable:4702)
#endif
-#include "cryptopp/randpool.h"
-
#ifdef _MSC_VER
#pragma warning(pop)
#endif
+
+
+
#define HANDLE_PACKET_READ(Proc, Type, Var) \
Type Var; \
{ \
@@ -49,17 +50,6 @@
-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...
@@ -93,81 +83,6 @@ enum
-// Converts a raw 160-bit SHA1 digest into a Java Hex representation
-// According to http://wiki.vg/wiki/index.php?title=Protocol_Encryption&oldid=2802
-static void DigestToJava(byte a_Digest[20], AString & a_Out)
-{
- bool IsNegative = (a_Digest[0] >= 0x80);
- if (IsNegative)
- {
- // Two's complement:
- bool carry = true; // Add one to the whole number
- for (int i = 19; i >= 0; i--)
- {
- a_Digest[i] = ~a_Digest[i];
- if (carry)
- {
- carry = (a_Digest[i] == 0xff);
- a_Digest[i]++;
- }
- }
- }
- a_Out.clear();
- a_Out.reserve(40);
- for (int i = 0; i < 20; i++)
- {
- AppendPrintf(a_Out, "%02x", a_Digest[i]);
- }
- while ((a_Out.length() > 0) && (a_Out[0] == '0'))
- {
- a_Out.erase(0, 1);
- }
- if (IsNegative)
- {
- a_Out.insert(0, "-");
- }
-}
-
-
-
-
-
-/*
-// Self-test the hash formatting for known values:
-// sha1(Notch) : 4ed1f46bbe04bc756bcb17c0c7ce3e4632f06a48
-// sha1(jeb_) : -7c9d5b0044c130109a5d7b5fb5c317c02b4e28c1
-// sha1(simon) : 88e16a1019277b15d58faf0541e11910eb756f6
-
-class Test
-{
-public:
- Test(void)
- {
- AString DigestNotch, DigestJeb, DigestSimon;
- byte Digest[20];
- CryptoPP::SHA1 Checksum;
- Checksum.Update((const byte *)"Notch", 5);
- Checksum.Final(Digest);
- DigestToJava(Digest, DigestNotch);
- Checksum.Restart();
- Checksum.Update((const byte *)"jeb_", 4);
- Checksum.Final(Digest);
- DigestToJava(Digest, DigestJeb);
- Checksum.Restart();
- Checksum.Update((const byte *)"simon", 5);
- Checksum.Final(Digest);
- DigestToJava(Digest, DigestSimon);
- printf("Notch: \"%s\"", DigestNotch.c_str());
- printf("jeb_: \"%s\"", DigestJeb.c_str());
- printf("simon: \"%s\"", DigestSimon.c_str());
- }
-} test;
-*/
-
-
-
-
-
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cProtocol132:
@@ -197,11 +112,11 @@ void cProtocol132::DataReceived(const char * a_Data, int a_Size)
{
if (m_IsEncrypted)
{
- byte Decrypted[512];
+ Byte Decrypted[512];
while (a_Size > 0)
{
int NumBytes = (a_Size > (int)sizeof(Decrypted)) ? (int)sizeof(Decrypted) : a_Size;
- m_Decryptor.ProcessData(Decrypted, (byte *)a_Data, NumBytes);
+ m_Decryptor.ProcessData(Decrypted, (Byte *)a_Data, NumBytes);
super::DataReceived((const char *)Decrypted, NumBytes);
a_Size -= NumBytes;
a_Data += NumBytes;
@@ -582,9 +497,7 @@ int cProtocol132::ParseHandshake(void)
return PARSE_OK; // Player is not allowed into the server
}
- // Send a 0xFD Encryption Key Request http://wiki.vg/Protocol#0xFD
- CryptoPP::StringSink sink(m_ServerPublicKey); // 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#0xFD
SendEncryptionKeyRequest();
return PARSE_OK;
@@ -596,7 +509,7 @@ int cProtocol132::ParseHandshake(void)
int cProtocol132::ParseClientStatuses(void)
{
- HANDLE_PACKET_READ(ReadByte, byte, Status);
+ HANDLE_PACKET_READ(ReadByte, Byte, Status);
if ((Status & 1) == 0)
{
m_Client->HandleLogin(39, m_Username);
@@ -714,11 +627,11 @@ void cProtocol132::Flush(void)
int a_Size = m_DataToSend.size();
if (m_IsEncrypted)
{
- byte Encrypted[8192]; // Larger buffer, we may be sending lots of data (chunks)
+ Byte Encrypted[8192]; // Larger buffer, we may be sending lots of data (chunks)
while (a_Size > 0)
{
int NumBytes = (a_Size > (int)sizeof(Encrypted)) ? (int)sizeof(Encrypted) : a_Size;
- m_Encryptor.ProcessData(Encrypted, (byte *)a_Data, NumBytes);
+ m_Encryptor.ProcessData(Encrypted, (Byte *)a_Data, NumBytes);
super::SendData((const char *)Encrypted, NumBytes);
a_Size -= NumBytes;
a_Data += NumBytes;
@@ -880,8 +793,8 @@ void cProtocol132::SendEncryptionKeyRequest(void)
cCSLock Lock(m_CSPacket);
WriteByte(0xfd);
WriteString(cRoot::Get()->GetServer()->GetServerID());
- WriteShort((short)m_ServerPublicKey.size());
- SendData(m_ServerPublicKey.data(), m_ServerPublicKey.size());
+ WriteShort((short)(cRoot::Get()->GetServer()->GetPublicKeyDER().size()));
+ SendData(cRoot::Get()->GetServer()->GetPublicKeyDER().data(), cRoot::Get()->GetServer()->GetPublicKeyDER().size());
WriteShort(4);
WriteInt((int)(intptr_t)this); // Using 'this' as the cryptographic nonce, so that we don't have to generate one each time :)
Flush();
@@ -894,13 +807,11 @@ void cProtocol132::SendEncryptionKeyRequest(void)
void cProtocol132::HandleEncryptionKeyResponse(const AString & a_EncKey, const AString & a_EncNonce)
{
// Decrypt EncNonce using privkey
- RSAES<PKCS1v15>::Decryptor rsaDecryptor(cRoot::Get()->GetServer()->GetPrivateKey());
- time_t CurTime = time(NULL);
- CryptoPP::RandomPool rng;
- rng.Put((const byte *)&CurTime, sizeof(CurTime));
+ cRSAPrivateKey & rsaDecryptor = cRoot::Get()->GetServer()->GetPrivateKey();
+
Int32 DecryptedNonce[MAX_ENC_LEN / sizeof(Int32)];
- DecodingResult res = rsaDecryptor.Decrypt(rng, (const byte *)a_EncNonce.data(), a_EncNonce.size(), (byte *)DecryptedNonce);
- if (!res.isValidCoding || (res.messageLength != 4))
+ int res = rsaDecryptor.Decrypt((const Byte *)a_EncNonce.data(), a_EncNonce.size(), (Byte *)DecryptedNonce, sizeof(DecryptedNonce));
+ if (res != 4)
{
LOGD("Bad nonce length");
m_Client->Kick("Hacked client");
@@ -914,9 +825,9 @@ void cProtocol132::HandleEncryptionKeyResponse(const AString & a_EncKey, const A
}
// 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))
+ Byte DecryptedKey[MAX_ENC_LEN];
+ res = rsaDecryptor.Decrypt((const Byte *)a_EncKey.data(), a_EncKey.size(), DecryptedKey, sizeof(DecryptedKey));
+ if (res != 16)
{
LOGD("Bad key length");
m_Client->Kick("Hacked client");
@@ -932,6 +843,12 @@ void cProtocol132::HandleEncryptionKeyResponse(const AString & a_EncKey, const A
Flush();
}
+ #ifdef _DEBUG
+ AString DecryptedKeyHex;
+ CreateHexDump(DecryptedKeyHex, DecryptedKey, res, 16);
+ LOGD("Received encryption key, %d bytes:\n%s", res, DecryptedKeyHex.c_str());
+ #endif
+
StartEncryption(DecryptedKey);
return;
}
@@ -940,21 +857,21 @@ void cProtocol132::HandleEncryptionKeyResponse(const AString & a_EncKey, const A
-void cProtocol132::StartEncryption(const byte * a_Key)
+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_Encryptor.Init(a_Key, a_Key);
+ m_Decryptor.Init(a_Key, a_Key);
m_IsEncrypted = true;
// Prepare the m_AuthServerID:
- CryptoPP::SHA1 Checksum;
+ cSHA1Checksum Checksum;
AString ServerID = cRoot::Get()->GetServer()->GetServerID();
- Checksum.Update((const byte *)ServerID.c_str(), ServerID.length());
+ Checksum.Update((const Byte *)ServerID.c_str(), ServerID.length());
Checksum.Update(a_Key, 16);
- Checksum.Update((const byte *)m_ServerPublicKey.c_str(), m_ServerPublicKey.length());
- byte Digest[20];
- Checksum.Final(Digest);
- DigestToJava(Digest, m_AuthServerID);
+ Checksum.Update((const Byte *)cRoot::Get()->GetServer()->GetPublicKeyDER().data(), cRoot::Get()->GetServer()->GetPublicKeyDER().size());
+ Byte Digest[20];
+ Checksum.Finalize(Digest);
+ cSHA1Checksum::DigestToJava(Digest, m_AuthServerID);
}
diff --git a/src/Protocol/Protocol132.h b/src/Protocol/Protocol132.h
index 80fc8740a..89f4636f5 100644
--- a/src/Protocol/Protocol132.h
+++ b/src/Protocol/Protocol132.h
@@ -20,13 +20,12 @@
#pragma warning(disable:4702)
#endif
-#include "cryptopp/modes.h"
-#include "cryptopp/aes.h"
-
#ifdef _MSC_VER
#pragma warning(pop)
#endif
+#include "../Crypto.h"
+
@@ -79,16 +78,15 @@ public:
protected:
bool m_IsEncrypted;
- CryptoPP::CFB_Mode<CryptoPP::AES>::Decryption m_Decryptor;
- CryptoPP::CFB_Mode<CryptoPP::AES>::Encryption m_Encryptor;
+
+ cAESCFBDecryptor m_Decryptor;
+ cAESCFBEncryptor m_Encryptor;
+
AString m_DataToSend;
/// The ServerID used for session authentication; set in StartEncryption(), used in GetAuthServerID()
AString m_AuthServerID;
- /// The server's public key, as used by SendEncryptionKeyRequest() and StartEncryption()
- AString m_ServerPublicKey;
-
virtual void SendData(const char * a_Data, int a_Size) override;
// DEBUG:
@@ -108,7 +106,7 @@ protected:
void HandleEncryptionKeyResponse(const AString & a_EncKey, const AString & a_EncNonce);
/// Starts the symmetric encryption with the specified key; also sets m_AuthServerID
- void StartEncryption(const byte * a_Key);
+ void StartEncryption(const Byte * a_Key);
} ;
diff --git a/src/Protocol/Protocol14x.cpp b/src/Protocol/Protocol14x.cpp
index 127ce9d4b..f82e6de45 100644
--- a/src/Protocol/Protocol14x.cpp
+++ b/src/Protocol/Protocol14x.cpp
@@ -33,8 +33,6 @@ Implements the 1.4.x protocol classes representing these protocols:
#pragma warning(disable:4702)
#endif
-#include "cryptopp/randpool.h"
-
#ifdef _MSC_VER
#pragma warning(pop)
#endif
diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp
index 504dd99c3..9bb2cfbf0 100644
--- a/src/Protocol/Protocol17x.cpp
+++ b/src/Protocol/Protocol17x.cpp
@@ -90,11 +90,11 @@ void cProtocol172::DataReceived(const char * a_Data, int a_Size)
{
if (m_IsEncrypted)
{
- byte Decrypted[512];
+ 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);
+ m_Decryptor.ProcessData(Decrypted, (Byte *)a_Data, NumBytes);
AddReceivedData((const char *)Decrypted, NumBytes);
a_Size -= NumBytes;
a_Data += NumBytes;
@@ -1736,11 +1736,11 @@ void cProtocol172::SendData(const char * a_Data, int a_Size)
{
if (m_IsEncrypted)
{
- byte Encrypted[8192]; // Larger buffer, we may be sending lots of data (chunks)
+ Byte Encrypted[8192]; // 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);
+ m_Encryptor.ProcessData(Encrypted, (Byte *)a_Data, NumBytes);
m_Client->SendData((const char *)Encrypted, NumBytes);
a_Size -= NumBytes;
a_Data += NumBytes;
diff --git a/src/Protocol/Protocol17x.h b/src/Protocol/Protocol17x.h
index cac7f0d29..72544b575 100644
--- a/src/Protocol/Protocol17x.h
+++ b/src/Protocol/Protocol17x.h
@@ -26,21 +26,20 @@ Declares the 1.7.x protocol classes:
#pragma warning(disable:4702)
#endif
-#include "cryptopp/modes.h"
-#include "cryptopp/aes.h"
-
#ifdef _MSC_VER
#pragma warning(pop)
#endif
+#include "../Crypto.h"
+
class cProtocol172 :
- public cProtocol // TODO
+ public cProtocol
{
- typedef cProtocol super; // TODO
+ typedef cProtocol super;
public:
@@ -220,9 +219,10 @@ protected:
cByteBuffer m_OutPacketLenBuffer;
bool m_IsEncrypted;
- CryptoPP::CFB_Mode<CryptoPP::AES>::Decryption m_Decryptor;
- CryptoPP::CFB_Mode<CryptoPP::AES>::Encryption m_Encryptor;
+ cAESCFBDecryptor m_Decryptor;
+ cAESCFBEncryptor m_Encryptor;
+
/** The logfile where the comm is logged, when g_ShouldLogComm is true */
cFile m_CommLogFile;
diff --git a/src/Protocol/ProtocolRecognizer.cpp b/src/Protocol/ProtocolRecognizer.cpp
index de5dd3fb9..32409c2aa 100644
--- a/src/Protocol/ProtocolRecognizer.cpp
+++ b/src/Protocol/ProtocolRecognizer.cpp
@@ -965,7 +965,7 @@ void cProtocolRecognizer::SendLengthlessServerPing(void)
m_Buffer.ResetRead();
if (m_Buffer.CanReadBytes(2))
{
- byte val;
+ Byte val;
m_Buffer.ReadByte(val); // Packet type - Serverlist ping
m_Buffer.ReadByte(val); // 0x01 magic value
ASSERT(val == 0x01);
diff --git a/src/Server.cpp b/src/Server.cpp
index 34ee066cb..f64af62eb 100644
--- a/src/Server.cpp
+++ b/src/Server.cpp
@@ -284,17 +284,9 @@ int cServer::GetNumPlayers(void)
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?
-
LOGD("Generating protocol encryption keypair...");
-
- time_t CurTime = time(NULL);
- CryptoPP::RandomPool rng;
- rng.Put((const byte *)&CurTime, sizeof(CurTime));
- m_PrivateKey.GenerateRandomWithKeySize(rng, 1024);
- CryptoPP::RSA::PublicKey pk(m_PrivateKey);
- m_PublicKey = pk;
+ VERIFY(m_PrivateKey.Generate(1024));
+ m_PublicKeyDER = m_PrivateKey.GetPubKeyDER();
}
diff --git a/src/Server.h b/src/Server.h
index bb55e81b6..15eafc00a 100644
--- a/src/Server.h
+++ b/src/Server.h
@@ -23,8 +23,7 @@
#pragma warning(disable:4702)
#endif
-#include "cryptopp/rsa.h"
-#include "cryptopp/randpool.h"
+#include "Crypto.h"
#ifdef _MSC_VER
#pragma warning(pop)
@@ -110,8 +109,8 @@ public: // tolua_export
/** Returns base64 encoded favicon data (obtained from favicon.png) */
const AString & GetFaviconData(void) const { return m_FaviconData; }
- CryptoPP::RSA::PrivateKey & GetPrivateKey(void) { return m_PrivateKey; }
- CryptoPP::RSA::PublicKey & GetPublicKey (void) { return m_PublicKey; }
+ cRSAPrivateKey & GetPrivateKey(void) { return m_PrivateKey; }
+ const AString & GetPublicKeyDER(void) const { return m_PublicKeyDER; }
private:
@@ -180,8 +179,11 @@ private:
bool m_bRestarting;
- CryptoPP::RSA::PrivateKey m_PrivateKey;
- CryptoPP::RSA::PublicKey m_PublicKey;
+ /** The private key used for the assymetric encryption start in the protocols */
+ cRSAPrivateKey m_PrivateKey;
+
+ /** Public key for m_PrivateKey, ASN1-DER-encoded */
+ AString m_PublicKeyDER;
cRCONServer m_RCONServer;