Index: source/lobby/scripting/JSInterface_Lobby.cpp =================================================================== --- source/lobby/scripting/JSInterface_Lobby.cpp +++ source/lobby/scripting/JSInterface_Lobby.cpp @@ -23,6 +23,7 @@ #include "lib/utf8.h" #include "lobby/IXmppClient.h" #include "ps/Profile.h" +#include "ps/Util.h" #include "scriptinterface/ScriptInterface.h" #include "third_party/encryption/pkcs5_pbkdf2.h" @@ -358,14 +359,7 @@ unsigned char encrypted[DIGESTSIZE]; pbkdf2(encrypted, (unsigned char*)password.c_str(), password.length(), salt_buffer, DIGESTSIZE, ITERATIONS); - static const char base16[] = "0123456789ABCDEF"; - char hex[2 * DIGESTSIZE]; - for (int i = 0; i < DIGESTSIZE; ++i) - { - hex[i*2] = base16[encrypted[i] >> 4]; // 4 high bits - hex[i*2 + 1] = base16[encrypted[i] & 0x0F]; // 4 low bits - } - return std::string(hex, sizeof(hex)); + return Hexify(encrypted, DIGESTSIZE); } std::wstring JSI_Lobby::EncryptPassword(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), const std::wstring& pass, const std::wstring& user) Index: source/maths/tests/test_MD5.h =================================================================== --- source/maths/tests/test_MD5.h +++ source/maths/tests/test_MD5.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2010 Wildfire Games. +/* Copyright (C) 2018 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -18,16 +18,14 @@ #include "lib/self_test.h" #include "maths/MD5.h" +#include "ps/Util.h" class TestMD5 : public CxxTest::TestSuite { public: std::string decode(u8* digest) { - char digeststr[MD5::DIGESTSIZE*2+1]; - for (size_t i = 0; i < MD5::DIGESTSIZE; ++i) - sprintf_s(digeststr+2*i, 3, "%02x", (unsigned int)digest[i]); - return digeststr; + return Hexify(digest, MD5::DIGESTSIZE); } void compare(const char* input, const char* expected) Index: source/ps/CacheLoader.cpp =================================================================== --- source/ps/CacheLoader.cpp +++ source/ps/CacheLoader.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2013 Wildfire Games. +/* Copyright (C) 2018 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -20,6 +20,7 @@ #include "CacheLoader.h" #include "ps/CLogger.h" +#include "ps/Util.h" #include "maths/MD5.h" #include @@ -136,17 +137,18 @@ // Use a short prefix of the full hash (we don't need high collision-resistance), // converted to hex + u8 digest[MD5::DIGESTSIZE]; hash.Final(digest); - std::wstringstream digestPrefix; - digestPrefix << std::hex; - for (size_t i = 0; i < 8; ++i) - digestPrefix << std::setfill(L'0') << std::setw(2) << (int)digest[i]; // Get the mod path OsPath path; m_VFS->GetRealPath(sourcePath, path); - // Construct the final path - return VfsPath("cache") / path_name_only(path.BeforeCommon(sourcePath).Parent().string().c_str()) / sourcePath.ChangeExtension(sourcePath.Extension().string() + L"." + digestPrefix.str() + m_FileExtension); + return VfsPath("cache") / + path_name_only(path.BeforeCommon(sourcePath).Parent().string().c_str()) / + sourcePath.ChangeExtension(sourcePath.Extension().string() + + L"." + + wstring_from_utf8(Hexify(digest, MD5::DIGESTSIZE)) + + m_FileExtension); } Index: source/ps/ModIo.cpp =================================================================== --- source/ps/ModIo.cpp +++ source/ps/ModIo.cpp @@ -34,6 +34,7 @@ #include "ps/GameSetup/Paths.h" #include "ps/Mod.h" #include "ps/ModInstaller.h" +#include "ps/Util.h" #include "scriptinterface/ScriptConversions.h" #include "scriptinterface/ScriptInterface.h" @@ -520,17 +521,15 @@ { u8 digest[MD5::DIGESTSIZE]; m_CallbackData->md5.Final(digest); - std::stringstream md5digest; - md5digest << std::hex << std::setfill('0'); - for (size_t i = 0; i < MD5::DIGESTSIZE; ++i) - md5digest << std::setw(2) << (int)digest[i]; + std::string md5digest = Hexify(digest, MD5::DIGESTSIZE); - if (m_ModData[m_DownloadModID].properties.at("filehash_md5") != md5digest.str()) + + if (m_ModData[m_DownloadModID].properties.at("filehash_md5") != md5digest) { err = fmt::sprintf( g_L10n.Translate("Invalid file. Expected md5 %s, got %s."), m_ModData[m_DownloadModID].properties.at("filehash_md5").c_str(), - md5digest.str()); + md5digest); return false; } } Index: source/ps/Util.h =================================================================== --- source/ps/Util.h +++ source/ps/Util.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 Wildfire Games. +/* Copyright (C) 2018 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -35,5 +35,6 @@ Status tex_write(Tex* t, const VfsPath& filename); std::string Hexify(const std::string& s); +std::string Hexify(const u8* s, size_t length); #endif // PS_UTIL_H Index: source/ps/Util.cpp =================================================================== --- source/ps/Util.cpp +++ source/ps/Util.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 Wildfire Games. +/* Copyright (C) 2018 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -431,6 +431,15 @@ std::stringstream str; str << std::hex; for (const char& c : s) - str << std::setfill('0') << std::setw(2) << (int)(unsigned char)c; + str << std::setfill('0') << std::setw(2) << static_cast(static_cast(c)); + return str.str(); +} + +std::string Hexify(const u8* s, size_t length) +{ + std::stringstream str; + str << std::hex; + for (size_t i = 0; i < length; ++i) + str << std::setfill('0') << std::setw(2) << static_cast(s[i]); return str.str(); } Index: source/ps/scripting/JSInterface_Main.cpp =================================================================== --- source/ps/scripting/JSInterface_Main.cpp +++ source/ps/scripting/JSInterface_Main.cpp @@ -29,6 +29,7 @@ #include "ps/GameSetup/Atlas.h" #include "ps/Globals.h" #include "ps/Hotkey.h" +#include "ps/Util.h" #include "scriptinterface/ScriptInterface.h" #include "tools/atlas/GameInterface/GameLoop.h" @@ -118,11 +119,7 @@ m.Update((const u8*)input.c_str(), input.length()); m.Final(digest); - char digeststr[MD5::DIGESTSIZE*2+1]; - for (size_t i = 0; i < MD5::DIGESTSIZE; ++i) - sprintf_s(digeststr+2*i, 3, "%02x", (unsigned int)digest[i]); - - return digeststr; + return Hexify(digest, MD5::DIGESTSIZE); } void JSI_Main::RegisterScriptFunctions(const ScriptInterface& scriptInterface)