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/crypto.cc | |
| 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/crypto.cc')
| -rw-r--r-- | src/crypto.cc | 107 |
1 files changed, 106 insertions, 1 deletions
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; +} |
