Reversed from client version v1581.
AccountID and CryptoID are sent in the 41F Packet (Server->Client), which is structured:
When the client sends the 41C packet on the game server, it then switches to these new keys. Therefore, packets decrypted from the client must now be decrypted using the new keys generated by SetKey().
Regards,
Infamous Noone.
Code:
/*
EUDEMON PACKET ENCRYPTION/DECRYPTION, MARCH 30th, 2012
Copyright (C) 2012 InfamousNoone (of http://elitepvpers.com) and http://conquerai.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
GNU General Public License: http://www.gnu.org/licenses/
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using ICSPublicLibrary;
namespace EudemonAI.Network
{
public unsafe class EudemonCryptographer : INetworkEncryption
{
//
//
// REVERSED BY InfamousNoone @ E*PVP (http://www.elitepvpers.com)
// OF CONQUERAI (http://conquerai.com) -- 2012, March 28th
//
// Special thanks for contributions (from elitepvpers.com):
// hio77
// funhacker
//
//
[StructLayout(LayoutKind.Explicit)]
private struct Counter
{
[FieldOffset(0)]
public ushort Value;
[FieldOffset(0)]
public byte Low;
[FieldOffset(1)]
public byte High;
}
private static byte[] skey1 =
{
0x9A,0x71,0x9E,0x65,0xB2,0xE9,0x96,0xBD,0x0A,0xA1,0xCE,0x55,0xA2,0x99,0x46,0x2D
,0x7A,0xD1,0xFE,0x45,0x92,0x49,0xF6,0x9D,0xEA,0x01,0x2E,0x35,0x82,0xF9,0xA6,0x0D
,0x5A,0x31,0x5E,0x25,0x72,0xA9,0x56,0x7D,0xCA,0x61,0x8E,0x15,0x62,0x59,0x06,0xED
,0x3A,0x91,0xBE,0x05,0x52,0x09,0xB6,0x5D,0xAA,0xC1,0xEE,0xF5,0x42,0xB9,0x66,0xCD
,0x1A,0xF1,0x1E,0xE5,0x32,0x69,0x16,0x3D,0x8A,0x21,0x4E,0xD5,0x22,0x19,0xC6,0xAD
,0xFA,0x51,0x7E,0xC5,0x12,0xC9,0x76,0x1D,0x6A,0x81,0xAE,0xB5,0x02,0x79,0x26,0x8D
,0xDA,0xB1,0xDE,0xA5,0xF2,0x29,0xD6,0xFD,0x4A,0xE1,0x0E,0x95,0xE2,0xD9,0x86,0x6D
,0xBA,0x11,0x3E,0x85,0xD2,0x89,0x36,0xDD,0x2A,0x41,0x6E,0x75,0xC2,0x39,0xE6,0x4D
};
private static byte[] skey2 = { 0x7E, 0xDE, 0xFE, 0x5E };
private static byte[] skey3 =
{
0xE4,0xAF,0x60,0x3B,0xCC,0x37,0x68,0xE3,0x74,0x7F,0x30,0x0B,0xDC,0x47,0xB8,0x73
,0x04,0x0F,0x00,0x1B,0xEC,0x97,0x08,0xC3,0x94,0xDF,0xD0,0x6B,0xFC,0x27,0x58,0x53
,0x24,0xEF,0xA0,0x7B,0x0C,0x77,0xA8,0x23,0xB4,0xBF,0x70,0x4B,0x1C,0x87,0xF8,0xB3
,0x44,0x4F,0x40,0x5B,0x2C,0xD7,0x48,0x03,0xD4,0x1F,0x10,0xAB,0x3C,0x67,0x98,0x93
,0x64,0x2F,0xE0,0xBB,0x4C,0xB7,0xE8,0x63,0xF4,0xFF,0xB0,0x8B,0x5C,0xC7,0x38,0xF3
,0x84,0x8F,0x80,0x9B,0x6C,0x17,0x88,0x43,0x14,0x5F,0x50,0xEB,0x7C,0xA7,0xD8,0xD3
,0xA4,0x6F,0x20,0xFB,0x8C,0xF7,0x28,0xA3,0x34,0x3F,0xF0,0xCB,0x9C,0x07,0x78,0x33
,0xC4,0xCF,0xC0,0xDB,0xAC,0x57,0xC8,0x83,0x54,0x9F,0x90,0x2B,0xBC,0xE7,0x18,0x13
};
private static byte[] skey4 =
{
0x1A,0x50,0x9E,0x44,0x32,0xC8,0x96,0x1C,0x0A,0x80,0xCE,0x54,0x22,0x98,0x46,0x0C
,0x7A,0xD0,0xFE,0x44,0x12,0x48,0xF6,0x1C,0x6A,0x00,0x2E,0x14,0x02,0xD8,0xA6,0x0C
,0x5A,0x10,0x5E,0x04,0x72,0x88,0x56,0x5C,0x4A,0x40,0x8E,0x14,0x62,0x58,0x06,0x4C
,0x3A,0x90,0xBE,0x04,0x52,0x08,0xB6,0x5C,0x2A,0xC0,0xEE,0x54,0x42,0x98,0x66,0x4C
};
private byte[] key1, key2, key3, key4;
private Counter inCounter;
private Counter outCounter;
public bool IsServer { get; set; }
public uint CryptoKey { get; private set; }
public EudemonCryptographer()
{
IsServer = false;
inCounter = new Counter();
outCounter = new Counter();
key1 = Inflate(skey1, 256);
key2 = Inflate(skey2, 256);
key3 = Inflate(skey3, 256);
key4 = Inflate(skey4, 256);
}
private byte[] Inflate(byte[] key, int size)
{
if (size % key.Length != 0)
throw new ArgumentException("Cannot inflate, size modulated by the key length must be zero.");
byte[] inflation = new byte[size];
for (int i = 0; i < size; i += key.Length)
Array.Copy(key, 0, inflation, i, key.Length);
return inflation;
}
private byte Nibble(byte arg)
{
return (byte)((arg >> 4) | (arg << 4));
}
private uint ExchangeLongBits(uint nData, int nBits)
{
return (nData>>nBits) | (nData<<(32-nBits));
}
public void SetKey(uint accountId, uint cryptoId)
{
uint key = ExchangeLongBits(accountId, 7) + ExchangeLongBits(cryptoId, 0xb);
key ^= 0x6279;
key ^= cryptoId;
uint num2 = (key & 0xFFFF); // edx
uint num1 = ((key >> 16) & 0xFFFF); // eax
num1 *= num1;
num2 *= num2;
fixed (void* ptr1 = key1, ptr2 = key2, ptr3 = key3, ptr4 = key4)
{
uint* k1 = (uint*)ptr1;
uint* k2 = (uint*)ptr2;
uint* k3 = (uint*)ptr3;
uint* k4 = (uint*)ptr4;
for (int i = 0; i < 64; i++)
{
k1[i] = k1[i] ^ num2;
k2[i] = k2[i] ^ num1;
k3[i] = k1[i] ^ k2[i];
k4[i] = k1[i] & k2[i];
}
}
}
public void Decrypt(byte[] @in, int inOffset, byte[] @out, int outOffset, int length)
{
if (!IsServer) // Server->Client
{
for (int i = 0; i < length; i++)
{
byte al = @in[inOffset + i];
al = Nibble(al);
al -= skey4[inCounter.High % skey4.Length];
al ^= skey2[inCounter.High % skey2.Length];
al -= skey3[inCounter.Low % skey3.Length];
al ^= skey1[inCounter.Low % skey1.Length];
@out[outOffset + i] = al;
inCounter.Value++;
}
}
else // Client -> Server
{
for (int i = 0; i < length; i++)
{
byte al = @in[inOffset + i];
al = Nibble(al);
al -= key4[inCounter.High];
al ^= key2[inCounter.High];
al -= key3[inCounter.Low];
al ^= key1[inCounter.Low];
@out[outOffset + i] = al;
inCounter.Value++;
}
}
//fixed (byte* bf = @out)
// App.Log("Decrypt After -- \n" + Packet.CreatePacketStringWithNumbers(bf + outOffset, length));
}
public unsafe void Encrypt(byte* @in, byte[] @out, int length)
{
//App.Log("Encrypt Before -- \n" + Packet.CreatePacketStringWithNumbers(@in, length));
if (!IsServer) // Client->Server
{
for (int i = 0; i < length; i++)
{
byte al = @in[i];
al ^= key1[outCounter.Low];
al += key3[outCounter.Low];
al ^= key2[outCounter.High];
al += key4[outCounter.High];
al = Nibble(al);
@out[i] = al;
outCounter.Value++;
}
}
else // Server -> Client
{
for (int i = 0; i < length; i++)
{
byte al = @in[i];
al ^= skey1[outCounter.Low % skey1.Length];
al += skey3[outCounter.Low % skey3.Length];
al ^= skey2[outCounter.High % skey2.Length];
al += skey4[outCounter.High % skey4.Length];
al = Nibble(al);
@out[i] = al;
outCounter.Value++;
}
}
}
}
}
Code:
AccountID = msg.ReadInt32();
CryptoID = msg.ReadInt32();
int port = msg.ReadInt32();
int unknown = msg.ReadInt32();
string host = msg.ReadCString(32);
Regards,
Infamous Noone.