Message ID Encryption

Forum closed. All further discussion to be discussed at https://github.com/OpenKore/

Moderator: Moderators

Message
Author
Phobe
Noob
Noob
Posts: 2
Joined: 07 Oct 2008, 19:51
Noob?: Yes

Message ID Encryption

#1 Post by Phobe »

I'm interested in learning how the encryption works, but I'm not familiar with PERL (JAVA programmer here). Here are my questions:

Are param1 and param2 read in raw (little endian)? I'm not very familiar with PERL's packing method so I'm not sure how it processes the numbers. My guess is that it is read in little endian but is converted into big endian in initialize_message_id_encryption

Also, how is the message ID read? Is it converted to big endian or is it left as little endian?

Can anyone supply me with sample input/output generated by these methods so I can make sure I interpreted the code correctly (server encryption key, enc_val1, enc_val2, unencrypted packet, new enc_val1, and encrypted packet)? I can probably answer all of the questions by myself if I had sample input/output to play with.

Here's the related code to make it easier on you guys:

Code: Select all

'02AE' => ['initialize_message_id_encryption', 'V1 V1', [qw(param1 param2)]],

sub initialize_message_id_encryption {
	my ($self, $args) = @_;
	if ($masterServer->{messageIDEncryption} ne '0') {
		$messageSender->sendMessageIDEncryptionInitialized();

		my @c;
		my $shtmp = $args->{param1};
		for (my $i = 8; $i > 0; $i--) {
			$c[$i] = $shtmp & 0x0F;
			$shtmp >>= 4;
		}
		my $w = ($c[6]<<12) + ($c[4]<<8) + ($c[7]<<4) + $c[1];
		$enc_val1 = ($c[2]<<12) + ($c[3]<<8) + ($c[5]<<4) + $c[8];
		$enc_val2 = (((($enc_val1 ^ 0x0000F3AC) + $w) << 16) | (($enc_val1 ^ 0x000049DF) + $w)) ^ $args->{param2};
	}
}

sub encryptMessageID {
	use bytes;
	my ($self, $r_message) = @_;

	if ($self->{net}->getState() != Network::IN_GAME) {
		$enc_val1 = 0;
		$enc_val2 = 0;
		return;
	}

	my $messageID = unpack("v", $$r_message);
	if ($enc_val1 != 0 && $enc_val2 != 0) {
		# Prepare encryption
		$enc_val1 = (0x000343FD * $enc_val1) + $enc_val2;
		$enc_val1 = $enc_val1 % 2 ** 32;
		debug (sprintf("enc_val1 = %x", $enc_val1) . "\n", "sendPacket", 2);
		# Encrypt message ID
		$messageID = $messageID ^ (($enc_val1 >> 16) & 0x7FFF);
		$messageID &= 0xFFFF;
		$$r_message = pack("v", $messageID) . substr($$r_message, 2);
	}
}

Motivus
Developers
Developers
Posts: 157
Joined: 04 Apr 2008, 13:33
Noob?: Yes

Re: Message ID Encryption

#2 Post by Motivus »

C++ version from my ragnarok online plugin system:

Code: Select all

void EncInit(DWORD paramOne, DWORD paramTwo)
{
	char c[8];
	DWORD dwTemp=paramOne;

	for (int i=7; i >= 0; i--) {
		c[i] = dwTemp & 0x0F;
		dwTemp >>= 4;
	}

	WORD w = (c[5]<<12) + (c[3]<<8) + (c[6]<<4) + c[0];
	DWORD encValOne = (c[1]<<12) + (c[2]<<8) + (c[4]<<4) + c[7];
	DWORD encValTwo = ((((encValOne ^ 0x0000F3AC) + w) << 16) | ((encValOne ^ 0x000049DF) + w)) ^ paramTwo;
	
	gVar.encOne=encValOne;
	gVar.encTwo=encValTwo;
}

WORD EncPrefix()
{
	int iEnc=(0x000343FD * gVar.encOne) + gVar.encTwo;
	DWORD tempEncOne=iEnc % 4294967296;
	WORD dwRet=(tempEncOne >> 16) & 0x7FFF;	

	gVar.encOne=tempEncOne;
	return dwRet;
}

