Register for your free account! | Forgot your password?

Go Back   elitepvpers > MMORPGs > Nostale
You last visited: Today at 05:45

  • Please register to post and access all features, it's quick, easy and FREE!

Advertisement



[EU, Client] Cryptography

Discussion on [EU, Client] Cryptography within the Nostale forum part of the MMORPGs category.

Reply
 
Old   #1
 
Cryless~'s Avatar
 
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;
	}
}
Cryless~ is offline  
Thanks
16 Users
Old 12/05/2015, 13:51   #2
 
0Lucifer0's Avatar
 
elite*gold: 0
Join Date: May 2009
Posts: 1,005
Received Thanks: 1,019
Good job!
0Lucifer0 is offline  
Old 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.
abssy is offline  
Old 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 ?
PainToTheWorld is offline  
Old 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?
BladeTiger12 is offline  
Old 12/22/2015, 23:21   #6
 
elite*gold: 0
Join Date: Dec 2015
Posts: 39
Received Thanks: 23
Quote:
Originally Posted by PainToTheWorld View Post
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.
Trollcrap- is offline  
Old 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 :/



btw is the packet identifier random?
PainToTheWorld is offline  
Old 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);
BladeTiger12 is offline  
Old 12/24/2015, 23:14   #9
 
elite*gold: 0
Join Date: Dec 2015
Posts: 39
Received Thanks: 23
Quote:
Originally Posted by BladeTiger12 View Post
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 ~
Trollcrap- is offline  
Thanks
1 User
Old 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?
lika85 is offline  
Old 03/03/2017, 15:01   #11
 
elite*gold: 0
Join Date: Jul 2012
Posts: 4
Received Thanks: 0
This is still correct way?
ArtTorn is offline  
Old 03/03/2017, 15:04   #12

 
FI0w's Avatar
 
elite*gold: 50
Join Date: Jul 2014
Posts: 1,699
Received Thanks: 1,165
Quote:
Originally Posted by ArtTorn View Post
This is still correct way?
Just PW is wrong you dont need to Encrypt/Decrypt it anymore you can just use SHA512 Uppercase :P
FI0w is offline  
Thanks
1 User
Old 03/08/2017, 14:33   #13
 
Cryless~'s Avatar
 
elite*gold: 0
Join Date: Sep 2015
Posts: 482
Received Thanks: 532
Quote:
Originally Posted by xSensitivex View Post
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));
}
Cryless~ is offline  
Old 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?
lika85 is offline  
Old 10/22/2017, 20:21   #15
 
-Nokis's Avatar
 
elite*gold: 0
Join Date: Oct 2017
Posts: 11
Received Thanks: 16
Quote:
Originally Posted by lika85 View Post
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.
-Nokis is offline  
Thanks
2 Users
Reply


Similar Threads 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.


Powered by vBulletin®
Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
SEO by vBSEO ©2011, Crawlability, Inc.
This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

Support | Contact Us | FAQ | Advertising | Privacy Policy | Terms of Service | Abuse
Copyright ©2025 elitepvpers All Rights Reserved.