diff options
| author | fusion32 <marcopuzziello@gmail.com> | 2025-07-03 10:10:27 -0300 |
|---|---|---|
| committer | fusion32 <marcopuzziello@gmail.com> | 2025-07-03 10:46:43 -0300 |
| commit | e65dc561acab7a9e49f59777f16cb040c574c64d (patch) | |
| tree | 2206c066b97b1948a4b98647c91a369d3b9863c8 /src | |
| parent | e782274ade8d7307e157a997d6ac3bcaa4130024 (diff) | |
| download | game-e65dc561acab7a9e49f59777f16cb040c574c64d.tar.gz game-e65dc561acab7a9e49f59777f16cb040c574c64d.zip | |
implement `crypto.cc` with OpenSSL + fix config loading
I considered reversing the original `vlong` implementation but
OpenSSL is just simpler, more secure, and most importantly, is
already there. I also made it so the key is now stored in a PEM
file (`tibia.pem`) so it can be easily swapped without re-compiling.
This was the last piece to build and run a working executable,
except that we now need to implement a query manager for the server
to communicate with. I was able to fix a small problem with loading
the config before hitting the problem with the query manager, which
was expected.
The next task should be getting a query manager up and running
before starting phase two of upgrading and fixing the server itself.
Diffstat (limited to 'src')
| -rw-r--r-- | src/communication.cc | 14 | ||||
| -rw-r--r-- | src/config.cc | 6 | ||||
| -rw-r--r-- | src/crypto.cc | 107 | ||||
| -rw-r--r-- | src/crypto.hh | 38 | ||||
| -rw-r--r-- | src/main.cc | 2 | ||||
| -rw-r--r-- | src/query.hh | 2 |
6 files changed, 120 insertions, 49 deletions
diff --git a/src/communication.cc b/src/communication.cc index 9f0e6e5..a15e20a 100644 --- a/src/communication.cc +++ b/src/communication.cc @@ -23,16 +23,6 @@ #define MAX_COMMUNICATION_THREADS 1100 #define COMMUNICATION_THREAD_STACK_SIZE ((int)KB(64)) -static const char RSA_PRIME_P[] = - "1201758001370723323398753778257470257713354828752713123415294815" - "0506251412291888866940292054989907714155267326586216043845592229" - "084368540020196135619327879"; - -static const char RSA_PRIME_Q[] = - "1189892136861686835188050824611210139447876026576932541274639840" - "5473436969889506919017477758618276066588858607419440134394668095" - "105156501566867770737187273"; - static int TERMINALVERSION[3] = {770, 770, 770}; static int TCPSocket; static ThreadHandle AcceptorThread; @@ -1533,7 +1523,9 @@ void InitCommunication(void){ AcceptorThreadPID = 0; ActiveConnections = 0; QueryManagerConnectionPool.init(); - PrivateKey.init(RSA_PRIME_P, RSA_PRIME_Q); + + // TODO(fusion): This is arbitrary, should probably be set in the config. + PrivateKey.initFromFile("tibia.pem"); OpenSocket(); if(TCPSocket == -1){ diff --git a/src/config.cc b/src/config.cc index 257985b..b9c33bc 100644 --- a/src/config.cc +++ b/src/config.cc @@ -106,6 +106,7 @@ void ReadConfig(void){ MANAGER_DATABASE.Database[0] = 0; char FileName[4096]; +#if 0 if(const char *Home = getenv("home")){ snprintf(FileName, sizeof(FileName), "%s/.tibia", Home); }else if(const char *Home = getenv("HOME")){ @@ -113,6 +114,9 @@ void ReadConfig(void){ }else{ snprintf(FileName, sizeof(FileName), ".tibia"); } +#else + snprintf(FileName, sizeof(FileName), ".tibia"); +#endif if(!FileExists(FileName)){ throw "cannot find config-file"; @@ -130,7 +134,7 @@ void ReadConfig(void){ } char Identifier[MAX_IDENT_LENGTH]; - strcpy(Identifier, Script.readIdentifier()); + strcpy(Identifier, Script.getIdentifier()); Script.readSymbol('='); // TODO(fusion): Ughh... Get rid of all `strcpy`s. A malicious configuration diff --git a/src/crypto.cc b/src/crypto.cc index b6df866..aa53dc3 100644 --- a/src/crypto.cc +++ b/src/crypto.cc @@ -1,3 +1,108 @@ #include "crypto.hh" -// TODO +#include <openssl/err.h> +#include <openssl/pem.h> + +static void DumpOpenSSLErrors(const char *Where, const char *What){ + error("OpenSSL error(s) while executing %s at %s:\n", What, Where); + ERR_print_errors_cb( + [](const char *str, usize len, void *u) -> int { + // NOTE(fusion): These error strings already have trailing newlines, + // for whatever reason. + error("> %s", str); + return 1; + }, NULL); +} + +// TRSAPrivateKey +// ============================================================================= +TRSAPrivateKey::TRSAPrivateKey(void){ + m_RSA = NULL; +} + +TRSAPrivateKey::~TRSAPrivateKey(void){ + if(m_RSA){ + RSA_free(m_RSA); + m_RSA = NULL; + } +} + +void TRSAPrivateKey::initFromFile(const char *FileName){ + if(m_RSA != NULL){ + error("TRSAPrivateKey::init: Key already initialized.\n"); + return; + } + + FILE *File = fopen(FileName, "rb"); + if(File == NULL){ + error("TRSAPrivateKey::initFromFile: Failed to open \"%s\".\n", FileName); + return; + } + + m_RSA = PEM_read_RSAPrivateKey(File, NULL, NULL, NULL); + fclose(File); + + if(m_RSA == NULL){ + error("TRSAPrivateKey::initFromFile: Failed to read key from \"%s\".\n", FileName); + DumpOpenSSLErrors("TRSAPrivateKey::initFromFile", "PEM_read_RSAPrivateKey"); + }else if(RSA_size(m_RSA) != 128){ + error("TRSAPrivateKey::initFromFile: File \"%s\" doesn't contain a 1024-bit key", FileName); + RSA_free(m_RSA); + m_RSA = NULL; + } +} + +void TRSAPrivateKey::decrypt(uint8 *Data){ + if(m_RSA == NULL){ + error("TRSAPrivateKey::decrypt: Key not initialized.\n"); + return; + } + + // TODO(fusion): Pass in the length of `Data` for checking. + ASSERT(RSA_size(m_RSA) == 128); + + if(RSA_private_decrypt(128, Data, Data, m_RSA, RSA_NO_PADDING) == -1){ + DumpOpenSSLErrors("TRSAPrivateKey::decrypt", "RSA_private_decrypt"); + } +} + +// TXTEASymmetricKey +// ============================================================================= +void TXTEASymmetricKey::init(TReadBuffer *Buffer){ + m_SymmetricKey[0] = Buffer->readQuad(); + m_SymmetricKey[1] = Buffer->readQuad(); + m_SymmetricKey[2] = Buffer->readQuad(); + m_SymmetricKey[3] = Buffer->readQuad(); +} + +void TXTEASymmetricKey::encrypt(uint8 *Data){ + // TODO(fusion): This assumes both data endpoints have the same byte order. + // It's unlikely that there is anything other than little-endian but we + // should use a few helping functions to ensure compatibility. + uint32 Sum = 0x00000000UL; + uint32 Delta = 0x9E3779B9UL; + uint32 V0 = *(uint32*)(&Data[0]); + uint32 V1 = *(uint32*)(&Data[4]); + for(int i = 0; i < 32; i += 1){ + V0 += (((V1 << 4) ^ (V1 >> 5)) + V1) ^ (Sum + m_SymmetricKey[Sum & 3]); + Sum += Delta; + V1 += (((V0 << 4) ^ (V0 >> 5)) + V0) ^ (Sum + m_SymmetricKey[(Sum >> 11) & 3]); + } + *(uint32*)(&Data[0]) = V0; + *(uint32*)(&Data[4]) = V1; +} + +void TXTEASymmetricKey::decrypt(uint8 *Data){ + // TODO(fusion): Same as above. + uint32 Sum = 0xC6EF3720UL; + uint32 Delta = 0x9E3779B9UL; + uint32 V0 = *(uint32*)(&Data[0]); + uint32 V1 = *(uint32*)(&Data[4]); + for(int i = 0; i < 32; i += 1){ + V1 -= (((V0 << 4) ^ (V0 >> 5)) + V0) ^ (Sum + m_SymmetricKey[(Sum >> 11) & 3]); + Sum -= Delta; + V0 -= (((V1 << 4) ^ (V1 >> 5)) + V1) ^ (Sum + m_SymmetricKey[Sum & 3]); + } + *(uint32*)(&Data[0]) = V0; + *(uint32*)(&Data[4]) = V1; +} diff --git a/src/crypto.hh b/src/crypto.hh index 7159a37..b649ad8 100644 --- a/src/crypto.hh +++ b/src/crypto.hh @@ -2,52 +2,20 @@ #define TIBIA_CRYPTO_HH_ 1 #include "common.hh" - -// TODO(fusion): We might want to scrap this implementation and use OpenSSL instead. - -struct vlong_flex_unit{ - uint32 n; - uint32 *a; - uint32 z; -}; - -struct vlong_value: vlong_flex_unit { - uint32 share; -}; - -struct vlong{ - vlong_value *value; - int negative; -}; - -struct vlong_montgomery{ - vlong R; - vlong R1; - vlong m; - vlong n1; - vlong T; - vlong k; - uint32 N; -}; +#include <openssl/rsa.h> struct TRSAPrivateKey{ TRSAPrivateKey(void); ~TRSAPrivateKey(void); - void init(const char *PrimeP, const char *PrimeQ); + void initFromFile(const char *FileName); void decrypt(uint8 *Data); // single 128 bytes block // DATA // ================= - vlong m_PrimeP; - vlong m_PrimeQ; - vlong m_U; - vlong m_DP; - vlong m_DQ; + RSA *m_RSA; }; struct TXTEASymmetricKey{ - TXTEASymmetricKey(void); - ~TXTEASymmetricKey(void); void init(TReadBuffer *Buffer); void encrypt(uint8 *Data); // single 8 bytes block void decrypt(uint8 *Data); // single 8 bytes block diff --git a/src/main.cc b/src/main.cc index 92e7e73..2089641 100644 --- a/src/main.cc +++ b/src/main.cc @@ -216,7 +216,7 @@ void LoadWorldConfig(void){ static void InitAll(void){ try{ ReadConfig(); - //SetQueryManagerLoginData(1, WorldName); + SetQueryManagerLoginData(1, WorldName); LoadWorldConfig(); InitSHM(!BeADaemon); LockGame(); diff --git a/src/query.hh b/src/query.hh index dbba9dc..6ac6afb 100644 --- a/src/query.hh +++ b/src/query.hh @@ -187,4 +187,6 @@ struct TQueryManagerPoolConnection{ TQueryManagerConnection *QueryManagerConnection; }; +void SetQueryManagerLoginData(int Type, const char *Data); + #endif //TIBIA_QUERY_HH_ |