//This function is never used, but in theory if you wanted to unload XKore or a dll you'd need this function to tell the client encryption is on and generate valid keys so there is no disconnection
//paramOne, paramTwo   can be fed to init enc to gen current keys or sent to the client in a 0x02AE packet
void EncReverse(DWORD encOne, DWORD encTwo)
{
	WORD cOne=encOne^0xF3AC;
	WORD cTwo=encOne^0x000049DF;

	DWORD paramTwo=(cOne << 16) | cTwo;
	paramTwo^=encTwo;

	DWORD paramOne=(((encOne &0xF000) << 12) + ((encOne &0xF00) << 12) + ((encOne &0xF0) << 8) + (encOne &0xF));
}
for EncPrefix() you just ^ the packet header by its output (first short/WORD/2bytes in every packet)
Oh no.

Phobe
Noob
Noob
Posts: 2
Joined: 07 Oct 2008, 19:51
Noob?: Yes

Re: Message ID Encryption

#3 Post by Phobe »

Thanks for the above code--it made things a little clearer. Java doesn't support unsigned values so its a bit clumsy working with them. It took a while to get my code working, but then I ran into another problem.

I was messing around with encrypting message IDs with the ones sent by the client and it led to a problem where the packets weren't 'chopped' already. I know Kore can chop incoming packets by using recvPackets.txt, but there's none for outgoing packets.

I suspect Kore is already able to chop these packets also or else proxy mode wouldn't work. Insight as to know Kore does this would be appreciated.

Motivus
Developers
Developers
Posts: 157
Joined: 04 Apr 2008, 13:33
Noob?: Yes

Re: Message ID Encryption

#4 Post by Motivus »

Phobe wrote:Thanks for the above code--it made things a little clearer. Java doesn't support unsigned values so its a bit clumsy working with them. It took a while to get my code working, but then I ran into another problem.

I was messing around with encrypting message IDs with the ones sent by the client and it led to a problem where the packets weren't 'chopped' already. I know Kore can chop incoming packets by using recvPackets.txt, but there's none for outgoing packets.

I suspect Kore is already able to chop these packets also or else proxy mode wouldn't work. Insight as to know Kore does this would be appreciated.
All sends are sent individually to begin with.

The only time you can get close to combined sends is holding alt+g down while changing maps. It will send ~90 requests instantly, and it appears as the same send even though the client treats them as individual sends.

You could just loop through sends by length.
Oh no.

kali
OpenKore Monk
OpenKore Monk
Posts: 457
Joined: 04 Apr 2008, 10:10

Re: Message ID Encryption

#5 Post by kali »

Phobe wrote:I suspect Kore is already able to chop these packets also or else proxy mode wouldn't work. Insight as to know Kore does this would be appreciated.
It makes use of the file called recvpackets.txt which contain lengths of packets as recognized by the client. The first short int denotes the packet id, while the next byte(?) denotes the length of that particular packet. If the packet has variable length, it is denoted as 0. This means that kore needs to read the next short int from the packet to determine the length of the packet itself, minus 4 bytes (id + length).

I wrote a java parser for the ro protocol, just in case you're interested in seeing an alternative implementation. It's GPL though, so take care not to be infected if you're developing a proprietary application and sharing it (shame on you XD) :P
Got your topic trashed by a mod?

Trashing topics is one click, and moving a topic to its proper forum is a lot harder. You expend the least effort in deciding where to post, mods expend the least effort by trashing.

Have a nice day.

sli
Perl Monk
Perl Monk
Posts: 810
Joined: 04 Apr 2008, 17:26
Noob?: No

Re: Message ID Encryption

#6 Post by sli »

Gotta love Python for this kind of thing. Calling a list element (that contains a function reference) as a funtion. Makes plugins/hooking so much easier.

Code: Select all

header = s.recv(2)
body = s.recv(recvpackets[header])
packet_handlers[header](body)
cs : ee : realist

Locked