diff --git a/OpenRCT2.xcodeproj/project.pbxproj b/OpenRCT2.xcodeproj/project.pbxproj index 647207345e..b53a9e1c1d 100644 --- a/OpenRCT2.xcodeproj/project.pbxproj +++ b/OpenRCT2.xcodeproj/project.pbxproj @@ -802,6 +802,7 @@ E6C71B6165224F65AA87E65B /* RideUseSystem.h in Headers */ = {isa = PBXBuildFile; fileRef = 2DA720D496604387806AC168 /* RideUseSystem.h */; }; C8D612EB56BD4214BEC0F7FF /* GroupVector.hpp in Headers */ = {isa = PBXBuildFile; fileRef = F4D523B8782E4C458AF1490D /* GroupVector.hpp */; }; B2F44E535BD14A03BE8B9D14 /* ZipStream.hpp in Headers */ = {isa = PBXBuildFile; fileRef = F28A181D311D4E078FDB090C /* ZipStream.hpp */; }; + 7CDC7EE9B12E40FB9FE78546 /* Crypt.OpenRCT2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4248E4E4394842D4AF6119DA /* Crypt.OpenRCT2.cpp */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -1907,6 +1908,7 @@ 2DA720D496604387806AC168 /* RideUseSystem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RideUseSystem.h; path = src/openrct2/peep/RideUseSystem.h; sourceTree = SOURCE_ROOT; }; F4D523B8782E4C458AF1490D /* GroupVector.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = GroupVector.hpp; path = src/openrct2/core/GroupVector.hpp; sourceTree = SOURCE_ROOT; }; F28A181D311D4E078FDB090C /* ZipStream.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = ZipStream.hpp; path = src/openrct2/core/ZipStream.hpp; sourceTree = SOURCE_ROOT; }; + 4248E4E4394842D4AF6119DA /* Crypt.OpenRCT2.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Crypt.OpenRCT2.cpp; path = src/openrct2/core/Crypt.OpenRCT2.cpp; sourceTree = SOURCE_ROOT; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -2578,6 +2580,7 @@ BA2317BF6FB54E328DEB7055 /* EnumMap.hpp */, F4D523B8782E4C458AF1490D /* GroupVector.hpp */, F28A181D311D4E078FDB090C /* ZipStream.hpp */, + 4248E4E4394842D4AF6119DA /* Crypt.OpenRCT2.cpp */, ); path = core; sourceTree = ""; @@ -4484,6 +4487,7 @@ 5B6E418A2F264952BA0CC2F2 /* ScTileElement.cpp in Sources */, 6C90BE01D190493295071B23 /* ScTile.cpp in Sources */, 258C212125F84FA2B4C3BCAE /* RideUseSystem.cpp in Sources */, + 7CDC7EE9B12E40FB9FE78546 /* Crypt.OpenRCT2.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/src/openrct2/core/Crypt.OpenRCT2.cpp b/src/openrct2/core/Crypt.OpenRCT2.cpp new file mode 100644 index 0000000000..f3ad2d17d5 --- /dev/null +++ b/src/openrct2/core/Crypt.OpenRCT2.cpp @@ -0,0 +1,101 @@ +/***************************************************************************** + * Copyright (c) 2014-2021 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "Crypt.h" + +#include +#include +#include +#include +#include + +using namespace Crypt; + +class OpenRCT2FNV1aAlgorithm : public FNV1aAlgorithm +{ +private: + static constexpr uint64_t Offset = 0xCBF29CE484222325ULL; + static constexpr uint64_t Prime = 0x00000100000001B3ULL; + + uint64_t _data = Offset; + uint8_t _rem[8]{}; + size_t _remLen{}; + + void ProcessRemainder() + { + if (_remLen > 0) + { + uint64_t temp{}; + std::memcpy(&temp, _rem, _remLen); + _data ^= temp; + _data *= Prime; + _remLen = 0; + } + } + +public: + HashAlgorithm* Clear() override + { + _data = Offset; + return this; + } + + HashAlgorithm* Update(const void* data, size_t dataLen) override + { + if (dataLen == 0) + return this; + + auto src = reinterpret_cast(data); + if (_remLen > 0) + { + // We have remainder, so fill rest of it with bytes from src + auto fillLen = sizeof(uint64_t) - _remLen; + assert(_remLen + fillLen <= sizeof(uint64_t)); + std::memcpy(_rem + _remLen, src, fillLen); + src = reinterpret_cast(reinterpret_cast(src) + fillLen); + _remLen += fillLen; + dataLen -= fillLen; + ProcessRemainder(); + } + + // Process every block of 8 bytes + while (dataLen >= sizeof(uint64_t)) + { + auto temp = *src++; + _data ^= temp; + _data *= Prime; + dataLen -= sizeof(uint64_t); + } + + // Store the remaining data (< 8 bytes) + if (dataLen > 0) + { + _remLen = dataLen; + std::memcpy(&_rem, src, dataLen); + } + return this; + } + + Result Finish() override + { + ProcessRemainder(); + + Result res; + std::memcpy(res.data(), &_data, sizeof(_data)); + return res; + } +}; + +namespace Crypt +{ + std::unique_ptr CreateFNV1a() + { + return std::make_unique(); + } +} // namespace Crypt diff --git a/src/openrct2/core/Crypt.h b/src/openrct2/core/Crypt.h index 18967bd875..87baf9c751 100644 --- a/src/openrct2/core/Crypt.h +++ b/src/openrct2/core/Crypt.h @@ -48,13 +48,20 @@ namespace Crypt using Sha1Algorithm = HashAlgorithm<20>; using Sha256Algorithm = HashAlgorithm<32>; + using FNV1aAlgorithm = HashAlgorithm<8>; // Factories + [[nodiscard]] std::unique_ptr CreateFNV1a(); [[nodiscard]] std::unique_ptr CreateSHA1(); [[nodiscard]] std::unique_ptr CreateSHA256(); [[nodiscard]] std::unique_ptr CreateRSA(); [[nodiscard]] std::unique_ptr CreateRSAKey(); + inline FNV1aAlgorithm::Result FNV1a(const void* data, size_t dataLen) + { + return CreateFNV1a()->Update(data, dataLen)->Finish(); + } + inline Sha1Algorithm::Result SHA1(const void* data, size_t dataLen) { return CreateSHA1()->Update(data, dataLen)->Finish(); diff --git a/src/openrct2/libopenrct2.vcxproj b/src/openrct2/libopenrct2.vcxproj index d49c087fba..7010f9cf3e 100644 --- a/src/openrct2/libopenrct2.vcxproj +++ b/src/openrct2/libopenrct2.vcxproj @@ -598,6 +598,7 @@ +