TrinityCore
Loading...
Searching...
No Matches
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 "PacketOperators.h"
25#include "RSA.h"
26
28{
29ByteBuffer& operator<<(ByteBuffer& data, VirtualRealmNameInfo const& virtualRealmInfo)
30{
31 data << WorldPackets::Bits<1>(virtualRealmInfo.IsLocal);
32 data << WorldPackets::Bits<1>(virtualRealmInfo.IsInternalRealm);
33 data << WorldPackets::SizedString::BitsSize<8>(virtualRealmInfo.RealmNameActual);
34 data << WorldPackets::SizedString::BitsSize<8>(virtualRealmInfo.RealmNameNormalized);
35 data.FlushBits();
36
37 data << SizedString::Data(virtualRealmInfo.RealmNameActual);
38 data << SizedString::Data(virtualRealmInfo.RealmNameNormalized);
39
40 return data;
41}
42
43ByteBuffer& operator<<(ByteBuffer& data, VirtualRealmInfo const& virtualRealmInfo)
44{
45 data << uint32(virtualRealmInfo.RealmAddress);
46 data << virtualRealmInfo.RealmNameInfo;
47
48 return data;
49}
50
52{
55}
56
58{
60 return &_worldPacket;
61}
62
67
75
77{
78 uint32 realmJoinTicketSize;
79
85 _worldPacket.read(Digest.data(), Digest.size());
86 _worldPacket >> Bits<1>(UseIPv6);
87 _worldPacket >> realmJoinTicketSize;
88 if (realmJoinTicketSize)
89 {
90 RealmJoinTicket.resize(std::min(realmJoinTicketSize, uint32(_worldPacket.size() - _worldPacket.rpos())));
92 }
93}
94
95ByteBuffer& operator<<(ByteBuffer& data, GameTime const& gameTime)
96{
97 data << uint32(gameTime.BillingType);
98 data << uint32(gameTime.MinutesRemaining);
99 data << uint32(gameTime.RealBillingType);
100 data << Bits<1>(gameTime.IsInIGR);
101 data << Bits<1>(gameTime.IsPaidForByIGR);
102 data << Bits<1>(gameTime.IsCAISEnabled);
103 data.FlushBits();
104
105 return data;
106}
107
109{
110 for (std::size_t i = 0; i < 16; ++i)
111 {
112 data << buildKey.BuildKey[i];
113 data << buildKey.ConfigKey[i];
114 }
115
116 return data;
117}
118
120{
121 data << uint32(successInfo.VirtualRealmAddress);
122 data << Size<uint32>(successInfo.VirtualRealms);
123 data << uint32(successInfo.TimeRested);
124 data << uint8(successInfo.ActiveExpansionLevel);
125 data << uint8(successInfo.AccountExpansionLevel);
126 data << uint32(successInfo.TimeSecondsUntilPCKick);
127 data << Size<uint32>(*successInfo.AvailableClasses);
128 data << Size<uint32>(successInfo.Templates);
129 data << uint32(successInfo.CurrencyID);
130 data << successInfo.Time;
131
132 for (RaceClassAvailability const& raceClassAvailability : *successInfo.AvailableClasses)
133 {
134 data << uint8(raceClassAvailability.RaceID);
135 data << Size<uint32>(raceClassAvailability.Classes);
136
137 for (ClassAvailability const& classAvailability : raceClassAvailability.Classes)
138 {
139 data << uint8(classAvailability.ClassID);
140 data << uint8(classAvailability.ActiveExpansionLevel);
141 data << uint8(classAvailability.AccountExpansionLevel);
142 data << uint8(classAvailability.MinActiveExpansionLevel);
143 }
144 }
145
146 data << Bits<1>(successInfo.IsExpansionTrial);
147 data << Bits<1>(successInfo.ForceCharacterTemplate);
148 data << OptionalInit(successInfo.NumPlayersHorde);
149 data << OptionalInit(successInfo.NumPlayersAlliance);
150 data << OptionalInit(successInfo.ExpansionTrialExpiration);
151 data << OptionalInit(successInfo.CurrentBuild);
152 data.FlushBits();
153
154 data << successInfo.GameTimeInfo;
155
156 if (successInfo.NumPlayersHorde)
157 data << uint16(*successInfo.NumPlayersHorde);
158
159 if (successInfo.NumPlayersAlliance)
160 data << uint16(*successInfo.NumPlayersAlliance);
161
162 if (successInfo.ExpansionTrialExpiration)
163 data << *successInfo.ExpansionTrialExpiration;
164
165 if (successInfo.CurrentBuild)
166 data << *successInfo.CurrentBuild;
167
168 for (VirtualRealmInfo const& virtualRealm : successInfo.VirtualRealms)
169 data << virtualRealm;
170
171 for (CharacterTemplate const* characterTemplate : successInfo.Templates)
172 {
173 data << uint32(characterTemplate->TemplateSetId);
174 data << Size<uint32>(characterTemplate->Classes);
175 for (CharacterTemplateClass const& templateClass : characterTemplate->Classes)
176 {
177 data << uint8(templateClass.ClassID);
178 data << uint8(templateClass.FactionGroup);
179 }
180
181 data << SizedString::BitsSize<7>(characterTemplate->Name);
182 data << SizedString::BitsSize<10>(characterTemplate->Description);
183 data.FlushBits();
184
185 data << SizedString::Data(characterTemplate->Name);
186 data << SizedString::Data(characterTemplate->Description);
187 }
188
189 return data;
190}
191
193{
194 data << uint32(waitInfo.WaitCount);
195 data << uint32(waitInfo.WaitTime);
197 data << WorldPackets::Bits<1>(waitInfo.HasFCM);
198 data << WorldPackets::Bits<1>(waitInfo.CanCreateOnlyIfExisting);
199 data.FlushBits();
200
201 return data;
202}
203
219
221{
223
224 return &_worldPacket;
225}
226
227namespace
228{
229std::string const RSAPrivateKey = R"(-----BEGIN RSA PRIVATE KEY-----
230MIIEpAIBAAKCAQEA7rPc1NPDtFRRzmZbyzK48PeSU8YZ8gyFL4omqXpFn2DE683q
231f41Z2FeyYHsJTJtouMft7x6ADeZrN1tTkOsYEw1/Q2SD2pjmrMIwooKlxsvH+4af
232n6kCagNJxTj7wMhVzMDOJZG+hc/R0TfOzIPS6jCAB3uAn51EVCIpvoba20jFqfkT
233NpUjdvEO3IQNlAISqJfzOxTuqm+YBSdOH6Ngpana2BffM8viE1SLGLDKubuIZAbf
234dabXYQC7sFoOetR3CE0V4hCDsASqnot3qQaJXQhdD7gua8HLZM9uXNtPWGUIUfsN
235SBpvtj0fC93+Gx3wv7Ana/WOvMdAAf+nC4DWXwIDAQABAoIBACKa5q/gB2Y0Nyvi
236APrDXrZoXclRVd+WWxSaRaKaPE+vuryovI9DUbwgcpa0H5QAj70CFwdsd4oMVozO
2376519x56zfTiq8MaXFhIDkQNuR1Q7pMFdMfT2jogJ8/7olO7M3EtzxC8EIwfJKhTX
238r15M2h3jbBwplmsNZKOB1GVvrXjOm1KtOZ4CTTM0WrPaLVDT9ax8pykjmFw16vGP
239j/R5Dky9VpabtfZOu/AEW259XDEiQgTrB4Eg+S4GJjHqAzPZBmMy/xhlDK4oMXef
240qXScfD4w0RxuuCFr6lxLPZz0S35BK1kIWmIkuv+9eQuI4Hr1CyVwch4fkfvrp84x
2418tvAFnkCgYEA87NZaG9a8/Mob6GgY4BVLHJVOSzzFdNyMA+4LfSbtzgON2RSZyeD
2420JpDowwXssw5XOyUUctj2cLLdlMCpDfdzk4F/PEakloDJWpason3lmur0/5Oq3T9
2433+fnNUl4d3UOs1jcJ1yGQ/BfrTyRTcEoZx8Mu9mJ4ituVkKuLeG5vX0CgYEA+r/w
244QBJS6kDyQPj1k/SMClUhWhyADwDod03hHTQHc9BleJyjXmVy+/pWhN7aELhjgLbf
245o/Gm3aKJjCxS4qBmqUKwAvGoSVux1Bo2ZjcfF7sX9BXBOlFTG+bPVCZUoaksTyXN
246g7GsA1frKkWWkgQuOeK3o/p9IZoBl93vEgcTGgsCgYEAv5ucCIjFMllUybCCsrkM
247Ps4GQ9YbqmV9ulwhq8BPTlc8lkDCqWhgM3uXAnNXjrUTxQQd+dG4yFZoMrhBs2xZ
248cQPXoXDQO5GaN6jPduETUamGiD/DCvwJQCrNlxAVL5dR36FWN3x/9JriHwsoE8Jz
249SeEX2frIdpM/RYNX/6sipuECgYEA+rwFRDxOdvm8hGWuQ2WMxyQ7Nn07PEV/LxVM
250HkSRkyh23vVakyDEqty3uSOSUJfgv6ud07TnU8ac3fLQatdT8LrDgB4fVkN/fYU8
251kldaGwO1vxgl4OfDQCo7dXzisciViwtVBvQZ+jnm6J0vJBFUHAPt9+WZTIlQQIjm
25271LtseMCgYBSAhs6lshtz+ujR3fmc4QqJVGqeXvEBPAVm6yYoKYRLwVs/rFv3WLN
253LOwwBQ6lz7P9RqYYB5wVlaRvEhb9+lCve/xVcxMeZ5GkOBPxVygYV9l/wNdE25Nz
254OHYtKG3GK3GEcFDwZU2LPHq21EroUAdtRfbrJ4KW2yc8igtXKxTBYw==
255-----END RSA PRIVATE KEY-----
256)";
257
258std::array<uint8, 32> constexpr EnterEncryptedModePrivateKey =
259{
260 0x08, 0xBD, 0xC7, 0xA3, 0xCC, 0xC3, 0x4F, 0x3F,
261 0x6A, 0x0B, 0xFF, 0xCF, 0x31, 0xC1, 0xB6, 0x97,
262 0x69, 0x1E, 0x72, 0x9A, 0x0A, 0xAB, 0x2C, 0x77,
263 0xC3, 0x6F, 0x8A, 0xE7, 0x5A, 0x9A, 0xA7, 0xC9
264};
265
266std::unique_ptr<Trinity::Crypto::RsaSignature> ConnectToRSA;
267std::unique_ptr<Trinity::Crypto::Ed25519> EnterEncryptedModeSigner;
268}
269
271{
272 std::unique_ptr<Trinity::Crypto::RsaSignature> rsa = std::make_unique<Trinity::Crypto::RsaSignature>();
273 if (!rsa->LoadKeyFromString(RSAPrivateKey))
274 return false;
275
276 ConnectToRSA = std::move(rsa);
277 return true;
278}
279
281{
282 ConnectToRSA.reset();
283}
284
286{
287 ByteBuffer whereBuffer;
288 whereBuffer << uint8(Payload.Where.Type);
289 switch (Payload.Where.Type)
290 {
291 case IPv4:
292 whereBuffer.append(Payload.Where.Address.V4.data(), Payload.Where.Address.V4.size());
293 break;
294 case IPv6:
295 whereBuffer.append(Payload.Where.Address.V6.data(), Payload.Where.Address.V6.size());
296 break;
297 case NamedSocket:
298 whereBuffer << Payload.Where.Address.Name.data();
299 break;
300 default:
301 break;
302 }
303
304 ByteBuffer signBuffer;
305 signBuffer.append(whereBuffer);
306 signBuffer << uint32(Payload.Where.Type);
307 signBuffer << uint16(Payload.Port);
308
309 Trinity::Crypto::RsaSignature rsa(*ConnectToRSA);
311 std::vector<uint8> signature;
312 rsa.Sign(signBuffer.data(), signBuffer.size(), digestGenerator, signature);
313
314 _worldPacket.append(signature.data(), signature.size());
315 _worldPacket.append(whereBuffer);
322
323 return &_worldPacket;
324}
325
335
337{
338 _worldPacket >> Con;
339 _worldPacket >> As<uint32>(Serial);
340}
341
343{
344 std::unique_ptr<Trinity::Crypto::Ed25519> ed25519 = std::make_unique<Trinity::Crypto::Ed25519>();
345 if (!ed25519->LoadFromByteArray(EnterEncryptedModePrivateKey))
346 return false;
347
348 EnterEncryptedModeSigner = std::move(ed25519);
349 return true;
350}
351
353{
354 EnterEncryptedModeSigner.reset();
355}
356
357std::array<uint8, 32> constexpr EnableEncryptionSeed = { 0x66, 0xBE, 0x29, 0x79, 0xEF, 0xF2, 0xD5, 0xB5, 0x61, 0x53, 0xF6, 0x5F, 0x45, 0xAE, 0x81, 0xCB,
358 0x32, 0xEC, 0x94, 0xEC, 0x75, 0xB3, 0x5F, 0x44, 0x6A, 0x63, 0x43, 0x67, 0x17, 0x20, 0x44, 0x34 };
359std::array<uint8, 16> constexpr EnableEncryptionContext = { 0xA7, 0x1F, 0xB6, 0x9B, 0xC9, 0x7C, 0xDD, 0x96, 0xE9, 0xBB, 0xB8, 0x21, 0x39, 0x8D, 0x5A, 0xD4 };
360
362{
363 std::array<uint8, 64> toSign = Trinity::Crypto::HMAC_SHA512::GetDigestOf(EncryptionKey,
364 std::array<uint8, 1>{uint8(Enabled ? 1 : 0)},
366
367 Trinity::Crypto::Ed25519 ed25519(*EnterEncryptedModeSigner);
368 std::vector<uint8> signature;
369
370 ed25519.SignWithContext(toSign, { EnableEncryptionContext.begin(), EnableEncryptionContext.end() }, signature);
371
373 _worldPacket.append(signature.data(), signature.size());
374 _worldPacket << Bits<1>(Enabled);
376
377 return &_worldPacket;
378}
379
384}
uint8_t uint8
Definition Define.h:156
int32_t int32
Definition Define.h:150
uint64_t uint64
Definition Define.h:153
uint16_t uint16
Definition Define.h:155
uint32_t uint32
Definition Define.h:154
size_t rpos() const
Definition ByteBuffer.h:448
void resize(size_t newsize)
Definition ByteBuffer.h:571
void append(T value)
Definition ByteBuffer.h:130
size_t size() const
Definition ByteBuffer.h:568
void FlushBits()
Definition ByteBuffer.h:141
uint8 * data()
Definition ByteBuffer.h:565
bool Sign(std::array< uint8, N > const &message, DigestGenerator &generator, std::vector< uint8 > &output)
Definition RSA.h:87
static Digest GetDigestOf(Container const &seed, uint8 const *data, size_t len)
Definition HMAC.h:41
WorldPacket const * Write() override
std::array< uint8, DigestLength > Digest
uint32 Result
the result of the authentication process, possible values are BattlenetRpcErrorCode
WorldPacket const * Write() override
Optional< AuthWaitInfo > WaitInfo
contains the queue wait information in case the account is in the login queue.
Optional< AuthSuccessInfo > SuccessInfo
contains the packet data in case that it has account information (It is never set when WaitInfo is se...
std::array< uint8, DigestLength > Digest
WorldPacket const * Write() override
std::array< uint8, 32 > const & EncryptionKey
WorldPacket const * Write() override
WorldPacket _worldPacket
Definition Packet.h:43
std::array< uint8, 32 > constexpr EnableEncryptionSeed
ByteBuffer & operator<<(ByteBuffer &data, VirtualRealmNameInfo const &virtualRealmInfo)
std::array< uint8, 16 > constexpr EnableEncryptionContext
DataWriter< Container > Data(Container const &value)
OptionalInitWriter< T > OptionalInit(Optional< T > const &value)
std::vector< RaceClassAvailability > const * AvailableClasses
the minimum AccountExpansion required to select race/class combinations
uint8 ActiveExpansionLevel
the current server expansion, the possible values are in Expansions
uint8 AccountExpansionLevel
the current expansion of this account, the possible values are in Expansions
bool ForceCharacterTemplate
forces the client to always use a character template when creating a new character.
uint32 TimeRested
affects the return value of the GetBillingTimeRested() client API call, it is the number of seconds y...
std::vector< CharacterTemplate const * > Templates
list of pre-made character templates.
Optional< Timestamp<> > ExpansionTrialExpiration
expansion trial expiration unix timestamp
Optional< uint16 > NumPlayersAlliance
number of alliance players in this realm.
uint32 VirtualRealmAddress
a special identifier made from the Index, BattleGroup and Region.
uint32 CurrencyID
this is probably used for the ingame shop.
std::vector< VirtualRealmInfo > VirtualRealms
list of realms connected to this one (inclusive)
Optional< uint16 > NumPlayersHorde
number of horde players in this realm.
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...
union WorldPackets::Auth::ConnectTo::SocketAddress::@310 Address
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