TrinityCore
AuthenticationPackets.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
19#include "BigNumber.h"
21#include "Ed25519.h"
22#include "HMAC.h"
23#include "ObjectMgr.h"
24#include "RSA.h"
25
27{
28 data.WriteBit(virtualRealmInfo.IsLocal);
29 data.WriteBit(virtualRealmInfo.IsInternalRealm);
30 data.WriteBits(virtualRealmInfo.RealmNameActual.length(), 8);
31 data.WriteBits(virtualRealmInfo.RealmNameNormalized.length(), 8);
32 data.FlushBits();
33
34 data.WriteString(virtualRealmInfo.RealmNameActual);
35 data.WriteString(virtualRealmInfo.RealmNameNormalized);
36
37 return data;
38}
39
41{
42 data << uint32(virtualRealmInfo.RealmAddress);
43 data << virtualRealmInfo.RealmNameInfo;
44
45 return data;
46}
47
49{
50 try
51 {
52 Read();
53 return true;
54 }
55 catch (ByteBufferException const& /*ex*/)
56 {
57 }
58
59 return false;
60}
61
63{
64 _worldPacket >> Serial;
65 _worldPacket >> Latency;
66}
67
69{
70 _worldPacket << uint32(Serial);
71 return &_worldPacket;
72}
73
75{
76 _worldPacket.append(DosChallenge.data(), DosChallenge.size());
77 _worldPacket.append(Challenge.data(), Challenge.size());
78 _worldPacket << uint8(DosZeroBits);
79 return &_worldPacket;
80}
81
83{
84 uint32 realmJoinTicketSize;
85
86 _worldPacket >> DosResponse;
87 _worldPacket >> RegionID;
88 _worldPacket >> BattlegroupID;
89 _worldPacket >> RealmID;
90 _worldPacket.read(LocalChallenge.data(), LocalChallenge.size());
91 _worldPacket.read(Digest.data(), Digest.size());
92 UseIPv6 = _worldPacket.ReadBit();
93 _worldPacket >> realmJoinTicketSize;
94 if (realmJoinTicketSize)
95 {
96 RealmJoinTicket.resize(std::min(realmJoinTicketSize, uint32(_worldPacket.size() - _worldPacket.rpos())));
97 _worldPacket.read(reinterpret_cast<uint8*>(&RealmJoinTicket[0]), RealmJoinTicket.size());
98 }
99}
100
102{
103 data << uint32(waitInfo.WaitCount);
104 data << uint32(waitInfo.WaitTime);
106 data.WriteBit(waitInfo.HasFCM);
107 data.WriteBit(waitInfo.CanCreateOnlyIfExisting);
108 data.FlushBits();
109
110 return data;
111}
112
114{
115 _worldPacket << uint32(Result);
116 _worldPacket.WriteBit(SuccessInfo.has_value());
117 _worldPacket.WriteBit(WaitInfo.has_value());
118 _worldPacket.FlushBits();
119
120 if (SuccessInfo)
121 {
122 _worldPacket << uint32(SuccessInfo->VirtualRealmAddress);
123 _worldPacket << uint32(SuccessInfo->VirtualRealms.size());
124 _worldPacket << uint32(SuccessInfo->TimeRested);
125 _worldPacket << uint8(SuccessInfo->ActiveExpansionLevel);
126 _worldPacket << uint8(SuccessInfo->AccountExpansionLevel);
127 _worldPacket << uint32(SuccessInfo->TimeSecondsUntilPCKick);
128 _worldPacket << uint32(SuccessInfo->AvailableClasses->size());
129 _worldPacket << uint32(SuccessInfo->Templates.size());
130 _worldPacket << uint32(SuccessInfo->CurrencyID);
131 _worldPacket << SuccessInfo->Time;
132
133 for (RaceClassAvailability const& raceClassAvailability : *SuccessInfo->AvailableClasses)
134 {
135 _worldPacket << uint8(raceClassAvailability.RaceID);
136 _worldPacket << uint32(raceClassAvailability.Classes.size());
137
138 for (ClassAvailability const& classAvailability : raceClassAvailability.Classes)
139 {
140 _worldPacket << uint8(classAvailability.ClassID);
141 _worldPacket << uint8(classAvailability.ActiveExpansionLevel);
142 _worldPacket << uint8(classAvailability.AccountExpansionLevel);
143 _worldPacket << uint8(classAvailability.MinActiveExpansionLevel);
144 }
145 }
146
147 _worldPacket.WriteBit(SuccessInfo->IsExpansionTrial);
148 _worldPacket.WriteBit(SuccessInfo->ForceCharacterTemplate);
149 _worldPacket.WriteBit(SuccessInfo->NumPlayersHorde.has_value());
150 _worldPacket.WriteBit(SuccessInfo->NumPlayersAlliance.has_value());
151 _worldPacket.WriteBit(SuccessInfo->ExpansionTrialExpiration.has_value());
152 _worldPacket.WriteBit(SuccessInfo->NewBuildKeys.has_value());
153 _worldPacket.FlushBits();
154
155 {
156 _worldPacket << uint32(SuccessInfo->GameTimeInfo.BillingPlan);
157 _worldPacket << uint32(SuccessInfo->GameTimeInfo.TimeRemain);
158 _worldPacket << uint32(SuccessInfo->GameTimeInfo.Unknown735);
159 // 3x same bit is not a mistake - preserves legacy client behavior of BillingPlanFlags::SESSION_IGR
160 _worldPacket.WriteBit(SuccessInfo->GameTimeInfo.InGameRoom); // inGameRoom check in function checking which lua event to fire when remaining time is near end - BILLING_NAG_DIALOG vs IGR_BILLING_NAG_DIALOG
161 _worldPacket.WriteBit(SuccessInfo->GameTimeInfo.InGameRoom); // inGameRoom lua return from Script_GetBillingPlan
162 _worldPacket.WriteBit(SuccessInfo->GameTimeInfo.InGameRoom); // not used anywhere in the client
163 _worldPacket.FlushBits();
164 }
165
166 if (SuccessInfo->NumPlayersHorde)
167 _worldPacket << uint16(*SuccessInfo->NumPlayersHorde);
168
169 if (SuccessInfo->NumPlayersAlliance)
170 _worldPacket << uint16(*SuccessInfo->NumPlayersAlliance);
171
172 if (SuccessInfo->ExpansionTrialExpiration)
173 _worldPacket << *SuccessInfo->ExpansionTrialExpiration;
174
175 if (SuccessInfo->NewBuildKeys)
176 {
177 for (std::size_t i = 0; i < 16; ++i)
178 {
179 _worldPacket << SuccessInfo->NewBuildKeys->NewBuildKey[i];
180 _worldPacket << SuccessInfo->NewBuildKeys->SomeKey[i];
181 }
182 }
183
184 for (VirtualRealmInfo const& virtualRealm : SuccessInfo->VirtualRealms)
185 _worldPacket << virtualRealm;
186
187 for (CharacterTemplate const* characterTemplate : SuccessInfo->Templates)
188 {
189 _worldPacket << uint32(characterTemplate->TemplateSetId);
190 _worldPacket << uint32(characterTemplate->Classes.size());
191 for (CharacterTemplateClass const& templateClass : characterTemplate->Classes)
192 {
193 _worldPacket << uint8(templateClass.ClassID);
194 _worldPacket << uint8(templateClass.FactionGroup);
195 }
196
197 _worldPacket.WriteBits(characterTemplate->Name.length(), 7);
198 _worldPacket.WriteBits(characterTemplate->Description.length(), 10);
199 _worldPacket.FlushBits();
200
201 _worldPacket.WriteString(characterTemplate->Name);
202 _worldPacket.WriteString(characterTemplate->Description);
203 }
204 }
205
206 if (WaitInfo)
207 _worldPacket << *WaitInfo;
208
209 return &_worldPacket;
210}
211
213{
214 _worldPacket << WaitInfo;
215
216 return &_worldPacket;
217}
218
219namespace
220{
221std::string const RSAPrivateKey = R"(-----BEGIN RSA PRIVATE KEY-----
222MIIEpAIBAAKCAQEA7rPc1NPDtFRRzmZbyzK48PeSU8YZ8gyFL4omqXpFn2DE683q
223f41Z2FeyYHsJTJtouMft7x6ADeZrN1tTkOsYEw1/Q2SD2pjmrMIwooKlxsvH+4af
224n6kCagNJxTj7wMhVzMDOJZG+hc/R0TfOzIPS6jCAB3uAn51EVCIpvoba20jFqfkT
225NpUjdvEO3IQNlAISqJfzOxTuqm+YBSdOH6Ngpana2BffM8viE1SLGLDKubuIZAbf
226dabXYQC7sFoOetR3CE0V4hCDsASqnot3qQaJXQhdD7gua8HLZM9uXNtPWGUIUfsN
227SBpvtj0fC93+Gx3wv7Ana/WOvMdAAf+nC4DWXwIDAQABAoIBACKa5q/gB2Y0Nyvi
228APrDXrZoXclRVd+WWxSaRaKaPE+vuryovI9DUbwgcpa0H5QAj70CFwdsd4oMVozO
2296519x56zfTiq8MaXFhIDkQNuR1Q7pMFdMfT2jogJ8/7olO7M3EtzxC8EIwfJKhTX
230r15M2h3jbBwplmsNZKOB1GVvrXjOm1KtOZ4CTTM0WrPaLVDT9ax8pykjmFw16vGP
231j/R5Dky9VpabtfZOu/AEW259XDEiQgTrB4Eg+S4GJjHqAzPZBmMy/xhlDK4oMXef
232qXScfD4w0RxuuCFr6lxLPZz0S35BK1kIWmIkuv+9eQuI4Hr1CyVwch4fkfvrp84x
2338tvAFnkCgYEA87NZaG9a8/Mob6GgY4BVLHJVOSzzFdNyMA+4LfSbtzgON2RSZyeD
2340JpDowwXssw5XOyUUctj2cLLdlMCpDfdzk4F/PEakloDJWpason3lmur0/5Oq3T9
2353+fnNUl4d3UOs1jcJ1yGQ/BfrTyRTcEoZx8Mu9mJ4ituVkKuLeG5vX0CgYEA+r/w
236QBJS6kDyQPj1k/SMClUhWhyADwDod03hHTQHc9BleJyjXmVy+/pWhN7aELhjgLbf
237o/Gm3aKJjCxS4qBmqUKwAvGoSVux1Bo2ZjcfF7sX9BXBOlFTG+bPVCZUoaksTyXN
238g7GsA1frKkWWkgQuOeK3o/p9IZoBl93vEgcTGgsCgYEAv5ucCIjFMllUybCCsrkM
239Ps4GQ9YbqmV9ulwhq8BPTlc8lkDCqWhgM3uXAnNXjrUTxQQd+dG4yFZoMrhBs2xZ
240cQPXoXDQO5GaN6jPduETUamGiD/DCvwJQCrNlxAVL5dR36FWN3x/9JriHwsoE8Jz
241SeEX2frIdpM/RYNX/6sipuECgYEA+rwFRDxOdvm8hGWuQ2WMxyQ7Nn07PEV/LxVM
242HkSRkyh23vVakyDEqty3uSOSUJfgv6ud07TnU8ac3fLQatdT8LrDgB4fVkN/fYU8
243kldaGwO1vxgl4OfDQCo7dXzisciViwtVBvQZ+jnm6J0vJBFUHAPt9+WZTIlQQIjm
24471LtseMCgYBSAhs6lshtz+ujR3fmc4QqJVGqeXvEBPAVm6yYoKYRLwVs/rFv3WLN
245LOwwBQ6lz7P9RqYYB5wVlaRvEhb9+lCve/xVcxMeZ5GkOBPxVygYV9l/wNdE25Nz
246OHYtKG3GK3GEcFDwZU2LPHq21EroUAdtRfbrJ4KW2yc8igtXKxTBYw==
247-----END RSA PRIVATE KEY-----
248)";
249
250std::array<uint8, 32> constexpr EnterEncryptedModePrivateKey =
251{
252 0x08, 0xBD, 0xC7, 0xA3, 0xCC, 0xC3, 0x4F, 0x3F,
253 0x6A, 0x0B, 0xFF, 0xCF, 0x31, 0xC1, 0xB6, 0x97,
254 0x69, 0x1E, 0x72, 0x9A, 0x0A, 0xAB, 0x2C, 0x77,
255 0xC3, 0x6F, 0x8A, 0xE7, 0x5A, 0x9A, 0xA7, 0xC9
256};
257
258std::unique_ptr<Trinity::Crypto::RsaSignature> ConnectToRSA;
259std::unique_ptr<Trinity::Crypto::Ed25519> EnterEncryptedModeSigner;
260}
261
263{
264 std::unique_ptr<Trinity::Crypto::RsaSignature> rsa = std::make_unique<Trinity::Crypto::RsaSignature>();
265 if (!rsa->LoadKeyFromString(RSAPrivateKey))
266 return false;
267
268 ConnectToRSA = std::move(rsa);
269 return true;
270}
271
273{
274 ConnectToRSA.reset();
275}
276
278{
279}
280
282{
283 ByteBuffer whereBuffer;
284 whereBuffer << uint8(Payload.Where.Type);
285 switch (Payload.Where.Type)
286 {
287 case IPv4:
288 whereBuffer.append(Payload.Where.Address.V4.data(), Payload.Where.Address.V4.size());
289 break;
290 case IPv6:
291 whereBuffer.append(Payload.Where.Address.V6.data(), Payload.Where.Address.V6.size());
292 break;
293 case NamedSocket:
294 whereBuffer << Payload.Where.Address.Name.data();
295 break;
296 default:
297 break;
298 }
299
300 ByteBuffer signBuffer;
301 signBuffer.append(whereBuffer);
302 signBuffer << uint32(Payload.Where.Type);
303 signBuffer << uint16(Payload.Port);
304
305 Trinity::Crypto::RsaSignature rsa(*ConnectToRSA);
307 std::vector<uint8> signature;
308 rsa.Sign(signBuffer.contents(), signBuffer.size(), digestGenerator, signature);
309
310 _worldPacket.append(signature.data(), signature.size());
311 _worldPacket.append(whereBuffer);
312 _worldPacket << uint16(Payload.Port);
313 _worldPacket << uint32(Serial);
314 _worldPacket << uint8(Con);
315 _worldPacket << uint64(Key);
316
317 return &_worldPacket;
318}
319
321{
322 _worldPacket >> DosResponse;
323 _worldPacket >> Key;
324 _worldPacket.read(LocalChallenge.data(), LocalChallenge.size());
325 _worldPacket.read(Digest.data(), Digest.size());
326}
327
329{
330 Serial = _worldPacket.read<ConnectToSerial>();
331 _worldPacket >> Con;
332}
333
335{
336 std::unique_ptr<Trinity::Crypto::Ed25519> ed25519 = std::make_unique<Trinity::Crypto::Ed25519>();
337 if (!ed25519->LoadFromByteArray(EnterEncryptedModePrivateKey))
338 return false;
339
340 EnterEncryptedModeSigner = std::move(ed25519);
341 return true;
342}
343
345{
346 EnterEncryptedModeSigner.reset();
347}
348
349std::array<uint8, 16> constexpr EnableEncryptionSeed = { 0x90, 0x9C, 0xD0, 0x50, 0x5A, 0x2C, 0x14, 0xDD, 0x5C, 0x2C, 0xC0, 0x64, 0x14, 0xF3, 0xFE, 0xC9 };
350std::array<uint8, 16> constexpr EnableEncryptionContext = { 0xA7, 0x1F, 0xB6, 0x9B, 0xC9, 0x7C, 0xDD, 0x96, 0xE9, 0xBB, 0xB8, 0x21, 0x39, 0x8D, 0x5A, 0xD4 };
351
353{
354 std::array<uint8, 32> toSign = Trinity::Crypto::HMAC_SHA256::GetDigestOf(EncryptionKey,
355 std::array<uint8, 1>{uint8(Enabled ? 1 : 0)},
357
358 Trinity::Crypto::Ed25519 ed25519(*EnterEncryptedModeSigner);
359 std::vector<uint8> signature;
360
361 ed25519.SignWithContext(toSign, { EnableEncryptionContext.begin(), EnableEncryptionContext.end() }, signature);
362
363 _worldPacket.append(signature.data(), signature.size());
364 _worldPacket.WriteBit(Enabled);
365 _worldPacket.FlushBits();
366
367 return &_worldPacket;
368}
ByteBuffer & operator<<(ByteBuffer &data, WorldPackets::Auth::VirtualRealmNameInfo const &virtualRealmInfo)
std::array< uint8, 16 > constexpr EnableEncryptionSeed
std::array< uint8, 16 > constexpr EnableEncryptionContext
uint8_t uint8
Definition: Define.h:144
uint64_t uint64
Definition: Define.h:141
uint16_t uint16
Definition: Define.h:143
uint32_t uint32
Definition: Define.h:142
void WriteString(std::string const &str)
Definition: ByteBuffer.h:500
void append(T value)
Definition: ByteBuffer.h:143
bool WriteBit(bool bit)
Definition: ByteBuffer.h:175
void WriteBits(std::size_t value, int32 bits)
Definition: ByteBuffer.h:203
size_t size() const
Definition: ByteBuffer.h:536
void FlushBits()
Definition: ByteBuffer.h:155
uint8 * contents()
Definition: ByteBuffer.h:522
bool Sign(std::array< uint8, N > const &message, DigestGenerator &generator, std::vector< uint8 > &output)
Definition: RSA.h:99
static Digest GetDigestOf(Container const &seed, uint8 const *data, size_t len)
Definition: HMAC.h:41
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
virtual void Read()=0
@ SMSG_CONNECT_TO
Definition: Opcodes.h:1153
ByteBuffer & operator<<(ByteBuffer &data, Movement::MonsterSplineFilterKey const &monsterSplineFilterKey)
std::vector< CharacterTemplateClass > Classes
uint8 MinActiveExpansionLevel
Definition: ObjectMgr.h:1025
uint8 AccountExpansionLevel
Definition: ObjectMgr.h:1024
uint8 ActiveExpansionLevel
Definition: ObjectMgr.h:1023
std::vector< ClassAvailability > Classes
Definition: ObjectMgr.h:1031
bool HasFCM
true if the account has a forced character migration pending.
bool CanCreateOnlyIfExisting
Can create characters on realm only if player has other existing characters there.
uint32 WaitCount
position of the account in the login queue
uint32 WaitTime
Wait time in login queue in minutes, if sent queued and this value is 0 client displays "unknown time...
uint32 RealmAddress
the virtual address of this realm, constructed as RealmHandle::Region << 24 | RealmHandle::Battlegrou...
std::string RealmNameActual
the name of the realm
std::string RealmNameNormalized
the name of the realm without spaces
bool IsLocal
true if the realm is the same as the account's home realm