* Use different crypt types for different client versions
TODO: TBC is completely missing
This commit is contained in:
parent
bee304a453
commit
e8a10d26f1
@ -4,11 +4,17 @@
|
|||||||
#include "WorldSocket.h"
|
#include "WorldSocket.h"
|
||||||
#include "Opcodes.h"
|
#include "Opcodes.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
WorldSocket::WorldSocket(SocketHandler &h, WorldSession *s) : TcpSocket(h)
|
WorldSocket::WorldSocket(SocketHandler &h, WorldSession *s) : TcpSocket(h)
|
||||||
{
|
{
|
||||||
_session = s;
|
_session = s;
|
||||||
_gothdr = false;
|
_gothdr = false;
|
||||||
_ok=false;
|
_ok=false;
|
||||||
|
|
||||||
|
//Dummy functions for unencrypted packets on WorldSocket
|
||||||
|
pDecryptRecv = &AuthCrypt::DecryptRecvDummy;
|
||||||
|
pEncryptSend = &AuthCrypt::EncryptSendDummy;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WorldSocket::IsOk(void)
|
bool WorldSocket::IsOk(void)
|
||||||
@ -78,16 +84,17 @@ void WorldSocket::OnRead()
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(GetSession()->GetInstance()->GetConf()->clientbuild > 6005)
|
||||||
|
{
|
||||||
// read first byte and check if size is 3 or 2 bytes
|
// read first byte and check if size is 3 or 2 bytes
|
||||||
uint8 firstSizeByte;
|
uint8 firstSizeByte;
|
||||||
ibuf.Read((char*)&firstSizeByte, 1);
|
ibuf.Read((char*)&firstSizeByte, 1);
|
||||||
_crypt.DecryptRecv(&firstSizeByte, 1);
|
(_crypt.*pDecryptRecv)(&firstSizeByte, 1);
|
||||||
|
|
||||||
if (firstSizeByte & 0x80) // got large packet
|
if (firstSizeByte & 0x80) // got large packet
|
||||||
{
|
{
|
||||||
ServerPktHeaderBig hdr;
|
ServerPktHeaderBig hdr;
|
||||||
ibuf.Read(((char*)&hdr) + 1, sizeof(ServerPktHeaderBig) - 1); // read *big* header, except first byte
|
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
|
(_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
|
hdr.size[0] = firstSizeByte; // assign missing first byte
|
||||||
|
|
||||||
uint32 realsize = ((hdr.size[0]&0x7F) << 16) | (hdr.size[1] << 8) | hdr.size[2];
|
uint32 realsize = ((hdr.size[0]&0x7F) << 16) | (hdr.size[1] << 8) | hdr.size[2];
|
||||||
@ -98,12 +105,23 @@ void WorldSocket::OnRead()
|
|||||||
{
|
{
|
||||||
ServerPktHeader hdr;
|
ServerPktHeader hdr;
|
||||||
ibuf.Read(((char*)&hdr) + 1, sizeof(ServerPktHeader) - 1); // read header, except first byte
|
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
|
(_crypt.*pDecryptRecv)(((uint8*)&hdr) + 1, sizeof(ServerPktHeader) - 1); // decrypt all except first
|
||||||
hdr.size |= firstSizeByte; // add already decrypted first byte
|
hdr.size |= firstSizeByte; // add already decrypted first byte
|
||||||
|
|
||||||
_remaining = ntohs(hdr.size) - 2;
|
_remaining = ntohs(hdr.size) - 2;
|
||||||
_opcode = hdr.cmd;
|
_opcode = hdr.cmd;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
if(_opcode > MAX_OPCODE_ID)
|
if(_opcode > MAX_OPCODE_ID)
|
||||||
{
|
{
|
||||||
@ -114,7 +132,6 @@ void WorldSocket::OnRead()
|
|||||||
// TODO: invent some way how to recover the crypt (reconnect?)
|
// TODO: invent some way how to recover the crypt (reconnect?)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// the header is fine, now check if there are more data
|
// 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)
|
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));
|
memset(&hdr,0,sizeof(ClientPktHeader));
|
||||||
hdr.size = ntohs(pkt.size()+4);
|
hdr.size = ntohs(pkt.size()+4);
|
||||||
hdr.cmd = pkt.GetOpcode();
|
hdr.cmd = pkt.GetOpcode();
|
||||||
_crypt.EncryptSend((uint8*)&hdr, 6);
|
(_crypt.*pEncryptSend)((uint8*)&hdr, 6);
|
||||||
ByteBuffer final(pkt.size()+6);
|
ByteBuffer final(pkt.size()+6);
|
||||||
final.append((uint8*)&hdr,sizeof(ClientPktHeader));
|
final.append((uint8*)&hdr,sizeof(ClientPktHeader));
|
||||||
if(pkt.size())
|
if(pkt.size())
|
||||||
@ -148,7 +165,27 @@ void WorldSocket::SendWorldPacket(WorldPacket &pkt)
|
|||||||
|
|
||||||
void WorldSocket::InitCrypt(BigNumber *k)
|
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();
|
const char *hexstr = k->AsHexStr();
|
||||||
logdebug("WorldSocket: Crypt initialized [%s]",hexstr);
|
logdebug("WorldSocket: Crypt initialized [%s]",hexstr);
|
||||||
OPENSSL_free((void*)hexstr);
|
OPENSSL_free((void*)hexstr);
|
||||||
|
|||||||
@ -7,6 +7,7 @@
|
|||||||
class WorldSession;
|
class WorldSession;
|
||||||
class BigNumber;
|
class BigNumber;
|
||||||
|
|
||||||
|
|
||||||
#if defined( __GNUC__ )
|
#if defined( __GNUC__ )
|
||||||
#pragma pack(1)
|
#pragma pack(1)
|
||||||
#else
|
#else
|
||||||
@ -60,6 +61,9 @@ public:
|
|||||||
private:
|
private:
|
||||||
WorldSession *_session;
|
WorldSession *_session;
|
||||||
AuthCrypt _crypt;
|
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
|
bool _gothdr; // true if only the header was recieved yet
|
||||||
uint16 _opcode; // stores the last recieved opcode
|
uint16 _opcode; // stores the last recieved opcode
|
||||||
uint32 _remaining; // bytes amount of the next data packet
|
uint32 _remaining; // bytes amount of the next data packet
|
||||||
|
|||||||
@ -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 };
|
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);
|
HmacHash serverEncryptHmac(SEED_KEY_SIZE, (uint8*)ClientDecryptionKey);
|
||||||
@ -60,7 +61,7 @@ void AuthCrypt::Init(BigNumber *K)
|
|||||||
_initialized = true;
|
_initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AuthCrypt::DecryptRecv(uint8 *data, size_t len)
|
void AuthCrypt::DecryptRecv_12340(uint8 *data, size_t len)
|
||||||
{
|
{
|
||||||
if (!_initialized)
|
if (!_initialized)
|
||||||
return;
|
return;
|
||||||
@ -68,10 +69,65 @@ void AuthCrypt::DecryptRecv(uint8 *data, size_t len)
|
|||||||
_decrypt.UpdateData(len, data);
|
_decrypt.UpdateData(len, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AuthCrypt::EncryptSend(uint8 *data, size_t len)
|
void AuthCrypt::EncryptSend_12340(uint8 *data, size_t len)
|
||||||
{
|
{
|
||||||
if (!_initialized)
|
if (!_initialized)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_encrypt.UpdateData(len, data);
|
_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());
|
||||||
|
}
|
||||||
|
|||||||
@ -30,15 +30,35 @@ class AuthCrypt
|
|||||||
AuthCrypt();
|
AuthCrypt();
|
||||||
~AuthCrypt();
|
~AuthCrypt();
|
||||||
|
|
||||||
void Init(BigNumber *K);
|
//Dummy
|
||||||
void DecryptRecv(uint8 *, size_t);
|
void DecryptRecvDummy(uint8 *, size_t){return;};
|
||||||
void EncryptSend(uint8 *, size_t);
|
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; }
|
bool IsInitialized() { return _initialized; }
|
||||||
|
|
||||||
|
const static size_t CRYPTED_SEND_LEN_6005 = 6;
|
||||||
|
const static size_t CRYPTED_RECV_LEN_6005 = 4;
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool _initialized;
|
||||||
|
//3.3.5
|
||||||
SARC4 _decrypt;
|
SARC4 _decrypt;
|
||||||
SARC4 _encrypt;
|
SARC4 _encrypt;
|
||||||
bool _initialized;
|
|
||||||
|
//1.12.2
|
||||||
|
std::vector<uint8> _key;
|
||||||
|
uint8 _send_i, _send_j, _recv_i, _recv_j;
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user