* Use different crypt types for different client versions

TODO: TBC is completely missing
This commit is contained in:
shlainn 2011-09-07 19:01:41 +02:00
parent bee304a453
commit e8a10d26f1
4 changed files with 147 additions and 30 deletions

View File

@ -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,31 +84,43 @@ void WorldSocket::OnRead()
break; break;
} }
// read first byte and check if size is 3 or 2 bytes if(GetSession()->GetInstance()->GetConf()->clientbuild > 6005)
uint8 firstSizeByte;
ibuf.Read((char*)&firstSizeByte, 1);
_crypt.DecryptRecv(&firstSizeByte, 1);
if (firstSizeByte & 0x80) // got large packet
{ {
ServerPktHeaderBig hdr; // read first byte and check if size is 3 or 2 bytes
ibuf.Read(((char*)&hdr) + 1, sizeof(ServerPktHeaderBig) - 1); // read *big* header, except first byte uint8 firstSizeByte;
_crypt.DecryptRecv(((uint8*)&hdr) + 1, sizeof(ServerPktHeaderBig) - 1); // decrypt 2 of 3 bytes (first one already decrypted above) of size, and cmd ibuf.Read((char*)&firstSizeByte, 1);
hdr.size[0] = firstSizeByte; // assign missing first byte (_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]; uint32 realsize = ((hdr.size[0]&0x7F) << 16) | (hdr.size[1] << 8) | hdr.size[2];
_remaining = realsize - 2; _remaining = realsize - 2;
_opcode = hdr.cmd; _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; ServerPktHeader hdr;
ibuf.Read(((char*)&hdr) + 1, sizeof(ServerPktHeader) - 1); // read header, except first byte ibuf.Read(((char*)&hdr), sizeof(ServerPktHeader)); // read header, except first byte
_crypt.DecryptRecv(((uint8*)&hdr) + 1, sizeof(ServerPktHeader) - 1); // decrypt all except first (_crypt.*pDecryptRecv)(((uint8*)&hdr), sizeof(ServerPktHeader)); // decrypt all except first
hdr.size |= firstSizeByte; // add already decrypted first byte
_remaining = ntohs(hdr.size) - 2;
_opcode = hdr.cmd;
_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);

View File

@ -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

View File

@ -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());
}

View File

@ -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