mxoemu/Proxy/Logging.cpp

1403 lines
45 KiB
C++
Raw Permalink Normal View History

2009-08-11 12:17:38 +00:00
#include "Logging.h"
#include "Util.h"
#include "TCPVariableLengthPacket.h"
#include "EncryptedPacket.h"
2009-08-12 19:55:32 +00:00
#include "SequencedPacket.h"
2009-08-11 12:17:38 +00:00
#pragma pack(1)
void LogPacket(const char *pData,size_t pSize,PacketDirection direction,string comment="")
{
string dirStr;
if (direction == CLIENT_TO_AUTH)
{
dirStr = "Client->AUTH";
}
else if (direction == AUTH_TO_CLIENT)
{
dirStr = "AUTH->Client";
}
else if (direction == CLIENT_TO_MARGIN)
{
dirStr = "Client->MARGIN";
}
else if (direction == MARGIN_TO_CLIENT)
{
dirStr = "MARGIN->Client";
}
else if (direction == CLIENT_TO_WORLD)
{
dirStr = "Client->WORLD";
}
else if (direction == WORLD_TO_CLIENT)
{
dirStr = "WORLD->Client";
}
char dateStr [9];
char timeStr [9];
_strdate_s(dateStr,9);
_strtime_s(timeStr,9);
std::ofstream File;
File.open("Packets.log",std::ios::app);
File << dirStr << " " << "[" << timeStr << " " << dateStr << "]" << " " << "packet size: " << pSize << endl;
if (comment.length() > 0)
{
File << comment << endl;
}
string text;
ConvertBytesintoHex((byte *)pData,text,(unsigned int)pSize);
File << text << endl;
int j = 0;
for (unsigned int i = 0;i < pSize;i++)
{
j++;
if (j == 33)
{
File << endl;
j = 1;
}
if (pData[i] > 31 && pData[i] < 127)
File << pData[i] << " ";
else
File << "." << " ";
}
File << endl << endl;
File.close();
}
2009-08-12 19:55:32 +00:00
void LogWorldPacket(const char *pData,size_t pSize,PacketDirection direction,uint16 localSeq,uint16 remoteSeq,uint8 flags)
2009-08-11 12:17:38 +00:00
{
stringstream comment;
2009-08-12 19:55:32 +00:00
comment << "PSS: " << hex << (int)flags << " LocalSeq: " << dec << localSeq << " RemoteSeq: " << dec << remoteSeq;
2009-08-11 12:17:38 +00:00
LogPacket(pData,pSize,direction,comment.str());
}
void LogString(string &title,string &contents)
{
char dateStr [9];
char timeStr [9];
_strdate(dateStr);
_strtime(timeStr);
std::ofstream File;
File.open("Packets.log",std::ios::app);
File << "[" << timeStr << " " << dateStr << "]" << " " << title << endl << contents << endl;
File.close();
}
enum
{
AS_GetPublicKeyRequest = 0x06,
AS_GetPublicKeyReply = 0x07,
AS_AuthRequest = 0x08,
AS_AuthChallenge = 0x09,
AS_AuthChallengeResponse = 0x0A,
AS_AuthReply = 0x0B,
AS_CreateCharacterRequest = 0x0C,
AS_CreateCharacterReply = 0x0D,
AS_DeleteCharacterRequest = 0x0E,
AS_DeleteCharacterReply = 0x0F,
AS_LockAccountRequest = 0x10,
AS_LockAccountReply = 0x11,
AS_UnlockAccountRequest = 0x12,
AS_UnlockAccountReply = 0x13,
AS_PSAuthenticateRequest = 0x14,
AS_WorldIdAndStatus = 0x15,
AS_PSAuthenticateReply = 0x16,
AS_PSCreateCharacterRequest = 0x17,
AS_PSCreateCharacterReply = 0x18,
AS_PSGetWorldListRequest = 0x19,
AS_PSGetWorldListReply = 0x1A,
AS_PSGetWorldPopulationsRequest = 0x1B,
AS_PSGetWorldPopulationsReply = 0x1C,
AS_GetAccountInfoRequest = 0x1D,
AS_GetAccountInfoReply = 0x1E,
AS_ProxyConnectRequest = 0x1F,
AS_ProxyConnectReply = 0x20,
AS_WorldShuttingDown = 0x21,
AS_PSResetAccountInUseRequest = 0x22,
AS_SetTransSessionPenaltyRequest = 0x23,
AS_PSSetTransSessionPenaltyRequest = 0x24,
AS_PSSetTransSessionPenaltyReply = 0x25,
AS_SetWorldStatusRequest = 0x26,
AS_SetWorldStatusReply = 0x27,
AS_PSSetWorldStatusRequest = 0x28,
AS_PSSetWorldStatusReply = 0x29,
AS_UnlockAllAccountsRequest = 0x2A,
AS_LockRecoveringAccountRequest = 0x2B,
AS_LockRecoveringAccountReply = 0x2C,
AS_RefreshCertificateRequest = 0x2D,
AS_RefreshCertificateReply = 0x2E,
AS_PSCertRefreshRequest = 0x2F,
AS_PSCertRefreshReply = 0x30,
AS_PSSetWorldVersionRequest = 0x31,
AS_PSSetWorldVersionReply = 0x32,
AS_IAmProxyLeader = 0x33,
AS_RouteToAuthServer = 0x34,
AS_GetWorldListRequest = 0x35,
AS_GetWorldListReply = 0x36
};
const string GetStringForAuthOpcode(int theOpcode)
{
switch (theOpcode)
{
case AS_GetPublicKeyRequest:
return "AS_GetPublicKeyRequest";
case AS_GetPublicKeyReply:
return "AS_GetPublicKeyReply";
case AS_AuthRequest:
return "AS_AuthRequest";
case AS_AuthChallenge:
return "AS_AuthChallenge";
case AS_AuthChallengeResponse:
return "AS_AuthChallengeResponse";
case AS_AuthReply:
return "AS_AuthReply";
case AS_CreateCharacterRequest:
return "AS_CreateCharacterRequest";
case AS_CreateCharacterReply:
return "AS_CreateCharacterReply";
case AS_DeleteCharacterRequest:
return "AS_DeleteCharacterRequest";
case AS_DeleteCharacterReply:
return "AS_DeleteCharacterReply";
case AS_LockAccountRequest:
return "AS_LockAccountRequest";
case AS_LockAccountReply:
return "AS_LockAccountReply";
case AS_UnlockAccountRequest:
return "AS_UnlockAccountRequest";
case AS_UnlockAccountReply:
return "AS_UnlockAccountReply";
case AS_PSAuthenticateRequest:
return "AS_PSAuthenticateRequest";
case AS_WorldIdAndStatus:
return "AS_WorldIdAndStatus";
case AS_PSAuthenticateReply:
return "AS_PSAuthenticateReply";
case AS_PSCreateCharacterRequest:
return "AS_PSCreateCharacterRequest";
case AS_PSCreateCharacterReply:
return "AS_PSCreateCharacterReply";
case AS_PSGetWorldListRequest:
return "AS_PSGetWorldListRequest";
case AS_PSGetWorldListReply:
return "AS_PSGetWorldListReply";
case AS_PSGetWorldPopulationsRequest:
return "AS_PSGetWorldPopulationsRequest";
case AS_PSGetWorldPopulationsReply:
return "AS_PSGetWorldPopulationsReply";
case AS_GetAccountInfoRequest:
return "AS_GetAccountInfoRequest";
case AS_GetAccountInfoReply:
return "AS_GetAccountInfoReply";
case AS_ProxyConnectRequest:
return "AS_ProxyConnectRequest";
case AS_ProxyConnectReply:
return "AS_ProxyConnectReply";
case AS_WorldShuttingDown:
return "AS_WorldShuttingDown";
case AS_PSResetAccountInUseRequest:
return "AS_PSResetAccountInUseRequest";
case AS_SetTransSessionPenaltyRequest:
return "AS_SetTransSessionPenaltyRequest";
case AS_PSSetTransSessionPenaltyRequest:
return "AS_PSSetTransSessionPenaltyRequest";
case AS_PSSetTransSessionPenaltyReply:
return "AS_PSSetTransSessionPenaltyReply";
case AS_SetWorldStatusRequest:
return "AS_SetWorldStatusRequest";
case AS_SetWorldStatusReply:
return "AS_SetWorldStatusReply";
case AS_PSSetWorldStatusRequest:
return "AS_PSSetWorldStatusRequest";
case AS_PSSetWorldStatusReply:
return "AS_PSSetWorldStatusReply";
case AS_UnlockAllAccountsRequest:
return "AS_UnlockAllAccountsRequest";
case AS_LockRecoveringAccountRequest:
return "AS_LockRecoveringAccountRequest";
case AS_LockRecoveringAccountReply:
return "AS_LockRecoveringAccountReply";
case AS_RefreshCertificateRequest:
return "AS_RefreshCertificateRequest";
case AS_RefreshCertificateReply:
return "AS_RefreshCertificateReply";
case AS_PSCertRefreshRequest:
return "AS_PSCertRefreshRequest";
case AS_PSCertRefreshReply:
return "AS_PSCertRefreshReply";
case AS_PSSetWorldVersionRequest:
return "AS_PSSetWorldVersionRequest";
case AS_PSSetWorldVersionReply:
return "AS_PSSetWorldVersionReply";
case AS_IAmProxyLeader:
return "AS_IAmProxyLeader";
case AS_RouteToAuthServer:
return "AS_RouteToAuthServer";
case AS_GetWorldListRequest:
return "AS_GetWorldListRequest";
case AS_GetWorldListReply:
return "AS_GetWorldListReply";
}
return "AS_UNDEFINED";
}
CryptoPP::AutoSeededRandomPool randPool;
CryptoPP::RSA::PrivateKey LoadRSAPrivateKey()
{
ifstream f_privateKey;
f_privateKey.open("privkey.dat",ios::binary);
f_privateKey.seekg(0,ios::end);
ifstream::pos_type keySize = f_privateKey.tellg();
vector<byte> storage;
storage.resize(keySize);
f_privateKey.seekg(0,ios::beg);
f_privateKey.read((char*)&storage[0],storage.size());
f_privateKey.close();
string pkeyStr = string((const char*)&storage[0],storage.size());
CryptoPP::InvertibleRSAFunction params;
CryptoPP::StringSource pkeySource(pkeyStr,true);
params.BERDecodePrivateKey(pkeySource,false,pkeySource.MaxRetrievable());
CryptoPP::RSA::PrivateKey privateKey( params );
return privateKey;
}
CryptoPP::RSAES_OAEP_SHA_Decryptor LoadRSADecryptor()
{
return CryptoPP::RSAES_OAEP_SHA_Decryptor(LoadRSAPrivateKey());
}
ByteBuffer SignWith1024Bit( byte *message,size_t messageLen )
{
CryptoPP::Weak::RSASSA_PKCS1v15_MD5_Signer signer1024bit(LoadRSAPrivateKey());
//generate signature
ByteBuffer signMe;
signMe.append(message,messageLen);
signMe.rpos(0);
vector<byte> signature;
signature.resize(signer1024bit.MaxSignatureLength());
size_t actualSignatureSize = signer1024bit.SignMessage(randPool,(byte*)signMe.contents(),signMe.size(),&signature[0]);
signature.resize(actualSignatureSize);
ByteBuffer toReturn;
toReturn.append(&signature[0],signature.size());
toReturn.rpos(0);
toReturn.wpos(0);
return toReturn;
}
CryptoPP::RSAES_OAEP_SHA_Encryptor LoadMxORSAEncryptor()
{
ifstream f_mxoPublic;
f_mxoPublic.open("mxopub.dat",ios::binary);
f_mxoPublic.seekg(0,ios::end);
ifstream::pos_type keySize = f_mxoPublic.tellg();
vector<byte> storage;
storage.resize(keySize);
f_mxoPublic.seekg(0,ios::beg);
f_mxoPublic.read((char*)&storage[0],storage.size());
f_mxoPublic.close();
string keyString = string((const char*)&storage[0],storage.size());
keyString = keyString.substr(4);
CryptoPP::StringSource keySource(keyString,true);
CryptoPP::Integer modulus;
modulus.BERDecode(keySource);
CryptoPP::Integer exponent;
exponent.BERDecode(keySource);
CryptoPP::RSA::PublicKey publicKey;
publicKey.Initialize(modulus,exponent);
return CryptoPP::RSAES_OAEP_SHA_Encryptor(publicKey);
}
ByteBuffer GetPubKeyPacket()
{
ifstream f_publicKey;
f_publicKey.open("pubkey.dat",ios::binary);
f_publicKey.seekg(0,ios::end);
ifstream::pos_type keySize = f_publicKey.tellg();
vector<byte> storage;
storage.resize(keySize);
f_publicKey.seekg(0,ios::beg);
f_publicKey.read((char*)&storage[0],storage.size());
f_publicKey.close();
string keyString = string((const char*)&storage[0],storage.size());
keyString = keyString.substr(4);
CryptoPP::StringSource keySource(keyString,true);
CryptoPP::Integer modulus;
modulus.BERDecode(keySource);
ByteBuffer keySourceBuf;
keySourceBuf.append((const byte*)keyString.data(),keyString.size());
byte theSignature[256];
keySourceBuf.rpos(keySourceBuf.size()-sizeof(theSignature));
keySourceBuf.read(theSignature,sizeof(theSignature));
string pubKeyModulusStr;
CryptoPP::StringSink pubKeyModulusSink(pubKeyModulusStr);
modulus.Encode(pubKeyModulusSink,modulus.MinEncodedSize());
ByteBuffer result;
result << uint16(pubKeyModulusStr.size());
result.append(pubKeyModulusStr);
result << uint16(sizeof(theSignature));
result.append(theSignature,sizeof(theSignature));
return result;
}
string RSAMxOEncrypt(string input)
{
string output;
CryptoPP::StringSource(input,true, new CryptoPP::PK_EncryptorFilter(randPool, LoadMxORSAEncryptor(), new CryptoPP::StringSink(output)));
return output;
}
string RSADecrypt(string input)
{
string output;
CryptoPP::StringSource(input,true, new CryptoPP::PK_DecryptorFilter(randPool, LoadRSADecryptor(), new CryptoPP::StringSink(output)));
return output;
}
byte auth_Key[16];
byte challenge[16];
const byte blankIV[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
bool clientRequiresPubKeySent = false;
string ClientToAuth(const char* pData,size_t pSize)
{
string hexadecm;
TCPVariableLengthPacket varLenPacket((const byte*)pData,pSize);
ByteBuffer thePacket;
thePacket.append((const byte*)varLenPacket.contents(),varLenPacket.size());
thePacket.rpos(0);
byte packetOpcode;
thePacket >> packetOpcode;
switch(packetOpcode)
{
default:
{
stringstream theComment;
theComment << GetStringForAuthOpcode(packetOpcode) << endl;
LogPacket(thePacket.contents(),thePacket.size(),CLIENT_TO_AUTH,theComment.str());
TCPVariableLengthPacket withAddedLen;
withAddedLen.append((const byte*)thePacket.contents(),thePacket.size());
ByteBuffer sendMe = withAddedLen.GetContentsWithSize();
return string(sendMe.contents(),sendMe.size());
}
case AS_GetPublicKeyRequest:
{
uint32 clientVersion;
thePacket >> clientVersion;
uint32 rsaVersion;
thePacket >> rsaVersion;
ConvertBytesintoHex((const byte*)thePacket.contents(),hexadecm,thePacket.size());
cout << "Received AS_GetPublicKeyRequest from client: |" << hexadecm << "|" << endl;
stringstream comments;
comments << GetStringForAuthOpcode(AS_GetPublicKeyRequest) << endl;
comments << "clientVersion: " << clientVersion << endl;
comments << "rsaVersion: " << rsaVersion << endl;
if (rsaVersion != 4)
{
clientRequiresPubKeySent = true;
}
else
{
clientRequiresPubKeySent = false;
}
//we will always send OK to REAL server
TCPVariableLengthPacket awesome;
awesome << uint8(AS_GetPublicKeyRequest);
awesome << clientVersion;
awesome << uint32(4);
LogPacket(thePacket.contents(),thePacket.size(),CLIENT_TO_AUTH,comments.str());
ByteBuffer sendMe = awesome.GetContentsWithSize();
ConvertBytesintoHex((const byte*)sendMe.contents(),hexadecm,sendMe.size());
cout << "Sending AS_GetPublicKeyRequest to server: |" << hexadecm << "|" << endl;
return string(sendMe.contents(),sendMe.size());
}
case AS_AuthRequest:
{
typedef struct
{
uint32 rsaType;
uint32 unknownz1;
char unknownz2[31];
uint16 blobLen;
}requestHdr;
ConvertBytesintoHex((const byte*)thePacket.contents(),hexadecm,thePacket.size());
cout << "Received AS_AuthRequest from client: |" << hexadecm << "|" << endl;
stringstream comments;
comments << GetStringForAuthOpcode(AS_AuthRequest) << endl;
requestHdr requestHeader;
memset(&requestHeader,0,sizeof(requestHeader));
thePacket.read((uint8 *)&requestHeader,sizeof(requestHeader));
vector<byte> encryptedBlob;
encryptedBlob.resize(requestHeader.blobLen);
thePacket.read(&encryptedBlob[0],encryptedBlob.size());
string decryptedBlob = RSADecrypt(string((const char*)&encryptedBlob[0],encryptedBlob.size()));
ConvertBytesintoHex((const byte*)decryptedBlob.data(),hexadecm,decryptedBlob.size());
comments << "RSA Blob:|" << hexadecm << "|" << endl;
ByteBuffer blobBuf(decryptedBlob);
blobBuf.read(1);
uint32 rsaMethod;
blobBuf >> rsaMethod;
comments << "rsaMethod is " << rsaMethod << endl;
uint16 someShort;
blobBuf >> someShort;
comments << "someShort is " << someShort << endl;
memset(auth_Key,0,sizeof(auth_Key));
blobBuf.read(auth_Key,sizeof(auth_Key));
ConvertBytesintoHex(auth_Key,hexadecm,sizeof(auth_Key));
comments << "Auth TF key: |" << hexadecm << "|" << endl;
uint32 theTime;
blobBuf >> theTime;
comments << "time is: " << hex << theTime << endl;
uint16 usernameLen;
blobBuf >> usernameLen;
vector<char> usernameVect;
usernameVect.resize(usernameLen);
blobBuf.read((uint8 *)&usernameVect[0],usernameVect.size());
string theUsername(&usernameVect[0],usernameVect.size());
comments << "Username: |" << theUsername << "|" << endl;
string reEncryptedBlob = RSAMxOEncrypt(decryptedBlob);
TCPVariableLengthPacket awesome;
awesome << byte(AS_AuthRequest);
awesome.append((const byte*)&requestHeader,sizeof(requestHeader));
awesome.append(reEncryptedBlob);
LogPacket(thePacket.contents(),thePacket.size(),CLIENT_TO_AUTH,comments.str());
ByteBuffer sendMe = awesome.GetContentsWithSize();
ConvertBytesintoHex((const byte*)sendMe.contents(),hexadecm,sendMe.size());
cout << "Sending AS_AuthRequest to server: |" << hexadecm << "|" << endl;
return string(sendMe.contents(),sendMe.size());
}
case AS_AuthChallengeResponse:
{
ConvertBytesintoHex((const byte*)thePacket.contents(),hexadecm,thePacket.size());
cout << "Received AS_AuthChallengeResponse from client: |" << hexadecm << "|" << endl;
stringstream comments;
comments << GetStringForAuthOpcode(AS_AuthChallengeResponse) << endl;
uint16 someShort;
thePacket >> someShort;
comments << "someShort is " << someShort << endl;
uint16 cipherTextLen;
thePacket >> cipherTextLen;
vector<byte> cipherText;
cipherText.resize(cipherTextLen);
thePacket.read(&cipherText[0],cipherText.size());
//now we have the ciphertext, lets decrypt
string cipherInput((const char*)&cipherText[0],cipherText.size());
string plainOutput;
//this message is done with 0 as iv
CryptoPP::CBC_Mode<CryptoPP::Twofish>::Decryption TFDecrypt(auth_Key,sizeof(auth_Key),blankIV);
CryptoPP::StringSource(cipherInput, true,
new CryptoPP::StreamTransformationFilter(
TFDecrypt, new CryptoPP::StringSink(plainOutput),
CryptoPP::BlockPaddingSchemeDef::BlockPaddingScheme::NO_PADDING));
size_t packetSize = 0;
ByteBuffer chRspPlain(plainOutput);
uint8 someByte;
chRspPlain >> someByte;
packetSize += sizeof(someByte);
byte processedChallenge[16];
chRspPlain.read(processedChallenge,sizeof(processedChallenge));
packetSize += sizeof(processedChallenge);
uint16 unknown1;
chRspPlain >> unknown1;
packetSize += sizeof(unknown1);
uint16 unknown2;
chRspPlain >> unknown2;
packetSize += sizeof(unknown2);
uint16 unknown3;
chRspPlain >> unknown3;
packetSize += sizeof(unknown3);
uint16 passwordLen;
chRspPlain >> passwordLen;
packetSize += sizeof(passwordLen);
vector<char> password;
password.resize(passwordLen);
chRspPlain.read((byte*)&password[0],password.size());
packetSize += password.size();
uint16 soePassLen;
chRspPlain >> soePassLen;
packetSize += sizeof(soePassLen);
vector<char> soePass;
soePass.resize(soePassLen);
chRspPlain.read((byte*)&soePass[0],soePass.size());
packetSize += soePass.size();
uint16 paddingLen;
chRspPlain >> paddingLen;
packetSize += sizeof(paddingLen);
vector<byte> padding;
padding.resize(paddingLen);
chRspPlain.read(&padding[0],paddingLen);
packetSize += padding.size();
if (packetSize != chRspPlain.size())
{
comments << "Challenge response blob size mismatch, expected " << dec << packetSize << ", received " << chRspPlain.size() << endl;
}
ConvertBytesintoHex(processedChallenge,hexadecm,sizeof(processedChallenge));
{
char someCharsHere[1024];
sprintf(someCharsHere,"Parsed contents: 1(const 23): |%d|, 2(size): |%d|, 3(size): |%d|, User Password: |%s|, SOE Password: |%s|",unknown1,unknown2,unknown3,"CENSORED",&soePass[0]);
comments << someCharsHere << endl;
}
LogPacket(thePacket.contents(),thePacket.size(),CLIENT_TO_AUTH,comments.str());
TCPVariableLengthPacket withAddedLen;
withAddedLen.append((const byte*)thePacket.contents(),thePacket.size());
ByteBuffer sendMe = withAddedLen.GetContentsWithSize();
cout << "Sending AS_AuthChallengeResponse to server unchanged" << endl;
return string(sendMe.contents(),sendMe.size());
}
}
}
typedef struct
{
uint8 unknownByte; //always 01
uint32 userId1; //4 bytes, last byte is 00 on real server, unique per user
char userName[33]; //32 for actual text, 0 for null terminator (if max len)
uint16 unknownShort; //always 256
uint32 padding1; //4 bytes of 0 padding
uint32 timeStamp; //10 minutes ahead of current time
byte padding2[32]; //32 bytes of 0 padding
uint16 publicExponent; //17 for cryptopp, but big endian format here
byte modulus[96]; //768bit public modulus of user RSA key
uint32 userId2; //4 bytes, unique per user, users registered later have this number higher
} signedDataStruct;
byte savedSignature[128];
signedDataStruct savedSignedData;
CryptoPP::RSAES_OAEP_SHA_Decryptor marginBlobDecryptor;
ByteBuffer RSAMarginBlobDecrypt(const byte* pData,size_t pLen)
{
string input = string((const char*)pData,pLen);
string output;
CryptoPP::StringSource(input,true, new CryptoPP::PK_DecryptorFilter(randPool, marginBlobDecryptor, new CryptoPP::StringSink(output)));
ByteBuffer returnMe;
returnMe.append((const byte*)output.data(),output.size());
return returnMe;
}
string AuthToClient(const char* pData,size_t pSize)
{
string hexadecm;
TCPVariableLengthPacket varLenPacket((const byte*)pData,pSize);
ByteBuffer thePacket;
thePacket.append((const byte*)varLenPacket.contents(),varLenPacket.size());
thePacket.rpos(0);
byte packetOpcode;
thePacket >> packetOpcode;
switch(packetOpcode)
{
default:
{
stringstream theComment;
theComment << GetStringForAuthOpcode(packetOpcode) << endl;
LogPacket(thePacket.contents(),thePacket.size(),AUTH_TO_CLIENT,theComment.str());
TCPVariableLengthPacket withAddedLen;
withAddedLen.append((const byte*)thePacket.contents(),thePacket.size());
ByteBuffer sendMe = withAddedLen.GetContentsWithSize();
return string(sendMe.contents(),sendMe.size());
}
case AS_GetPublicKeyReply:
{
ConvertBytesintoHex((const byte*)thePacket.contents(),hexadecm,thePacket.size());
cout << "Received AS_GetPublicKeyReply from server: |" << hexadecm << "|" << endl;
stringstream comments;
comments << GetStringForAuthOpcode(AS_GetPublicKeyReply) << endl;
uint32 padding0;
thePacket >> padding0;
uint32 serverTime;
thePacket >> serverTime;
comments << "serverTime: " << dec << serverTime << endl;
uint32 rsaMethod;
thePacket >> rsaMethod;
comments << "serverRsaMethod: " << dec << rsaMethod << endl;
TCPVariableLengthPacket awesome;
if (clientRequiresPubKeySent == true)
{
awesome
<< byte(AS_GetPublicKeyReply)
<< uint32(0)
<< uint32(_time32(NULL)) //time
<< uint32(0x04) //rsa method
<< uint8(0x12)
<< uint8(0x00)
<< uint8(0x11) //public exponent
<< uint8(0x94)
<< uint8(0x00);
awesome.append(GetPubKeyPacket());
}
else
{
awesome
<< byte(AS_GetPublicKeyReply)
<< uint32(0)
<< uint32(_time32(NULL)) //time
<< uint32(0x04) //rsa method
<< byte(0)
<< uint32(0);
}
LogPacket(thePacket.contents(),thePacket.size(),AUTH_TO_CLIENT,comments.str());
ByteBuffer sendMe = awesome.GetContentsWithSize();
ConvertBytesintoHex((const byte*)sendMe.contents(),hexadecm,sendMe.size());
cout << "Sending AS_GetPublicKeyReply to client: |" << hexadecm << "|" << endl;
return string(sendMe.contents(),sendMe.size());
}
case AS_AuthChallenge:
{
ConvertBytesintoHex((const byte*)thePacket.contents(),hexadecm,thePacket.size());
cout << "Received AS_AuthChallenge from server: |" << hexadecm << "|" << endl;
stringstream comments;
comments << GetStringForAuthOpcode(AS_AuthChallenge) << endl;
//this is just 16 bytes of data (the CHALLENGE)
byte theChallenger[16];
thePacket.read(theChallenger,sizeof(theChallenger));
string cipherChallenge = string((char*)theChallenger,sizeof(theChallenger));
memcpy(challenge,theChallenger,sizeof(challenge));
ConvertBytesintoHex(challenge,hexadecm,sizeof(challenge));
comments << "Original challenge from server: |" << hexadecm << "|" << endl;
//to get finalChallenge from the challenge, we need to decrypt with auth key and 0 iv, then hash with md5
CryptoPP::CBC_Mode<CryptoPP::Twofish>::Decryption TFDecrypt(auth_Key,sizeof(auth_Key),blankIV);
string plainChallenge;
CryptoPP::StringSource(cipherChallenge, true,
new CryptoPP::StreamTransformationFilter(
TFDecrypt, new CryptoPP::StringSink(plainChallenge),
CryptoPP::BlockPaddingSchemeDef::BlockPaddingScheme::NO_PADDING));
ConvertBytesintoHex((const byte*)plainChallenge.data(),hexadecm,plainChallenge.size());
comments << "Decrypted Challenge: |" << hexadecm << "|" << endl;
byte finalChallenge[16];
CryptoPP::Weak::MD5 md5object;
//feed decrypted challenge to md5 object
md5object.Update((const byte*)plainChallenge.data(),plainChallenge.size());
//end hash goes to finalCallenge
md5object.Final(finalChallenge);
ConvertBytesintoHex(finalChallenge,hexadecm,sizeof(finalChallenge));
comments << "Processed Challenge: |" << hexadecm << "|" << endl;
LogPacket(thePacket.contents(),thePacket.size(),AUTH_TO_CLIENT,comments.str());
TCPVariableLengthPacket withAddedLen;
withAddedLen.append((const byte*)thePacket.contents(),thePacket.size());
ByteBuffer sendMe = withAddedLen.GetContentsWithSize();
cout << "Sending AS_AuthChallenge to client unchanged" << endl;
return string(sendMe.contents(),sendMe.size());
}
case AS_AuthReply:
{
ConvertBytesintoHex((const byte*)thePacket.contents(),hexadecm,thePacket.size());
cout << "Received AS_AuthReply from server: |" << hexadecm << "|" << endl;
stringstream comments;
comments << GetStringForAuthOpcode(AS_AuthReply) << endl;
int authDataOffset = -1;
int encryptedBlobOffset = -1;
for (int i=0;i<thePacket.size();i++)
{
byte *thePacketPtr = (byte*)(&thePacket.contents()[i]);
static byte bytesToFind[2] = { 0x36, 0x01 };
if (!memcmp(thePacketPtr,bytesToFind,sizeof(bytesToFind)))
{
authDataOffset = i;
break;
}
}
for (int i=0;i<thePacket.size();i++)
{
byte *thePacketPtr = (byte*)(&thePacket.contents()[i]);
static byte bytesToFind[2] = { 0x60, 0x00 };
if (!memcmp(thePacketPtr,bytesToFind,sizeof(bytesToFind)))
{
encryptedBlobOffset = i;
break;
}
}
vector<byte> worldListData;
if (authDataOffset != -1)
{
thePacket.rpos(0);
worldListData.resize(authDataOffset);
thePacket.read(&worldListData[0],worldListData.size());
thePacket.rpos(authDataOffset);
uint16 thirtySixZeroOne;
thePacket >> thirtySixZeroOne;
thePacket.read(savedSignature,sizeof(savedSignature));
thePacket.read((byte*)&savedSignedData,sizeof(savedSignedData));
}
else
{
cout << "VERY BIG ERROR HERE BOSS" << endl;
}
signedDataStruct newSignedData;
memcpy(&newSignedData,&savedSignedData,sizeof(newSignedData));
//just change time
newSignedData.timeStamp = _time32(NULL) + (60*10);
string zeUsername = string(newSignedData.userName);
comments << "Username: " << zeUsername << " UserId1: " << dec << newSignedData.userId1 << " UserId2: " << dec << newSignedData.userId2 << endl;
//resign
//its not that actual part which is signed, but the md5 of it, and sign makes a md5 of that, i think wb is just fucking with us
byte signMePlease[16];
CryptoPP::Weak::MD5 md5Object;
md5Object.Update((const byte*)&newSignedData,sizeof(newSignedData));
md5Object.Final(signMePlease);
ByteBuffer newSignature = SignWith1024Bit(signMePlease,sizeof(signMePlease));
vector<byte> encryptedBlob;
if (encryptedBlobOffset != -1)
{
thePacket.rpos(encryptedBlobOffset);
uint16 blobSize;
thePacket >> blobSize;
encryptedBlob.resize(blobSize);
thePacket.read(&encryptedBlob[0],encryptedBlob.size());
}
else
{
cout << "ANOTHER BIG ERROR HERE BOSS" << endl;
}
//to decrypt 96 byte exponent, use auth_key as key and challenge as IV
CryptoPP::CBC_Mode<CryptoPP::Twofish>::Decryption TFDecrypt(auth_Key,sizeof(auth_Key),challenge);
string decryptedPrivateExponent;
CryptoPP::StringSource( string( (const char*) &encryptedBlob[0],encryptedBlob.size() ) ,
true,
new CryptoPP::StreamTransformationFilter(
TFDecrypt, new CryptoPP::StringSink(decryptedPrivateExponent),
CryptoPP::BlockPaddingSchemeDef::BlockPaddingScheme::NO_PADDING));
//extract keys
CryptoPP::Integer publicExponent(uint32(swap16(newSignedData.publicExponent)));
CryptoPP::Integer modulus;
modulus.Decode(newSignedData.modulus,sizeof(newSignedData.modulus));
//and private exponent is inside the now decrypted blo
CryptoPP::Integer privateExponent;
privateExponent.Decode((const byte*)decryptedPrivateExponent.data(),decryptedPrivateExponent.size());
//comment the keys
comments << "e: " << hex << publicExponent << " n: " << hex << modulus << " d: " << hex << privateExponent << endl;
//initialize our margin blob decryptor with this key
CryptoPP::RSA::PrivateKey marginPrivateKey;
marginPrivateKey.Initialize(modulus,publicExponent,privateExponent);
marginBlobDecryptor = CryptoPP::RSAES_OAEP_SHA_Decryptor(marginPrivateKey);
//reassemble our new packet
TCPVariableLengthPacket awesome;
//non touched worldlist data
awesome.append(&worldListData[0],worldListData.size());
//36 01 indicates start of auth data
awesome << uint16(swap16(0x3601));
//then the signature of the signed data
awesome.append(newSignature);
//then the signed data itself
awesome.append((const byte*)&newSignedData,sizeof(newSignedData));
//then the size of the encrypted blob
awesome << uint16(encryptedBlob.size());
//then the encrypted blob itself
awesome.append(&encryptedBlob[0],encryptedBlob.size());
//then the size of username including null end character
uint16 userNameLength = uint16(strlen(zeUsername.c_str())+1);
awesome << userNameLength;
//then the username including null end character
awesome.append((const byte*)zeUsername.c_str(),userNameLength);
LogPacket(thePacket.contents(),thePacket.size(),AUTH_TO_CLIENT,comments.str());
ByteBuffer sendMe = awesome.GetContentsWithSize();
ConvertBytesintoHex((const byte*)sendMe.contents(),hexadecm,sendMe.size());
cout << "Sending AS_AuthReply to client: |" << hexadecm << "|" << endl;
return string(sendMe.contents(),sendMe.size());
}
}
}
typedef enum MarginOpcode
{
CERT_ConnectRequest = 0x01,
CERT_Challenge = 0x02,
CERT_ChallengeResponse = 0x03,
CERT_ConnectReply = 0x04,
CERT_NewSessionKey = 0x05,
MS_ConnectRequest = 0x06,
MS_ConnectChallenge = 0x07,
MS_ConnectChallengeResponse = 0x08,
MS_ConnectReply = 0x09,
MS_ClaimCharacterNameRequest = 0x0A,
MS_ClaimCharacterNameReply = 0x0B,
MS_CreateCharacterRequest = 0x0C,
MS_DeleteCharacterRequest = 0x0D,
MS_DeleteCharacterReply = 0x0E,
MS_LoadCharacterRequest = 0x0F,
MS_LoadCharacterReply = 0x10,
MS_EstablishUDPSessionReply = 0x11,
MS_RefreshSessionKeyRequest = 0x12,
MS_RefreshSessionKeyReply = 0x13,
MS_ServerShuttingDown = 0x14,
MS_FailoverRequest = 0x15,
MS_FailoverReply = 0x16,
MS_AdjustFloodgateRequest = 0x17,
MS_AdjustFloodgateReply = 0x18,
MS_GetPlayerListRequest = 0x19,
MS_GetPlayerListReply = 0x1A,
MS_FakePopulationRequest = 0x1B,
MS_UnloadCharacterRequest = 0x1C,
MS_GetClientIPRequest = 0x1D,
MS_GetClientIPReply = 0x1E
};
const string GetStringForMarginOpcode(int theOpcode)
{
switch (theOpcode)
{
case CERT_ConnectRequest:
return "CERT_ConnectRequest";
case CERT_Challenge:
return "CERT_Challenge";
case CERT_ChallengeResponse:
return "CERT_ChallengeResponse";
case CERT_ConnectReply:
return "CERT_ConnectReply";
case CERT_NewSessionKey:
return "CERT_NewSessionKey";
case MS_ConnectRequest:
return "MS_ConnectRequest";
case MS_ConnectChallenge:
return "MS_ConnectChallenge";
case MS_ConnectChallengeResponse:
return "MS_ConnectChallengeResponse";
case MS_ConnectReply:
return "MS_ConnectReply";
case MS_ClaimCharacterNameRequest:
return "MS_ClaimCharacterNameRequest";
case MS_ClaimCharacterNameReply:
return "MS_ClaimCharacterNameReply";
case MS_CreateCharacterRequest:
return "MS_CreateCharacterRequest";
case MS_DeleteCharacterRequest:
return "MS_DeleteCharacterRequest";
case MS_DeleteCharacterReply:
return "MS_DeleteCharacterReply";
case MS_LoadCharacterRequest:
return "MS_LoadCharacterRequest";
case MS_LoadCharacterReply:
return "MS_LoadCharacterReply";
case MS_EstablishUDPSessionReply:
return "MS_EstablishUDPSessionReply";
case MS_RefreshSessionKeyRequest:
return "MS_RefreshSessionKeyRequest";
case MS_RefreshSessionKeyReply:
return "MS_RefreshSessionKeyReply";
case MS_ServerShuttingDown:
return "MS_ServerShuttingDown";
case MS_FailoverRequest:
return "MS_FailoverRequest";
case MS_FailoverReply:
return "MS_FailoverReply";
case MS_AdjustFloodgateRequest:
return "MS_AdjustFloodgateRequest";
case MS_AdjustFloodgateReply:
return "MS_AdjustFloodgateReply";
case MS_GetPlayerListRequest:
return "MS_GetPlayerListRequest";
case MS_GetPlayerListReply:
return "MS_GetPlayerListReply";
case MS_FakePopulationRequest:
return "MS_FakePopulationRequest";
case MS_UnloadCharacterRequest:
return "MS_UnloadCharacterRequest";
case MS_GetClientIPRequest:
return "MS_GetClientIPRequest";
case MS_GetClientIPReply:
return "MS_GetClientIPReply";
}
return "MS_UNDEFINED";
}
CryptoPP::CBC_Mode<CryptoPP::Twofish>::Encryption *TFEncryptCTM = NULL;
CryptoPP::CBC_Mode<CryptoPP::Twofish>::Decryption *TFDecryptCTM = NULL;
CryptoPP::CBC_Mode<CryptoPP::Twofish>::Encryption *TFEncryptMTC = NULL;
CryptoPP::CBC_Mode<CryptoPP::Twofish>::Decryption *TFDecryptMTC = NULL;
CryptoPP::CBC_Mode<CryptoPP::Twofish>::Decryption *TFDecryptCTW = NULL;
CryptoPP::CBC_Mode<CryptoPP::Twofish>::Encryption *TFEncryptCTW = NULL;
CryptoPP::CBC_Mode<CryptoPP::Twofish>::Decryption *TFDecryptWTC = NULL;
CryptoPP::CBC_Mode<CryptoPP::Twofish>::Encryption *TFEncryptWTC = NULL;
byte theMarginBlobChallenge[16];
string ClientToMargin( const char* pData,size_t pSize )
{
stringstream comment;
string hexadecm;
TCPVariableLengthPacket packetContents((const byte*)pData,pSize);
bool encrypted = true;
byte firstByte;
packetContents >> firstByte;
if (firstByte >= CERT_ConnectRequest && firstByte <= CERT_NewSessionKey)
{
uint16 firstShort;
packetContents >> firstShort;
if (firstShort == 3)
{
encrypted = false;
}
}
//reset position (since we just read 3 bytes)
packetContents.rpos(0);
ByteBuffer packetData;
if (encrypted == true && TFDecryptCTM != NULL)
{
try
{
EncryptedPacket packetTodecrypt(packetContents,TFDecryptCTM);
packetData.append((const byte*)packetTodecrypt.contents(),packetTodecrypt.size());
comment << "encrypted=true ";
}
catch (...)
{
ConvertBytesintoHex((const byte*)packetContents.contents(),hexadecm,packetContents.size());
cout << "Decryption exception for CTM packet: |" << hexadecm << "|" << endl;
encrypted = false;
}
}
if (encrypted == false || TFDecryptCTM == NULL)
{
packetData.append((const byte*)packetContents.contents(),packetContents.size());
comment << "encrypted=false ";
}
byte packetOpcode;
packetData >> packetOpcode;
ByteBuffer packetToSend;
switch (packetOpcode)
{
default:
{
comment << GetStringForMarginOpcode(packetOpcode);
LogPacket(packetData.contents(),packetData.size(),CLIENT_TO_MARGIN,comment.str());
packetToSend = packetData;
packetToSend.rpos(0);
break;
}
case CERT_ConnectRequest:
{
//log the original packet
comment << GetStringForMarginOpcode(CERT_ConnectRequest);
LogPacket(packetData.contents(),packetData.size(),CLIENT_TO_MARGIN,comment.str());
//this packet contains clients copy of the signature & signed data, however it is wrong since we tampered with it before for our pubkey
//so, just replace it with the cached copy from real server we gathered earlier
packetToSend.clear();
packetToSend << uint8(CERT_ConnectRequest);
packetToSend << uint16(3);
packetToSend << uint16(swap16(0x3601)); //auth data start, next is signature
packetToSend.append(savedSignature,sizeof(savedSignature)); //next is signed data, also cached
packetToSend.append((const byte*)&savedSignedData,sizeof(savedSignedData));
//thats it for the packet, break, function epilog will add header as necessary
break;
}
case CERT_ChallengeResponse:
{
comment << GetStringForMarginOpcode(CERT_ChallengeResponse) << endl;
//we are not going to modify this packet, just snoop around :D , so just copy input packet as output
packetToSend.clear();
packetToSend.append((const byte*)packetData.contents(),packetData.size());
byte clientsChallenge[16];
packetData.read(clientsChallenge,sizeof(clientsChallenge));
ConvertBytesintoHex(clientsChallenge,hexadecm,sizeof(clientsChallenge));
comment << "Client's challenge: |" << hexadecm << "|, which ";
if (!memcmp(clientsChallenge,theMarginBlobChallenge,sizeof(clientsChallenge)))
{
comment << "matches the server copy." << endl;
}
else
{
comment << "doesn't match the server copy!" << endl;
}
LogPacket(packetData.contents(),packetData.size(),CLIENT_TO_MARGIN,comment.str());
break;
}
}
if (encrypted == true && TFEncryptCTM != NULL)
{
EncryptedPacket giveMeDataToEncrypt;
giveMeDataToEncrypt.append((const byte*)packetToSend.contents(),packetToSend.size());
ByteBuffer encryptedData = giveMeDataToEncrypt.toCipherText(TFEncryptCTM);
TCPVariableLengthPacket giveMeDataToAddLengthTo;
giveMeDataToAddLengthTo.append((const byte*)encryptedData.contents(),encryptedData.size());
ByteBuffer sendMe = giveMeDataToAddLengthTo.GetContentsWithSize();
return string(sendMe.contents(),sendMe.size());
}
else
{
TCPVariableLengthPacket giveMeDataToAddLengthTo;
giveMeDataToAddLengthTo.append((const byte*)packetToSend.contents(),packetToSend.size());
ByteBuffer sendMe = giveMeDataToAddLengthTo.GetContentsWithSize();
return string(sendMe.contents(),sendMe.size());
}
}
string MarginToClient( const char* pData,size_t pSize )
{
stringstream comment;
string hexadecm;
TCPVariableLengthPacket packetContents((const byte*)pData,pSize);
bool encrypted = true;
byte firstByte;
packetContents >> firstByte;
if (firstByte >= CERT_ConnectRequest && firstByte <= CERT_NewSessionKey)
{
uint16 firstShort;
packetContents >> firstShort;
if (firstShort == 3)
{
encrypted = false;
}
}
//reset position (since we just read 3 bytes)
packetContents.rpos(0);
ByteBuffer packetData;
if (encrypted == true && TFDecryptMTC != NULL)
{
try
{
EncryptedPacket packetTodecrypt(packetContents,TFDecryptMTC);
packetData.append((const byte*)packetTodecrypt.contents(),packetTodecrypt.size());
comment << "encrypted=true ";
}
catch (...)
{
ConvertBytesintoHex((const byte*)packetContents.contents(),hexadecm,packetContents.size());
cout << "Decryption exception for MTC packet: |" << hexadecm << "|" << endl;
encrypted = false;
}
}
if (encrypted == false || TFDecryptMTC == NULL)
{
packetData.append((const byte*)packetContents.contents(),packetContents.size());
comment << "encrypted=false ";
}
byte packetOpcode;
packetData >> packetOpcode;
ByteBuffer packetToSend;
switch (packetOpcode)
{
default:
{
comment << GetStringForMarginOpcode(packetOpcode);
LogPacket(packetData.contents(),packetData.size(),MARGIN_TO_CLIENT,comment.str());
packetToSend = packetData;
packetToSend.rpos(0);
break;
}
case CERT_Challenge:
{
comment << GetStringForMarginOpcode(CERT_Challenge) << endl;
//we are not going to modify this packet, just snoop around :D , so just copy input packet as output
packetToSend.clear();
packetToSend.append((const byte*)packetData.contents(),packetData.size());
uint16 numberThree;
packetData >> numberThree;
uint16 rsaBlobSize;
packetData >> rsaBlobSize;
vector<byte> rsaBlob;
rsaBlob.resize(rsaBlobSize);
packetData.read(&rsaBlob[0],rsaBlob.size());
ByteBuffer blobContents = RSAMarginBlobDecrypt(&rsaBlob[0],rsaBlob.size());
uint8 alwaysZero;
blobContents >> alwaysZero;
if (alwaysZero != 0)
{
cout << "First byte of CERT_Challenge not right !" << endl;
}
byte theTwofishKey[16];
blobContents.read(theTwofishKey,sizeof(theTwofishKey));
blobContents.read(theMarginBlobChallenge,sizeof(theMarginBlobChallenge));
//since we have twofish key, we can initialize all those twofish encryptors/decryptors (its the same for all margin/world)
if (TFEncryptCTM != NULL)
delete TFEncryptCTM;
if (TFDecryptCTM != NULL)
delete TFDecryptCTM;
if (TFEncryptMTC != NULL)
delete TFEncryptMTC;
if (TFDecryptMTC != NULL)
delete TFDecryptMTC;
TFEncryptCTM = new CryptoPP::CBC_Mode<CryptoPP::Twofish>::Encryption(theTwofishKey,sizeof(theTwofishKey),blankIV);
TFDecryptCTM = new CryptoPP::CBC_Mode<CryptoPP::Twofish>::Decryption(theTwofishKey,sizeof(theTwofishKey),blankIV);
TFEncryptMTC = new CryptoPP::CBC_Mode<CryptoPP::Twofish>::Encryption(theTwofishKey,sizeof(theTwofishKey),blankIV);
TFDecryptMTC = new CryptoPP::CBC_Mode<CryptoPP::Twofish>::Decryption(theTwofishKey,sizeof(theTwofishKey),blankIV);
if (TFEncryptCTW != NULL)
delete TFEncryptCTW;
if (TFDecryptCTW != NULL)
delete TFDecryptCTW;
if (TFEncryptWTC != NULL)
delete TFEncryptWTC;
if (TFDecryptWTC != NULL)
delete TFDecryptWTC;
TFEncryptCTW = new CryptoPP::CBC_Mode<CryptoPP::Twofish>::Encryption(theTwofishKey,sizeof(theTwofishKey),blankIV);
TFDecryptCTW = new CryptoPP::CBC_Mode<CryptoPP::Twofish>::Decryption(theTwofishKey,sizeof(theTwofishKey),blankIV);
TFEncryptWTC = new CryptoPP::CBC_Mode<CryptoPP::Twofish>::Encryption(theTwofishKey,sizeof(theTwofishKey),blankIV);
TFDecryptWTC = new CryptoPP::CBC_Mode<CryptoPP::Twofish>::Decryption(theTwofishKey,sizeof(theTwofishKey),blankIV);
ConvertBytesintoHex(theTwofishKey,hexadecm,sizeof(theTwofishKey));
comment << "Margin/World Twofish Key: |" << hexadecm << "| TF Crypto Engines initialized!" << endl;
ConvertBytesintoHex(theMarginBlobChallenge,hexadecm,sizeof(theMarginBlobChallenge));
comment << "Margin CERT Challenge: |" << hexadecm << "|" << endl;
LogPacket(packetData.contents(),packetData.size(),MARGIN_TO_CLIENT,comment.str());
break;
}
}
if (encrypted == true && TFEncryptMTC != NULL)
{
EncryptedPacket giveMeDataToEncrypt;
giveMeDataToEncrypt.append((const byte*)packetToSend.contents(),packetToSend.size());
ByteBuffer encryptedData = giveMeDataToEncrypt.toCipherText(TFEncryptMTC);
TCPVariableLengthPacket giveMeDataToAddLengthTo;
giveMeDataToAddLengthTo.append((const byte*)encryptedData.contents(),encryptedData.size());
ByteBuffer sendMe = giveMeDataToAddLengthTo.GetContentsWithSize();
return string(sendMe.contents(),sendMe.size());
}
else
{
TCPVariableLengthPacket giveMeDataToAddLengthTo;
giveMeDataToAddLengthTo.append((const byte*)packetToSend.contents(),packetToSend.size());
ByteBuffer sendMe = giveMeDataToAddLengthTo.GetContentsWithSize();
return string(sendMe.contents(),sendMe.size());
}
}
2009-08-12 19:55:32 +00:00
uint16 CTW_remoteSeq = 0;
uint16 CTW_localSeq = 0;
2009-08-11 12:17:38 +00:00
uint8 CTW_flags = 0;
2009-08-12 19:55:32 +00:00
uint16 WTC_remoteSeq = 0;
uint16 WTC_localSeq = 0;
2009-08-11 12:17:38 +00:00
uint8 WTC_flags = 0;
string ClientToWorld( const char* pData,size_t pSize )
{
stringstream comment;
if (pData[0] != 0x01 || TFDecryptCTW == NULL)
{
//data is not encrypted, no idea what to do with it, just log as is
comment << "Not Encrypted";
LogPacket(pData,pSize,CLIENT_TO_WORLD,comment.str());
return string(pData,pSize);
}
else
{
//packet is encrypted, lets decrypt, log the plaintext, then reencrypt
ByteBuffer encryptedContents;
encryptedContents.append((const byte*)&pData[1],pSize-1); //skip the first byte
EncryptedPacket encryptionless(encryptedContents,TFDecryptCTW);
2009-08-12 19:55:32 +00:00
SequencedPacket headerless(encryptionless);
2009-08-11 12:17:38 +00:00
2009-08-12 19:55:32 +00:00
CTW_remoteSeq = headerless.getRemoteSeq();
CTW_localSeq = headerless.getLocalSeq();
2009-08-11 12:17:38 +00:00
CTW_flags = headerless.getPSS();
2009-08-12 19:55:32 +00:00
LogWorldPacket(headerless.contents(),headerless.size(),CLIENT_TO_WORLD,CTW_localSeq,CTW_remoteSeq,CTW_flags);
2009-08-11 12:17:38 +00:00
//reencrypt
ByteBuffer reencrypted = encryptionless.toCipherText(TFEncryptCTW);
ByteBuffer withLeadingZeroOne;
withLeadingZeroOne << uint8(0x01);
withLeadingZeroOne.append((const byte*)reencrypted.contents(),reencrypted.size());
return string(withLeadingZeroOne.contents(),withLeadingZeroOne.size());
}
}
string WorldToClient( const char* pData,size_t pSize )
{
stringstream comment;
if (pData[0] != 0x01 || TFDecryptWTC == NULL)
{
//data is not encrypted, no idea what to do with it, just log as is
comment << "Not Encrypted";
LogPacket(pData,pSize,WORLD_TO_CLIENT,comment.str());
return string(pData,pSize);
}
else
{
//packet is encrypted, lets decrypt, log the plaintext, then reencrypt
ByteBuffer encryptedContents;
encryptedContents.append((const byte*)&pData[1],pSize-1); //skip the first byte
EncryptedPacket encryptionless(encryptedContents,TFDecryptWTC);
2009-08-12 19:55:32 +00:00
SequencedPacket headerless(encryptionless);
2009-08-11 12:17:38 +00:00
2009-08-12 19:55:32 +00:00
WTC_remoteSeq = headerless.getRemoteSeq();
WTC_localSeq = headerless.getLocalSeq();
2009-08-11 12:17:38 +00:00
WTC_flags = headerless.getPSS();
2009-08-12 19:55:32 +00:00
LogWorldPacket(headerless.contents(),headerless.size(),WORLD_TO_CLIENT,WTC_localSeq,WTC_remoteSeq,WTC_flags);
2009-08-11 12:17:38 +00:00
//reencrypt
ByteBuffer reencrypted = encryptionless.toCipherText(TFEncryptWTC);
ByteBuffer withLeadingZeroOne;
withLeadingZeroOne << uint8(0x01);
withLeadingZeroOne.append((const byte*)reencrypted.contents(),reencrypted.size());
return string(withLeadingZeroOne.contents(),withLeadingZeroOne.size());
}
}