forked from seishun/SteamPP
-
Notifications
You must be signed in to change notification settings - Fork 0
/
cmclient.cpp
86 lines (73 loc) · 2.97 KB
/
cmclient.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#include <cryptopp/modes.h>
#include "cmclient.h"
const char* MAGIC = "VT01";
std::uint32_t PROTO_MASK = 0x80000000;
SteamClient::CMClient::CMClient(std::function<void(std::size_t, std::function<void(unsigned char*)>)> write) : write(std::move(write)) {
steamID.instance = 1;
steamID.universe = static_cast<unsigned>(EUniverse::Public);
steamID.type = static_cast<unsigned>(EAccountType::Individual);
}
void SteamClient::CMClient::WriteMessage(EMsg emsg, std::size_t length, const std::function<void(unsigned char*)> &fill) {
if (emsg == EMsg::ChannelEncryptResponse) {
WritePacket(sizeof(MsgHdr) + length, [emsg, &fill](unsigned char* buffer) {
auto header = new (buffer) MsgHdr;
header->msg = static_cast<std::uint32_t>(emsg);
fill(buffer + sizeof(MsgHdr));
});
} else {
WritePacket(sizeof(ExtendedClientMsgHdr) + length, [this, emsg, &fill](unsigned char* buffer) {
auto header = new (buffer) ExtendedClientMsgHdr;
header->msg = static_cast<std::uint32_t>(emsg);
header->sessionID = sessionID;
header->steamID = steamID;
fill(buffer + sizeof(ExtendedClientMsgHdr));
});
}
}
void SteamClient::CMClient::WriteMessage(EMsg emsg, const google::protobuf::Message &message, std::uint64_t job_id) {
CMsgProtoBufHeader proto;
proto.set_steamid(steamID);
proto.set_client_sessionid(sessionID);
if (job_id) {
proto.set_jobid_target(job_id);
}
auto proto_size = proto.ByteSize();
auto message_size = message.ByteSize();
WritePacket(sizeof(MsgHdrProtoBuf) + proto_size + message_size, [emsg, &proto, proto_size, &message, message_size](unsigned char* buffer) {
auto header = new (buffer) MsgHdrProtoBuf;
header->headerLength = proto_size;
header->msg = static_cast<std::uint32_t>(emsg) | PROTO_MASK;
proto.SerializeToArray(header->proto, proto_size);
message.SerializeToArray(header->proto + proto_size, message_size);
});
}
void SteamClient::CMClient::WritePacket(const std::size_t length, const std::function<void(unsigned char* buffer)> &fill) {
if (encrypted) {
auto crypted_size = 16 + (length / 16 + 1) * 16; // IV + crypted message padded to multiple of 16
write(8 + crypted_size, [&](unsigned char* out_buffer) {
auto in_buffer = new unsigned char[length];
fill(in_buffer);
byte iv[16];
rnd.GenerateBlock(iv, 16);
auto crypted_iv = out_buffer + 8;
ECB_Mode<AES>::Encryption(sessionKey, sizeof(sessionKey)).ProcessData(crypted_iv, iv, sizeof(iv));
auto crypted_data = crypted_iv + 16;
CBC_Mode<AES>::Encryption e(sessionKey, sizeof(sessionKey), iv);
ArraySource(
in_buffer,
length,
true,
new StreamTransformationFilter(e, new ArraySink(crypted_data, crypted_size - 16))
);
*reinterpret_cast<std::uint32_t*>(out_buffer) = crypted_size;
std::copy(MAGIC, MAGIC + 4, out_buffer + 4);
delete[] in_buffer;
});
} else {
write(8 + length, [&](unsigned char* buffer) {
*reinterpret_cast<std::uint32_t*>(buffer) = length;
std::copy(MAGIC, MAGIC + 4, buffer + 4);
fill(buffer + 8);
});
}
}