Code:
----------------------
.h
-----------------------
#pragma once
#ifndef __CRYPTO_H
#define __CRYPTO_H
#include <string>
#include <vector>
class Crypto
{
public:
std::vector<unsigned char> encryptGamePacket(const std::string& buf, int session, bool is_session_packet = 0) const;
std::vector<unsigned char> encryptLoginPacket(const std::string& buf) const;
std::string decryptLoginPacket(const std::vector<unsigned char>& buf, std::size_t len) const;
std::vector<std::string> decryptGamePacket(const std::vector<unsigned char>& buf, std::size_t len) const;
std::string encryptPasswordString(const std::string& password) const;
std::string createLoginHash(const std::string& user) const;
std::string createLoginVersion(void) const;
int randomNumber(int min, int max) const;
private:
void completeGamePacketEncrypt(std::vector<unsigned char>& buf, int session, bool is_session_packet = 0) const;
};
namespace CryptoVar
{
extern std::string dxhash;
extern std::string glhash;
extern std::string version;
}
#endif
----------------------
.cpp
-----------------------
#include "Crypto.h"
#include <algorithm>
#include <sstream>
#include <random>
#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1
#include <md5.h>
#include <hex.h>
#pragma comment(lib, "cryptlib.lib")
namespace CryptoVar
{
std::string dxhash;
std::string glhash;
std::string version;
}
std::string Crypto::decryptLoginPacket(const std::vector<unsigned char>& buf, std::size_t len) const
{
std::string output;
std::transform(buf.begin(), buf.begin() + len, std::back_inserter(output),
[](unsigned char c)
{
return c - 0xF;
}
);
return output;
}
std::vector<unsigned char> Crypto::encryptLoginPacket(const std::string& buf) const
{
std::vector<unsigned char> output;
std::transform(buf.begin(), buf.end(), std::back_inserter(output),
[](char c)
{
return (c ^ 0xC3) + 0xF;
}
);
return output;
}
std::string Crypto::encryptPasswordString(const std::string& password) const
{
static unsigned char table[] = {0x2E, 0x2A, 0x17, 0x4F, 0x20, 0x24, 0x47, 0x11, 0x5B, 0x37,
0x53, 0x43, 0x15, 0x34, 0x45, 0x25, 0x4B, 0x1D, 0x2F, 0x58, 0x2B, 0x32, 0x63};
std::stringstream output;
std::size_t random_start_pos = randomNumber(0, 22);
std::string password_hex_string;
CryptoPP::StringSource(password,
true, new CryptoPP::HexEncoder(new CryptoPP::StringSink(password_hex_string)));
output << std::uppercase << std::hex << int(table[random_start_pos]);
unsigned char first = 0, second = 0;
for(std::size_t i = 0; i < password_hex_string.length(); ++i, ++i, ++random_start_pos)
{
second = table[random_start_pos] & 0xF;
first = (table[random_start_pos] & 0xF0) >> 4;
output << std::uppercase << std::hex << int(first);
output << std::uppercase << password_hex_string.at(i);
output << std::uppercase << std::hex << int(second);
output << std::uppercase << password_hex_string.at(i+1);
if(random_start_pos == 22)
random_start_pos = -1;
}
return output.str();
}
std::string Crypto::createLoginHash(const std::string& user) const
{
CryptoPP::Weak1::MD5 hash;
std::string output;
std::string login_string_to_hash = CryptoVar::dxhash;
login_string_to_hash += CryptoVar::glhash;
login_string_to_hash += user;
CryptoPP::StringSource(login_string_to_hash,
true, new CryptoPP::HashFilter(hash, new CryptoPP::HexEncoder(new CryptoPP::StringSink(output))));
return output;
}
std::string Crypto::createLoginVersion(void) const
{
std::string test2 = CryptoVar::dxhash;
std::string test = CryptoVar::version;
std::stringstream output;
output << "00" << std::uppercase << std::hex << int(randomNumber(0, 126))
<< std::uppercase << std::hex << int(randomNumber(0, 126))
<< std::uppercase << std::hex << int(randomNumber(0, 126))
<< '\v' << CryptoVar::version;
return output.str();
}
int Crypto::randomNumber(int min, int max) const
{
std::random_device seeder;
std::mt19937 engine(seeder());
std::uniform_int_distribution<int> generator(min, max);
return generator(engine);
}
std::vector<std::string> Crypto::decryptGamePacket(const std::vector<unsigned char>& buf, std::size_t len) const
{
std::vector<std::string> output;
std::string current_packet;
static const char keys[] = {' ','-','.','0','1','2','3','4','5','6','7','8','9','n'};
std::size_t index = 0;
unsigned char currentByte = 0, length = 0, first = 0, second = 0;
while(index < len)
{
currentByte = buf[index];
++index;
if(currentByte == 0xFF)
{
output.push_back(current_packet);
current_packet.clear();
continue;
}
length = currentByte & 0x7F;
if(currentByte & 0x80)
{
while(length)
{
if(index <= len)
{
currentByte = buf[index];
++index;
first = keys[((currentByte & 0xF0u) >> 4) -1];
if(first != 0x6E)
current_packet += first;
if(length <= 1)
break;
second = keys[(currentByte & 0xF) -1];
if(second != 0x6E)
current_packet += second;
length -= 2;
} else
{
--length;
}
}
} else
{
while(length)
{
if(index <= len)
{
current_packet += buf[index] ^ 0xFF;
++index;
}
--length;
}
}
}
return output;
}
std::vector<unsigned char> Crypto::encryptGamePacket(const std::string& buf, int session, bool is_session_packet) const
{
std::size_t packet_length = buf.size();
std::string packet_mask;
std::transform(buf.begin(), buf.end(), std::back_inserter(packet_mask),
[](char c)
{
if(c == '#')
return '0';
if(!(c -= 0x20) || (c += 0xF1) < 0 || (c -= 0xB) < 0 || !(c -= 0xC5))
return '1';
return '0';
}
);
std::vector<unsigned char> output;
std::size_t sequences = 0, sequence_counter = 0;
std::size_t last_position = 0, current_position = 0, length = 0;
unsigned char current_byte = 0;
while(current_position <= packet_length)
{
last_position = current_position;
while(current_position < packet_length && packet_mask[current_position] == '0')
++current_position;
if(current_position)
{
length = (current_position - last_position);
sequences = (length / 0x7E);
for(std::size_t i = 0; i < length; ++i, ++last_position)
{
if(i == (sequence_counter * 0x7E))
{
if(!sequences)
{
output.push_back(length - i);
} else
{
output.push_back(0x7E);
--sequences;
++sequence_counter;
}
}
output.push_back(buf[last_position] ^ 0xFF);
}
}
if(current_position >= packet_length)
break;
last_position = current_position;
while(current_position < packet_length && packet_mask[current_position] == '1')
++current_position;
if(current_position)
{
length = (current_position - last_position);
sequences = (length / 0x7E);
for(std::size_t i = 0; i < length; ++i, ++last_position)
{
if(i == (sequence_counter * 0x7E))
{
if(!sequences)
{
output.push_back((length - i) | 0x80);
} else
{
output.push_back(0x7E | 0x80);
--sequences;
++sequence_counter;
}
}
current_byte = buf[last_position];
switch(current_byte)
{
case 0x20:
current_byte = 1;
break;
case 0x2D:
current_byte = 2;
break;
case 0x2E:
current_byte = 3;
break;
case 0xFF:
current_byte = 0xE;
break;
default:
current_byte -= 0x2C;
break;
}
if(current_byte != 0x00)
{
if(i % 2 == 0)
{
output.push_back(current_byte << 4);
} else
{
output.back() |= current_byte;
}
}
}
}
}
output.push_back(0xFF);
completeGamePacketEncrypt(output, session, is_session_packet);
return output;
}
void Crypto::completeGamePacketEncrypt(std::vector<unsigned char>& buf, int session, bool is_session_packet) const
{
unsigned char session_number = (((session >> 6) & 0xFF) & 0x80000003);
if(session_number < 0)
session_number = (((session_number - 1) | 0xFFFFFFFC) + 1);
unsigned char session_key = (session & 0xFF);
if(is_session_packet)
session_number = -1;
switch (session_number)
{
case 0:
for(std::size_t i = 0; i < buf.size(); ++i)
buf[i] = (buf[i] + (session_key + 0x40));
break;
case 1:
for(std::size_t i = 0; i < buf.size(); ++i)
buf[i] = (buf[i] - (session_key + 0x40));
break;
case 2:
for(std::size_t i = 0; i < buf.size(); ++i)
buf[i] = ((buf[i] ^ 0xC3) + (session_key + 0x40));
break;
case 3:
for(std::size_t i = 0; i < buf.size(); ++i)
buf[i] = ((buf[i] ^ 0xC3) - (session_key + 0x40));
break;
default:
for(std::size_t i = 0; i < buf.size(); ++i)
buf[i] = buf[i] + 0x0F;
break;
}
}