#include #include "auth3_server.hpp" #include "../keys.hpp" #include #include namespace demonware { namespace { #pragma pack(push, 1) struct auth_ticket { unsigned int m_magicNumber; char m_type; unsigned int m_titleID; unsigned int m_timeIssued; unsigned int m_timeExpires; unsigned __int64 m_licenseID; unsigned __int64 m_userID; char m_username[64]; char m_sessionKey[24]; char m_usingHashMagicNumber[3]; char m_hash[4]; }; #pragma pack(pop) } void auth3_server::send_reply(reply* data) { if (!data) return; this->send(data->data()); } void auth3_server::handle(const std::string& packet) { if (packet.starts_with("POST /auth/")) { #ifdef DW_DEBUG printf("[DW]: [auth]: user requested authentication.\n"); #endif return; } unsigned int title_id = 0; unsigned int iv_seed = 0; std::string identity{}; std::string token{}; rapidjson::Document j; j.Parse(packet.data(), packet.size()); if (j.HasMember("title_id") && j["title_id"].IsString()) { title_id = std::stoul(j["title_id"].GetString()); } if (j.HasMember("iv_seed") && j["iv_seed"].IsString()) { iv_seed = std::stoul(j["iv_seed"].GetString()); } if (j.HasMember("identity") && j["identity"].IsString()) { identity = j["identity"].GetString(); } if (j.HasMember("extra_data") && j["extra_data"].IsString()) { rapidjson::Document extra_data; auto& ed = j["extra_data"]; extra_data.Parse(ed.GetString(), ed.GetStringLength()); if (extra_data.HasMember("token") && extra_data["token"].IsString()) { auto& token_field = extra_data["token"]; std::string token_b64(token_field.GetString(), token_field.GetStringLength()); token = utils::cryptography::base64::decode(token_b64); } } #ifdef DW_DEBUG printf("[DW]: [auth]: authenticating user %s\n", token.data() + 64); #endif std::string auth_key(reinterpret_cast(token.data() + 32), 24); std::string session_key( "\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37", 24); // client_ticket auth_ticket ticket{}; std::memset(&ticket, 0x0, sizeof ticket); ticket.m_magicNumber = 0x0EFBDADDE; ticket.m_type = 0; ticket.m_titleID = title_id; ticket.m_timeIssued = static_cast(time(nullptr)); ticket.m_timeExpires = ticket.m_timeIssued + 30000; ticket.m_licenseID = 0; ticket.m_userID = reinterpret_cast(token.data() + 56); strncpy_s(ticket.m_username, sizeof(ticket.m_username), reinterpret_cast(token.data() + 64), 64); std::memcpy(ticket.m_sessionKey, session_key.data(), 24); const auto iv = utils::cryptography::tiger::compute(std::string(reinterpret_cast(&iv_seed), 4)); const auto ticket_enc = utils::cryptography::des3::encrypt( std::string(reinterpret_cast(&ticket), sizeof(ticket)), iv, auth_key); const auto ticket_b64 = utils::cryptography::base64::encode( reinterpret_cast(ticket_enc.data()), 128); // server_ticket uint8_t auth_data[128]; std::memset(&auth_data, 0, sizeof auth_data); std::memcpy(auth_data, session_key.data(), 24); const auto auth_data_b64 = utils::cryptography::base64::encode(auth_data, 128); demonware::set_session_key(session_key); // header time char date[64]; const auto now = time(nullptr); tm gmtm{}; gmtime_s(&gmtm, &now); strftime(date, 64, "%a, %d %b %G %T", &gmtm); // json content rapidjson::Document doc; doc.SetObject(); doc.AddMember("auth_task", "29", doc.GetAllocator()); doc.AddMember("code", "700", doc.GetAllocator()); auto seed = std::to_string(iv_seed); doc.AddMember("iv_seed", rapidjson::StringRef(seed.data(), seed.size()), doc.GetAllocator()); doc.AddMember("client_ticket", rapidjson::StringRef(ticket_b64.data(), ticket_b64.size()), doc.GetAllocator()); doc.AddMember("server_ticket", rapidjson::StringRef(auth_data_b64.data(), auth_data_b64.size()), doc.GetAllocator()); doc.AddMember("client_id", "", doc.GetAllocator()); doc.AddMember("account_type", "steam", doc.GetAllocator()); doc.AddMember("crossplay_enabled", false, doc.GetAllocator()); doc.AddMember("loginqueue_eanbled", false, doc.GetAllocator()); rapidjson::Value value{}; doc.AddMember("lsg_endpoint", value, doc.GetAllocator()); rapidjson::StringBuffer buffer{}; rapidjson::Writer> writer(buffer); doc.Accept(writer); // http stuff std::string result; result.append("HTTP/1.1 200 OK\r\n"); result.append("Server: TornadoServer/4.5.3\r\n"); result.append("Content-Type: application/json\r\n"); result.append(utils::string::va("Date: %s GMT\r\n", date)); result.append(utils::string::va("Content-Length: %d\r\n\r\n", buffer.GetLength())); result.append(buffer.GetString(), buffer.GetLength()); raw_reply reply(result); this->send_reply(&reply); #ifdef DW_DEBUG printf("[DW]: [auth]: user successfully authenticated.\n"); #endif } }