/* * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information * * 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 2 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. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ #include "AuthenticationPackets.h" #include "BigNumber.h" #include "CharacterTemplateDataStore.h" #include "Ed25519.h" #include "HMAC.h" #include "ObjectMgr.h" #include "PacketOperators.h" #include "RSA.h" namespace WorldPackets::Auth { ByteBuffer& operator<<(ByteBuffer& data, VirtualRealmNameInfo const& virtualRealmInfo) { data << WorldPackets::Bits<1>(virtualRealmInfo.IsLocal); data << WorldPackets::Bits<1>(virtualRealmInfo.IsInternalRealm); data << WorldPackets::SizedString::BitsSize<8>(virtualRealmInfo.RealmNameActual); data << WorldPackets::SizedString::BitsSize<8>(virtualRealmInfo.RealmNameNormalized); data.FlushBits(); data << SizedString::Data(virtualRealmInfo.RealmNameActual); data << SizedString::Data(virtualRealmInfo.RealmNameNormalized); return data; } ByteBuffer& operator<<(ByteBuffer& data, VirtualRealmInfo const& virtualRealmInfo) { data << uint32(virtualRealmInfo.RealmAddress); data << virtualRealmInfo.RealmNameInfo; return data; } void Ping::Read() { _worldPacket >> Serial; _worldPacket >> Latency; } WorldPacket const* Pong::Write() { _worldPacket << uint32(Serial); return &_worldPacket; } WorldPacket const* AuthChallenge::Write() { _worldPacket.append(DosChallenge.data(), DosChallenge.size()); _worldPacket.append(Challenge.data(), Challenge.size()); _worldPacket << uint8(DosZeroBits); return &_worldPacket; } void AuthSession::Read() { uint32 realmJoinTicketSize; _worldPacket >> DosResponse; _worldPacket >> RegionID; _worldPacket >> BattlegroupID; _worldPacket >> RealmID; _worldPacket.read(LocalChallenge.data(), LocalChallenge.size()); _worldPacket.read(Digest.data(), Digest.size()); _worldPacket >> Bits<1>(UseIPv6); _worldPacket >> realmJoinTicketSize; if (realmJoinTicketSize) { RealmJoinTicket.resize(std::min(realmJoinTicketSize, uint32(_worldPacket.size() - _worldPacket.rpos()))); _worldPacket.read(RealmJoinTicket.data(), RealmJoinTicket.size()); } } ByteBuffer& operator<<(ByteBuffer& data, GameTime const& gameTime) { data << uint32(gameTime.BillingType); data << uint32(gameTime.MinutesRemaining); data << uint32(gameTime.RealBillingType); data << Bits<1>(gameTime.IsInIGR); data << Bits<1>(gameTime.IsPaidForByIGR); data << Bits<1>(gameTime.IsCAISEnabled); data.FlushBits(); return data; } ByteBuffer& operator<<(ByteBuffer& data, BaseBuildKey const& buildKey) { for (std::size_t i = 0; i < 16; ++i) { data << buildKey.BuildKey[i]; data << buildKey.ConfigKey[i]; } return data; } ByteBuffer& operator<<(ByteBuffer& data, AuthSuccessInfo const& successInfo) { data << uint32(successInfo.VirtualRealmAddress); data << Size(successInfo.VirtualRealms); data << uint32(successInfo.TimeRested); data << uint8(successInfo.ActiveExpansionLevel); data << uint8(successInfo.AccountExpansionLevel); data << uint32(successInfo.TimeSecondsUntilPCKick); data << Size(*successInfo.AvailableClasses); data << Size(successInfo.Templates); data << uint32(successInfo.CurrencyID); data << successInfo.Time; for (RaceClassAvailability const& raceClassAvailability : *successInfo.AvailableClasses) { data << uint8(raceClassAvailability.RaceID); data << Size(raceClassAvailability.Classes); for (ClassAvailability const& classAvailability : raceClassAvailability.Classes) { data << uint8(classAvailability.ClassID); data << uint8(classAvailability.ActiveExpansionLevel); data << uint8(classAvailability.AccountExpansionLevel); data << uint8(classAvailability.MinActiveExpansionLevel); } } data << Bits<1>(successInfo.IsExpansionTrial); data << Bits<1>(successInfo.ForceCharacterTemplate); data << OptionalInit(successInfo.NumPlayersHorde); data << OptionalInit(successInfo.NumPlayersAlliance); data << OptionalInit(successInfo.ExpansionTrialExpiration); data << OptionalInit(successInfo.CurrentBuild); data.FlushBits(); data << successInfo.GameTimeInfo; if (successInfo.NumPlayersHorde) data << uint16(*successInfo.NumPlayersHorde); if (successInfo.NumPlayersAlliance) data << uint16(*successInfo.NumPlayersAlliance); if (successInfo.ExpansionTrialExpiration) data << *successInfo.ExpansionTrialExpiration; if (successInfo.CurrentBuild) data << *successInfo.CurrentBuild; for (VirtualRealmInfo const& virtualRealm : successInfo.VirtualRealms) data << virtualRealm; for (CharacterTemplate const* characterTemplate : successInfo.Templates) { data << uint32(characterTemplate->TemplateSetId); data << Size(characterTemplate->Classes); for (CharacterTemplateClass const& templateClass : characterTemplate->Classes) { data << uint8(templateClass.ClassID); data << uint8(templateClass.FactionGroup); } data << SizedString::BitsSize<7>(characterTemplate->Name); data << SizedString::BitsSize<10>(characterTemplate->Description); data.FlushBits(); data << SizedString::Data(characterTemplate->Name); data << SizedString::Data(characterTemplate->Description); } return data; } ByteBuffer& operator<<(ByteBuffer& data, AuthWaitInfo const& waitInfo) { data << uint32(waitInfo.WaitCount); data << uint32(waitInfo.WaitTime); data << uint8(waitInfo.AllowedFactionGroupForCharacterCreate); data << WorldPackets::Bits<1>(waitInfo.HasFCM); data << WorldPackets::Bits<1>(waitInfo.CanCreateOnlyIfExisting); data.FlushBits(); return data; } WorldPacket const* AuthResponse::Write() { _worldPacket << uint32(Result); _worldPacket << OptionalInit(SuccessInfo); _worldPacket << OptionalInit(WaitInfo); _worldPacket.FlushBits(); if (SuccessInfo) _worldPacket << *SuccessInfo; if (WaitInfo) _worldPacket << *WaitInfo; return &_worldPacket; } WorldPacket const* WaitQueueUpdate::Write() { _worldPacket << WaitInfo; return &_worldPacket; } namespace { std::string const RSAPrivateKey = R"(-----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEA7rPc1NPDtFRRzmZbyzK48PeSU8YZ8gyFL4omqXpFn2DE683q f41Z2FeyYHsJTJtouMft7x6ADeZrN1tTkOsYEw1/Q2SD2pjmrMIwooKlxsvH+4af n6kCagNJxTj7wMhVzMDOJZG+hc/R0TfOzIPS6jCAB3uAn51EVCIpvoba20jFqfkT NpUjdvEO3IQNlAISqJfzOxTuqm+YBSdOH6Ngpana2BffM8viE1SLGLDKubuIZAbf dabXYQC7sFoOetR3CE0V4hCDsASqnot3qQaJXQhdD7gua8HLZM9uXNtPWGUIUfsN SBpvtj0fC93+Gx3wv7Ana/WOvMdAAf+nC4DWXwIDAQABAoIBACKa5q/gB2Y0Nyvi APrDXrZoXclRVd+WWxSaRaKaPE+vuryovI9DUbwgcpa0H5QAj70CFwdsd4oMVozO 6519x56zfTiq8MaXFhIDkQNuR1Q7pMFdMfT2jogJ8/7olO7M3EtzxC8EIwfJKhTX r15M2h3jbBwplmsNZKOB1GVvrXjOm1KtOZ4CTTM0WrPaLVDT9ax8pykjmFw16vGP j/R5Dky9VpabtfZOu/AEW259XDEiQgTrB4Eg+S4GJjHqAzPZBmMy/xhlDK4oMXef qXScfD4w0RxuuCFr6lxLPZz0S35BK1kIWmIkuv+9eQuI4Hr1CyVwch4fkfvrp84x 8tvAFnkCgYEA87NZaG9a8/Mob6GgY4BVLHJVOSzzFdNyMA+4LfSbtzgON2RSZyeD 0JpDowwXssw5XOyUUctj2cLLdlMCpDfdzk4F/PEakloDJWpason3lmur0/5Oq3T9 3+fnNUl4d3UOs1jcJ1yGQ/BfrTyRTcEoZx8Mu9mJ4ituVkKuLeG5vX0CgYEA+r/w QBJS6kDyQPj1k/SMClUhWhyADwDod03hHTQHc9BleJyjXmVy+/pWhN7aELhjgLbf o/Gm3aKJjCxS4qBmqUKwAvGoSVux1Bo2ZjcfF7sX9BXBOlFTG+bPVCZUoaksTyXN g7GsA1frKkWWkgQuOeK3o/p9IZoBl93vEgcTGgsCgYEAv5ucCIjFMllUybCCsrkM Ps4GQ9YbqmV9ulwhq8BPTlc8lkDCqWhgM3uXAnNXjrUTxQQd+dG4yFZoMrhBs2xZ cQPXoXDQO5GaN6jPduETUamGiD/DCvwJQCrNlxAVL5dR36FWN3x/9JriHwsoE8Jz SeEX2frIdpM/RYNX/6sipuECgYEA+rwFRDxOdvm8hGWuQ2WMxyQ7Nn07PEV/LxVM HkSRkyh23vVakyDEqty3uSOSUJfgv6ud07TnU8ac3fLQatdT8LrDgB4fVkN/fYU8 kldaGwO1vxgl4OfDQCo7dXzisciViwtVBvQZ+jnm6J0vJBFUHAPt9+WZTIlQQIjm 71LtseMCgYBSAhs6lshtz+ujR3fmc4QqJVGqeXvEBPAVm6yYoKYRLwVs/rFv3WLN LOwwBQ6lz7P9RqYYB5wVlaRvEhb9+lCve/xVcxMeZ5GkOBPxVygYV9l/wNdE25Nz OHYtKG3GK3GEcFDwZU2LPHq21EroUAdtRfbrJ4KW2yc8igtXKxTBYw== -----END RSA PRIVATE KEY----- )"; std::array constexpr EnterEncryptedModePrivateKey = { 0x08, 0xBD, 0xC7, 0xA3, 0xCC, 0xC3, 0x4F, 0x3F, 0x6A, 0x0B, 0xFF, 0xCF, 0x31, 0xC1, 0xB6, 0x97, 0x69, 0x1E, 0x72, 0x9A, 0x0A, 0xAB, 0x2C, 0x77, 0xC3, 0x6F, 0x8A, 0xE7, 0x5A, 0x9A, 0xA7, 0xC9 }; std::unique_ptr ConnectToRSA; std::unique_ptr EnterEncryptedModeSigner; } bool ConnectTo::InitializeEncryption() { std::unique_ptr rsa = std::make_unique(); if (!rsa->LoadKeyFromString(RSAPrivateKey)) return false; ConnectToRSA = std::move(rsa); return true; } void ConnectTo::ShutdownEncryption() { ConnectToRSA.reset(); } WorldPacket const* ConnectTo::Write() { ByteBuffer whereBuffer; whereBuffer << uint8(Payload.Where.Type); switch (Payload.Where.Type) { case IPv4: whereBuffer.append(Payload.Where.Address.V4.data(), Payload.Where.Address.V4.size()); break; case IPv6: whereBuffer.append(Payload.Where.Address.V6.data(), Payload.Where.Address.V6.size()); break; case NamedSocket: whereBuffer << Payload.Where.Address.Name.data(); break; default: break; } ByteBuffer signBuffer; signBuffer.append(whereBuffer); signBuffer << uint32(Payload.Where.Type); signBuffer << uint16(Payload.Port); Trinity::Crypto::RsaSignature rsa(*ConnectToRSA); Trinity::Crypto::RsaSignature::SHA256 digestGenerator; std::vector signature; rsa.Sign(signBuffer.data(), signBuffer.size(), digestGenerator, signature); _worldPacket.append(signature.data(), signature.size()); _worldPacket.append(whereBuffer); _worldPacket << uint16(Payload.Port); _worldPacket << uint32(Serial); _worldPacket << uint8(Con); _worldPacket << uint64(Key); _worldPacket << uint32(NativeRealmAddress); _worldPacket << uint32(Key3); return &_worldPacket; } void AuthContinuedSession::Read() { _worldPacket >> DosResponse; _worldPacket.read(LocalChallenge.data(), LocalChallenge.size()); _worldPacket.read(Digest.data(), Digest.size()); _worldPacket >> Key; _worldPacket >> NativeRealmAddress; _worldPacket >> Key3; } void ConnectToFailed::Read() { _worldPacket >> Con; _worldPacket >> As(Serial); } bool EnterEncryptedMode::InitializeEncryption() { std::unique_ptr ed25519 = std::make_unique(); if (!ed25519->LoadFromByteArray(EnterEncryptedModePrivateKey)) return false; EnterEncryptedModeSigner = std::move(ed25519); return true; } void EnterEncryptedMode::ShutdownEncryption() { EnterEncryptedModeSigner.reset(); } std::array constexpr EnableEncryptionSeed = { 0x66, 0xBE, 0x29, 0x79, 0xEF, 0xF2, 0xD5, 0xB5, 0x61, 0x53, 0xF6, 0x5F, 0x45, 0xAE, 0x81, 0xCB, 0x32, 0xEC, 0x94, 0xEC, 0x75, 0xB3, 0x5F, 0x44, 0x6A, 0x63, 0x43, 0x67, 0x17, 0x20, 0x44, 0x34 }; std::array constexpr EnableEncryptionContext = { 0xA7, 0x1F, 0xB6, 0x9B, 0xC9, 0x7C, 0xDD, 0x96, 0xE9, 0xBB, 0xB8, 0x21, 0x39, 0x8D, 0x5A, 0xD4 }; WorldPacket const* EnterEncryptedMode::Write() { std::array toSign = Trinity::Crypto::HMAC_SHA512::GetDigestOf(EncryptionKey, std::array{uint8(Enabled ? 1 : 0)}, EnableEncryptionSeed); Trinity::Crypto::Ed25519 ed25519(*EnterEncryptedModeSigner); std::vector signature; ed25519.SignWithContext(toSign, { EnableEncryptionContext.begin(), EnableEncryptionContext.end() }, signature); _worldPacket << int32(RegionGroup); _worldPacket.append(signature.data(), signature.size()); _worldPacket << Bits<1>(Enabled); _worldPacket.FlushBits(); return &_worldPacket; } void QueuedMessagesEnd::Read() { _worldPacket >> Timestamp; } }