diff --git a/src/Client/World/WorldSocket.cpp b/src/Client/World/WorldSocket.cpp index 7c4254c..f255d3f 100644 --- a/src/Client/World/WorldSocket.cpp +++ b/src/Client/World/WorldSocket.cpp @@ -4,11 +4,17 @@ #include "WorldSocket.h" #include "Opcodes.h" + + WorldSocket::WorldSocket(SocketHandler &h, WorldSession *s) : TcpSocket(h) { _session = s; _gothdr = false; _ok=false; + + //Dummy functions for unencrypted packets on WorldSocket + pDecryptRecv = &AuthCrypt::DecryptRecvDummy; + pEncryptSend = &AuthCrypt::EncryptSendDummy; } bool WorldSocket::IsOk(void) @@ -78,31 +84,43 @@ void WorldSocket::OnRead() break; } - // read first byte and check if size is 3 or 2 bytes - uint8 firstSizeByte; - ibuf.Read((char*)&firstSizeByte, 1); - _crypt.DecryptRecv(&firstSizeByte, 1); - - if (firstSizeByte & 0x80) // got large packet + if(GetSession()->GetInstance()->GetConf()->clientbuild > 6005) { - ServerPktHeaderBig hdr; - ibuf.Read(((char*)&hdr) + 1, sizeof(ServerPktHeaderBig) - 1); // read *big* header, except first byte - _crypt.DecryptRecv(((uint8*)&hdr) + 1, sizeof(ServerPktHeaderBig) - 1); // decrypt 2 of 3 bytes (first one already decrypted above) of size, and cmd - hdr.size[0] = firstSizeByte; // assign missing first byte + // read first byte and check if size is 3 or 2 bytes + uint8 firstSizeByte; + ibuf.Read((char*)&firstSizeByte, 1); + (_crypt.*pDecryptRecv)(&firstSizeByte, 1); + if (firstSizeByte & 0x80) // got large packet + { + ServerPktHeaderBig hdr; + ibuf.Read(((char*)&hdr) + 1, sizeof(ServerPktHeaderBig) - 1); // read *big* header, except first byte + (_crypt.*pDecryptRecv)(((uint8*)&hdr) + 1, sizeof(ServerPktHeaderBig) - 1); // decrypt 2 of 3 bytes (first one already decrypted above) of size, and cmd + hdr.size[0] = firstSizeByte; // assign missing first byte - uint32 realsize = ((hdr.size[0]&0x7F) << 16) | (hdr.size[1] << 8) | hdr.size[2]; - _remaining = realsize - 2; - _opcode = hdr.cmd; + uint32 realsize = ((hdr.size[0]&0x7F) << 16) | (hdr.size[1] << 8) | hdr.size[2]; + _remaining = realsize - 2; + _opcode = hdr.cmd; + } + else // "normal" packet + { + ServerPktHeader hdr; + ibuf.Read(((char*)&hdr) + 1, sizeof(ServerPktHeader) - 1); // read header, except first byte + (_crypt.*pDecryptRecv)(((uint8*)&hdr) + 1, sizeof(ServerPktHeader) - 1); // decrypt all except first + hdr.size |= firstSizeByte; // add already decrypted first byte + + _remaining = ntohs(hdr.size) - 2; + _opcode = hdr.cmd; + } } - else // "normal" packet + else { - ServerPktHeader hdr; - ibuf.Read(((char*)&hdr) + 1, sizeof(ServerPktHeader) - 1); // read header, except first byte - _crypt.DecryptRecv(((uint8*)&hdr) + 1, sizeof(ServerPktHeader) - 1); // decrypt all except first - hdr.size |= firstSizeByte; // add already decrypted first byte + ServerPktHeader hdr; + ibuf.Read(((char*)&hdr), sizeof(ServerPktHeader)); // read header, except first byte + (_crypt.*pDecryptRecv)(((uint8*)&hdr), sizeof(ServerPktHeader)); // decrypt all except first - _remaining = ntohs(hdr.size) - 2; - _opcode = hdr.cmd; + _remaining = ntohs(hdr.size) - 2; + _opcode = hdr.cmd; + } if(_opcode > MAX_OPCODE_ID) @@ -114,7 +132,6 @@ void WorldSocket::OnRead() // TODO: invent some way how to recover the crypt (reconnect?) return; } - // the header is fine, now check if there are more data if(_remaining == 0) // this is a packet with no data (like CMSG_NULL_ACTION) { @@ -138,7 +155,7 @@ void WorldSocket::SendWorldPacket(WorldPacket &pkt) memset(&hdr,0,sizeof(ClientPktHeader)); hdr.size = ntohs(pkt.size()+4); hdr.cmd = pkt.GetOpcode(); - _crypt.EncryptSend((uint8*)&hdr, 6); + (_crypt.*pEncryptSend)((uint8*)&hdr, 6); ByteBuffer final(pkt.size()+6); final.append((uint8*)&hdr,sizeof(ClientPktHeader)); if(pkt.size()) @@ -148,7 +165,27 @@ void WorldSocket::SendWorldPacket(WorldPacket &pkt) void WorldSocket::InitCrypt(BigNumber *k) { - _crypt.Init(k); + //As crypt + switch(GetSession()->GetInstance()->GetConf()->clientbuild) + { + case 6005: + { + logdebug("Setting Crypt to Build 6005"); + pInit = &AuthCrypt::Init_6005; + pDecryptRecv = &AuthCrypt::DecryptRecv_6005; + pEncryptSend = &AuthCrypt::EncryptSend_6005; + break; + } + default: + { + logdebug("Setting Crypt to Build 12340"); + pInit = &AuthCrypt::Init_12340; + pDecryptRecv = &AuthCrypt::DecryptRecv_12340; + pEncryptSend = &AuthCrypt::EncryptSend_12340; + break; + } + } + (_crypt.*pInit)(k); const char *hexstr = k->AsHexStr(); logdebug("WorldSocket: Crypt initialized [%s]",hexstr); OPENSSL_free((void*)hexstr); diff --git a/src/Client/World/WorldSocket.h b/src/Client/World/WorldSocket.h index 3a4134e..c398341 100644 --- a/src/Client/World/WorldSocket.h +++ b/src/Client/World/WorldSocket.h @@ -7,6 +7,7 @@ class WorldSession; class BigNumber; + #if defined( __GNUC__ ) #pragma pack(1) #else @@ -60,6 +61,9 @@ public: private: WorldSession *_session; AuthCrypt _crypt; + void (AuthCrypt::*pInit)(BigNumber *); + void (AuthCrypt::*pDecryptRecv)(uint8 *, size_t); + void (AuthCrypt::*pEncryptSend)(uint8 *, size_t); bool _gothdr; // true if only the header was recieved yet uint16 _opcode; // stores the last recieved opcode uint32 _remaining; // bytes amount of the next data packet diff --git a/src/shared/Auth/AuthCrypt.cpp b/src/shared/Auth/AuthCrypt.cpp index 8a0d14f..ec0ca50 100644 --- a/src/shared/Auth/AuthCrypt.cpp +++ b/src/shared/Auth/AuthCrypt.cpp @@ -30,7 +30,8 @@ AuthCrypt::~AuthCrypt() } -void AuthCrypt::Init(BigNumber *K) +// 3.3.5 +void AuthCrypt::Init_12340(BigNumber *K) { uint8 ClientDecryptionKey[SEED_KEY_SIZE] = { 0xCC, 0x98, 0xAE, 0x04, 0xE8, 0x97, 0xEA, 0xCA, 0x12, 0xDD, 0xC0, 0x93, 0x42, 0x91, 0x53, 0x57 }; HmacHash serverEncryptHmac(SEED_KEY_SIZE, (uint8*)ClientDecryptionKey); @@ -60,7 +61,7 @@ void AuthCrypt::Init(BigNumber *K) _initialized = true; } -void AuthCrypt::DecryptRecv(uint8 *data, size_t len) +void AuthCrypt::DecryptRecv_12340(uint8 *data, size_t len) { if (!_initialized) return; @@ -68,10 +69,65 @@ void AuthCrypt::DecryptRecv(uint8 *data, size_t len) _decrypt.UpdateData(len, data); } -void AuthCrypt::EncryptSend(uint8 *data, size_t len) +void AuthCrypt::EncryptSend_12340(uint8 *data, size_t len) { if (!_initialized) return; _encrypt.UpdateData(len, data); } + + +//1.12.2 +void AuthCrypt::Init_6005(BigNumber *K) +{ + _send_i = _send_j = _recv_i = _recv_j = 0; + + SetKey_6005(K->AsByteArray(),40); + _initialized = true; + +} + +void AuthCrypt::DecryptRecv_6005(uint8 *data, size_t len) +{ + if (!_initialized) + return; + + if (len < CRYPTED_RECV_LEN_6005) + return; + + for (size_t t = 0; t < CRYPTED_RECV_LEN_6005; t++) + { + _recv_i %= _key.size(); + uint8 x = (data[t] - _recv_j) ^ _key[_recv_i]; + ++_recv_i; + _recv_j = data[t]; + data[t] = x; + + + } + +} + +void AuthCrypt::EncryptSend_6005(uint8 *data, size_t len) +{ + if (!_initialized) + return; + if (len < CRYPTED_SEND_LEN_6005) + return; + + for (size_t t = 0; t < CRYPTED_SEND_LEN_6005; t++) + { + _send_i %= _key.size(); + uint8 x = (data[t] ^ _key[_send_i]) + _send_j; + ++_send_i; + data[t] = _send_j = x; + } + +} + +void AuthCrypt::SetKey_6005(uint8 *key, size_t len) +{ + _key.resize(len); + std::copy(key, key + len, _key.begin()); +} diff --git a/src/shared/Auth/AuthCrypt.h b/src/shared/Auth/AuthCrypt.h index 28ee766..70bb165 100644 --- a/src/shared/Auth/AuthCrypt.h +++ b/src/shared/Auth/AuthCrypt.h @@ -30,15 +30,35 @@ class AuthCrypt AuthCrypt(); ~AuthCrypt(); - void Init(BigNumber *K); - void DecryptRecv(uint8 *, size_t); - void EncryptSend(uint8 *, size_t); + //Dummy + void DecryptRecvDummy(uint8 *, size_t){return;}; + void EncryptSendDummy(uint8 *, size_t){return;}; + + //3.3.5 + void Init_12340(BigNumber *K); + void DecryptRecv_12340(uint8 *, size_t); + void EncryptSend_12340(uint8 *, size_t); + + //1.12.X + void Init_6005(BigNumber *K); + void SetKey_6005(uint8 *, size_t); + void DecryptRecv_6005(uint8 *, size_t); + void EncryptSend_6005(uint8 *, size_t); bool IsInitialized() { return _initialized; } + const static size_t CRYPTED_SEND_LEN_6005 = 6; + const static size_t CRYPTED_RECV_LEN_6005 = 4; + + private: + bool _initialized; + //3.3.5 SARC4 _decrypt; SARC4 _encrypt; - bool _initialized; + + //1.12.2 + std::vector _key; + uint8 _send_i, _send_j, _recv_i, _recv_j; }; #endif