Client writes this:
Code:
ByteStream rsa_buffer = new ByteStream(518);
int[] isaacSeeds = new int[4];
isaacSeeds[2] = (int) (9.9999999E7 * Math.random());
isaacSeeds[1] = (int) (Math.random() * 9.9999999E7);
isaacSeeds[3] = (int) (9.9999999E7 * Math.random());
isaacSeeds[0] = (int) (9.9999999E7 * Math.random());
rsa_buffer.writeByte(10); // rsa validation byte
rsa_buffer.writeInt(isaacSeeds[0]);
rsa_buffer.writeInt(isaacSeeds[1]);
rsa_buffer.writeInt(isaacSeeds[2]);
rsa_buffer.writeInt(isaacSeeds[3]);
rsa_buffer.writeLong(0L); // for validation once again?
rsa_buffer.writeNullTerminatedString(Class_ci.password);
rsa_buffer.writeLong(SocketIncomingVector.username);
rsa_buffer.writeLong(er.client_session_key);
rsa_buffer.encryptWithRSA(jaa.PUBLIC_RSA_KEY, wi.RSA_MODULUS_KEY); // rsa encryption happens here
Class_ub.e(0);
hha var_hha = bl.e(-104);
ByteStreamUtil lobby_buffer = ((hha) var_hha).r;
if (lba.M != 2) {
//### LOBBY HEADER
lobby_buffer.writeByte(((Class_qg) ps.lobbyPacket).opcode); // opcode
lobby_buffer.writeShort((int) 0);
int pre_rsa_position = ((ByteStream) lobby_buffer).position;
lobby_buffer.writeInt(633); // revision
//### LOBBY HEADER
//### RSA PART
lobby_buffer.writeBytes(((ByteStream) rsa_buffer).buffer, ((ByteStream) rsa_buffer).position, 0); // rsa block
//### RSA PART
//## LOBBY BODY
int post_rsa_position = ((ByteStream) lobby_buffer).position;
lobby_buffer.writeNullTerminatedString(eq.H); // something CS2 / interface related
lobby_buffer.writeByte(((saa) jk.h).news_server_id); // news server id for openening shit out of the client
lobby_buffer.writeByte(lba.L); // something CS2 / interface related
Class_bd.writeUID(lobby_buffer, (byte) 105); // UID kind of data
lobby_buffer.writeNullTerminatedString(jaa.APPLET_SETTINGS); // applet settings
lobby_buffer.writeInt(wda.e); // some webhost connection related id
Class_re.writeCacheVersions(-3203, lobby_buffer); // writes the cache versions, in 633 there are 35 of them
//## LOBBY BODY
//## LOBBY BODY XTEA ENCRYPTION
lobby_buffer.encryptWithXTEA(((ByteStream) lobby_buffer).position, isaacSeeds, post_rsa_position);
//## LOBBY BODY XTEA ENCRYPTION
int buffer_length_minus_header = ((ByteStream) lobby_buffer).position - pre_rsa_position;
lobby_buffer.writeShort(buffer_length_minus_header, (byte) -87);
}
This is somewhat messy so I'll break it up in pieces of code, to conclude with the structure of the entire packet.
This is written first to the outgoing vector:
Code:
lobby_buffer.writeByte(((Class_qg) ps.lobbyPacket).opcode); // opcode
lobby_buffer.writeShort((int) 0);
int pre_rsa_position = ((ByteStream) lobby_buffer).position;
lobby_buffer.writeInt(633); // revision
After that the rsa buffer is added to the buffer:
Code:
lobby_buffer.writeBytes(((ByteStream) rsa_buffer).buffer, ((ByteStream) rsa_buffer).position, 0); // rsa block
Which was composed here:
Code:
ByteStream rsa_buffer = new ByteStream(518);
int[] isaacSeeds = new int[4];
isaacSeeds[2] = (int) (9.9999999E7 * Math.random());
isaacSeeds[1] = (int) (Math.random() * 9.9999999E7);
isaacSeeds[3] = (int) (9.9999999E7 * Math.random());
isaacSeeds[0] = (int) (9.9999999E7 * Math.random());
rsa_buffer.writeByte(10); // rsa validation byte
rsa_buffer.writeInt(isaacSeeds[0]);
rsa_buffer.writeInt(isaacSeeds[1]);
rsa_buffer.writeInt(isaacSeeds[2]);
rsa_buffer.writeInt(isaacSeeds[3]);
rsa_buffer.writeLong(0L); // for validation once again?
rsa_buffer.writeNullTerminatedString(Class_ci.password);
rsa_buffer.writeLong(SocketIncomingVector.username);
rsa_buffer.writeLong(er.client_session_key);
rsa_buffer.encryptWithRSA(jaa.PUBLIC_RSA_KEY, wi.RSA_MODULUS_KEY); // rsa encryption happens here
Just to show you the cleaned rsa method:
Code:
final void encryptWithRSA(BigInteger public_key, BigInteger modulus) {
int unencrypted_length = ((ByteStream) this).position;
((ByteStream) this).position = 0;
byte[] rsa_data = new byte[unencrypted_length];
readBytes(rsa_data, 4, unencrypted_length, 0);
BigInteger unencrypted_data = new BigInteger(rsa_data);
BigInteger encrypted_data = unencrypted_data.modPow(public_key, modulus);
byte[] encrypted_buffer = encrypted_data.toByteArray();
((ByteStream) this).position = 0;
writeShort(encrypted_buffer.length);
writeBytes(encrypted_buffer, encrypted_buffer.length, 0);
}
After that we get this part:
Code:
int post_rsa_position = ((ByteStream) lobby_buffer).position;
lobby_buffer.writeNullTerminatedString(eq.H); // something CS2 / interface related
lobby_buffer.writeByte(((saa) jk.h).news_server_id); // news server id for openening shit out of the client
lobby_buffer.writeByte(lba.L); // something CS2 / interface related
Class_bd.writeUID(lobby_buffer, (byte) 105); // UID kind of data
lobby_buffer.writeNullTerminatedString(jaa.APPLET_SETTINGS); // applet settings
lobby_buffer.writeInt(wda.e); // some webhost connection related id
Class_re.writeCacheVersions(-3203, lobby_buffer); // writes the cache versions, in 633 there are 35 of them
lobby_buffer.encryptWithXTEA(((ByteStream) lobby_buffer).position, isaacSeeds, post_rsa_position);
int buffer_length_minus_header = ((ByteStream) lobby_buffer).position - pre_rsa_position;
lobby_buffer.writeShort(buffer_length_minus_header, (byte) -87);
The isaac seeds are also used for the encryption of the lobby block with xtea here:
Code:
final void encryptWithXTEA(int lobby_end_offset, int[] xtea_key, int lobby_start_offset) {
int lobby_buffer_length = ((ByteStream) this).position;
int post_rsa_length = lobby_start_offset;
((ByteStream) this).position = post_rsa_length;
int num_rounds = (lobby_end_offset - post_rsa_length) / 8;
for (int i_11_ = 0; num_rounds > i_11_; i_11_++) {
int value1 = readInt();
int value2 = readInt();
int sum = 0;
int delta = -1640531527;
int cycles = 32;
while (0 < cycles--) {
value1 += (xtea_key[sum & 0x3] + sum ^ (value2 << 4 ^ value2 >>> 5) + value2);
sum += delta;
value2 += (sum + xtea_key[~0x89ffffc & sum >>> 11] ^ value1 + (value1 >>> 5 ^ value1 << 4));
}
((ByteStream) this).position -= 8;
writeInt(value1);
writeInt(value2);
}
((ByteStream) this).position = lobby_buffer_length;
}
To conlude the structure of all this, this is what the client is reading:
Code:
byte lobby_opcode = 17;
short isaac_validation_number = 0;
int revision;
byte rsa_validation_number = 10;
int[4] isaac_seeds; // used for decryption of the lobby data too
long rsa_validation_number_2 = 0; // actually I'm not sure what this is for, could be used as an extra backup for validation?
string password;
long username;
long client_session_key;
string eq.H; // probably something related to CS2 / interfaces
byte new_server_id; // the id of the news server used, what could be done with this?
byte[24] uid; // this is some kind of user identification
int wda.e; // contains the id for some
int[35] cache_file_versions; // the cache versions of each cache file
short buffer_length_minus_header;
Although this is the structure of this packet, you'll need to know how to decrypt the xtea encrypted part:
Code:
final void decryptXTEA(int start_offset, int[] xtea_key, int length) {
((ByteStream) this).position = start_offset;
int num_rounds = (length - 1) / 8;
for (int i_62_ = 0; num_rounds > i_62_; i_62_++) {
int value1 = readInt();
int value2 = readInt();
int sum = -957401312;
int delta = -1640531527;
int cycles = 32;
while (0 < cycles--) {
value2 -= (xtea_key[sum >>> 11 & ~0x4d9ffffc] + sum ^ value1 + (value1 >>> 5 ^ value1 << 4));
sum -= delta;
value1 -= (value2 + (value2 << 4 ^ value2 >>> 5) ^ xtea_key[sum & 0x3] + sum);
}
((ByteStream) this).position -= 8;
writeInt(value1);
writeInt(value2);
}
}