* 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 "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);

View File

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

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

View File

@ -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<uint8> _key;
uint8 _send_i, _send_j, _recv_i, _recv_j;
};
#endif