|
You last visited: Today at 05:45
Advertisement
[EU, Client] Cryptography
Discussion on [EU, Client] Cryptography within the Nostale forum part of the MMORPGs category.
12/04/2015, 17:19
|
#1
|
elite*gold: 0
Join Date: Sep 2015
Posts: 482
Received Thanks: 532
|
[EU, Client] Cryptography
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;
}
}
|
|
|
12/05/2015, 13:51
|
#2
|
elite*gold: 0
Join Date: May 2009
Posts: 1,005
Received Thanks: 1,019
|
Good job!
|
|
|
12/05/2015, 21:26
|
#3
|
elite*gold: 0
Join Date: Nov 2015
Posts: 1
Received Thanks: 0
|
Thanks a lot, I was just searching for this a week ago and you just post it. Amazing job.
|
|
|
12/22/2015, 21:06
|
#4
|
elite*gold: 0
Join Date: Sep 2010
Posts: 133
Received Thanks: 29
|
I've tested all encryptions and it works well . but when I send my session and id / pw to the game server , I get no response . Is there a solution to this problem ?
|
|
|
12/22/2015, 21:20
|
#5
|
elite*gold: 64
Join Date: May 2011
Posts: 1,229
Received Thanks: 854
|
Then is your packet build wrong. Can you send code snippet where you send that packet?
|
|
|
12/22/2015, 23:21
|
#6
|
elite*gold: 0
Join Date: Dec 2015
Posts: 39
Received Thanks: 23
|
Quote:
Originally Posted by PainToTheWorld
I've tested all encryptions and it works well . but when I send my session and id / pw to the game server , I get no response . Is there a solution to this problem ?
|
Well, it also happens when you send too fast the packets to world server.
|
|
|
12/23/2015, 18:17
|
#7
|
elite*gold: 0
Join Date: Sep 2010
Posts: 133
Received Thanks: 29
|
did it with different delays .. unfortunately it does not work :/
pChannel = new TConnection();
pChannel->Connect(ServerList.Channels[iIndex].sIP, ServerList.Channels[iIndex].iPort);
pChannel->StartRecv();
pChannel->iSession = ServerList.iSession;
pChannel->SendSession();
Sleep(200);
pChannel->SendGamePacket("ID");
Sleep(200);
pChannel->SendGamePacket("PW");
int TConnection::SendGamePacket(std::string sPacket)
{
int iResult;
std::vector<unsigned char> sEncrypted = EncryptGamePacket(FormatString("%d %s", iPacketCount, sPacket.c_str()), iSession, false);
iResult = send(soConnect, &sEncrypted.front(), sEncrypted.size(), 0);
if (iResult == SOCKET_ERROR)
{
__Log("send failed with error: %d\n", WSAGetLastError());
closesocket(soConnect);
WSACleanup();
return 1;
}
iPacketCount++;
return iResult;
}
btw is the packet identifier random?
|
|
|
12/23/2015, 19:21
|
#8
|
elite*gold: 64
Join Date: May 2011
Posts: 1,229
Received Thanks: 854
|
Yes it's random. (Just generate it 1 time and add for new packet +1)
You have to send the SessionID...(Wait 1sec~)...IP|PW same packet.
Like:
Code:
// You need it like this:
std::vector<byte> bytes;
bytes.push_back(EncryptGame("IDENTIFIER ID")); //EncryptGame("25555 Test")
bytes.push_back(0xFF);
bytes.push_back(EncryptGame("IDENTIFIER PW")); //EncryptGame("25556 Rofl")
send(bytes);
|
|
|
12/24/2015, 23:14
|
#9
|
elite*gold: 0
Join Date: Dec 2015
Posts: 39
Received Thanks: 23
|
Quote:
Originally Posted by BladeTiger12
Yes it's random. (Just generate it 1 time and add for new packet +1)
You have to send the SessionID...(Wait 1sec~)...IP|PW same packet.
Like:
Code:
// You need it like this:
std::vector<byte> bytes;
bytes.push_back(EncryptGame("IDENTIFIER ID")); //EncryptGame("25555 Test")
bytes.push_back(0xFF);
bytes.push_back(EncryptGame("IDENTIFIER PW")); //EncryptGame("25556 Rofl")
send(bytes);
|
There is not a rule about ID|PW, server is async and splits by delimiter.. 1s is right pause ~
|
|
|
08/09/2016, 20:24
|
#10
|
elite*gold: 0
Join Date: Jan 2016
Posts: 36
Received Thanks: 0
|
While compiling it returns error
"32 2 H:\DevC++\Dev-Cpp\MinGW64\lib\gcc\x86_64-w64-mingw32\4.9.2\include\c++\bits\c++0x_warning.h [Error] #error This file requires compiler and library support for the ISO C++ 2011 standard. This support is currently experimental, and must be enabled with the -std=c++11 or -std=gnu++11 compiler options.
md5.h No such file or directory"
for hex.h too. Missing md5.h and hex.h, where can i find it?
|
|
|
03/03/2017, 15:01
|
#11
|
elite*gold: 0
Join Date: Jul 2012
Posts: 4
Received Thanks: 0
|
This is still correct way?
|
|
|
03/03/2017, 15:04
|
#12
|
elite*gold: 50
Join Date: Jul 2014
Posts: 1,699
Received Thanks: 1,165
|
Quote:
Originally Posted by ArtTorn
This is still correct way?
|
Just PW is wrong you dont need to Encrypt/Decrypt it anymore you can just use SHA512 Uppercase :P
|
|
|
03/08/2017, 14:33
|
#13
|
elite*gold: 0
Join Date: Sep 2015
Posts: 482
Received Thanks: 532
|
Quote:
Originally Posted by xSensitivex
Just PW is wrong you dont need to Encrypt/Decrypt it anymore you can just use SHA512 Uppercase :P
|
openssl
Code:
std::string NTCryptoHelper::ToHex(unsigned char *digest, std::size_t length)
{
static char table[] = {
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
};
std::string result;
for (std::size_t i = 0; i < length; i++) {
result += table[digest[i] / 16];
result += table[digest[i] % 16];
}
return result;
}
Code:
std::string NTCryptoHelper::Sha512(const std::string& plainText)
{
unsigned char digest[SHA512_DIGEST_LENGTH];
SHA512((unsigned char*)plainText.c_str(), plainText.length(), digest);
return ToHex(digest, sizeof(digest));
}
|
|
|
08/24/2017, 12:51
|
#14
|
elite*gold: 0
Join Date: Jan 2016
Posts: 36
Received Thanks: 0
|
Code:
public static ArrayList<String> DecryptGamePacketTest(ArrayList<Integer> buf) {
int len = buf.size();
ArrayList<String> output = new ArrayList<String>();
ArrayList<Integer> current_packet = new ArrayList<Integer>();
char keys[] = { ' ', '-', '.', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'n' };
int index = 0;
int currentByte = 0, length = 0, first = 0, second = 0;
while (index < len) {
currentByte = buf.get(index);
++index;
if (currentByte == 0xFF) {
output.add(ArrayListToString(current_packet));
//System.out.println("RECEIVED: "+ArrayListToString(current_packet));
current_packet = new ArrayList<Integer>();
continue;
}
length = (currentByte & 0x7F);
if (((currentByte & 0x80) & 0xFF) != 0 && currentByte!=0) {
while (length != 0) {
if (index < len) {
currentByte = buf.get(index);
++index;
try{
first = keys[(((currentByte & 0xF0) ) >> 4) - 1];
if (first != 0x6E)
current_packet.add(first);
if (length <= 1)
break;
second = keys[(currentByte & 0xF) - 1];
if (second != 0x6E)
current_packet.add(second);
length -= 2;
}
catch(Exception e){System.out.println("Exception packet: "+ArrayListToString(current_packet));}
} else {
--length;
}
}
} else {
while (length != 0) {
if (index < len) {
//current_packet.add(buf.get(index) ^ 0xFF);¨
current_packet.add(buf.get(index) ^ 0xFF);
++index;
}
--length;
}
}
}
return output;
}
This is DecryptGamePacket function i currently use in Java and i have problems with chars with diacritics (ěščřžýáíé). Probably becouse java uses 2 byte chars and in this function it is only 1 byte. But in client diacritics and other **** chars are working. Is it working for you? How this can be fixed?
|
|
|
10/22/2017, 20:21
|
#15
|
elite*gold: 0
Join Date: Oct 2017
Posts: 11
Received Thanks: 16
|
Quote:
Originally Posted by lika85
Code:
public static ArrayList<String> DecryptGamePacketTest(ArrayList<Integer> buf) {
int len = buf.size();
ArrayList<String> output = new ArrayList<String>();
ArrayList<Integer> current_packet = new ArrayList<Integer>();
char keys[] = { ' ', '-', '.', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'n' };
int index = 0;
int currentByte = 0, length = 0, first = 0, second = 0;
while (index < len) {
currentByte = buf.get(index);
++index;
if (currentByte == 0xFF) {
output.add(ArrayListToString(current_packet));
//System.out.println("RECEIVED: "+ArrayListToString(current_packet));
current_packet = new ArrayList<Integer>();
continue;
}
length = (currentByte & 0x7F);
if (((currentByte & 0x80) & 0xFF) != 0 && currentByte!=0) {
while (length != 0) {
if (index < len) {
currentByte = buf.get(index);
++index;
try{
first = keys[(((currentByte & 0xF0) ) >> 4) - 1];
if (first != 0x6E)
current_packet.add(first);
if (length <= 1)
break;
second = keys[(currentByte & 0xF) - 1];
if (second != 0x6E)
current_packet.add(second);
length -= 2;
}
catch(Exception e){System.out.println("Exception packet: "+ArrayListToString(current_packet));}
} else {
--length;
}
}
} else {
while (length != 0) {
if (index < len) {
//current_packet.add(buf.get(index) ^ 0xFF);¨
current_packet.add(buf.get(index) ^ 0xFF);
++index;
}
--length;
}
}
}
return output;
}
This is DecryptGamePacket function i currently use in Java and i have problems with chars with diacritics (ěščřžýáíé). Probably becouse java uses 2 byte chars and in this function it is only 1 byte. But in client diacritics and other shit chars are working. Is it working for you? How this can be fixed? 
|
The NosTale Client uses the Windows-1252 encoding. You have to encode ‘current_packet’ in win1252.
|
|
|
 |
|
Similar Threads
|
CLIENT CRYPTOGRAPHY
04/08/2016 - Nostale - 6 Replies
C++ - CLIENT - LOGIN
// RETURN A RANDOM NUMBER
int Random(int start, int end) { return rand()%(end-start)+start; }
// RETURN ENCRYPTED PASSWORD
std::string pwEncrypt(std::string password)
{
const unsigned char secondtable = { 0x2E, 0x2A, 0x17, 0x4F, 0x20, 0x24, 0x47, 0x11, 0x5B, 0x37, 0x53,
0x43, 0x15, 0x34, 0x45, 0x25, 0x4B, 0x1D, 0x2F, 0x58, 0x2B, 0x32, 0x63 };
|
[PHP - CLIENT] Login Cryptography
11/02/2013 - Nostale - 30 Replies
Hi community ! :pimp:
today i open this thread for release the login cryptography written in php..
// encrypt 'NoS0575..' packet
function packet_enc($packet)
{
$str_enc = "";
for($i = 0; $i < strlen($packet); $i++)
$str_enc .= chr((ord($packet)^195) + 15);
|
Auth Cryptography
02/01/2013 - CO2 Private Server - 3 Replies
i Wonder if the Auth Cryptography has changed at patch 5698 cuz i couldnt login into My Pserver ... after checking PasswordSeed (1059) & Login (1052) & Auth Response (1055) .. none of them has changed
Regards
Shadowman123
|
Help with cryptography
05/16/2012 - CO2 Programming - 10 Replies
Hello ppl, so ive been learning general hacking methods for quite a decent while now, first i started out with small things such as memory hacks and then i started learning even more which led me to packet sniffing and that led me to the idea of fiddling around with conquer. Now that ive had a chance to play around with it i decided to hook the connect function of the game and i was successful at doing so, i also managed to get the client to connect to my socket first rather than connect to the...
|
Client Server Cryptography?
07/14/2009 - Archlord - 7 Replies
i was wondering, the communication between alefcient and the game server is encrypted, and alefclient binary seems to use Cryptography API (CNG) with most of its functions like:
BCryptCloseAlgorithmProvider
BCryptCreateHash
BCryptDecrypt
BCryptDeriveKey
BCryptDestroyHash
BCryptDestroyKey
BCryptDestroySecret
BCryptDuplicateHash
|
All times are GMT +1. The time now is 05:48.
|
|