From 3b479abf64309021ca1d3e9b8fdd074a479913bb Mon Sep 17 00:00:00 2001 From: Anonymous275 Date: Fri, 15 Dec 2023 18:16:12 +0000 Subject: [PATCH] v2.0.84 - add hash check - new routes for updates - use C++ 20 --- CMakeLists.txt | 2 +- include/Startup.h | 13 +- include/hashpp.h | 4642 +++++++++++++++++++++++++++++++++++++++ src/Network/Core.cpp | 2 + src/Security/BeamNG.cpp | 8 +- src/Startup.cpp | 118 +- 6 files changed, 4741 insertions(+), 44 deletions(-) create mode 100644 include/hashpp.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 953d57b..7564057 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ if (WIN32) STRING(REPLACE "/MDd" "/MTd" CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG}) endif(WIN32) -set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG") diff --git a/include/Startup.h b/include/Startup.h index f837188..7487146 100755 --- a/include/Startup.h +++ b/include/Startup.h @@ -7,6 +7,9 @@ /// #pragma once #include +#include +#include + void InitLauncher(int argc, char* argv[]); std::string GetEP(char*P = nullptr); std::string GetGamePath(); @@ -14,4 +17,12 @@ std::string GetVer(); std::string GetEN(); void StartProxy(); void ConfigInit(); -extern bool Dev; \ No newline at end of file +extern bool Dev; + +struct VersionParser { + explicit VersionParser(const std::string& from_string); + std::strong_ordering operator<=>(VersionParser const& rhs) const noexcept; + bool operator==(VersionParser const& rhs) const noexcept; + std::vector split; + std::vector data; +}; diff --git a/include/hashpp.h b/include/hashpp.h new file mode 100644 index 0000000..08b5eb8 --- /dev/null +++ b/include/hashpp.h @@ -0,0 +1,4642 @@ +#if !defined(HASHPP_H) +#define HASHPP_H + +/* + + Copyright (c) 2012-2021 Johnny (pseud. Dread) + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + ---------------------------------------------------------------------- + + hash++ : header-only hash implementations in C++ + This header file contains implementations of Message Digest + and Secure Hash Algorithm family hash algorithms for others + to view internal mechanisms of said algorithms, as well as + for substitution in sources absent the need for heavier + crypto-related libraries such as OpenSSL or Crypto++. + +*/ + +#define GU64B(x, y, z) do { \ + (x) = ( ((uint64_t) (y)[(z)]) << 56 ) \ + | ( ((uint64_t) (y)[(z) + 1]) << 48 ) \ + | ( ((uint64_t) (y)[(z) + 2]) << 40 ) \ + | ( ((uint64_t) (y)[(z) + 3]) << 32 ) \ + | ( ((uint64_t) (y)[(z) + 4]) << 24 ) \ + | ( ((uint64_t) (y)[(z) + 5]) << 16 ) \ + | ( ((uint64_t) (y)[(z) + 6]) << 8 ) \ + | ( ((uint64_t) (y)[(z) + 7]) ); \ +} while(0) \ + +#define PU64B(x, y, z) do { \ + (y)[(z) ] = (uint8_t) ( (x) >> 56 ); \ + (y)[(z) + 1] = (uint8_t) ( (x) >> 48 ); \ + (y)[(z) + 2] = (uint8_t) ( (x) >> 40 ); \ + (y)[(z) + 3] = (uint8_t) ( (x) >> 32 ); \ + (y)[(z) + 4] = (uint8_t) ( (x) >> 24 ); \ + (y)[(z) + 5] = (uint8_t) ( (x) >> 16 ); \ + (y)[(z) + 6] = (uint8_t) ( (x) >> 8 ); \ + (y)[(z) + 7] = (uint8_t) ( (x) ); \ +} while(0) \ + +#define PU128B(l,h,y,z) do { \ + PU64B(((l) >> 61) ^ ((h) << 3), (y), (z)); \ + PU64B(((l) << 3), (y), (z) + 8); \ +} while(0) \ + +#include +#include +#include +#include +#if defined(HASHPP_INCLUDE_METRICS) +#include +#endif + +namespace hashpp { + enum class ALGORITHMS : uint8_t { + // MDX Family + MD5, MD4, MD2, + + // SHA-X Family + SHA1, SHA2_224, SHA2_256, + SHA2_384, SHA2_512, SHA2_512_224, + SHA2_512_256 /*, SHA3_224, SHA3_256, + SHA3_384, SHA3_512, SHAKE128, + SHAKE256 */ + }; + + // class containing common data and methods to be + // derived from by algorithm classes for common use + // internally + class common { + public: + // helper functions to rotate left + constexpr uint32_t rl32(uint32_t x, uint32_t y) noexcept { + return (x << y) | (x >> (32 - y)); + } + constexpr uint64_t rl64(uint64_t x, uint64_t y) noexcept { + return (x << y) | (x >> (64 - y)); + } + + // helper functions to rotate right + constexpr uint32_t rr32(uint32_t x, uint32_t y) noexcept { + return (x >> y) | (x << (32 - y)); + } + constexpr uint64_t rr64(uint64_t x, uint64_t y) noexcept { + return (x >> y) | (x << (64 - y)); + } + + // hex table for converting bytes to representable + // hexadecimal strings for output via getHash + const char* hexTable[256] = { + "00", "01", "02", "03", "04", "05", "06", "07", + "08", "09", "0a", "0b", "0c", "0d", "0e", "0f", + "10", "11", "12", "13", "14", "15", "16", "17", + "18", "19", "1a", "1b", "1c", "1d", "1e", "1f", + "20", "21", "22", "23", "24", "25", "26", "27", + "28", "29", "2a", "2b", "2c", "2d", "2e", "2f", + "30", "31", "32", "33", "34", "35", "36", "37", + "38", "39", "3a", "3b", "3c", "3d", "3e", "3f", + "40", "41", "42", "43", "44", "45", "46", "47", + "48", "49", "4a", "4b", "4c", "4d", "4e", "4f", + "50", "51", "52", "53", "54", "55", "56", "57", + "58", "59", "5a", "5b", "5c", "5d", "5e", "5f", + "60", "61", "62", "63", "64", "65", "66", "67", + "68", "69", "6a", "6b", "6c", "6d", "6e", "6f", + "70", "71", "72", "73", "74", "75", "76", "77", + "78", "79", "7a", "7b", "7c", "7d", "7e", "7f", + "80", "81", "82", "83", "84", "85", "86", "87", + "88", "89", "8a", "8b", "8c", "8d", "8e", "8f", + "90", "91", "92", "93", "94", "95", "96", "97", + "98", "99", "9a", "9b", "9c", "9d", "9e", "9f", + "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", + "a8", "a9", "aa", "ab", "ac", "ad", "ae", "af", + "b0", "b1", "b2", "b3", "b4", "b5", "b6", "b7", + "b8", "b9", "ba", "bb", "bc", "bd", "be", "bf", + "c0", "c1", "c2", "c3", "c4", "c5", "c6", "c7", + "c8", "c9", "ca", "cb", "cc", "cd", "ce", "cf", + "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", + "d8", "d9", "da", "db", "dc", "dd", "de", "df", + "e0", "e1", "e2", "e3", "e4", "e5", "e6", "e7", + "e8", "e9", "ea", "eb", "ec", "ed", "ee", "ef", + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", + "f8", "f9", "fa", "fb", "fc", "fd", "fe", "ff" + }; + + // get hexadecimal hash from data + std::string getHash(const std::string& data) { + this->ctx_init(); + this->ctx_update(reinterpret_cast(const_cast(data.c_str())), data.length()); + this->ctx_final(); + + return this->bytesToHexString(); + } + + // get hexadecimal hash from file + std::string getHash(const std::filesystem::path& path) { + std::ifstream file(path, std::ios::binary); + std::vector buf(1024 * 1024, 0); + + this->ctx_init(); + while (file) { + file.read(buf.data(), buf.size()); + this->ctx_update(reinterpret_cast(buf.data()), file.gcount()); + } + this->ctx_final(); + + return this->bytesToHexString(); + } + + // get hexadecimal HMAC from key-data pair + std::string getHMAC(const std::string& key, const std::string& data) { + return this->HMAC(key, data); + } + + protected: + // virtual functions to be overridden by each algorithm implementation. + virtual std::vector getBytes() = 0; + virtual void ctx_init() = 0; + virtual void ctx_update(const uint8_t*, size_t) = 0; + virtual void ctx_final() = 0; + + // H as defined in https://www.rfc-editor.org/rfc/rfc2104 for + // Keyed-Hashing for Message Authentication + virtual std::string _H(const std::string&, const std::string&) = 0; + virtual std::string HMAC(const std::string&, const std::string&) = 0; + + // Helper function to convert hex string to bytes and return them in a vector + std::vector fromHex(const std::string& hex) { + std::vector bytes; + for (size_t i = 0; i < hex.length(); i += 2) { + std::string byteString = hex.substr(i, 2); + uint8_t byte = static_cast(strtol(byteString.c_str(), NULL, 16)); + bytes.push_back(byte); + } + return bytes; + } + + private: + std::string bytesToHexString() { + const std::vector digest = this->getBytes(); + std::string hash; + + for (const auto& d : digest) { + hash += this->hexTable[d]; + } + + return hash; + } + }; + + // Message Digest (MDX) hash family - excluding MD6 + namespace MD { + class MD5 : public common { + protected: + std::vector getBytes() override { + return std::vector(context.digest, context.digest + 16); + } + + // private members + private: + const uint8_t BLOCK_SIZE = 64, DIGEST_SIZE = 16; + + typedef struct { + uint64_t size; + uint32_t buf[4]; + uint8_t in[64], digest[16]; + } CTX; + + // CTX context instance + CTX context = { 0 }; + + // per-round shift amounts + // as per: https://en.wikipedia.org/wiki/MD5#Pseudocode + const uint8_t S[64] = { + 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, + 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, + 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, + 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21 + }; + + // as per: https://en.wikipedia.org/wiki/MD5#Pseudocode + const uint32_t K[64] = { + 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 + }; + + // pad data for when we need to... well.. pad to appropriate size + uint8_t pad[64] = { + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + // MD5 algorithm-defined constants + // as per: https://en.wikipedia.org/wiki/MD5#Pseudocode + const uint32_t A = 0x67452301; + const uint32_t B = 0xefcdab89; + const uint32_t C = 0x98badcfe; + const uint32_t D = 0x10325476; + + // the byte 0x36 repeated 'B' times where 'B' => block size + std::vector ipad = { + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36 + }; + + // the byte 0x5c repeated 'B' times + std::vector opad = { + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c + }; + + // private class methods + private: + // initialize our context for this hash function + inline void ctx_init() override; + inline void ctx_transform(const uint32_t* data); + inline void ctx_update(const uint8_t* data, size_t len) override; + inline void ctx_final() override; + + inline std::string _H(const std::string& a, const std::string& b) override; + inline std::string HMAC(const std::string& key, const std::string& data) override; + + // auxiliary functions defined by the algorithm + // as per: https://en.wikipedia.org/wiki/MD5#Algorithm + constexpr uint32_t F(const uint32_t B, const uint32_t C, const uint32_t D); + constexpr uint32_t G(const uint32_t B, const uint32_t C, const uint32_t D); + constexpr uint32_t H(const uint32_t B, const uint32_t C, const uint32_t D); + constexpr uint32_t I(const uint32_t B, const uint32_t C, const uint32_t D); + }; + class MD4 : public common { + protected: + std::vector getBytes() override { + return std::vector(context.digest, context.digest + 16); + } + + // private members + private: + const uint8_t BLOCK_SIZE = 64, DIGEST_SIZE = 16; + + typedef struct { + uint64_t size; + uint32_t buf[4]; + uint8_t in[64], digest[16]; + } CTX; + + // CTX context instance + CTX context = { 0 }; + + const uint8_t S[64] = { + 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, + 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, + 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, + 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21 + }; + + const uint32_t K[64] = { + 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 + }; + + // pad data for when we need to... well.. pad to appropriate size + uint8_t pad[64] = { + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + // algorithm-defined constants + const uint32_t A = 0x67452301; + const uint32_t B = 0xefcdab89; + const uint32_t C = 0x98badcfe; + const uint32_t D = 0x10325476; + + // the byte 0x36 repeated 'B' times where 'B' => block size + std::vector ipad = { + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36 + }; + + // the byte 0x5c repeated 'B' times + std::vector opad = { + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c + }; + + // private class methods + private: + // initialize our context for this hash function + inline void ctx_init() override; + inline void ctx_transform(const uint32_t* data); + inline void ctx_update(const uint8_t* data, size_t len) override; + inline void ctx_final() override; + + inline std::string _H(const std::string& a, const std::string& b) override; + inline std::string HMAC(const std::string& key, const std::string& data) override; + + // auxiliary functions defined by the algorithm + // as per: http://practicalcryptography.com/hashes/md4-hash/ + constexpr uint32_t F(const uint32_t B, const uint32_t C, const uint32_t D); + constexpr uint32_t G(const uint32_t B, const uint32_t C, const uint32_t D); + constexpr uint32_t H(const uint32_t B, const uint32_t C, const uint32_t D); + + // round functions + constexpr void R1(uint32_t& a, const uint32_t b, const uint32_t c, const uint32_t d, const uint32_t k, const uint32_t s); + constexpr void R2(uint32_t& a, const uint32_t b, const uint32_t c, const uint32_t d, const uint32_t k, const uint32_t s); + constexpr void R3(uint32_t& a, const uint32_t b, const uint32_t c, const uint32_t d, const uint32_t k, const uint32_t s); + }; + class MD2 : public common { + protected: + std::vector getBytes() override { + return std::vector(context.digest, context.digest + 16); + } + + // private members + private: + const uint8_t BLOCK_SIZE = 16, DIGEST_SIZE = 16; + + typedef struct { + uint8_t buf[16], state[48], checksum[16], digest[16]; + uint64_t size; + } CTX; + + CTX context = { 0 }; + + // S-table values for MD2 algorithm + // as per: https://en.wikipedia.org/wiki/MD2_(hash_function)#Description + const uint8_t S[256] = { + 0x29, 0x2E, 0x43, 0xC9, 0xA2, 0xD8, 0x7C, 0x01, 0x3D, 0x36, 0x54, 0xA1, 0xEC, 0xF0, 0x06, 0x13, + 0x62, 0xA7, 0x05, 0xF3, 0xC0, 0xC7, 0x73, 0x8C, 0x98, 0x93, 0x2B, 0xD9, 0xBC, 0x4C, 0x82, 0xCA, + 0x1E, 0x9B, 0x57, 0x3C, 0xFD, 0xD4, 0xE0, 0x16, 0x67, 0x42, 0x6F, 0x18, 0x8A, 0x17, 0xE5, 0x12, + 0xBE, 0x4E, 0xC4, 0xD6, 0xDA, 0x9E, 0xDE, 0x49, 0xA0, 0xFB, 0xF5, 0x8E, 0xBB, 0x2F, 0xEE, 0x7A, + 0xA9, 0x68, 0x79, 0x91, 0x15, 0xB2, 0x07, 0x3F, 0x94, 0xC2, 0x10, 0x89, 0x0B, 0x22, 0x5F, 0x21, + 0x80, 0x7F, 0x5D, 0x9A, 0x5A, 0x90, 0x32, 0x27, 0x35, 0x3E, 0xCC, 0xE7, 0xBF, 0xF7, 0x97, 0x03, + 0xFF, 0x19, 0x30, 0xB3, 0x48, 0xA5, 0xB5, 0xD1, 0xD7, 0x5E, 0x92, 0x2A, 0xAC, 0x56, 0xAA, 0xC6, + 0x4F, 0xB8, 0x38, 0xD2, 0x96, 0xA4, 0x7D, 0xB6, 0x76, 0xFC, 0x6B, 0xE2, 0x9C, 0x74, 0x04, 0xF1, + 0x45, 0x9D, 0x70, 0x59, 0x64, 0x71, 0x87, 0x20, 0x86, 0x5B, 0xCF, 0x65, 0xE6, 0x2D, 0xA8, 0x02, + 0x1B, 0x60, 0x25, 0xAD, 0xAE, 0xB0, 0xB9, 0xF6, 0x1C, 0x46, 0x61, 0x69, 0x34, 0x40, 0x7E, 0x0F, + 0x55, 0x47, 0xA3, 0x23, 0xDD, 0x51, 0xAF, 0x3A, 0xC3, 0x5C, 0xF9, 0xCE, 0xBA, 0xC5, 0xEA, 0x26, + 0x2C, 0x53, 0x0D, 0x6E, 0x85, 0x28, 0x84, 0x09, 0xD3, 0xDF, 0xCD, 0xF4, 0x41, 0x81, 0x4D, 0x52, + 0x6A, 0xDC, 0x37, 0xC8, 0x6C, 0xC1, 0xAB, 0xFA, 0x24, 0xE1, 0x7B, 0x08, 0x0C, 0xBD, 0xB1, 0x4A, + 0x78, 0x88, 0x95, 0x8B, 0xE3, 0x63, 0xE8, 0x6D, 0xE9, 0xCB, 0xD5, 0xFE, 0x3B, 0x00, 0x1D, 0x39, + 0xF2, 0xEF, 0xB7, 0x0E, 0x66, 0x58, 0xD0, 0xE4, 0xA6, 0x77, 0x72, 0xF8, 0xEB, 0x75, 0x4B, 0x0A, + 0x31, 0x44, 0x50, 0xB4, 0x8F, 0xED, 0x1F, 0x1A, 0xDB, 0x99, 0x8D, 0x33, 0x9F, 0x11, 0x83, 0x14 + }; + + // the byte 0x36 repeated 'B' times where 'B' => block size + std::vector ipad = { + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36 + }; + + // the byte 0x5c repeated 'B' times + std::vector opad = { + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c + }; + + inline void ctx_init() override; + inline void ctx_transform(const uint8_t* data); + inline void ctx_update(const uint8_t* data, size_t len) override; + inline void ctx_final() override; + + inline std::string _H(const std::string& a, const std::string& b) override; + inline std::string HMAC(const std::string& key, const std::string& data) override; + }; + + // MD5 + inline void hashpp::MD::MD5::ctx_init() { + this->context = { + 0, + {this->A, this->B, this->C, this->D} + }; + } + inline void hashpp::MD::MD5::ctx_transform(const uint32_t* data) { + uint32_t results[4] = { + this->context.buf[0], // a0 + this->context.buf[1], // b0 + this->context.buf[2], // c0 + this->context.buf[3] // d0 + }; + + uint32_t E, j, t; + for (uint32_t i = 0; i < 64; ++i) { + switch (i / 16) { + case 0: + { + E = this->F(results[1], results[2], results[3]); + j = i; + break; + } + case 1: + { + E = this->G(results[1], results[2], results[3]); + j = ((i * 5) + 1) % 16; + break; + } + case 2: + { + E = this->H(results[1], results[2], results[3]); + j = ((i * 3) + 5) % 16; + break; + } + default: + { + E = this->I(results[1], results[2], results[3]); + j = (i * 7) % 16; + break; + } + } + + t = results[3]; + results[3] = results[2]; results[2] = results[1]; + results[1] = results[1] + this->rl32(results[0] + E + K[i] + data[j], S[i]); + results[0] = t; + } + + for (uint32_t z = 0; z < 4; z++) { + this->context.buf[z] += results[z]; + } + } + inline void hashpp::MD::MD5::ctx_update(const uint8_t* data, size_t len) { + uint32_t input[16], offset = this->context.size % 64; + this->context.size += static_cast(len); + + for (uint32_t i = 0; i < len; ++i) { + this->context.in[offset++] = static_cast(*(data + i)); + + if (offset % 64 == 0) { + for (uint32_t j = 0; j < 16; ++j) { + input[j] = static_cast(this->context.in[(j * 4) + 3]) << 24 | + static_cast(this->context.in[(j * 4) + 2]) << 16 | + static_cast(this->context.in[(j * 4) + 1]) << 8 | + static_cast(this->context.in[(j * 4)]); + } + this->ctx_transform(input); + offset = 0; + } + } + } + inline void hashpp::MD::MD5::ctx_final() { + uint32_t input[16]; + uint32_t offset = this->context.size % 64; + uint32_t plen = offset < 56 ? 56 - offset : (56 + 64) - offset; + + this->ctx_update(this->pad, plen); + this->context.size -= static_cast(plen); + + for (uint32_t j = 0; j < 14; ++j) { + input[j] = static_cast(this->context.in[(j * 4) + 3]) << 24 | + static_cast(this->context.in[(j * 4) + 2]) << 16 | + static_cast(this->context.in[(j * 4) + 1]) << 8 | + static_cast(this->context.in[(j * 4)]); + } + input[14] = static_cast(this->context.size * 8); + input[15] = static_cast((this->context.size * 8) >> 32); + + this->ctx_transform(input); + + for (uint32_t i = 0; i < 4; ++i) { + this->context.digest[(i * 4) + 0] = static_cast((this->context.buf[i] & 0x000000FF)); + this->context.digest[(i * 4) + 1] = static_cast((this->context.buf[i] & 0x0000FF00) >> 8); + this->context.digest[(i * 4) + 2] = static_cast((this->context.buf[i] & 0x00FF0000) >> 16); + this->context.digest[(i * 4) + 3] = static_cast((this->context.buf[i] & 0xFF000000) >> 24); + } + } + inline std::string MD5::_H(const std::string& a, const std::string& b) { + return this->getHash(a + b); + } + inline std::string MD5::HMAC(const std::string& key, const std::string& data) { + uint8_t k[64] = {0}; + + // (1) append zeros to the end of K to create a B byte string + // (e.g., if K is of length 20 bytes and B = 64, then K will be + // appended with 44 zero bytes 0x00) where B is the block size + if (key.length() > this->BLOCK_SIZE) { + // if K is longer than B bytes, reset K to K=H(K) + // where K can either be composed of entirely bytes of H(K) + // (if H(K) == L [where L => digest]) or the first L bytes of + // H(K) (if H(K) != L) followed by the remaining zeros (if H(K) < L) + std::vector k_ = this->fromHex(this->getHash(key)); + for (uint32_t i = 0; i < this->DIGEST_SIZE; ++i) { + k[i] = k_[i]; + } + } + else { + // if K is shorter than B bytes, append zeros to the end of K + // until K is B bytes long + for (uint32_t i = 0; i < key.length(); ++i) { + k[i] = key[i]; + } + } + + // (2) XOR (bitwise exclusive-OR) the B byte string computed in step (1) with ipad + for (uint32_t i = 0; i < this->BLOCK_SIZE; ++i) { + this->ipad[i] ^= k[i]; + } + + // (3) append the stream of data 'data' to the B byte string resulting from step (2) + for (uint32_t i = 0; i < data.length(); ++i) { + this->ipad.push_back(data[i]); + } + + // (4) apply H to the stream generated in step (3) + // see step (6) + + // (5) XOR (bitwise exclusive-OR) the B byte string computed in step (1) with opad + for (uint32_t i = 0; i < this->BLOCK_SIZE; ++i) { + this->opad[i] ^= k[i]; + } + + // (6) append the H result from step (4) to the B byte string resulting from step (5) + std::vector h_ = this->fromHex(this->getHash(std::string(this->ipad.begin(), this->ipad.end()))); + for (uint32_t i = 0; i < this->DIGEST_SIZE; ++i) { + this->opad.push_back(h_[i]); + } + + // (7) apply H to the stream generated in step (6) and output the result + return this->getHash(std::string(this->opad.begin(), this->opad.end())); + } + constexpr uint32_t hashpp::MD::MD5::F(const uint32_t B, const uint32_t C, const uint32_t D) { return ((B & C) | (~B & D)); } + constexpr uint32_t hashpp::MD::MD5::G(const uint32_t B, const uint32_t C, const uint32_t D) { return ((B & D) | (C & ~D)); } + constexpr uint32_t hashpp::MD::MD5::H(const uint32_t B, const uint32_t C, const uint32_t D) { return ((B ^ C ^ D)); } + constexpr uint32_t hashpp::MD::MD5::I(const uint32_t B, const uint32_t C, const uint32_t D) { return (C ^ (B | ~D)); } + + // MD4 + inline void hashpp::MD::MD4::ctx_init() { + this->context = { + 0, + {this->A, this->B, this->C, this->D} + }; + } + inline void hashpp::MD::MD4::ctx_transform(const uint32_t* data) { + uint32_t results[4] { + this->context.buf[0], // a0 + this->context.buf[1], // b0 + this->context.buf[2], // c0 + this->context.buf[3] // d0 + }; + + // perform rounds as described by the algorithm + // as per: http://practicalcryptography.com/hashes/md4-hash/ + for (uint32_t i = 0, j = 0; i < 4; ++i, j += 4) { + this->R1(results[0], results[1], results[2], results[3], data[j], 3); + this->R1(results[3], results[0], results[1], results[2], data[j + 1], 7); + this->R1(results[2], results[3], results[0], results[1], data[j + 2], 11); + this->R1(results[1], results[2], results[3], results[0], data[j + 3], 19); + } + + for (uint32_t i = 0; i < 4; ++i) { + this->R2(results[0], results[1], results[2], results[3], data[0 + i], 3); + this->R2(results[3], results[0], results[1], results[2], data[4 + i], 5); + this->R2(results[2], results[3], results[0], results[1], data[8 + i], 9); + this->R2(results[1], results[2], results[3], results[0], data[12 + i], 13); + } + + for (uint32_t i = 0, _h = 0; i < 4; ++i) { + i == 1 ? _h = 2 : 0; i == 2 ? _h = 1 : 0; i == 3 ? _h = 3 : 0; + this->R3(results[0], results[1], results[2], results[3], data[0 + _h], 3); + this->R3(results[3], results[0], results[1], results[2], data[8 + _h], 9); + this->R3(results[2], results[3], results[0], results[1], data[4 + _h], 11); + this->R3(results[1], results[2], results[3], results[0], data[12 + _h], 15); + } + + for (uint32_t z = 0; z < 4; z++) { + this->context.buf[z] += results[z]; + } + } + inline void hashpp::MD::MD4::ctx_update(const uint8_t* data, size_t len) { + uint32_t input[16], offset = this->context.size % 64; + this->context.size += static_cast(len); + + for (uint32_t i = 0; i < len; ++i) { + this->context.in[offset++] = static_cast(*(data + i)); + + if (offset % 64 == 0) { + for (uint32_t j = 0; j < 16; ++j) { + input[j] = static_cast(this->context.in[(j * 4) + 3]) << 24 | + static_cast(this->context.in[(j * 4) + 2]) << 16 | + static_cast(this->context.in[(j * 4) + 1]) << 8 | + static_cast(this->context.in[(j * 4)]); + } + this->ctx_transform(input); + offset = 0; + } + } + } + inline void hashpp::MD::MD4::ctx_final() { + uint32_t input[16]; + uint32_t offset = this->context.size % 64, plen = offset < 56 ? 56 - offset : (56 + 64) - offset; + + this->ctx_update(this->pad, plen); + this->context.size -= static_cast(plen); + + for (uint32_t j = 0; j < 14; ++j) { + input[j] = static_cast(this->context.in[(j * 4) + 3]) << 24 | + static_cast(this->context.in[(j * 4) + 2]) << 16 | + static_cast(this->context.in[(j * 4) + 1]) << 8 | + static_cast(this->context.in[(j * 4)]); + } + input[14] = static_cast(this->context.size * 8); + input[15] = static_cast((this->context.size * 8) >> 32); + + this->ctx_transform(input); + + // move to digest as big-endian + // as per: https://stackoverflow.com/questions/19275955/convert-little-endian-to-big-endian/19276193 + for (uint32_t i = 0; i < 4; ++i) { + this->context.digest[(i * 4) + 0] = static_cast((this->context.buf[i] & 0x000000FF)); + this->context.digest[(i * 4) + 1] = static_cast((this->context.buf[i] & 0x0000FF00) >> 8); + this->context.digest[(i * 4) + 2] = static_cast((this->context.buf[i] & 0x00FF0000) >> 16); + this->context.digest[(i * 4) + 3] = static_cast((this->context.buf[i] & 0xFF000000) >> 24); + } + } + inline std::string MD4::_H(const std::string& a, const std::string& b) { + return this->getHash(a + b); + } + inline std::string MD4::HMAC(const std::string& key, const std::string& data) { + uint8_t k[64] = {0}; + + // (1) append zeros to the end of K to create a B byte string + // (e.g., if K is of length 20 bytes and B = 64, then K will be + // appended with 44 zero bytes 0x00) where B is the block size + if (key.length() > this->BLOCK_SIZE) { + // if K is longer than B bytes, reset K to K=H(K) + // where K can either be composed of entirely bytes of H(K) + // (if H(K) == L [where L => digest]) or the first L bytes of + // H(K) (if H(K) != L) followed by the remaining zeros (if H(K) < L) + std::vector k_ = this->fromHex(this->getHash(key)); + for (uint32_t i = 0; i < this->DIGEST_SIZE; ++i) { + k[i] = k_[i]; + } + } + else { + // if K is shorter than B bytes, append zeros to the end of K + // until K is B bytes long + for (uint32_t i = 0; i < key.length(); ++i) { + k[i] = key[i]; + } + } + + // (2) XOR (bitwise exclusive-OR) the B byte string computed in step (1) with ipad + for (uint32_t i = 0; i < this->BLOCK_SIZE; ++i) { + this->ipad[i] ^= k[i]; + } + + // (3) append the stream of data 'data' to the B byte string resulting from step (2) + for (uint32_t i = 0; i < data.length(); ++i) { + this->ipad.push_back(data[i]); + } + + // (4) apply H to the stream generated in step (3) + // see step (6) + + // (5) XOR (bitwise exclusive-OR) the B byte string computed in step (1) with opad + for (uint32_t i = 0; i < this->BLOCK_SIZE; ++i) { + this->opad[i] ^= k[i]; + } + + // (6) append the H result from step (4) to the B byte string resulting from step (5) + std::vector h_ = this->fromHex(this->getHash(std::string(this->ipad.begin(), this->ipad.end()))); + for (uint32_t i = 0; i < this->DIGEST_SIZE; ++i) { + this->opad.push_back(h_[i]); + } + + // (7) apply H to the stream generated in step (6) and output the result + return this->getHash(std::string(this->opad.begin(), this->opad.end())); + } + constexpr uint32_t hashpp::MD::MD4::F(const uint32_t B, const uint32_t C, const uint32_t D) { return ((B & C) | (~B & D)); } + constexpr uint32_t hashpp::MD::MD4::G(const uint32_t B, const uint32_t C, const uint32_t D) { return ((B & C) | (B & D) | (C & D)); } + constexpr uint32_t hashpp::MD::MD4::H(const uint32_t B, const uint32_t C, const uint32_t D) { return ((B ^ C ^ D)); } + constexpr void hashpp::MD::MD4::R1(uint32_t& a, const uint32_t b, const uint32_t c, const uint32_t d, const uint32_t k, const uint32_t s) { + a = this->rl32(a + this->F(b, c, d) + k, s); + } + constexpr void hashpp::MD::MD4::R2(uint32_t& a, const uint32_t b, const uint32_t c, const uint32_t d, const uint32_t k, const uint32_t s) { + a = this->rl32(a + this->G(b, c, d) + k + static_cast(0x5A827999), s); + } + constexpr void hashpp::MD::MD4::R3(uint32_t& a, const uint32_t b, const uint32_t c, const uint32_t d, const uint32_t k, const uint32_t s) { + a = this->rl32(a + this->H(b, c, d) + k + static_cast(0x6ED9EBA1), s); + } + + // MD2 + inline void hashpp::MD::MD2::ctx_init() { + memset(this->context.state, 0, 48); + memset(this->context.checksum, 0, 16); + memset(this->context.buf, 0, 16); + memset(this->context.digest, 0, 16); + this->context.size = 0; + } + inline void hashpp::MD::MD2::ctx_transform(const uint8_t* data) { + uint32_t j, k, t; + + for (j = 0; j < 16; ++j) { + this->context.state[j + 16] = data[j]; + this->context.state[j + 32] = (this->context.state[j + 16] ^ this->context.state[j]); + } + + t = 0; + for (j = 0; j < 18; ++j) { + for (k = 0; k < 48; ++k) { + this->context.state[k] ^= this->S[t]; + t = this->context.state[k]; + } + t = (t + j) & 0xFF; + } + + t = this->context.checksum[15]; + for (j = 0; j < 16; ++j) { + this->context.checksum[j] ^= this->S[data[j] ^ t]; + t = this->context.checksum[j]; + } + } + inline void hashpp::MD::MD2::ctx_update(const uint8_t* data, size_t len) { + for (uint16_t i = 0; i < len; ++i) { + this->context.buf[this->context.size] = data[i]; + this->context.size++; + if (this->context.size == 16) { + ctx_transform(this->context.buf); + this->context.size = 0; + } + } + } + inline void hashpp::MD::MD2::ctx_final() { + uint32_t pad = 16 - this->context.size; + while (this->context.size < 16) { + this->context.buf[this->context.size++] = pad; + } + ctx_transform(this->context.buf); + ctx_transform(this->context.checksum); + memcpy(this->context.digest, this->context.state, 16); + } + inline std::string MD2::_H(const std::string& a, const std::string& b) { + return this->getHash(a + b); + } + inline std::string MD2::HMAC(const std::string& key, const std::string& data) { + uint8_t k[16] = {0}; + + // (1) append zeros to the end of K to create a B byte string + // (e.g., if K is of length 20 bytes and B = 64, then K will be + // appended with 44 zero bytes 0x00) where B is the block size + if (key.length() > this->BLOCK_SIZE) { + // if K is longer than B bytes, reset K to K=H(K) + // where K can either be composed of entirely bytes of H(K) + // (if H(K) == L [where L => digest]) or the first L bytes of + // H(K) (if H(K) != L) followed by the remaining zeros (if H(K) < L) + std::vector k_ = this->fromHex(this->getHash(key)); + for (uint32_t i = 0; i < this->DIGEST_SIZE; ++i) { + k[i] = k_[i]; + } + } + else { + // if K is shorter than B bytes, append zeros to the end of K + // until K is B bytes long + for (uint32_t i = 0; i < key.length(); ++i) { + k[i] = key[i]; + } + } + + // (2) XOR (bitwise exclusive-OR) the B byte string computed in step (1) with ipad + for (uint32_t i = 0; i < this->BLOCK_SIZE; ++i) { + this->ipad[i] ^= k[i]; + } + + // (3) append the stream of data 'data' to the B byte string resulting from step (2) + for (uint32_t i = 0; i < data.length(); ++i) { + this->ipad.push_back(data[i]); + } + + // (4) apply H to the stream generated in step (3) + // see step (6) + + // (5) XOR (bitwise exclusive-OR) the B byte string computed in step (1) with opad + for (uint32_t i = 0; i < this->BLOCK_SIZE; ++i) { + this->opad[i] ^= k[i]; + } + + // (6) append the H result from step (4) to the B byte string resulting from step (5) + std::vector h_ = this->fromHex(this->getHash(std::string(this->ipad.begin(), this->ipad.end()))); + for (uint32_t i = 0; i < this->DIGEST_SIZE; ++i) { + this->opad.push_back(h_[i]); + } + + // (7) apply H to the stream generated in step (6) and output the result + return this->getHash(std::string(this->opad.begin(), this->opad.end())); + } + } + + // Secure Hash Algorithm (SHA) hash family + namespace SHA { + // SHA algorithms, such as SHA2-224, SHA2-384, + // SHA2-512-224, and SHA2-512-256 are simply + // truncated versions of their accompanying + // algorithm. + // + // for instance, SHA2-512-256 is SHA-512 + // truncated to a 256-bit digest length. + // likewise, SHA2-224 is SHA2-256 truncated + // to a 224-bit digest length. + // + // these truncations are achieved via the + // omission of trailing H-constants from + // the digest output, as well as different + // H-constant values from the orignal + // algorithm. + + class SHA1 : public common { + protected: + std::vector getBytes() override { + return std::vector(context.digest, context.digest + 20); + } + + private: + const uint8_t BLOCK_SIZE = 64, DIGEST_SIZE = 20; + + typedef struct { + uint32_t state[5], k[4], size; + uint64_t bitsize; + uint8_t data[64], digest[20]; + } CTX; + + CTX context = { 0 }; + + // constants (H) defined by SHA-1 algorithm + // as per: https://datatracker.ietf.org/doc/html/rfc3174 + const uint32_t H[5] = { + 0x67452301, + 0xEFCDAB89, + 0x98BADCFE, + 0x10325476, + 0xc3d2e1f0 + }; + + // more constants (K)... as per above + const uint32_t K[4] = { + 0x5a827999, + 0x6ed9eba1, + 0x8f1bbcdc, + 0xca62c1d6 + }; + + // the byte 0x36 repeated 'B' times where 'B' => block size + std::vector ipad = { + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36 + }; + + // the byte 0x5c repeated 'B' times + std::vector opad = { + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c + }; + + inline void ctx_init() override; + inline void ctx_transform(const uint8_t* data); + inline void ctx_update(const uint8_t* data, size_t len) override; + inline void ctx_final() override; + + inline std::string _H(const std::string& a, const std::string& b) override; + inline std::string HMAC(const std::string& key, const std::string& data) override; + + // SHA-1 functions defined by the algorithm + constexpr uint32_t A(const uint32_t A, const uint32_t B, const uint32_t C, const uint32_t D); + constexpr uint32_t B(const uint32_t A, const uint32_t B, const uint32_t C, const uint32_t D); + constexpr uint32_t C(const uint32_t A); + + // ...and more defined functions... + constexpr uint32_t F(const uint32_t B, const uint32_t C, const uint32_t D); + constexpr uint32_t G(const uint32_t B, const uint32_t C, const uint32_t D); + constexpr uint32_t J(const uint32_t B, const uint32_t C, const uint32_t D); + }; + class SHA2_224 : public common { + protected: + std::vector getBytes() override { + return std::vector(context.digest, context.digest + 28); + } + + private: + const uint8_t BLOCK_SIZE = 64, DIGEST_SIZE = 28; + + typedef struct { + uint32_t state[8]; + uint64_t size, bitsize; + uint8_t data[64], digest[28]; + } CTX; + + CTX context = { 0 }; + + // constants (H) defined by SHA2-224 algorithm + // as per: https://datatracker.ietf.org/doc/html/rfc3874 + const uint32_t H[8] = { + 0xC1059ED8, + 0x367CD507, + 0x3070DD17, + 0xF70E5939, + 0xFFC00B31, + 0x68581511, + 0x64F98FA7, + 0xBEFA4FA4 + }; + + // more constants (K)... as per above + const uint32_t K[64] = { + 0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5, + 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5, + 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3, + 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174, + 0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC, + 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA, + 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7, + 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967, + 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13, + 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85, + 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3, + 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070, + 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5, + 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3, + 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208, + 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2 + }; + + // the byte 0x36 repeated 'B' times where 'B' => block size + std::vector ipad = { + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36 + }; + + // the byte 0x5c repeated 'B' times + std::vector opad = { + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c + }; + + inline void ctx_init() override; + inline void ctx_transform(const uint8_t* data); + inline void ctx_update(const uint8_t* data, size_t len) override; + inline void ctx_final() override; + + inline std::string _H(const std::string& a, const std::string& b) override; + inline std::string HMAC(const std::string& key, const std::string& data) override; + + constexpr uint32_t A(const uint32_t A, const uint32_t B, const uint32_t C, const uint32_t D); + constexpr uint32_t F(const uint32_t B, const uint32_t C, const uint32_t D); + constexpr uint32_t G(const uint32_t B, const uint32_t C, const uint32_t D); + + // Sigma functions + // as per: https://datatracker.ietf.org/doc/html/rfc6234 + constexpr uint32_t SIGMA0(const uint32_t A); + constexpr uint32_t SIGMA1(const uint32_t A); + constexpr uint32_t SIGMA2(const uint32_t A); + constexpr uint32_t SIGMA3(const uint32_t A); + }; + class SHA2_256 : public common { + protected: + std::vector getBytes() override { + return std::vector(context.digest, context.digest + 32); + } + + private: + const uint8_t BLOCK_SIZE = 64, DIGEST_SIZE = 32; + + typedef struct { + uint32_t state[8], size; + uint64_t bitsize; + uint8_t data[64], digest[32]; + } CTX; + + CTX context = { 0 }; + + // constants (H) defined by SHA-256 algorithm + // as per: https://datatracker.ietf.org/doc/html/rfc6234 + const uint32_t H[8] = { + 0x6a09e667, + 0xbb67ae85, + 0x3c6ef372, + 0xa54ff53a, + 0x510e527f, + 0x9b05688c, + 0x1f83d9ab, + 0x5be0cd19 + }; + + // more constants (K)... as per above + const uint32_t K[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 + }; + + // the byte 0x36 repeated 'B' times where 'B' => block size + std::vector ipad = { + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36 + }; + + // the byte 0x5c repeated 'B' times + std::vector opad = { + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c + }; + + inline void ctx_init() override; + inline void ctx_transform(const uint8_t* data); + inline void ctx_update(const uint8_t* data, size_t len) override; + inline void ctx_final() override; + + inline std::string _H(const std::string& a, const std::string& b) override; + inline std::string HMAC(const std::string& key, const std::string& data) override; + + constexpr uint32_t A(const uint32_t A, const uint32_t B, const uint32_t C, const uint32_t D); + constexpr uint32_t F(const uint32_t B, const uint32_t C, const uint32_t D); + constexpr uint32_t G(const uint32_t B, const uint32_t C, const uint32_t D); + + // Sigma functions + // as per: https://datatracker.ietf.org/doc/html/rfc6234 + constexpr uint32_t SIGMA0(const uint32_t A); + constexpr uint32_t SIGMA1(const uint32_t A); + constexpr uint32_t SIGMA2(const uint32_t A); + constexpr uint32_t SIGMA3(const uint32_t A); + }; + class SHA2_384 : public common { + protected: + std::vector getBytes() override { + return std::vector(context.digest, context.digest + 48); + } + + private: + const uint8_t BLOCK_SIZE = 128, DIGEST_SIZE = 48; + + typedef struct { + uint64_t state[8], count[2]; + uint8_t data[128], digest[48]; + } CTX; + + CTX context = { 0 }; + + // constants (H) defined by SHA-512 algorithm + // as per: https://datatracker.ietf.org/doc/html/rfc4634 + const uint64_t H[8] = { + 0xCBBB9D5DC1059ED8, + 0x629A292A367CD507, + 0x9159015A3070DD17, + 0x152FECD8F70E5939, + 0x67332667FFC00B31, + 0x8EB44A8768581511, + 0xDB0C2E0D64F98FA7, + 0x47B5481DBEFA4FA4 + }; + + // more constants (K)... as per above + const uint64_t K[80] = { + 0x428A2F98D728AE22, 0x7137449123EF65CD, 0xB5C0FBCFEC4D3B2F, 0xE9B5DBA58189DBBC, + 0x3956C25BF348B538, 0x59F111F1B605D019, 0x923F82A4AF194F9B, 0xAB1C5ED5DA6D8118, + 0xD807AA98A3030242, 0x12835B0145706FBE, 0x243185BE4EE4B28C, 0x550C7DC3D5FFB4E2, + 0x72BE5D74F27B896F, 0x80DEB1FE3B1696B1, 0x9BDC06A725C71235, 0xC19BF174CF692694, + 0xE49B69C19EF14AD2, 0xEFBE4786384F25E3, 0x0FC19DC68B8CD5B5, 0x240CA1CC77AC9C65, + 0x2DE92C6F592B0275, 0x4A7484AA6EA6E483, 0x5CB0A9DCBD41FBD4, 0x76F988DA831153B5, + 0x983E5152EE66DFAB, 0xA831C66D2DB43210, 0xB00327C898FB213F, 0xBF597FC7BEEF0EE4, + 0xC6E00BF33DA88FC2, 0xD5A79147930AA725, 0x06CA6351E003826F, 0x142929670A0E6E70, + 0x27B70A8546D22FFC, 0x2E1B21385C26C926, 0x4D2C6DFC5AC42AED, 0x53380D139D95B3DF, + 0x650A73548BAF63DE, 0x766A0ABB3C77B2A8, 0x81C2C92E47EDAEE6, 0x92722C851482353B, + 0xA2BFE8A14CF10364, 0xA81A664BBC423001, 0xC24B8B70D0F89791, 0xC76C51A30654BE30, + 0xD192E819D6EF5218, 0xD69906245565A910, 0xF40E35855771202A, 0x106AA07032BBD1B8, + 0x19A4C116B8D2D0C8, 0x1E376C085141AB53, 0x2748774CDF8EEB99, 0x34B0BCB5E19B48A8, + 0x391C0CB3C5C95A63, 0x4ED8AA4AE3418ACB, 0x5B9CCA4F7763E373, 0x682E6FF3D6B2B8A3, + 0x748F82EE5DEFB2FC, 0x78A5636F43172F60, 0x84C87814A1F0AB72, 0x8CC702081A6439EC, + 0x90BEFFFA23631E28, 0xA4506CEBDE82BDE9, 0xBEF9A3F7B2C67915, 0xC67178F2E372532B, + 0xCA273ECEEA26619C, 0xD186B8C721C0C207, 0xEADA7DD6CDE0EB1E, 0xF57D4F7FEE6ED178, + 0x06F067AA72176FBA, 0x0A637DC5A2C898A6, 0x113F9804BEF90DAE, 0x1B710B35131C471B, + 0x28DB77F523047D84, 0x32CAAB7B40C72493, 0x3C9EBE0A15C9BEBC, 0x431D67C49C100D4C, + 0x4CC5D4BECB3E42B6, 0x597F299CFC657E2A, 0x5FCB6FAB3AD6FAEC, 0x6C44198C4A475817 + }; + + // the byte 0x36 repeated 'B' times where 'B' => block size + std::vector ipad = { + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36 + }; + + // the byte 0x5c repeated 'B' times + std::vector opad = { + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c + }; + + inline void ctx_init() override; + inline void ctx_transform(const uint8_t* data); + inline void ctx_update(const uint8_t* data, size_t len) override; + inline void ctx_final() override; + + inline std::string _H(const std::string& a, const std::string& b) override; + inline std::string HMAC(const std::string& key, const std::string& data) override; + + constexpr uint64_t F(const uint64_t A, const uint64_t B, const uint64_t C); + constexpr uint64_t G(const uint64_t A, const uint64_t B, const uint64_t C); + + // Sigma functions + // as per: https://datatracker.ietf.org/doc/html/rfc4634 + constexpr uint64_t SIGMA0(const uint64_t A); + constexpr uint64_t SIGMA1(const uint64_t A); + constexpr uint64_t SIGMA2(const uint64_t A); + constexpr uint64_t SIGMA3(const uint64_t A); + }; + class SHA2_512 : public common { + protected: + std::vector getBytes() override { + return std::vector(context.digest, context.digest + 64); + } + + private: + const uint8_t BLOCK_SIZE = 128, DIGEST_SIZE = 64; + + typedef struct { + uint64_t state[8], count[2]; + uint8_t data[128], digest[64]; + } CTX; + + CTX context = { 0 }; + + // constants (H) defined by SHA-512 algorithm + // as per: https://datatracker.ietf.org/doc/html/rfc4634 + const uint64_t H[8] = { + 0x6A09E667F3BCC908, + 0xBB67AE8584CAA73B, + 0x3C6EF372FE94F82B, + 0xA54FF53A5F1D36F1, + 0x510E527FADE682D1, + 0x9B05688C2B3E6C1F, + 0x1F83D9ABFB41BD6B, + 0x5BE0CD19137E2179 + }; + + // more constants (K)... as per above + const uint64_t K[80] = { + 0x428A2F98D728AE22, 0x7137449123EF65CD, 0xB5C0FBCFEC4D3B2F, 0xE9B5DBA58189DBBC, + 0x3956C25BF348B538, 0x59F111F1B605D019, 0x923F82A4AF194F9B, 0xAB1C5ED5DA6D8118, + 0xD807AA98A3030242, 0x12835B0145706FBE, 0x243185BE4EE4B28C, 0x550C7DC3D5FFB4E2, + 0x72BE5D74F27B896F, 0x80DEB1FE3B1696B1, 0x9BDC06A725C71235, 0xC19BF174CF692694, + 0xE49B69C19EF14AD2, 0xEFBE4786384F25E3, 0x0FC19DC68B8CD5B5, 0x240CA1CC77AC9C65, + 0x2DE92C6F592B0275, 0x4A7484AA6EA6E483, 0x5CB0A9DCBD41FBD4, 0x76F988DA831153B5, + 0x983E5152EE66DFAB, 0xA831C66D2DB43210, 0xB00327C898FB213F, 0xBF597FC7BEEF0EE4, + 0xC6E00BF33DA88FC2, 0xD5A79147930AA725, 0x06CA6351E003826F, 0x142929670A0E6E70, + 0x27B70A8546D22FFC, 0x2E1B21385C26C926, 0x4D2C6DFC5AC42AED, 0x53380D139D95B3DF, + 0x650A73548BAF63DE, 0x766A0ABB3C77B2A8, 0x81C2C92E47EDAEE6, 0x92722C851482353B, + 0xA2BFE8A14CF10364, 0xA81A664BBC423001, 0xC24B8B70D0F89791, 0xC76C51A30654BE30, + 0xD192E819D6EF5218, 0xD69906245565A910, 0xF40E35855771202A, 0x106AA07032BBD1B8, + 0x19A4C116B8D2D0C8, 0x1E376C085141AB53, 0x2748774CDF8EEB99, 0x34B0BCB5E19B48A8, + 0x391C0CB3C5C95A63, 0x4ED8AA4AE3418ACB, 0x5B9CCA4F7763E373, 0x682E6FF3D6B2B8A3, + 0x748F82EE5DEFB2FC, 0x78A5636F43172F60, 0x84C87814A1F0AB72, 0x8CC702081A6439EC, + 0x90BEFFFA23631E28, 0xA4506CEBDE82BDE9, 0xBEF9A3F7B2C67915, 0xC67178F2E372532B, + 0xCA273ECEEA26619C, 0xD186B8C721C0C207, 0xEADA7DD6CDE0EB1E, 0xF57D4F7FEE6ED178, + 0x06F067AA72176FBA, 0x0A637DC5A2C898A6, 0x113F9804BEF90DAE, 0x1B710B35131C471B, + 0x28DB77F523047D84, 0x32CAAB7B40C72493, 0x3C9EBE0A15C9BEBC, 0x431D67C49C100D4C, + 0x4CC5D4BECB3E42B6, 0x597F299CFC657E2A, 0x5FCB6FAB3AD6FAEC, 0x6C44198C4A475817 + }; + + // the byte 0x36 repeated 'B' times where 'B' => block size + std::vector ipad = { + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36 + }; + + // the byte 0x5c repeated 'B' times + std::vector opad = { + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c + }; + + inline void ctx_init() override; + inline void ctx_transform(const uint8_t* data); + inline void ctx_update(const uint8_t* data, size_t len) override; + inline void ctx_final() override; + + inline std::string _H(const std::string& a, const std::string& b) override; + inline std::string HMAC(const std::string& key, const std::string& data) override; + + constexpr uint64_t F(const uint64_t A, const uint64_t B, const uint64_t C); + constexpr uint64_t G(const uint64_t A, const uint64_t B, const uint64_t C); + + // Sigma functions + // as per: https://datatracker.ietf.org/doc/html/rfc4634 + constexpr uint64_t SIGMA0(const uint64_t A); + constexpr uint64_t SIGMA1(const uint64_t A); + constexpr uint64_t SIGMA2(const uint64_t A); + constexpr uint64_t SIGMA3(const uint64_t A); + }; + class SHA2_512_224 : public common { + protected: + std::vector getBytes() override { + return std::vector(context.digest, context.digest + 28); + } + + private: + const uint8_t BLOCK_SIZE = 128, DIGEST_SIZE = 28; + + typedef struct { + uint64_t state[8], count[2]; + uint8_t data[128], digest[32]; + } CTX; + + CTX context = { 0 }; + + // constants (H) defined by SHA-512/224 algorithm + // as per: https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/SHA512_224.pdf + const uint64_t H[8] = { + 0x8C3D37C819544DA2, + 0x73E1996689DCD4D6, + 0x1DFAB7AE32FF9C82, + 0x679DD514582F9FCF, + 0x0F6D2B697BD44DA8, + 0x77E36F7304C48942, + 0x3F9D85A86A1D36C8, + 0x1112E6AD91D692A1, + }; + + // more constants (K)... as per above + const uint64_t K[80] = { + 0x428A2F98D728AE22, 0x7137449123EF65CD, 0xB5C0FBCFEC4D3B2F, 0xE9B5DBA58189DBBC, + 0x3956C25BF348B538, 0x59F111F1B605D019, 0x923F82A4AF194F9B, 0xAB1C5ED5DA6D8118, + 0xD807AA98A3030242, 0x12835B0145706FBE, 0x243185BE4EE4B28C, 0x550C7DC3D5FFB4E2, + 0x72BE5D74F27B896F, 0x80DEB1FE3B1696B1, 0x9BDC06A725C71235, 0xC19BF174CF692694, + 0xE49B69C19EF14AD2, 0xEFBE4786384F25E3, 0x0FC19DC68B8CD5B5, 0x240CA1CC77AC9C65, + 0x2DE92C6F592B0275, 0x4A7484AA6EA6E483, 0x5CB0A9DCBD41FBD4, 0x76F988DA831153B5, + 0x983E5152EE66DFAB, 0xA831C66D2DB43210, 0xB00327C898FB213F, 0xBF597FC7BEEF0EE4, + 0xC6E00BF33DA88FC2, 0xD5A79147930AA725, 0x06CA6351E003826F, 0x142929670A0E6E70, + 0x27B70A8546D22FFC, 0x2E1B21385C26C926, 0x4D2C6DFC5AC42AED, 0x53380D139D95B3DF, + 0x650A73548BAF63DE, 0x766A0ABB3C77B2A8, 0x81C2C92E47EDAEE6, 0x92722C851482353B, + 0xA2BFE8A14CF10364, 0xA81A664BBC423001, 0xC24B8B70D0F89791, 0xC76C51A30654BE30, + 0xD192E819D6EF5218, 0xD69906245565A910, 0xF40E35855771202A, 0x106AA07032BBD1B8, + 0x19A4C116B8D2D0C8, 0x1E376C085141AB53, 0x2748774CDF8EEB99, 0x34B0BCB5E19B48A8, + 0x391C0CB3C5C95A63, 0x4ED8AA4AE3418ACB, 0x5B9CCA4F7763E373, 0x682E6FF3D6B2B8A3, + 0x748F82EE5DEFB2FC, 0x78A5636F43172F60, 0x84C87814A1F0AB72, 0x8CC702081A6439EC, + 0x90BEFFFA23631E28, 0xA4506CEBDE82BDE9, 0xBEF9A3F7B2C67915, 0xC67178F2E372532B, + 0xCA273ECEEA26619C, 0xD186B8C721C0C207, 0xEADA7DD6CDE0EB1E, 0xF57D4F7FEE6ED178, + 0x06F067AA72176FBA, 0x0A637DC5A2C898A6, 0x113F9804BEF90DAE, 0x1B710B35131C471B, + 0x28DB77F523047D84, 0x32CAAB7B40C72493, 0x3C9EBE0A15C9BEBC, 0x431D67C49C100D4C, + 0x4CC5D4BECB3E42B6, 0x597F299CFC657E2A, 0x5FCB6FAB3AD6FAEC, 0x6C44198C4A475817 + }; + + // the byte 0x36 repeated 'B' times where 'B' => block size + std::vector ipad = { + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36 + }; + + // the byte 0x5c repeated 'B' times + std::vector opad = { + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c + }; + + inline void ctx_init() override; + inline void ctx_transform(const uint8_t* data); + inline void ctx_update(const uint8_t* data, size_t len) override; + inline void ctx_final() override; + + inline std::string _H(const std::string& a, const std::string& b) override; + inline std::string HMAC(const std::string& key, const std::string& data) override; + + constexpr uint64_t F(const uint64_t A, const uint64_t B, const uint64_t C); + constexpr uint64_t G(const uint64_t A, const uint64_t B, const uint64_t C); + + // Sigma functions + // as per: https://datatracker.ietf.org/doc/html/rfc4634 + constexpr uint64_t SIGMA0(const uint64_t A); + constexpr uint64_t SIGMA1(const uint64_t A); + constexpr uint64_t SIGMA2(const uint64_t A); + constexpr uint64_t SIGMA3(const uint64_t A); + }; + class SHA2_512_256 : public common { + protected: + std::vector getBytes() override { + return std::vector(context.digest, context.digest + 32); + } + + private: + const uint8_t BLOCK_SIZE = 128, DIGEST_SIZE = 32; + + typedef struct { + uint64_t state[8], count[2]; + uint8_t data[128], digest[32]; + } CTX; + + CTX context = { 0 }; + + // constants (H) defined by SHA-512/256 algorithm + // as per: https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/SHA512_256.pdf + const uint64_t H[8] = { + 0x22312194FC2BF72C, + 0x9F555FA3C84C64C2, + 0x2393B86B6F53B151, + 0x963877195940EABD, + 0x96283EE2A88EFFE3, + 0xBE5E1E2553863992, + 0x2B0199FC2C85B8AA, + 0x0EB72DDC81C52CA2 + }; + + // more constants (K)... as per above + const uint64_t K[80] = { + 0x428A2F98D728AE22, 0x7137449123EF65CD, 0xB5C0FBCFEC4D3B2F, 0xE9B5DBA58189DBBC, + 0x3956C25BF348B538, 0x59F111F1B605D019, 0x923F82A4AF194F9B, 0xAB1C5ED5DA6D8118, + 0xD807AA98A3030242, 0x12835B0145706FBE, 0x243185BE4EE4B28C, 0x550C7DC3D5FFB4E2, + 0x72BE5D74F27B896F, 0x80DEB1FE3B1696B1, 0x9BDC06A725C71235, 0xC19BF174CF692694, + 0xE49B69C19EF14AD2, 0xEFBE4786384F25E3, 0x0FC19DC68B8CD5B5, 0x240CA1CC77AC9C65, + 0x2DE92C6F592B0275, 0x4A7484AA6EA6E483, 0x5CB0A9DCBD41FBD4, 0x76F988DA831153B5, + 0x983E5152EE66DFAB, 0xA831C66D2DB43210, 0xB00327C898FB213F, 0xBF597FC7BEEF0EE4, + 0xC6E00BF33DA88FC2, 0xD5A79147930AA725, 0x06CA6351E003826F, 0x142929670A0E6E70, + 0x27B70A8546D22FFC, 0x2E1B21385C26C926, 0x4D2C6DFC5AC42AED, 0x53380D139D95B3DF, + 0x650A73548BAF63DE, 0x766A0ABB3C77B2A8, 0x81C2C92E47EDAEE6, 0x92722C851482353B, + 0xA2BFE8A14CF10364, 0xA81A664BBC423001, 0xC24B8B70D0F89791, 0xC76C51A30654BE30, + 0xD192E819D6EF5218, 0xD69906245565A910, 0xF40E35855771202A, 0x106AA07032BBD1B8, + 0x19A4C116B8D2D0C8, 0x1E376C085141AB53, 0x2748774CDF8EEB99, 0x34B0BCB5E19B48A8, + 0x391C0CB3C5C95A63, 0x4ED8AA4AE3418ACB, 0x5B9CCA4F7763E373, 0x682E6FF3D6B2B8A3, + 0x748F82EE5DEFB2FC, 0x78A5636F43172F60, 0x84C87814A1F0AB72, 0x8CC702081A6439EC, + 0x90BEFFFA23631E28, 0xA4506CEBDE82BDE9, 0xBEF9A3F7B2C67915, 0xC67178F2E372532B, + 0xCA273ECEEA26619C, 0xD186B8C721C0C207, 0xEADA7DD6CDE0EB1E, 0xF57D4F7FEE6ED178, + 0x06F067AA72176FBA, 0x0A637DC5A2C898A6, 0x113F9804BEF90DAE, 0x1B710B35131C471B, + 0x28DB77F523047D84, 0x32CAAB7B40C72493, 0x3C9EBE0A15C9BEBC, 0x431D67C49C100D4C, + 0x4CC5D4BECB3E42B6, 0x597F299CFC657E2A, 0x5FCB6FAB3AD6FAEC, 0x6C44198C4A475817 + }; + + // the byte 0x36 repeated 'B' times where 'B' => block size + std::vector ipad = { + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36 + }; + + // the byte 0x5c repeated 'B' times + std::vector opad = { + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c + }; + + inline void ctx_init() override; + inline void ctx_transform(const uint8_t* data); + inline void ctx_update(const uint8_t* data, size_t len) override; + inline void ctx_final() override; + + inline std::string _H(const std::string& a, const std::string& b) override; + inline std::string HMAC(const std::string& key, const std::string& data) override; + + constexpr uint64_t F(const uint64_t A, const uint64_t B, const uint64_t C); + constexpr uint64_t G(const uint64_t A, const uint64_t B, const uint64_t C); + + // Sigma functions + // as per: https://datatracker.ietf.org/doc/html/rfc4634 + constexpr uint64_t SIGMA0(const uint64_t A); + constexpr uint64_t SIGMA1(const uint64_t A); + constexpr uint64_t SIGMA2(const uint64_t A); + constexpr uint64_t SIGMA3(const uint64_t A); + }; + + // SHA-1 + inline void hashpp::SHA::SHA1::ctx_init() { + this->context = { + {this->H[0], this->H[1], this->H[2], this->H[3], this->H[4]}, + {this->K[0], this->K[1], this->K[2], this->K[3]}, + 0, 0 + }; + } + inline void hashpp::SHA::SHA1::ctx_transform(const uint8_t* data) { + uint32_t t, m[80], i = 0, j = 0; + + for (; i < 16; ++i, j += 4) { + m[i] = this->A(data[j], data[j + 1], data[j + 2], data[j + 3]); + } + for (; i < 80; ++i) { + m[i] = this->B(m[i - 3], m[i - 8], m[i - 14], m[i - 16]); + m[i] = this->C(m[i]); + } + + uint32_t results[5] = { + this->context.state[0], + this->context.state[1], + this->context.state[2], + this->context.state[3], + this->context.state[4] + }; + + for (i = 0; i < 20; ++i) { + t = this->rl32(results[0], 5) + (F(results[1], results[2], results[3])) + results[4] + this->context.k[0] + m[i]; + results[4] = results[3]; + results[3] = results[2]; + results[2] = this->rl32(results[1], 30); + results[1] = results[0]; + results[0] = t; + } + for (; i < 40; ++i) { + t = this->rl32(results[0], 5) + (J(results[1], results[2], results[3])) + results[4] + this->context.k[1] + m[i]; + results[4] = results[3]; + results[3] = results[2]; + results[2] = this->rl32(results[1], 30); + results[1] = results[0]; + results[0] = t; + } + for (; i < 60; ++i) { + t = this->rl32(results[0], 5) + ((G(results[1], results[2], results[3]))) + results[4] + this->context.k[2] + m[i]; + results[4] = results[3]; + results[3] = results[2]; + results[2] = this->rl32(results[1], 30); + results[1] = results[0]; + results[0] = t; + } + for (; i < 80; ++i) { + t = this->rl32(results[0], 5) + (J(results[1], results[2], results[3])) + results[4] + this->context.k[3] + m[i]; + results[4] = results[3]; + results[3] = results[2]; + results[2] = this->rl32(results[1], 30); + results[1] = results[0]; + results[0] = t; + } + + for (uint32_t z = 0; z < 5; z++) { + this->context.state[z] += results[z]; + } + } + inline void hashpp::SHA::SHA1::ctx_update(const uint8_t* data, size_t len) { + size_t i; + + for (i = 0; i < len; ++i) { + this->context.data[this->context.size] = data[i]; + this->context.size++; + if (this->context.size == 64) { + this->ctx_transform(this->context.data); + this->context.bitsize += 512; + this->context.size = 0; + } + } + } + inline void hashpp::SHA::SHA1::ctx_final() { + uint32_t L = this->context.size; + + if (this->context.size < 56) { + this->context.data[L++] = 0x80; + while (L < 56) { + this->context.data[L++] = 0x00; + } + } + else { + this->context.data[L++] = 0x80; + while (L < 64) { + this->context.data[L++] = 0x00; + } + this->ctx_transform(this->context.data); + memset(this->context.data, 0, 56); + } + + this->context.bitsize += static_cast(this->context.size) * 8; + this->context.data[63] = this->context.bitsize; + this->context.data[62] = this->context.bitsize >> 8; + this->context.data[61] = this->context.bitsize >> 16; + this->context.data[60] = this->context.bitsize >> 24; + this->context.data[59] = this->context.bitsize >> 32; + this->context.data[58] = this->context.bitsize >> 40; + this->context.data[57] = this->context.bitsize >> 48; + this->context.data[56] = this->context.bitsize >> 56; + this->ctx_transform(this->context.data); + + for (L = 0; L < 4; ++L) { + this->context.digest[L] = (this->context.state[0] >> (24 - L * 8)) & 0x000000ff; + this->context.digest[L + 4] = (this->context.state[1] >> (24 - L * 8)) & 0x000000ff; + this->context.digest[L + 8] = (this->context.state[2] >> (24 - L * 8)) & 0x000000ff; + this->context.digest[L + 12] = (this->context.state[3] >> (24 - L * 8)) & 0x000000ff; + this->context.digest[L + 16] = (this->context.state[4] >> (24 - L * 8)) & 0x000000ff; + } + } + inline std::string SHA1::_H(const std::string& a, const std::string& b) { + return this->getHash(a + b); + } + inline std::string SHA1::HMAC(const std::string& key, const std::string& data) { + uint8_t k[64] = {0}; + + // (1) append zeros to the end of K to create a B byte string + // (e.g., if K is of length 20 bytes and B = 64, then K will be + // appended with 44 zero bytes 0x00) where B is the block size + if (key.length() > this->BLOCK_SIZE) { + // if K is longer than B bytes, reset K to K=H(K) + // where K can either be composed of entirely bytes of H(K) + // (if H(K) == L [where L => digest]) or the first L bytes of + // H(K) (if H(K) != L) followed by the remaining zeros (if H(K) < L) + std::vector k_ = this->fromHex(this->getHash(key)); + for (uint32_t i = 0; i < this->DIGEST_SIZE; ++i) { + k[i] = k_[i]; + } + } + else { + // if K is shorter than B bytes, append zeros to the end of K + // until K is B bytes long + for (uint32_t i = 0; i < key.length(); ++i) { + k[i] = key[i]; + } + } + + // (2) XOR (bitwise exclusive-OR) the B byte string computed in step (1) with ipad + for (uint32_t i = 0; i < this->BLOCK_SIZE; ++i) { + this->ipad[i] ^= k[i]; + } + + // (3) append the stream of data 'data' to the B byte string resulting from step (2) + for (uint32_t i = 0; i < data.length(); ++i) { + this->ipad.push_back(data[i]); + } + + // (4) apply H to the stream generated in step (3) + // see step (6) + + // (5) XOR (bitwise exclusive-OR) the B byte string computed in step (1) with opad + for (uint32_t i = 0; i < this->BLOCK_SIZE; ++i) { + this->opad[i] ^= k[i]; + } + + // (6) append the H result from step (4) to the B byte string resulting from step (5) + std::vector h_ = this->fromHex(this->getHash(std::string(this->ipad.begin(), this->ipad.end()))); + for (uint32_t i = 0; i < this->DIGEST_SIZE; ++i) { + this->opad.push_back(h_[i]); + } + + // (7) apply H to the stream generated in step (6) and output the result + return this->getHash(std::string(this->opad.begin(), this->opad.end())); + } + constexpr uint32_t hashpp::SHA::SHA1::A(const uint32_t A, const uint32_t B, const uint32_t C, const uint32_t D) { + return ((A << 24) + (B << 16) + (C << 8) + (D)); + } + constexpr uint32_t hashpp::SHA::SHA1::B(const uint32_t A, const uint32_t B, const uint32_t C, const uint32_t D) { + return ((A ^ B ^ C ^ D)); + } + constexpr uint32_t hashpp::SHA::SHA1::C(const uint32_t A) { return ((A << 1) | (A >> 31)); } + constexpr uint32_t hashpp::SHA::SHA1::F(const uint32_t B, const uint32_t C, const uint32_t D) { return ((B & C) ^ (~B & D)); } + constexpr uint32_t hashpp::SHA::SHA1::G(const uint32_t B, const uint32_t C, const uint32_t D) { return ((B & C) ^ (B & D) ^ (C & D)); } + constexpr uint32_t hashpp::SHA::SHA1::J(const uint32_t B, const uint32_t C, const uint32_t D) { return ((B ^ C ^ D)); } + + // SHA2-224 + inline void hashpp::SHA::SHA2_224::ctx_init() { + this->context = { + {this->H[0], this->H[1], this->H[2], this->H[3], + this->H[4], this->H[5], this->H[6], this->H[7]}, + 0, 0 + }; + } + inline void hashpp::SHA::SHA2_224::ctx_transform(const uint8_t* data) { + uint32_t m[64], i = 0, j = 0; + + for (; i < 16; ++i, j += 4) { + m[i] = this->A(data[j], data[j + 1], data[j + 2], data[j + 3]); + } for (; i < 64; ++i) { + m[i] = this->SIGMA3(m[i - 2]) + m[i - 7] + this->SIGMA2(m[i - 15]) + m[i - 16]; + } + + uint32_t results[8] = { + this->context.state[0], + this->context.state[1], + this->context.state[2], + this->context.state[3], + this->context.state[4], + this->context.state[5], + this->context.state[6], + this->context.state[7] + }; + + uint32_t t1, t2; + for (i = 0; i < 64; ++i) { + t1 = results[7] + this->SIGMA1(results[4]) + this->F(results[4], results[5], results[6]) + this->K[i] + m[i]; + t2 = this->SIGMA0(results[0]) + this->G(results[0], results[1], results[2]); + results[7] = results[6]; + results[6] = results[5]; + results[5] = results[4]; + results[4] = results[3] + t1; + results[3] = results[2]; + results[2] = results[1]; + results[1] = results[0]; + results[0] = t1 + t2; + } + + for (uint32_t z = 0; z < 8; z++) { + this->context.state[z] += results[z]; + } + } + inline void hashpp::SHA::SHA2_224::ctx_update(const uint8_t* data, size_t len) { + uint32_t i; + + for (i = 0; i < len; ++i) { + this->context.data[this->context.size] = data[i]; + this->context.size++; + if (this->context.size == 64) { + this->ctx_transform(this->context.data); + this->context.bitsize += 512; + this->context.size = 0; + } + } + } + inline void hashpp::SHA::SHA2_224::ctx_final() { + uint32_t i = this->context.size; + + if (this->context.size < 56) { + this->context.data[i++] = 0x80; + while (i < 56) { + this->context.data[i++] = 0x00; + } + } + else { + this->context.data[i++] = 0x80; + while (i < 64) { + this->context.data[i++] = 0x00; + } + this->ctx_transform(this->context.data); + memset(this->context.data, 0, 56); + } + + this->context.bitsize += static_cast(this->context.size) * 8; + this->context.data[63] = this->context.bitsize; + this->context.data[62] = this->context.bitsize >> 8; + this->context.data[61] = this->context.bitsize >> 16; + this->context.data[60] = this->context.bitsize >> 24; + this->context.data[59] = this->context.bitsize >> 32; + this->context.data[58] = this->context.bitsize >> 40; + this->context.data[57] = this->context.bitsize >> 48; + this->context.data[56] = this->context.bitsize >> 56; + this->ctx_transform(this->context.data); + + for (i = 0; i < 4; ++i) { + this->context.digest[i] = (this->context.state[0] >> (24 - i * 8)) & 0x000000ff; + this->context.digest[i + 4] = (this->context.state[1] >> (24 - i * 8)) & 0x000000ff; + this->context.digest[i + 8] = (this->context.state[2] >> (24 - i * 8)) & 0x000000ff; + this->context.digest[i + 12] = (this->context.state[3] >> (24 - i * 8)) & 0x000000ff; + this->context.digest[i + 16] = (this->context.state[4] >> (24 - i * 8)) & 0x000000ff; + this->context.digest[i + 20] = (this->context.state[5] >> (24 - i * 8)) & 0x000000ff; + this->context.digest[i + 24] = (this->context.state[6] >> (24 - i * 8)) & 0x000000ff; + } + } + inline std::string SHA2_224::_H(const std::string& a, const std::string& b) { + return this->getHash(a + b); + } + inline std::string SHA2_224::HMAC(const std::string& key, const std::string& data) { + uint8_t k[64] = {0}; + + // (1) append zeros to the end of K to create a B byte string + // (e.g., if K is of length 20 bytes and B = 64, then K will be + // appended with 44 zero bytes 0x00) where B is the block size + if (key.length() > this->BLOCK_SIZE) { + // if K is longer than B bytes, reset K to K=H(K) + // where K can either be composed of entirely bytes of H(K) + // (if H(K) == L [where L => digest]) or the first L bytes of + // H(K) (if H(K) != L) followed by the remaining zeros (if H(K) < L) + std::vector k_ = this->fromHex(this->getHash(key)); + for (uint32_t i = 0; i < this->DIGEST_SIZE; ++i) { + k[i] = k_[i]; + } + } + else { + // if K is shorter than B bytes, append zeros to the end of K + // until K is B bytes long + for (uint32_t i = 0; i < key.length(); ++i) { + k[i] = key[i]; + } + } + + // (2) XOR (bitwise exclusive-OR) the B byte string computed in step (1) with ipad + for (uint32_t i = 0; i < this->BLOCK_SIZE; ++i) { + this->ipad[i] ^= k[i]; + } + + // (3) append the stream of data 'data' to the B byte string resulting from step (2) + for (uint32_t i = 0; i < data.length(); ++i) { + this->ipad.push_back(data[i]); + } + + // (4) apply H to the stream generated in step (3) + // see step (6) + + // (5) XOR (bitwise exclusive-OR) the B byte string computed in step (1) with opad + for (uint32_t i = 0; i < this->BLOCK_SIZE; ++i) { + this->opad[i] ^= k[i]; + } + + // (6) append the H result from step (4) to the B byte string resulting from step (5) + std::vector h_ = this->fromHex(this->getHash(std::string(this->ipad.begin(), this->ipad.end()))); + for (uint32_t i = 0; i < this->DIGEST_SIZE; ++i) { + this->opad.push_back(h_[i]); + } + + // (7) apply H to the stream generated in step (6) and output the result + return this->getHash(std::string(this->opad.begin(), this->opad.end())); + } + constexpr uint32_t hashpp::SHA::SHA2_224::A(const uint32_t A, const uint32_t B, const uint32_t C, const uint32_t D) { + return ((A << 24) + (B << 16) + (C << 8) + (D)); + } + constexpr uint32_t hashpp::SHA::SHA2_224::F(const uint32_t B, const uint32_t C, const uint32_t D) { return ((B & C) ^ (~B & D)); } + constexpr uint32_t hashpp::SHA::SHA2_224::G(const uint32_t B, const uint32_t C, const uint32_t D) { return ((B & C) ^ (B & D) ^ (C & D)); } + constexpr uint32_t hashpp::SHA::SHA2_224::SIGMA0(const uint32_t A) { return (this->rr32(A, 2) ^ this->rr32(A, 13) ^ this->rr32(A, 22)); } + constexpr uint32_t hashpp::SHA::SHA2_224::SIGMA1(const uint32_t A) { return (this->rr32(A, 6) ^ this->rr32(A, 11) ^ this->rr32(A, 25)); } + constexpr uint32_t hashpp::SHA::SHA2_224::SIGMA2(const uint32_t A) { return (this->rr32(A, 7) ^ this->rr32(A, 18) ^ ((A) >> 3)); } + constexpr uint32_t hashpp::SHA::SHA2_224::SIGMA3(const uint32_t A) { return (this->rr32(A, 17) ^ this->rr32(A, 19) ^ ((A) >> 10)); } + + // SHA2-256 + inline void hashpp::SHA::SHA2_256::ctx_init() { + this->context = { + {this->H[0], this->H[1], this->H[2], this->H[3], + this->H[4], this->H[5], this->H[6], this->H[7]}, + 0, 0 + }; + } + inline void hashpp::SHA::SHA2_256::ctx_transform(const uint8_t* data) { + uint32_t m[64], i = 0, j = 0; + + for (; i < 16; ++i, j += 4) { + m[i] = this->A(data[j], data[j + 1], data[j + 2], data[j + 3]); + } + for (; i < 64; ++i) { + m[i] = this->SIGMA3(m[i - 2]) + m[i - 7] + this->SIGMA2(m[i - 15]) + m[i - 16]; + } + + uint32_t results[8] = { + this->context.state[0], + this->context.state[1], + this->context.state[2], + this->context.state[3], + this->context.state[4], + this->context.state[5], + this->context.state[6], + this->context.state[7] + }; + + uint32_t t1, t2; + for (i = 0; i < 64; ++i) { + t1 = results[7] + this->SIGMA1(results[4]) + this->F(results[4], results[5], results[6]) + this->K[i] + m[i]; + t2 = this->SIGMA0(results[0]) + this->G(results[0], results[1], results[2]); + results[7] = results[6]; + results[6] = results[5]; + results[5] = results[4]; + results[4] = results[3] + t1; + results[3] = results[2]; + results[2] = results[1]; + results[1] = results[0]; + results[0] = t1 + t2; + } + + for (uint32_t z = 0; z < 8; z++) { + this->context.state[z] += results[z]; + } + } + inline void hashpp::SHA::SHA2_256::ctx_update(const uint8_t* data, size_t len) { + uint32_t i; + + for (i = 0; i < len; ++i) { + this->context.data[this->context.size] = data[i]; + this->context.size++; + if (this->context.size == 64) { + this->ctx_transform(this->context.data); + this->context.bitsize += 512; + this->context.size = 0; + } + } + } + inline void hashpp::SHA::SHA2_256::ctx_final() { + uint32_t i = this->context.size; + + if (this->context.size < 56) { + this->context.data[i++] = 0x80; + while (i < 56) { + this->context.data[i++] = 0x00; + } + } + else { + this->context.data[i++] = 0x80; + while (i < 64) { + this->context.data[i++] = 0x00; + } + this->ctx_transform(this->context.data); + memset(this->context.data, 0, 56); + } + + this->context.bitsize += static_cast(this->context.size) * 8; + this->context.data[63] = this->context.bitsize; + this->context.data[62] = this->context.bitsize >> 8; + this->context.data[61] = this->context.bitsize >> 16; + this->context.data[60] = this->context.bitsize >> 24; + this->context.data[59] = this->context.bitsize >> 32; + this->context.data[58] = this->context.bitsize >> 40; + this->context.data[57] = this->context.bitsize >> 48; + this->context.data[56] = this->context.bitsize >> 56; + this->ctx_transform(this->context.data); + + for (i = 0; i < 4; ++i) { + this->context.digest[i] = (this->context.state[0] >> (24 - i * 8)) & 0x000000ff; + this->context.digest[i + 4] = (this->context.state[1] >> (24 - i * 8)) & 0x000000ff; + this->context.digest[i + 8] = (this->context.state[2] >> (24 - i * 8)) & 0x000000ff; + this->context.digest[i + 12] = (this->context.state[3] >> (24 - i * 8)) & 0x000000ff; + this->context.digest[i + 16] = (this->context.state[4] >> (24 - i * 8)) & 0x000000ff; + this->context.digest[i + 20] = (this->context.state[5] >> (24 - i * 8)) & 0x000000ff; + this->context.digest[i + 24] = (this->context.state[6] >> (24 - i * 8)) & 0x000000ff; + this->context.digest[i + 28] = (this->context.state[7] >> (24 - i * 8)) & 0x000000ff; + } + } + inline std::string SHA2_256::_H(const std::string& a, const std::string& b) { + return this->getHash(a + b); + } + inline std::string SHA2_256::HMAC(const std::string& key, const std::string& data) { + uint8_t k[64] = {0}; + + // (1) append zeros to the end of K to create a B byte string + // (e.g., if K is of length 20 bytes and B = 64, then K will be + // appended with 44 zero bytes 0x00) where B is the block size + if (key.length() > this->BLOCK_SIZE) { + // if K is longer than B bytes, reset K to K=H(K) + // where K can either be composed of entirely bytes of H(K) + // (if H(K) == L [where L => digest]) or the first L bytes of + // H(K) (if H(K) != L) followed by the remaining zeros (if H(K) < L) + std::vector k_ = this->fromHex(this->getHash(key)); + for (uint32_t i = 0; i < this->DIGEST_SIZE; ++i) { + k[i] = k_[i]; + } + } + else { + // if K is shorter than B bytes, append zeros to the end of K + // until K is B bytes long + for (uint32_t i = 0; i < key.length(); ++i) { + k[i] = key[i]; + } + } + + // (2) XOR (bitwise exclusive-OR) the B byte string computed in step (1) with ipad + for (uint32_t i = 0; i < this->BLOCK_SIZE; ++i) { + this->ipad[i] ^= k[i]; + } + + // (3) append the stream of data 'data' to the B byte string resulting from step (2) + for (uint32_t i = 0; i < data.length(); ++i) { + this->ipad.push_back(data[i]); + } + + // (4) apply H to the stream generated in step (3) + // see step (6) + + // (5) XOR (bitwise exclusive-OR) the B byte string computed in step (1) with opad + for (uint32_t i = 0; i < this->BLOCK_SIZE; ++i) { + this->opad[i] ^= k[i]; + } + + // (6) append the H result from step (4) to the B byte string resulting from step (5) + std::vector h_ = this->fromHex(this->getHash(std::string(this->ipad.begin(), this->ipad.end()))); + for (uint32_t i = 0; i < this->DIGEST_SIZE; ++i) { + this->opad.push_back(h_[i]); + } + + // (7) apply H to the stream generated in step (6) and output the result + return this->getHash(std::string(this->opad.begin(), this->opad.end())); + } + constexpr uint32_t hashpp::SHA::SHA2_256::A(const uint32_t A, const uint32_t B, const uint32_t C, const uint32_t D) { + return ((A << 24) + (B << 16) + (C << 8) + (D)); + } + constexpr uint32_t hashpp::SHA::SHA2_256::F(const uint32_t B, const uint32_t C, const uint32_t D) { return ((B & C) ^ (~B & D)); } + constexpr uint32_t hashpp::SHA::SHA2_256::G(const uint32_t B, const uint32_t C, const uint32_t D) { return ((B & C) ^ (B & D) ^ (C & D)); } + constexpr uint32_t hashpp::SHA::SHA2_256::SIGMA0(const uint32_t A) { return (this->rr32(A, 2) ^ this->rr32(A, 13) ^ this->rr32(A, 22)); } + constexpr uint32_t hashpp::SHA::SHA2_256::SIGMA1(const uint32_t A) { return (this->rr32(A, 6) ^ this->rr32(A, 11) ^ this->rr32(A, 25)); } + constexpr uint32_t hashpp::SHA::SHA2_256::SIGMA2(const uint32_t A) { return (this->rr32(A, 7) ^ this->rr32(A, 18) ^ ((A) >> 3)); } + constexpr uint32_t hashpp::SHA::SHA2_256::SIGMA3(const uint32_t A) { return (this->rr32(A, 17) ^ this->rr32(A, 19) ^ ((A) >> 10)); } + + // SHA2-384 + inline void hashpp::SHA::SHA2_384::ctx_init() { + this->context = { + {this->H[0], this->H[1], this->H[2], this->H[3], + this->H[4], this->H[5], this->H[6], this->H[7]}, + {0, 0} + }; + } + inline void hashpp::SHA::SHA2_384::ctx_transform(const uint8_t* data) { + uint64_t W[80]; + uint32_t i; + + uint64_t results[8] = { + this->context.state[0], + this->context.state[1], + this->context.state[2], + this->context.state[3], + this->context.state[4], + this->context.state[5], + this->context.state[6], + this->context.state[7] + }; + + for (i = 0; i < 16; i++) { + GU64B(W[i], data, 8 * i); + uint64_t t1, t2; + t1 = (results[7]) + this->SIGMA1((results[4])) + this->F((results[4]), (results[5]), (results[6])) + (this->K[i]) + (W[i]); + t2 = this->SIGMA0((results[0])) + this->G((results[0]), (results[1]), (results[2])); + (results[7]) = (results[6]); + (results[6]) = (results[5]); + (results[5]) = (results[4]); + (results[4]) = (results[3]) + t1; + (results[3]) = (results[2]); + (results[2]) = (results[1]); + (results[1]) = (results[0]); + (results[0]) = t1 + t2; + } + + for (i = 16; i < 80; i++) { + W[i] = this->SIGMA3(W[i - 2]) + W[i - 7] + this->SIGMA2(W[i - 15]) + W[i - 16]; + uint64_t t1, t2; + t1 = (results[7]) + this->SIGMA1((results[4])) + this->F((results[4]), (results[5]), (results[6])) + (this->K[i]) + (W[i]); + t2 = this->SIGMA0((results[0])) + this->G((results[0]), (results[1]), (results[2])); + (results[7]) = (results[6]); + (results[6]) = (results[5]); + (results[5]) = (results[4]); + (results[4]) = (results[3]) + t1; + (results[3]) = (results[2]); + (results[2]) = (results[1]); + (results[1]) = (results[0]); + (results[0]) = t1 + t2; + } + + for (uint32_t z = 0; z < 8; z++) { + this->context.state[z] += results[z]; + } + } + inline void hashpp::SHA::SHA2_384::ctx_update(const uint8_t* data, size_t len) { + uint32_t left, fill, rlen = len; + const uint8_t* ptr = data; + + if (len != 0) { + + left = this->context.count[0] & 0x7F; fill = 128 - left; + + this->context.count[0] += len; + if ((this->context.count[0]) < (len)) { + (this->context.count[1])++; + } + + if ((left > 0) && (rlen >= fill)) { + memcpy(this->context.data + left, ptr, fill); + this->ctx_transform(this->context.data); + ptr += fill; + rlen -= fill; + left = 0; + } + + while (rlen >= 128) { + this->ctx_transform(ptr); + ptr += 128; + rlen -= 128; + } + + if (rlen > 0) { + memcpy(this->context.data + left, ptr, rlen); + } + } + } + inline void hashpp::SHA::SHA2_384::ctx_final() { + uint32_t block_present = 0; + uint8_t last_padded_block[2 * 128]; + + memset(last_padded_block, 0, sizeof(last_padded_block)); + + block_present = this->context.count[0] % 128; + if (block_present != 0) { + memcpy(last_padded_block, this->context.data, block_present); + } + + last_padded_block[block_present] = 0x80; + + if (block_present > (128 - 1 - (2 * sizeof(uint64_t)))) { + PU128B(this->context.count[0], this->context.count[1], last_padded_block, 2 * (128 - sizeof(uint64_t))); + this->ctx_transform(last_padded_block); + this->ctx_transform(last_padded_block + 128); + } + else { + PU128B(this->context.count[0], this->context.count[1], + last_padded_block, + 128 - (2 * sizeof(uint64_t))); + this->ctx_transform(last_padded_block); + } + + PU64B(this->context.state[0], this->context.digest, 0); + PU64B(this->context.state[1], this->context.digest, 8); + PU64B(this->context.state[2], this->context.digest, 16); + PU64B(this->context.state[3], this->context.digest, 24); + PU64B(this->context.state[4], this->context.digest, 32); + PU64B(this->context.state[5], this->context.digest, 40); + } + inline std::string SHA2_384::_H(const std::string& a, const std::string& b) { + return this->getHash(a + b); + } + inline std::string SHA2_384::HMAC(const std::string& key, const std::string& data) { + uint8_t k[128] = {0}; + + // (1) append zeros to the end of K to create a B byte string + // (e.g., if K is of length 20 bytes and B = 64, then K will be + // appended with 44 zero bytes 0x00) where B is the block size + if (key.length() > this->BLOCK_SIZE) { + // if K is longer than B bytes, reset K to K=H(K) + // where K can either be composed of entirely bytes of H(K) + // (if H(K) == L [where L => digest]) or the first L bytes of + // H(K) (if H(K) != L) followed by the remaining zeros (if H(K) < L) + std::vector k_ = this->fromHex(this->getHash(key)); + for (uint32_t i = 0; i < this->DIGEST_SIZE; ++i) { + k[i] = k_[i]; + } + } + else { + // if K is shorter than B bytes, append zeros to the end of K + // until K is B bytes long + for (uint32_t i = 0; i < key.length(); ++i) { + k[i] = key[i]; + } + } + + // (2) XOR (bitwise exclusive-OR) the B byte string computed in step (1) with ipad + for (uint32_t i = 0; i < this->BLOCK_SIZE; ++i) { + this->ipad[i] ^= k[i]; + } + + // (3) append the stream of data 'data' to the B byte string resulting from step (2) + for (uint32_t i = 0; i < data.length(); ++i) { + this->ipad.push_back(data[i]); + } + + // (4) apply H to the stream generated in step (3) + // see step (6) + + // (5) XOR (bitwise exclusive-OR) the B byte string computed in step (1) with opad + for (uint32_t i = 0; i < this->BLOCK_SIZE; ++i) { + this->opad[i] ^= k[i]; + } + + // (6) append the H result from step (4) to the B byte string resulting from step (5) + std::vector h_ = this->fromHex(this->getHash(std::string(this->ipad.begin(), this->ipad.end()))); + for (uint32_t i = 0; i < this->DIGEST_SIZE; ++i) { + this->opad.push_back(h_[i]); + } + + // (7) apply H to the stream generated in step (6) and output the result + return this->getHash(std::string(this->opad.begin(), this->opad.end())); + } + constexpr uint64_t hashpp::SHA::SHA2_384::F(const uint64_t A, const uint64_t B, const uint64_t C) { return ((A & B) ^ (~A & C)); } + constexpr uint64_t hashpp::SHA::SHA2_384::G(const uint64_t A, const uint64_t B, const uint64_t C) { return ((A & B) ^ (A & C) ^ (B & C)); } + constexpr uint64_t hashpp::SHA::SHA2_384::SIGMA0(const uint64_t A) { return this->rr64(A, 28) ^ this->rr64(A, 34) ^ this->rr64(A, 39); } + constexpr uint64_t hashpp::SHA::SHA2_384::SIGMA1(const uint64_t A) { return this->rr64(A, 14) ^ this->rr64(A, 18) ^ this->rr64(A, 41); } + constexpr uint64_t hashpp::SHA::SHA2_384::SIGMA2(const uint64_t A) { return this->rr64(A, 1) ^ this->rr64(A, 8) ^ (A >> 7); } + constexpr uint64_t hashpp::SHA::SHA2_384::SIGMA3(const uint64_t A) { return this->rr64(A, 19) ^ this->rr64(A, 61) ^ (A >> 6); } + + // SHA2-512 + inline void hashpp::SHA::SHA2_512::ctx_init() { + this->context = { + {this->H[0], this->H[1], this->H[2], this->H[3], + this->H[4], this->H[5], this->H[6], this->H[7]}, + {0, 0} + }; + } + void hashpp::SHA::SHA2_512::ctx_transform(const uint8_t* data) { + uint64_t W[80]; + uint32_t i; + + uint64_t results[8] = { + this->context.state[0], + this->context.state[1], + this->context.state[2], + this->context.state[3], + this->context.state[4], + this->context.state[5], + this->context.state[6], + this->context.state[7] + }; + + for (i = 0; i < 16; i++) { + GU64B(W[i], data, 8 * i); + uint64_t t1, t2; + t1 = (results[7]) + this->SIGMA1((results[4])) + this->F((results[4]), (results[5]), (results[6])) + (this->K[i]) + (W[i]); + t2 = this->SIGMA0((results[0])) + this->G((results[0]), (results[1]), (results[2])); + (results[7]) = (results[6]); + (results[6]) = (results[5]); + (results[5]) = (results[4]); + (results[4]) = (results[3]) + t1; + (results[3]) = (results[2]); + (results[2]) = (results[1]); + (results[1]) = (results[0]); + (results[0]) = t1 + t2; + } + + for (i = 16; i < 80; i++) { + W[i] = this->SIGMA3(W[i - 2]) + W[i - 7] + this->SIGMA2(W[i - 15]) + W[i - 16]; + uint64_t t1, t2; + t1 = (results[7]) + this->SIGMA1((results[4])) + this->F((results[4]), (results[5]), (results[6])) + (this->K[i]) + (W[i]); + t2 = this->SIGMA0((results[0])) + this->G((results[0]), (results[1]), (results[2])); + (results[7]) = (results[6]); + (results[6]) = (results[5]); + (results[5]) = (results[4]); + (results[4]) = (results[3]) + t1; + (results[3]) = (results[2]); + (results[2]) = (results[1]); + (results[1]) = (results[0]); + (results[0]) = t1 + t2; + } + + for (uint32_t z = 0; z < 8; z++) { + this->context.state[z] += results[z]; + } + } + inline void hashpp::SHA::SHA2_512::ctx_update(const uint8_t* data, size_t len) { + uint32_t left, fill, rlen = len; + const uint8_t* ptr = data; + + if (len != 0) { + + left = this->context.count[0] & 0x7F; fill = 128 - left; + + this->context.count[0] += len; + if ((this->context.count[0]) < (len)) { + (this->context.count[1])++; + } + + if ((left > 0) && (rlen >= fill)) { + memcpy(this->context.data + left, ptr, fill); + this->ctx_transform(this->context.data); + ptr += fill; + rlen -= fill; + left = 0; + } + + while (rlen >= 128) { + this->ctx_transform(ptr); + ptr += 128; + rlen -= 128; + } + + if (rlen > 0) { + memcpy(this->context.data + left, ptr, rlen); + } + } + } + inline void hashpp::SHA::SHA2_512::ctx_final() { + uint32_t block_present = 0; + uint8_t last_padded_block[2 * 128]; + + memset(last_padded_block, 0, sizeof(last_padded_block)); + + block_present = this->context.count[0] % 128; + if (block_present != 0) { + memcpy(last_padded_block, this->context.data, block_present); + } + + last_padded_block[block_present] = 0x80; + + if (block_present > (128 - 1 - (2 * sizeof(uint64_t)))) { + PU128B(this->context.count[0], this->context.count[1], last_padded_block, 2 * (128 - sizeof(uint64_t))); + this->ctx_transform(last_padded_block); + this->ctx_transform(last_padded_block + 128); + } + else { + PU128B(this->context.count[0], this->context.count[1], + last_padded_block, + 128 - (2 * sizeof(uint64_t))); + this->ctx_transform(last_padded_block); + } + + PU64B(this->context.state[0], this->context.digest, 0); + PU64B(this->context.state[1], this->context.digest, 8); + PU64B(this->context.state[2], this->context.digest, 16); + PU64B(this->context.state[3], this->context.digest, 24); + PU64B(this->context.state[4], this->context.digest, 32); + PU64B(this->context.state[5], this->context.digest, 40); + PU64B(this->context.state[6], this->context.digest, 48); + PU64B(this->context.state[7], this->context.digest, 56); + } + inline std::string SHA2_512::_H(const std::string& a, const std::string& b) { + return this->getHash(a + b); + } + inline std::string SHA2_512::HMAC(const std::string& key, const std::string& data) { + uint8_t k[128] = {0}; + + // (1) append zeros to the end of K to create a B byte string + // (e.g., if K is of length 20 bytes and B = 64, then K will be + // appended with 44 zero bytes 0x00) where B is the block size + if (key.length() > this->BLOCK_SIZE) { + // if K is longer than B bytes, reset K to K=H(K) + // where K can either be composed of entirely bytes of H(K) + // (if H(K) == L [where L => digest]) or the first L bytes of + // H(K) (if H(K) != L) followed by the remaining zeros (if H(K) < L) + std::vector k_ = this->fromHex(this->getHash(key)); + for (uint32_t i = 0; i < this->DIGEST_SIZE; ++i) { + k[i] = k_[i]; + } + } + else { + // if K is shorter than B bytes, append zeros to the end of K + // until K is B bytes long + for (uint32_t i = 0; i < key.length(); ++i) { + k[i] = key[i]; + } + } + + // (2) XOR (bitwise exclusive-OR) the B byte string computed in step (1) with ipad + for (uint32_t i = 0; i < this->BLOCK_SIZE; ++i) { + this->ipad[i] ^= k[i]; + } + + // (3) append the stream of data 'data' to the B byte string resulting from step (2) + for (uint32_t i = 0; i < data.length(); ++i) { + this->ipad.push_back(data[i]); + } + + // (4) apply H to the stream generated in step (3) + // see step (6) + + // (5) XOR (bitwise exclusive-OR) the B byte string computed in step (1) with opad + for (uint32_t i = 0; i < this->BLOCK_SIZE; ++i) { + this->opad[i] ^= k[i]; + } + + // (6) append the H result from step (4) to the B byte string resulting from step (5) + std::vector h_ = this->fromHex(this->getHash(std::string(this->ipad.begin(), this->ipad.end()))); + for (uint32_t i = 0; i < this->DIGEST_SIZE; ++i) { + this->opad.push_back(h_[i]); + } + + // (7) apply H to the stream generated in step (6) and output the result + return this->getHash(std::string(this->opad.begin(), this->opad.end())); + } + constexpr uint64_t hashpp::SHA::SHA2_512::F(const uint64_t A, const uint64_t B, const uint64_t C) { return ((A & B) ^ (~A & C)); } + constexpr uint64_t hashpp::SHA::SHA2_512::G(const uint64_t A, const uint64_t B, const uint64_t C) { return ((A & B) ^ (A & C) ^ (B & C)); } + constexpr uint64_t hashpp::SHA::SHA2_512::SIGMA0(const uint64_t A) { return this->rr64(A, 28) ^ this->rr64(A, 34) ^ this->rr64(A, 39); } + constexpr uint64_t hashpp::SHA::SHA2_512::SIGMA1(const uint64_t A) { return this->rr64(A, 14) ^ this->rr64(A, 18) ^ this->rr64(A, 41); } + constexpr uint64_t hashpp::SHA::SHA2_512::SIGMA2(const uint64_t A) { return this->rr64(A, 1) ^ this->rr64(A, 8) ^ (A >> 7); } + constexpr uint64_t hashpp::SHA::SHA2_512::SIGMA3(const uint64_t A) { return this->rr64(A, 19) ^ this->rr64(A, 61) ^ (A >> 6); } + + // SHA2-512-224 + inline void hashpp::SHA::SHA2_512_224::ctx_init() { + this->context = { + {this->H[0], this->H[1], this->H[2], this->H[3], + this->H[4], this->H[5], this->H[6], this->H[7]}, + {0, 0} + }; + } + inline void hashpp::SHA::SHA2_512_224::ctx_transform(const uint8_t* data) { + uint64_t W[80]; + uint32_t i; + + uint64_t results[8] = { + this->context.state[0], + this->context.state[1], + this->context.state[2], + this->context.state[3], + this->context.state[4], + this->context.state[5], + this->context.state[6], + this->context.state[7] + }; + + for (i = 0; i < 16; i++) { + GU64B(W[i], data, 8 * i); + uint64_t t1, t2; + t1 = (results[7]) + this->SIGMA1((results[4])) + this->F((results[4]), (results[5]), (results[6])) + (this->K[i]) + (W[i]); + t2 = this->SIGMA0((results[0])) + this->G((results[0]), (results[1]), (results[2])); + (results[7]) = (results[6]); + (results[6]) = (results[5]); + (results[5]) = (results[4]); + (results[4]) = (results[3]) + t1; + (results[3]) = (results[2]); + (results[2]) = (results[1]); + (results[1]) = (results[0]); + (results[0]) = t1 + t2; + } + + for (i = 16; i < 80; i++) { + W[i] = this->SIGMA3(W[i - 2]) + W[i - 7] + this->SIGMA2(W[i - 15]) + W[i - 16]; + uint64_t t1, t2; + t1 = (results[7]) + this->SIGMA1((results[4])) + this->F((results[4]), (results[5]), (results[6])) + (this->K[i]) + (W[i]); + t2 = this->SIGMA0((results[0])) + this->G((results[0]), (results[1]), (results[2])); + (results[7]) = (results[6]); + (results[6]) = (results[5]); + (results[5]) = (results[4]); + (results[4]) = (results[3]) + t1; + (results[3]) = (results[2]); + (results[2]) = (results[1]); + (results[1]) = (results[0]); + (results[0]) = t1 + t2; + } + + for (uint32_t z = 0; z < 8; z++) { + this->context.state[z] += results[z]; + } + } + inline void hashpp::SHA::SHA2_512_224::ctx_update(const uint8_t* data, size_t len) { + uint32_t left, fill, rlen = len; + const uint8_t* ptr = data; + + if (len != 0) { + + left = this->context.count[0] & 0x7F; fill = 128 - left; + + this->context.count[0] += len; + if ((this->context.count[0]) < (len)) { + (this->context.count[1])++; + } + + if ((left > 0) && (rlen >= fill)) { + memcpy(this->context.data + left, ptr, fill); + this->ctx_transform(this->context.data); + ptr += fill; + rlen -= fill; + left = 0; + } + + while (rlen >= 128) { + this->ctx_transform(ptr); + ptr += 128; + rlen -= 128; + } + + if (rlen > 0) { + memcpy(this->context.data + left, ptr, rlen); + } + } + } + inline void hashpp::SHA::SHA2_512_224::ctx_final() { + uint32_t block_present = 0; + uint8_t last_padded_block[2 * 128]; + + memset(last_padded_block, 0, sizeof(last_padded_block)); + + block_present = this->context.count[0] % 128; + if (block_present != 0) { + memcpy(last_padded_block, this->context.data, block_present); + } + + last_padded_block[block_present] = 0x80; + + if (block_present > (128 - 1 - (2 * sizeof(uint64_t)))) { + /* We need an additional block */ + PU128B(this->context.count[0], this->context.count[1], last_padded_block, 2 * (128 - sizeof(uint64_t))); + this->ctx_transform(last_padded_block); + this->ctx_transform(last_padded_block + 128); + } + else { + PU128B(this->context.count[0], this->context.count[1], + last_padded_block, + 128 - (2 * sizeof(uint64_t))); + this->ctx_transform(last_padded_block); + } + + PU64B(this->context.state[0], this->context.digest, 0); + PU64B(this->context.state[1], this->context.digest, 8); + PU64B(this->context.state[2], this->context.digest, 16); + PU64B(this->context.state[3], this->context.digest, 24); + } + inline std::string SHA2_512_224::_H(const std::string& a, const std::string& b) { + return this->getHash(a + b); + } + inline std::string SHA2_512_224::HMAC(const std::string& key, const std::string& data) { + uint8_t k[128] = {0}; + + // (1) append zeros to the end of K to create a B byte string + // (e.g., if K is of length 20 bytes and B = 64, then K will be + // appended with 44 zero bytes 0x00) where B is the block size + if (key.length() > this->BLOCK_SIZE) { + // if K is longer than B bytes, reset K to K=H(K) + // where K can either be composed of entirely bytes of H(K) + // (if H(K) == L [where L => digest]) or the first L bytes of + // H(K) (if H(K) != L) followed by the remaining zeros (if H(K) < L) + std::vector k_ = this->fromHex(this->getHash(key)); + for (uint32_t i = 0; i < this->DIGEST_SIZE; ++i) { + k[i] = k_[i]; + } + } + else { + // if K is shorter than B bytes, append zeros to the end of K + // until K is B bytes long + for (uint32_t i = 0; i < key.length(); ++i) { + k[i] = key[i]; + } + } + + // (2) XOR (bitwise exclusive-OR) the B byte string computed in step (1) with ipad + for (uint32_t i = 0; i < this->BLOCK_SIZE; ++i) { + this->ipad[i] ^= k[i]; + } + + // (3) append the stream of data 'data' to the B byte string resulting from step (2) + for (uint32_t i = 0; i < data.length(); ++i) { + this->ipad.push_back(data[i]); + } + + // (4) apply H to the stream generated in step (3) + // see step (6) + + // (5) XOR (bitwise exclusive-OR) the B byte string computed in step (1) with opad + for (uint32_t i = 0; i < this->BLOCK_SIZE; ++i) { + this->opad[i] ^= k[i]; + } + + // (6) append the H result from step (4) to the B byte string resulting from step (5) + std::vector h_ = this->fromHex(this->getHash(std::string(this->ipad.begin(), this->ipad.end()))); + for (uint32_t i = 0; i < this->DIGEST_SIZE; ++i) { + this->opad.push_back(h_[i]); + } + + // (7) apply H to the stream generated in step (6) and output the result + return this->getHash(std::string(this->opad.begin(), this->opad.end())); + } + constexpr uint64_t hashpp::SHA::SHA2_512_224::F(const uint64_t A, const uint64_t B, const uint64_t C) { return ((A & B) ^ (~A & C)); } + constexpr uint64_t hashpp::SHA::SHA2_512_224::G(const uint64_t A, const uint64_t B, const uint64_t C) { return ((A & B) ^ (A & C) ^ (B & C)); } + constexpr uint64_t hashpp::SHA::SHA2_512_224::SIGMA0(const uint64_t A) { return this->rr64(A, 28) ^ this->rr64(A, 34) ^ this->rr64(A, 39); } + constexpr uint64_t hashpp::SHA::SHA2_512_224::SIGMA1(const uint64_t A) { return this->rr64(A, 14) ^ this->rr64(A, 18) ^ this->rr64(A, 41); } + constexpr uint64_t hashpp::SHA::SHA2_512_224::SIGMA2(const uint64_t A) { return this->rr64(A, 1) ^ this->rr64(A, 8) ^ (A >> 7); } + constexpr uint64_t hashpp::SHA::SHA2_512_224::SIGMA3(const uint64_t A) { return this->rr64(A, 19) ^ this->rr64(A, 61) ^ (A >> 6); } + + // SHA2-512-256 + inline void hashpp::SHA::SHA2_512_256::ctx_init() { + this->context = { + {this->H[0], this->H[1], this->H[2], this->H[3], + this->H[4], this->H[5], this->H[6], this->H[7]}, + {0, 0} + }; + } + inline void hashpp::SHA::SHA2_512_256::ctx_transform(const uint8_t* data) { + uint64_t W[80]; + uint32_t i; + + uint64_t results[8] = { + this->context.state[0], + this->context.state[1], + this->context.state[2], + this->context.state[3], + this->context.state[4], + this->context.state[5], + this->context.state[6], + this->context.state[7] + }; + + for (i = 0; i < 16; i++) { + GU64B(W[i], data, 8 * i); + uint64_t t1, t2; + t1 = (results[7]) + this->SIGMA1((results[4])) + this->F((results[4]), (results[5]), (results[6])) + (this->K[i]) + (W[i]); + t2 = this->SIGMA0((results[0])) + this->G((results[0]), (results[1]), (results[2])); + (results[7]) = (results[6]); + (results[6]) = (results[5]); + (results[5]) = (results[4]); + (results[4]) = (results[3]) + t1; + (results[3]) = (results[2]); + (results[2]) = (results[1]); + (results[1]) = (results[0]); + (results[0]) = t1 + t2; + } + + for (i = 16; i < 80; i++) { + W[i] = this->SIGMA3(W[i - 2]) + W[i - 7] + this->SIGMA2(W[i - 15]) + W[i - 16]; + uint64_t t1, t2; + t1 = (results[7]) + this->SIGMA1((results[4])) + this->F((results[4]), (results[5]), (results[6])) + (this->K[i]) + (W[i]); + t2 = this->SIGMA0((results[0])) + this->G((results[0]), (results[1]), (results[2])); + (results[7]) = (results[6]); + (results[6]) = (results[5]); + (results[5]) = (results[4]); + (results[4]) = (results[3]) + t1; + (results[3]) = (results[2]); + (results[2]) = (results[1]); + (results[1]) = (results[0]); + (results[0]) = t1 + t2; + } + + for (uint32_t z = 0; z < 8; z++) { + this->context.state[z] += results[z]; + } + } + inline void hashpp::SHA::SHA2_512_256::ctx_update(const uint8_t* data, size_t len) { + uint32_t left, fill, rlen = len; + const uint8_t* ptr = data; + + if (len != 0) { + + left = this->context.count[0] & 0x7F; fill = 128 - left; + + this->context.count[0] += len; + if ((this->context.count[0]) < (len)) { + (this->context.count[1])++; + } + + if ((left > 0) && (rlen >= fill)) { + memcpy(this->context.data + left, ptr, fill); + this->ctx_transform(this->context.data); + ptr += fill; + rlen -= fill; + left = 0; + } + + while (rlen >= 128) { + this->ctx_transform(ptr); + ptr += 128; + rlen -= 128; + } + + if (rlen > 0) { + memcpy(this->context.data + left, ptr, rlen); + } + } + } + inline void hashpp::SHA::SHA2_512_256::ctx_final() { + uint32_t block_present = 0; + uint8_t last_padded_block[2 * 128]; + + memset(last_padded_block, 0, sizeof(last_padded_block)); + + block_present = this->context.count[0] % 128; + if (block_present != 0) { + memcpy(last_padded_block, this->context.data, block_present); + } + + last_padded_block[block_present] = 0x80; + + if (block_present > (128 - 1 - (2 * sizeof(uint64_t)))) { + PU128B(this->context.count[0], this->context.count[1], last_padded_block, 2 * (128 - sizeof(uint64_t))); + this->ctx_transform(last_padded_block); + this->ctx_transform(last_padded_block + 128); + } + else { + PU128B(this->context.count[0], this->context.count[1], + last_padded_block, + 128 - (2 * sizeof(uint64_t))); + this->ctx_transform(last_padded_block); + } + + PU64B(this->context.state[0], this->context.digest, 0); + PU64B(this->context.state[1], this->context.digest, 8); + PU64B(this->context.state[2], this->context.digest, 16); + PU64B(this->context.state[3], this->context.digest, 24); + } + inline std::string SHA2_512_256::_H(const std::string& a, const std::string& b) { + return this->getHash(a + b); + } + inline std::string SHA2_512_256::HMAC(const std::string& key, const std::string& data) { + uint8_t k[128] = {0}; + + // (1) append zeros to the end of K to create a B byte string + // (e.g., if K is of length 20 bytes and B = 64, then K will be + // appended with 44 zero bytes 0x00) where B is the block size + if (key.length() > this->BLOCK_SIZE) { + // if K is longer than B bytes, reset K to K=H(K) + // where K can either be composed of entirely bytes of H(K) + // (if H(K) == L [where L => digest]) or the first L bytes of + // H(K) (if H(K) != L) followed by the remaining zeros (if H(K) < L) + std::vector k_ = this->fromHex(this->getHash(key)); + for (uint32_t i = 0; i < this->DIGEST_SIZE; ++i) { + k[i] = k_[i]; + } + } + else { + // if K is shorter than B bytes, append zeros to the end of K + // until K is B bytes long + for (uint32_t i = 0; i < key.length(); ++i) { + k[i] = key[i]; + } + } + + // (2) XOR (bitwise exclusive-OR) the B byte string computed in step (1) with ipad + for (uint32_t i = 0; i < this->BLOCK_SIZE; ++i) { + this->ipad[i] ^= k[i]; + } + + // (3) append the stream of data 'data' to the B byte string resulting from step (2) + for (uint32_t i = 0; i < data.length(); ++i) { + this->ipad.push_back(data[i]); + } + + // (4) apply H to the stream generated in step (3) + // see step (6) + + // (5) XOR (bitwise exclusive-OR) the B byte string computed in step (1) with opad + for (uint32_t i = 0; i < this->BLOCK_SIZE; ++i) { + this->opad[i] ^= k[i]; + } + + // (6) append the H result from step (4) to the B byte string resulting from step (5) + std::vector h_ = this->fromHex(this->getHash(std::string(this->ipad.begin(), this->ipad.end()))); + for (uint32_t i = 0; i < this->DIGEST_SIZE; ++i) { + this->opad.push_back(h_[i]); + } + + // (7) apply H to the stream generated in step (6) and output the result + return this->getHash(std::string(this->opad.begin(), this->opad.end())); + } + constexpr uint64_t hashpp::SHA::SHA2_512_256::F(const uint64_t A, const uint64_t B, const uint64_t C) { return ((A & B) ^ (~A & C)); } + constexpr uint64_t hashpp::SHA::SHA2_512_256::G(const uint64_t A, const uint64_t B, const uint64_t C) { return ((A & B) ^ (A & C) ^ (B & C)); } + constexpr uint64_t hashpp::SHA::SHA2_512_256::SIGMA0(const uint64_t A) { return this->rr64(A, 28) ^ this->rr64(A, 34) ^ this->rr64(A, 39); } + constexpr uint64_t hashpp::SHA::SHA2_512_256::SIGMA1(const uint64_t A) { return this->rr64(A, 14) ^ this->rr64(A, 18) ^ this->rr64(A, 41); } + constexpr uint64_t hashpp::SHA::SHA2_512_256::SIGMA2(const uint64_t A) { return this->rr64(A, 1) ^ this->rr64(A, 8) ^ (A >> 7); } + constexpr uint64_t hashpp::SHA::SHA2_512_256::SIGMA3(const uint64_t A) { return this->rr64(A, 19) ^ this->rr64(A, 61) ^ (A >> 6); } + } + + + // class used to store hash retrieved from get*Hash + // this class is used as an interface to access a + // hash returned by the above described function(s) + class hash { + public: + hash() noexcept = default; + hash(const hash& hashObj) noexcept : hashStr(hashObj.hashStr) {} + hash(hash&& hashObj) noexcept : hashStr(std::move(hashObj.hashStr)) {} + hash(const std::string& hex) noexcept : hashStr(hex) {} + hash(std::string&& hex) noexcept : hashStr(std::move(hex)) {} + + bool valid() const noexcept { return !this->hashStr.empty(); } + constexpr const std::string& getString() const noexcept { return this->hashStr; }; + + operator std::string() const noexcept { return this->hashStr; } + friend std::ostream& operator<<(std::ostream& _Ostr, const hashpp::hash& object) { + _Ostr << object.getString(); + return _Ostr; + } + + hash& operator=(const hashpp::hash& _rhs) noexcept { + if (this != &_rhs) { + this->hashStr = _rhs.getString(); + } + return *this; + } + + hash& operator=(hashpp::hash&& _rhs) noexcept { + if (this != &_rhs) { + this->hashStr = std::move(_rhs.hashStr); + } + return *this; + } + + bool operator==(const hashpp::hash& _rhs) const noexcept { + return _rhs.getString() == this->getString(); + } + + template , int> = 0> + bool operator==(const _Ty& _rhs) const noexcept { + return _rhs == this->getString(); + } + + private: + std::string hashStr; + }; + + + // class used to store hashes retrieved from get*Hashes + // this class is used to access multiple returned hashes + // of one or more hash algorithms + // + // for instance, we can get several hashes of several algorithms and print only + // selected algorithms like so: + // auto allHashes = hashpp::get::getHashes(ALGORITHMS::MD5, "data1", "data2", "data3", ...); + // for (auto hash : allHashes["MD5"]) { + // std::cout << hash << std::endl; + // } + // + // ... et cetera ... + + class hashCollection { + public: + hashCollection() noexcept = default; + hashCollection(const hashCollection& hc) noexcept : collection(hc.collection) {} + hashCollection(hashCollection&& hc) noexcept : collection(std::move(hc.collection)) {} + hashCollection(const std::vector>>& data) noexcept : collection(data) {} + hashCollection(std::vector>>&& data) noexcept : collection(std::move(data)) {} + + // operator[] overload to access collections of hashpp + // by their specific algorithm + std::vector operator[](const std::string& algoID) const { + return this->getHashesFromID(algoID); + } + + // function used to check if there are any hashes in the collection + // under the requested algorithm + // + // for instance, the below will check if allHashes has hash of type MD5 + // auto allHashes = getHashes(...); if (allHashes.valid("MD5")) { ... } + bool valid(const std::string& algoID) const noexcept { return !this->operator[](algoID).empty(); } + + std::vector>>::const_iterator begin() const noexcept { + return this->collection.begin(); + } + std::vector>>::const_iterator end() const noexcept { + return this->collection.end(); + } + + private: + std::vector>> collection; + std::vector getHashesFromID(const std::string& algoID) const { + for (const std::pair>& idHashCollectionPair : this->collection) { + if (!idHashCollectionPair.first.compare(algoID)) { + return idHashCollectionPair.second; + } + } + + // if no pair in collection contains requested algorithm ID + // just return an empty vector + return std::vector(); + } + }; + + // Ambiguous base container class to simplify original function signatures of getHash(...)-related functions + class Container { + public: // constructors + Container() noexcept = default; + Container(const Container& container) noexcept + : algorithm(container.algorithm), key(container.key), data(container.data) { + } + Container(Container&& container) noexcept + : algorithm(container.algorithm), key(std::move(container.key)), data(std::move(container.data)) { + } + Container( + ALGORITHMS algorithm, + const std::vector& data + ) noexcept : algorithm(algorithm), data(data) { + } + Container( + ALGORITHMS algorithm, + std::vector&& data + ) noexcept : algorithm(algorithm), data(std::move(data)) { + } + Container( + ALGORITHMS algorithm, + const std::vector& data, + const std::string& key + ) noexcept : algorithm(algorithm), data(data), key(key) { + } + Container( + ALGORITHMS algorithm, + std::vector&& data, + const std::string& key + ) noexcept : algorithm(algorithm), data(std::move(data)), key(key) { + } + Container( + ALGORITHMS algorithm, + const std::vector& data, + std::string&& key + ) noexcept : algorithm(algorithm), data(data), key(std::move(key)) { + } + Container( + ALGORITHMS algorithm, + std::vector&& data, + std::string&& key + ) noexcept : algorithm(algorithm), data(std::move(data)), key(std::move(key)) { + } + + template ...>, int> = 0> + Container( + ALGORITHMS algorithm, + const _Ts&... data + ) noexcept : algorithm(algorithm), data({ data... }) { + } + + template ..., std::negation>...>, int> = 0> + Container( + ALGORITHMS algorithm, + _Ts&&... data + ) noexcept : algorithm(algorithm), data({ std::forward<_Ts>(data)... }) { + } + + public: // member functions + constexpr const ALGORITHMS& getAlgorithm() const noexcept { return this->algorithm; } + constexpr const std::string& getKey() const noexcept { return this->key; } + constexpr const std::vector& getData() const noexcept { return this->data; } + void setAlgorithm(ALGORITHMS algorithm) noexcept { this->algorithm = algorithm; } + void setKey(const std::string& key) noexcept { this->key = key; } + + void setData(const std::vector& data) noexcept { this->data = data; } + void setData(std::vector&& data) noexcept { this->data = std::move(data); } + template void setData(const _Ts&... data) noexcept { this->data = { data... }; } + template >...>, int> = 0> + void setData(_Ts&&... data) noexcept { this->data = { std::forward<_Ts>(data)... }; } + + void appendData(const std::vector& data) noexcept { this->data.insert(this->data.end(), data.begin(), data.end()); } + void appendData(std::vector&& data) noexcept { this->data.insert(this->data.end(), std::make_move_iterator(data.begin()), std::make_move_iterator(data.end())); } + template void appendData(const _Ts&... data) noexcept { (this->data.push_back(data), ...); } + template >...>, int> = 0> + void appendData(_Ts&&... data) noexcept { (this->data.push_back(std::forward<_Ts>(data)), ...); } + + Container& operator=(const Container& _rhs) noexcept { + if (this != &_rhs) { + this->algorithm = _rhs.getAlgorithm(); + this->key = _rhs.getKey(); + this->data = _rhs.getData(); + } + return *this; + } + + Container& operator=(Container&& _rhs) noexcept { + if (this != &_rhs) { + this->algorithm = _rhs.algorithm; + this->key = std::move(_rhs.key); + this->data = std::move(_rhs.data); + } + return *this; + } + + private: // member variables + ALGORITHMS algorithm; + std::string key; + + // Holds arbitrary data; how this data is defined is determined + // by the functions that the container containing said data is passed to. + // (e.g., a call to getFilesHashes with a container will treat all data + // in it as paths to files to be hashed, and a call to getHashes with + // a container will treat all data as generic data to be hashed) + std::vector data; + }; + using HMAC_DataContainer = Container; + using DataContainer = Container; + using FilePathsContainer = Container; + + // interface class to allow use of static methods to access + // all algorithm classes and use their functions without + // the need of several instantiations of each class in + // the main source code of the user + // + // i.e., if a user wants to pass data to one or several + // algorithms and get the hash(es), they can do so via: + // hashpp::get::getHash or hashpp::get::getHashes + // + // the retrieval of file hashes is also possible via + // hashpp::get::getFileHash or collectively via + // hashpp::get::getFileHashes + // + // all hashpp::get methods return a hashpp::hash or a + // hashpp::hashCollection object. + // + // refer to the class definitions of both hashpp::hash and + // hashpp::hashCollection for info on how to use them + + class get { + public: + // function to return a resulting hash from selected ALGORITHM and passed data + static hashpp::hash getHash(hashpp::ALGORITHMS algorithm, const std::string& data) { + switch (algorithm) { + case hashpp::ALGORITHMS::MD5: + { + return { hashpp::MD::MD5().getHash(data) }; + } + case hashpp::ALGORITHMS::MD4: + { + return { hashpp::MD::MD4().getHash(data) }; + } + case hashpp::ALGORITHMS::MD2: + { + return { hashpp::MD::MD2().getHash(data) }; + } + case hashpp::ALGORITHMS::SHA1: + { + return { hashpp::SHA::SHA1().getHash(data) }; + } + case hashpp::ALGORITHMS::SHA2_224: + { + return { hashpp::SHA::SHA2_224().getHash(data) }; + } + case hashpp::ALGORITHMS::SHA2_256: + { + return { hashpp::SHA::SHA2_256().getHash(data) }; + } + case hashpp::ALGORITHMS::SHA2_384: + { + return { hashpp::SHA::SHA2_384().getHash(data) }; + } + case hashpp::ALGORITHMS::SHA2_512: + { + return { hashpp::SHA::SHA2_512().getHash(data) }; + } + case hashpp::ALGORITHMS::SHA2_512_224: + { + return { hashpp::SHA::SHA2_512_224().getHash(data) }; + } + case hashpp::ALGORITHMS::SHA2_512_256: + { + return { hashpp::SHA::SHA2_512_256().getHash(data) }; + } + default: + { + return hashpp::hash(); + } + } + } + + // function to return a resulting HMAC from selected ALGORITHM and passed key-data pair + static hashpp::hash getHMAC(hashpp::ALGORITHMS algorithm, const std::string& key, const std::string& data) { + switch (algorithm) { + case hashpp::ALGORITHMS::MD5: + { + return { hashpp::MD::MD5().getHMAC(key, data) }; + } + case hashpp::ALGORITHMS::MD4: + { + return { hashpp::MD::MD4().getHMAC(key, data) }; + } + case hashpp::ALGORITHMS::MD2: + { + return { hashpp::MD::MD2().getHMAC(key, data) }; + } + case hashpp::ALGORITHMS::SHA1: + { + return { hashpp::SHA::SHA1().getHMAC(key, data) }; + } + case hashpp::ALGORITHMS::SHA2_224: + { + return { hashpp::SHA::SHA2_224().getHMAC(key, data) }; + } + case hashpp::ALGORITHMS::SHA2_256: + { + return { hashpp::SHA::SHA2_256().getHMAC(key, data) }; + } + case hashpp::ALGORITHMS::SHA2_384: + { + return { hashpp::SHA::SHA2_384().getHMAC(key, data) }; + } + case hashpp::ALGORITHMS::SHA2_512: + { + return { hashpp::SHA::SHA2_512().getHMAC(key, data) }; + } + case hashpp::ALGORITHMS::SHA2_512_224: + { + return { hashpp::SHA::SHA2_512_224().getHMAC(key, data) }; + } + case hashpp::ALGORITHMS::SHA2_512_256: + { + return { hashpp::SHA::SHA2_512_256().getHMAC(key, data) }; + } + default: + { + return hashpp::hash(); + } + } + } + + // function to return a collection of resulting hashes from passed data container(s) + static hashpp::hashCollection getHashes(const DataContainer& dataSet) { + std::vector vMD5, vMD4, vMD2, vSHA1, vSHA2_224, vSHA2_256, vSHA2_384, vSHA2_512, vSHA2_512_224, vSHA2_512_256; + + switch (dataSet.getAlgorithm()) { + case hashpp::ALGORITHMS::MD5: + { + for (const std::string& data : dataSet.getData()) { + vMD5.push_back(hashpp::MD::MD5().getHash(data)); + } + break; + } + case hashpp::ALGORITHMS::MD4: + { + for (const std::string& data : dataSet.getData()) { + vMD4.push_back(hashpp::MD::MD4().getHash(data)); + } + break; + } + case hashpp::ALGORITHMS::MD2: + { + for (const std::string& data : dataSet.getData()) { + vMD2.push_back(hashpp::MD::MD2().getHash(data)); + } + break; + } + case hashpp::ALGORITHMS::SHA1: + { + for (const std::string& data : dataSet.getData()) { + vSHA1.push_back(hashpp::SHA::SHA1().getHash(data)); + } + break; + } + case hashpp::ALGORITHMS::SHA2_224: + { + for (const std::string& data : dataSet.getData()) { + vSHA2_224.push_back(hashpp::SHA::SHA2_224().getHash(data)); + } + break; + } + case hashpp::ALGORITHMS::SHA2_256: + { + for (const std::string& data : dataSet.getData()) { + vSHA2_256.push_back(hashpp::SHA::SHA2_256().getHash(data)); + } + break; + } + case hashpp::ALGORITHMS::SHA2_384: + { + for (const std::string& data : dataSet.getData()) { + vSHA2_384.push_back(hashpp::SHA::SHA2_384().getHash(data)); + } + break; + } + case hashpp::ALGORITHMS::SHA2_512: + { + for (const std::string& data : dataSet.getData()) { + vSHA2_512.push_back(hashpp::SHA::SHA2_512().getHash(data)); + } + break; + } + case hashpp::ALGORITHMS::SHA2_512_224: + { + for (const std::string& data : dataSet.getData()) { + vSHA2_512_224.push_back(hashpp::SHA::SHA2_512_224().getHash(data)); + } + break; + } + case hashpp::ALGORITHMS::SHA2_512_256: + { + for (const std::string& data : dataSet.getData()) { + vSHA2_512_256.push_back(hashpp::SHA::SHA2_512_256().getHash(data)); + } + break; + } + } + return hashCollection{ + { + { "MD5", vMD5 }, + { "MD4", vMD4 }, + { "MD2", vMD2 }, + { "SHA1", vSHA1 }, + { "SHA2-224", vSHA2_224 }, + { "SHA2-256", vSHA2_256 }, + { "SHA2-384", vSHA2_384 }, + { "SHA2-512", vSHA2_512 }, + { "SHA2-512-224", vSHA2_512_224 }, + { "SHA2-512-256", vSHA2_512_256 } + } + }; + } + + // function to return a collection of resulting hashes from passed data container(s) + static hashpp::hashCollection getHashes(const std::vector& dataSets) { + std::vector vMD5, vMD4, vMD2, vSHA1, vSHA2_224, vSHA2_256, vSHA2_384, vSHA2_512, vSHA2_512_224, vSHA2_512_256; + + for (const DataContainer& dataSet : dataSets) { + switch (dataSet.getAlgorithm()) { + case hashpp::ALGORITHMS::MD5: + { + for (const std::string& data : dataSet.getData()) { + vMD5.push_back(hashpp::MD::MD5().getHash(data)); + } + break; + } + case hashpp::ALGORITHMS::MD4: + { + for (const std::string& data : dataSet.getData()) { + vMD4.push_back(hashpp::MD::MD4().getHash(data)); + } + break; + } + case hashpp::ALGORITHMS::MD2: + { + for (const std::string& data : dataSet.getData()) { + vMD2.push_back(hashpp::MD::MD2().getHash(data)); + } + break; + } + case hashpp::ALGORITHMS::SHA1: + { + for (const std::string& data : dataSet.getData()) { + vSHA1.push_back(hashpp::SHA::SHA1().getHash(data)); + } + break; + } + case hashpp::ALGORITHMS::SHA2_224: + { + for (const std::string& data : dataSet.getData()) { + vSHA2_224.push_back(hashpp::SHA::SHA2_224().getHash(data)); + } + break; + } + case hashpp::ALGORITHMS::SHA2_256: + { + for (const std::string& data : dataSet.getData()) { + vSHA2_256.push_back(hashpp::SHA::SHA2_256().getHash(data)); + } + break; + } + case hashpp::ALGORITHMS::SHA2_384: + { + for (const std::string& data : dataSet.getData()) { + vSHA2_384.push_back(hashpp::SHA::SHA2_384().getHash(data)); + } + break; + } + case hashpp::ALGORITHMS::SHA2_512: + { + for (const std::string& data : dataSet.getData()) { + vSHA2_512.push_back(hashpp::SHA::SHA2_512().getHash(data)); + } + break; + } + case hashpp::ALGORITHMS::SHA2_512_224: + { + for (const std::string& data : dataSet.getData()) { + vSHA2_512_224.push_back(hashpp::SHA::SHA2_512_224().getHash(data)); + } + break; + } + case hashpp::ALGORITHMS::SHA2_512_256: + { + for (const std::string& data : dataSet.getData()) { + vSHA2_512_256.push_back(hashpp::SHA::SHA2_512_256().getHash(data)); + } + break; + } + } + } + return hashCollection{ + { + { "MD5", vMD5 }, + { "MD4", vMD4 }, + { "MD2", vMD2 }, + { "SHA1", vSHA1 }, + { "SHA2-224", vSHA2_224 }, + { "SHA2-256", vSHA2_256 }, + { "SHA2-384", vSHA2_384 }, + { "SHA2-512", vSHA2_512 }, + { "SHA2-512-224", vSHA2_512_224 }, + { "SHA2-512-256", vSHA2_512_256 } + } + }; + } + + // function to return a collection of resulting hashes from passed data container(s) + static hashpp::hashCollection getHashes(const std::initializer_list& dataSets) { + std::vector vMD5, vMD4, vMD2, vSHA1, vSHA2_224, vSHA2_256, vSHA2_384, vSHA2_512, vSHA2_512_224, vSHA2_512_256; + + for (const DataContainer& dataSet : dataSets) { + switch (dataSet.getAlgorithm()) { + case hashpp::ALGORITHMS::MD5: + { + for (const std::string& data : dataSet.getData()) { + vMD5.push_back(hashpp::MD::MD5().getHash(data)); + } + break; + } + case hashpp::ALGORITHMS::MD4: + { + for (const std::string& data : dataSet.getData()) { + vMD4.push_back(hashpp::MD::MD4().getHash(data)); + } + break; + } + case hashpp::ALGORITHMS::MD2: + { + for (const std::string& data : dataSet.getData()) { + vMD2.push_back(hashpp::MD::MD2().getHash(data)); + } + break; + } + case hashpp::ALGORITHMS::SHA1: + { + for (const std::string& data : dataSet.getData()) { + vSHA1.push_back(hashpp::SHA::SHA1().getHash(data)); + } + break; + } + case hashpp::ALGORITHMS::SHA2_224: + { + for (const std::string& data : dataSet.getData()) { + vSHA2_224.push_back(hashpp::SHA::SHA2_224().getHash(data)); + } + break; + } + case hashpp::ALGORITHMS::SHA2_256: + { + for (const std::string& data : dataSet.getData()) { + vSHA2_256.push_back(hashpp::SHA::SHA2_256().getHash(data)); + } + break; + } + case hashpp::ALGORITHMS::SHA2_384: + { + for (const std::string& data : dataSet.getData()) { + vSHA2_384.push_back(hashpp::SHA::SHA2_384().getHash(data)); + } + break; + } + case hashpp::ALGORITHMS::SHA2_512: + { + for (const std::string& data : dataSet.getData()) { + vSHA2_512.push_back(hashpp::SHA::SHA2_512().getHash(data)); + } + break; + } + case hashpp::ALGORITHMS::SHA2_512_224: + { + for (const std::string& data : dataSet.getData()) { + vSHA2_512_224.push_back(hashpp::SHA::SHA2_512_224().getHash(data)); + } + break; + } + case hashpp::ALGORITHMS::SHA2_512_256: + { + for (const std::string& data : dataSet.getData()) { + vSHA2_512_256.push_back(hashpp::SHA::SHA2_512_256().getHash(data)); + } + break; + } + } + } + return hashCollection{ + { + { "MD5", vMD5 }, + { "MD4", vMD4 }, + { "MD2", vMD2 }, + { "SHA1", vSHA1 }, + { "SHA2-224", vSHA2_224 }, + { "SHA2-256", vSHA2_256 }, + { "SHA2-384", vSHA2_384 }, + { "SHA2-512", vSHA2_512 }, + { "SHA2-512-224", vSHA2_512_224 }, + { "SHA2-512-256", vSHA2_512_256 } + } + }; + } + + // function to return a collection of resulting hashes from selected ALGORITHM and passed data + template ...>, int> = 0> + static hashpp::hashCollection getHashes(hashpp::ALGORITHMS algorithm, const _Ts&... data) { + switch (algorithm) { + case hashpp::ALGORITHMS::MD5: + { + std::vector vMD5; + (vMD5.push_back(hashpp::MD::MD5().getHash(static_cast(data))), ...); + return hashCollection{ {{ "MD5", vMD5 }} }; + } + case hashpp::ALGORITHMS::MD4: + { + std::vector vMD4; + (vMD4.push_back(hashpp::MD::MD4().getHash(static_cast(data))), ...); + return hashCollection{ {{ "MD4", vMD4 }} }; + } + case hashpp::ALGORITHMS::MD2: + { + std::vector vMD2; + (vMD2.push_back(hashpp::MD::MD2().getHash(static_cast(data))), ...); + return hashCollection{ {{ "MD2", vMD2 }} }; + } + case hashpp::ALGORITHMS::SHA1: + { + std::vector vSHA1; + (vSHA1.push_back(hashpp::SHA::SHA1().getHash(static_cast(data))), ...); + return hashCollection{ {{ "SHA1", vSHA1 }} }; + } + case hashpp::ALGORITHMS::SHA2_224: + { + std::vector vSHA2_224; + (vSHA2_224.push_back(hashpp::SHA::SHA2_224().getHash(static_cast(data))), ...); + return hashCollection{ {{ "SHA2-224", vSHA2_224 }} }; + } + case hashpp::ALGORITHMS::SHA2_256: + { + std::vector vSHA2_256; + (vSHA2_256.push_back(hashpp::SHA::SHA2_256().getHash(static_cast(data))), ...); + return hashCollection{ {{ "SHA2-256", vSHA2_256 }} }; + } + case hashpp::ALGORITHMS::SHA2_384: + { + std::vector vSHA_384; + (vSHA_384.push_back(hashpp::SHA::SHA2_384().getHash(static_cast(data))), ...); + return hashCollection{ {{ "SHA2-384", vSHA_384 }} }; + } + case hashpp::ALGORITHMS::SHA2_512: + { + std::vector vSHA2_512; + (vSHA2_512.push_back(hashpp::SHA::SHA2_512().getHash(static_cast(data))), ...); + return hashCollection{ {{ "SHA2-512", vSHA2_512 }} }; + } + case hashpp::ALGORITHMS::SHA2_512_224: + { + std::vector vSHA2_512_224; + (vSHA2_512_224.push_back(hashpp::SHA::SHA2_512_224().getHash(static_cast(data))), ...); + return hashCollection{ {{ "SHA2-512-224", vSHA2_512_224 }} }; + } + case hashpp::ALGORITHMS::SHA2_512_256: + { + std::vector vSHA2_512_256; + (vSHA2_512_256.push_back(hashpp::SHA::SHA2_512_256().getHash(static_cast(data))), ...); + return hashCollection{ {{ "SHA2-512-256", vSHA2_512_256 }} }; + } + } + } + + // function to return a collection of resulting HMACs from selected ALGORITHMS and passed key-data container(s) + static hashpp::hashCollection getHMACs(const HMAC_DataContainer& keyDataSet) { + std::vector vMD5, vMD4, vMD2, vSHA1, vSHA2_224, vSHA2_256, vSHA2_384, vSHA2_512, vSHA2_512_224, vSHA2_512_256; + + switch (keyDataSet.getAlgorithm()) { + case hashpp::ALGORITHMS::MD5: + { + for (const std::string& data : keyDataSet.getData()) { + vMD5.push_back(hashpp::MD::MD5().getHMAC(keyDataSet.getKey(), data)); + } + break; + } + case hashpp::ALGORITHMS::MD4: + { + for (const std::string& data : keyDataSet.getData()) { + vMD4.push_back(hashpp::MD::MD4().getHMAC(keyDataSet.getKey(), data)); + } + break; + } + case hashpp::ALGORITHMS::MD2: + { + for (const std::string& data : keyDataSet.getData()) { + vMD2.push_back(hashpp::MD::MD2().getHMAC(keyDataSet.getKey(), data)); + } + break; + } + case hashpp::ALGORITHMS::SHA1: + { + for (const std::string& data : keyDataSet.getData()) { + vSHA1.push_back(hashpp::SHA::SHA1().getHMAC(keyDataSet.getKey(), data)); + } + break; + } + case hashpp::ALGORITHMS::SHA2_224: + { + for (const std::string& data : keyDataSet.getData()) { + vSHA2_224.push_back(hashpp::SHA::SHA2_224().getHMAC(keyDataSet.getKey(), data)); + } + break; + } + case hashpp::ALGORITHMS::SHA2_256: + { + for (const std::string& data : keyDataSet.getData()) { + vSHA2_256.push_back(hashpp::SHA::SHA2_256().getHMAC(keyDataSet.getKey(), data)); + } + break; + } + case hashpp::ALGORITHMS::SHA2_384: + { + for (const std::string& data : keyDataSet.getData()) { + vSHA2_384.push_back(hashpp::SHA::SHA2_384().getHMAC(keyDataSet.getKey(), data)); + } + break; + } + case hashpp::ALGORITHMS::SHA2_512: + { + for (const std::string& data : keyDataSet.getData()) { + vSHA2_512.push_back(hashpp::SHA::SHA2_512().getHMAC(keyDataSet.getKey(), data)); + } + break; + } + case hashpp::ALGORITHMS::SHA2_512_224: + { + for (const std::string& data : keyDataSet.getData()) { + vSHA2_512_224.push_back(hashpp::SHA::SHA2_512_224().getHMAC(keyDataSet.getKey(), data)); + } + break; + } + case hashpp::ALGORITHMS::SHA2_512_256: + { + for (const std::string& data : keyDataSet.getData()) { + vSHA2_512_256.push_back(hashpp::SHA::SHA2_512_256().getHMAC(keyDataSet.getKey(), data)); + } + break; + } + } + return hashCollection{ + { + { "MD5", vMD5 }, + { "MD4", vMD4 }, + { "MD2", vMD2 }, + { "SHA1", vSHA1 }, + { "SHA2-224", vSHA2_224 }, + { "SHA2-256", vSHA2_256 }, + { "SHA2-384", vSHA2_384 }, + { "SHA2-512", vSHA2_512 }, + { "SHA2-512-224", vSHA2_512_224 }, + { "SHA2-512-256", vSHA2_512_256 } + } + }; + } + + // function to return a collection of resulting HMACs from selected ALGORITHMS and passed key-data container(s) + static hashpp::hashCollection getHMACs(const std::vector& keyDataSets) { + std::vector vMD5, vMD4, vMD2, vSHA1, vSHA2_224, vSHA2_256, vSHA2_384, vSHA2_512, vSHA2_512_224, vSHA2_512_256; + + for (const DataContainer& keyDataSet : keyDataSets) { + switch (keyDataSet.getAlgorithm()) { + case hashpp::ALGORITHMS::MD5: + { + for (const std::string& data : keyDataSet.getData()) { + vMD5.push_back(hashpp::MD::MD5().getHMAC(keyDataSet.getKey(), data)); + } + break; + } + case hashpp::ALGORITHMS::MD4: + { + for (const std::string& data : keyDataSet.getData()) { + vMD4.push_back(hashpp::MD::MD4().getHMAC(keyDataSet.getKey(), data)); + } + break; + } + case hashpp::ALGORITHMS::MD2: + { + for (const std::string& data : keyDataSet.getData()) { + vMD2.push_back(hashpp::MD::MD2().getHMAC(keyDataSet.getKey(), data)); + } + break; + } + case hashpp::ALGORITHMS::SHA1: + { + for (const std::string& data : keyDataSet.getData()) { + vSHA1.push_back(hashpp::SHA::SHA1().getHMAC(keyDataSet.getKey(), data)); + } + break; + } + case hashpp::ALGORITHMS::SHA2_224: + { + for (const std::string& data : keyDataSet.getData()) { + vSHA2_224.push_back(hashpp::SHA::SHA2_224().getHMAC(keyDataSet.getKey(), data)); + } + break; + } + case hashpp::ALGORITHMS::SHA2_256: + { + for (const std::string& data : keyDataSet.getData()) { + vSHA2_256.push_back(hashpp::SHA::SHA2_256().getHMAC(keyDataSet.getKey(), data)); + } + break; + } + case hashpp::ALGORITHMS::SHA2_384: + { + for (const std::string& data : keyDataSet.getData()) { + vSHA2_384.push_back(hashpp::SHA::SHA2_384().getHMAC(keyDataSet.getKey(), data)); + } + break; + } + case hashpp::ALGORITHMS::SHA2_512: + { + for (const std::string& data : keyDataSet.getData()) { + vSHA2_512.push_back(hashpp::SHA::SHA2_512().getHMAC(keyDataSet.getKey(), data)); + } + break; + } + case hashpp::ALGORITHMS::SHA2_512_224: + { + for (const std::string& data : keyDataSet.getData()) { + vSHA2_512_224.push_back(hashpp::SHA::SHA2_512_224().getHMAC(keyDataSet.getKey(), data)); + } + break; + } + case hashpp::ALGORITHMS::SHA2_512_256: + { + for (const std::string& data : keyDataSet.getData()) { + vSHA2_512_256.push_back(hashpp::SHA::SHA2_512_256().getHMAC(keyDataSet.getKey(), data)); + } + break; + } + } + } + return hashCollection{ + { + { "MD5", vMD5 }, + { "MD4", vMD4 }, + { "MD2", vMD2 }, + { "SHA1", vSHA1 }, + { "SHA2-224", vSHA2_224 }, + { "SHA2-256", vSHA2_256 }, + { "SHA2-384", vSHA2_384 }, + { "SHA2-512", vSHA2_512 }, + { "SHA2-512-224", vSHA2_512_224 }, + { "SHA2-512-256", vSHA2_512_256 } + } + }; + } + + // function to return a collection of resulting HMACs from selected ALGORITHMS and passed key-data container(s) + static hashpp::hashCollection getHMACs(const std::initializer_list& keyDataSets) { + std::vector vMD5, vMD4, vMD2, vSHA1, vSHA2_224, vSHA2_256, vSHA2_384, vSHA2_512, vSHA2_512_224, vSHA2_512_256; + + for (const DataContainer& keyDataSet : keyDataSets) { + switch (keyDataSet.getAlgorithm()) { + case hashpp::ALGORITHMS::MD5: + { + for (const std::string& data : keyDataSet.getData()) { + vMD5.push_back(hashpp::MD::MD5().getHMAC(keyDataSet.getKey(), data)); + } + break; + } + case hashpp::ALGORITHMS::MD4: + { + for (const std::string& data : keyDataSet.getData()) { + vMD4.push_back(hashpp::MD::MD4().getHMAC(keyDataSet.getKey(), data)); + } + break; + } + case hashpp::ALGORITHMS::MD2: + { + for (const std::string& data : keyDataSet.getData()) { + vMD2.push_back(hashpp::MD::MD2().getHMAC(keyDataSet.getKey(), data)); + } + break; + } + case hashpp::ALGORITHMS::SHA1: + { + for (const std::string& data : keyDataSet.getData()) { + vSHA1.push_back(hashpp::SHA::SHA1().getHMAC(keyDataSet.getKey(), data)); + } + break; + } + case hashpp::ALGORITHMS::SHA2_224: + { + for (const std::string& data : keyDataSet.getData()) { + vSHA2_224.push_back(hashpp::SHA::SHA2_224().getHMAC(keyDataSet.getKey(), data)); + } + break; + } + case hashpp::ALGORITHMS::SHA2_256: + { + for (const std::string& data : keyDataSet.getData()) { + vSHA2_256.push_back(hashpp::SHA::SHA2_256().getHMAC(keyDataSet.getKey(), data)); + } + break; + } + case hashpp::ALGORITHMS::SHA2_384: + { + for (const std::string& data : keyDataSet.getData()) { + vSHA2_384.push_back(hashpp::SHA::SHA2_384().getHMAC(keyDataSet.getKey(), data)); + } + break; + } + case hashpp::ALGORITHMS::SHA2_512: + { + for (const std::string& data : keyDataSet.getData()) { + vSHA2_512.push_back(hashpp::SHA::SHA2_512().getHMAC(keyDataSet.getKey(), data)); + } + break; + } + case hashpp::ALGORITHMS::SHA2_512_224: + { + for (const std::string& data : keyDataSet.getData()) { + vSHA2_512_224.push_back(hashpp::SHA::SHA2_512_224().getHMAC(keyDataSet.getKey(), data)); + } + break; + } + case hashpp::ALGORITHMS::SHA2_512_256: + { + for (const std::string& data : keyDataSet.getData()) { + vSHA2_512_256.push_back(hashpp::SHA::SHA2_512_256().getHMAC(keyDataSet.getKey(), data)); + } + break; + } + } + } + return hashCollection{ + { + { "MD5", vMD5 }, + { "MD4", vMD4 }, + { "MD2", vMD2 }, + { "SHA1", vSHA1 }, + { "SHA2-224", vSHA2_224 }, + { "SHA2-256", vSHA2_256 }, + { "SHA2-384", vSHA2_384 }, + { "SHA2-512", vSHA2_512 }, + { "SHA2-512-224", vSHA2_512_224 }, + { "SHA2-512-256", vSHA2_512_256 } + } + }; + } + + // function to return a collection of resulting HMACs from selected ALGORITHM, key, and data + template ...>, int> = 0> + static hashpp::hashCollection getHMACs(hashpp::ALGORITHMS algorithm, const std::string& key, const _Ts&... data) { + switch (algorithm) { + case hashpp::ALGORITHMS::MD5: + { + std::vector vMD5; + (vMD5.push_back(hashpp::MD::MD5().getHMAC(key, data)), ...); + return hashCollection{ {{ "MD5", vMD5 }} }; + } + case hashpp::ALGORITHMS::MD4: + { + std::vector vMD4; + (vMD4.push_back(hashpp::MD::MD4().getHMAC(key, data)), ...); + return hashCollection{ {{ "MD4", vMD4 }} }; + } + case hashpp::ALGORITHMS::MD2: + { + std::vector vMD2; + (vMD2.push_back(hashpp::MD::MD2().getHMAC(key, data)), ...); + return hashCollection{ {{ "MD2", vMD2 }} }; + } + case hashpp::ALGORITHMS::SHA1: + { + std::vector vSHA1; + (vSHA1.push_back(hashpp::SHA::SHA1().getHMAC(key, data)), ...); + return hashCollection{ {{ "SHA1", vSHA1 }} }; + } + case hashpp::ALGORITHMS::SHA2_224: + { + std::vector vSHA2_224; + (vSHA2_224.push_back(hashpp::SHA::SHA2_224().getHMAC(key, data)), ...); + return hashCollection{ {{ "SHA2-224", vSHA2_224 }} }; + } + case hashpp::ALGORITHMS::SHA2_256: + { + std::vector vSHA2_256; + (vSHA2_256.push_back(hashpp::SHA::SHA2_256().getHMAC(key, data)), ...); + return hashCollection{ {{ "SHA2-256", vSHA2_256 }} }; + } + case hashpp::ALGORITHMS::SHA2_384: + { + std::vector vSHA_384; + (vSHA_384.push_back(hashpp::SHA::SHA2_384().getHMAC(key, data)), ...); + return hashCollection{ {{ "SHA2-384", vSHA_384 }} }; + } + case hashpp::ALGORITHMS::SHA2_512: + { + std::vector vSHA2_512; + (vSHA2_512.push_back(hashpp::SHA::SHA2_512().getHMAC(key, data)), ...); + return hashCollection{ {{ "SHA2-512", vSHA2_512 }} }; + } + case hashpp::ALGORITHMS::SHA2_512_224: + { + std::vector vSHA2_512_224; + (vSHA2_512_224.push_back(hashpp::SHA::SHA2_512_224().getHMAC(key, data)), ...); + return hashCollection{ {{ "SHA2-512-224", vSHA2_512_224 }} }; + } + case hashpp::ALGORITHMS::SHA2_512_256: + { + std::vector vSHA2_512_256; + (vSHA2_512_256.push_back(hashpp::SHA::SHA2_512_256().getHMAC(key, data)), ...); + return hashCollection{ {{ "SHA2-512-256", vSHA2_512_256 }} }; + } + } + } + + // function to return a resulting hash from selected ALGORITHM and passed file + static hashpp::hash getFileHash(hashpp::ALGORITHMS algorithm, const std::string& path) { + if (std::filesystem::exists(path) && std::filesystem::is_regular_file(path)) { + switch (algorithm) { + case hashpp::ALGORITHMS::MD5: + { + return { hashpp::MD::MD5().getHash(std::filesystem::path(path)) }; + } + case hashpp::ALGORITHMS::MD4: + { + return { hashpp::MD::MD4().getHash(std::filesystem::path(path)) }; + } + case hashpp::ALGORITHMS::MD2: + { + return { hashpp::MD::MD2().getHash(std::filesystem::path(path)) }; + } + case hashpp::ALGORITHMS::SHA1: + { + return { hashpp::SHA::SHA1().getHash(std::filesystem::path(path)) }; + } + case hashpp::ALGORITHMS::SHA2_224: + { + return { hashpp::SHA::SHA2_224().getHash(std::filesystem::path(path)) }; + } + case hashpp::ALGORITHMS::SHA2_256: + { + return { hashpp::SHA::SHA2_256().getHash(std::filesystem::path(path)) }; + } + case hashpp::ALGORITHMS::SHA2_384: + { + return { hashpp::SHA::SHA2_384().getHash(std::filesystem::path(path)) }; + } + case hashpp::ALGORITHMS::SHA2_512: + { + return { hashpp::SHA::SHA2_512().getHash(std::filesystem::path(path)) }; + } + case hashpp::ALGORITHMS::SHA2_512_224: + { + return { hashpp::SHA::SHA2_512_224().getHash(std::filesystem::path(path)) }; + } + case hashpp::ALGORITHMS::SHA2_512_256: + { + return { hashpp::SHA::SHA2_512_256().getHash(std::filesystem::path(path)) }; + } + default: + { + return hashpp::hash(); + } + } + } + else { + return hashpp::hash(); + } + } + + // function to return a collection of resulting hashes from selected ALGORITHMS and passed file path container(s) (with recursive directory support) + static hashpp::hashCollection getFilesHashes(const FilePathsContainer& filePathSet) { + std::vector vMD5, vMD4, vMD2, vSHA1, vSHA2_224, vSHA2_256, vSHA2_384, vSHA2_512, vSHA2_512_224, vSHA2_512_256; + + switch (filePathSet.getAlgorithm()) { + case hashpp::ALGORITHMS::MD5: + { + for (const std::string& path : filePathSet.getData()) { + if (std::filesystem::exists(path) && std::filesystem::is_regular_file(path)) { + vMD5.push_back(hashpp::MD::MD5().getHash(std::filesystem::path(path))); + } + else if (std::filesystem::exists(path) && std::filesystem::is_directory(path)) { + for (const std::filesystem::directory_entry& item : std::filesystem::recursive_directory_iterator(path)) { + if (item.is_regular_file()) { + vMD5.push_back(hashpp::MD::MD5().getHash(item.path())); + } + } + } + } + break; + } + case hashpp::ALGORITHMS::MD4: + { + for (const std::string& path : filePathSet.getData()) { + if (std::filesystem::exists(path) && std::filesystem::is_regular_file(path)) { + vMD4.push_back(hashpp::MD::MD4().getHash(std::filesystem::path(path))); + } + else if (std::filesystem::exists(path) && std::filesystem::is_directory(path)) { + for (const std::filesystem::directory_entry& item : std::filesystem::recursive_directory_iterator(path)) { + if (item.is_regular_file()) { + vMD4.push_back(hashpp::MD::MD4().getHash(item.path())); + } + } + } + } + break; + } + case hashpp::ALGORITHMS::MD2: + { + for (const std::string& path : filePathSet.getData()) { + if (std::filesystem::exists(path) && std::filesystem::is_regular_file(path)) { + vMD2.push_back(hashpp::MD::MD2().getHash(std::filesystem::path(path))); + } + else if (std::filesystem::exists(path) && std::filesystem::is_directory(path)) { + for (const std::filesystem::directory_entry& item : std::filesystem::recursive_directory_iterator(path)) { + if (item.is_regular_file()) { + vMD2.push_back(hashpp::MD::MD2().getHash(item.path())); + } + } + } + } + break; + } + case hashpp::ALGORITHMS::SHA1: + { + for (const std::string& path : filePathSet.getData()) { + if (std::filesystem::exists(path) && std::filesystem::is_regular_file(path)) { + vSHA1.push_back(hashpp::SHA::SHA1().getHash(std::filesystem::path(path))); + } + else if (std::filesystem::exists(path) && std::filesystem::is_directory(path)) { + for (const std::filesystem::directory_entry& item : std::filesystem::recursive_directory_iterator(path)) { + if (item.is_regular_file()) { + vSHA1.push_back(hashpp::SHA::SHA1().getHash(item.path())); + } + } + } + } + break; + } + case hashpp::ALGORITHMS::SHA2_224: + { + for (const std::string& path : filePathSet.getData()) { + if (std::filesystem::exists(path) && std::filesystem::is_regular_file(path)) { + vSHA2_224.push_back(hashpp::SHA::SHA2_224().getHash(std::filesystem::path(path))); + } + else if (std::filesystem::exists(path) && std::filesystem::is_directory(path)) { + for (const std::filesystem::directory_entry& item : std::filesystem::recursive_directory_iterator(path)) { + if (item.is_regular_file()) { + vSHA2_224.push_back(hashpp::SHA::SHA2_224().getHash(item.path())); + } + } + } + } + break; + } + case hashpp::ALGORITHMS::SHA2_256: + { + for (const std::string& path : filePathSet.getData()) { + if (std::filesystem::exists(path) && std::filesystem::is_regular_file(path)) { + vSHA2_256.push_back(hashpp::SHA::SHA2_256().getHash(std::filesystem::path(path))); + } + else if (std::filesystem::exists(path) && std::filesystem::is_directory(path)) { + for (const std::filesystem::directory_entry& item : std::filesystem::recursive_directory_iterator(path)) { + if (item.is_regular_file()) { + vSHA2_256.push_back(hashpp::SHA::SHA2_256().getHash(item.path())); + } + } + } + } + break; + } + case hashpp::ALGORITHMS::SHA2_384: + { + for (const std::string& path : filePathSet.getData()) { + if (std::filesystem::exists(path) && std::filesystem::is_regular_file(path)) { + vSHA2_384.push_back(hashpp::SHA::SHA2_384().getHash(std::filesystem::path(path))); + } + else if (std::filesystem::exists(path) && std::filesystem::is_directory(path)) { + for (const std::filesystem::directory_entry& item : std::filesystem::recursive_directory_iterator(path)) { + if (item.is_regular_file()) { + vSHA2_384.push_back(hashpp::SHA::SHA2_384().getHash(item.path())); + } + } + } + } + break; + } + case hashpp::ALGORITHMS::SHA2_512: + { + for (const std::string& path : filePathSet.getData()) { + if (std::filesystem::exists(path) && std::filesystem::is_regular_file(path)) { + vSHA2_512.push_back(hashpp::SHA::SHA2_512().getHash(std::filesystem::path(path))); + } + else if (std::filesystem::exists(path) && std::filesystem::is_directory(path)) { + for (const std::filesystem::directory_entry& item : std::filesystem::recursive_directory_iterator(path)) { + if (item.is_regular_file()) { + vSHA2_512.push_back(hashpp::SHA::SHA2_512().getHash(item.path())); + } + } + } + } + break; + } + case hashpp::ALGORITHMS::SHA2_512_224: + { + for (const std::string& path : filePathSet.getData()) { + if (std::filesystem::exists(path) && std::filesystem::is_regular_file(path)) { + vSHA2_512_224.push_back(hashpp::SHA::SHA2_512_224().getHash(std::filesystem::path(path))); + } + else if (std::filesystem::exists(path) && std::filesystem::is_directory(path)) { + for (const std::filesystem::directory_entry& item : std::filesystem::recursive_directory_iterator(path)) { + if (item.is_regular_file()) { + vSHA2_512_224.push_back(hashpp::SHA::SHA2_512_224().getHash(item.path())); + } + } + } + } + break; + } + case hashpp::ALGORITHMS::SHA2_512_256: + { + for (const std::string& path : filePathSet.getData()) { + if (std::filesystem::exists(path) && std::filesystem::is_regular_file(path)) { + vSHA2_512_256.push_back(hashpp::SHA::SHA2_512_256().getHash(std::filesystem::path(path))); + } + else if (std::filesystem::exists(path) && std::filesystem::is_directory(path)) { + for (const std::filesystem::directory_entry& item : std::filesystem::recursive_directory_iterator(path)) { + if (item.is_regular_file()) { + vSHA2_512_256.push_back(hashpp::SHA::SHA2_512_256().getHash(item.path())); + } + } + } + } + break; + } + } + return hashCollection{ + { + { "MD5", vMD5 }, + { "MD4", vMD4 }, + { "MD2", vMD2 }, + { "SHA1", vSHA1 }, + { "SHA2-224", vSHA2_224 }, + { "SHA2-256", vSHA2_256 }, + { "SHA2-384", vSHA2_384 }, + { "SHA2-512", vSHA2_512 }, + { "SHA2-512-224", vSHA2_512_224 }, + { "SHA2-512-256", vSHA2_512_256 } + } + }; + } + + // function to return a collection of resulting hashes from selected ALGORITHMS and passed file path container(s) (with recursive directory support) + static hashpp::hashCollection getFilesHashes(const std::vector& filePathSets) { + std::vector vMD5, vMD4, vMD2, vSHA1, vSHA2_224, vSHA2_256, vSHA2_384, vSHA2_512, vSHA2_512_224, vSHA2_512_256; + + for (const FilePathsContainer& filePathSet : filePathSets) { + switch (filePathSet.getAlgorithm()) { + case hashpp::ALGORITHMS::MD5: + { + for (const std::string& path : filePathSet.getData()) { + if (std::filesystem::exists(path) && std::filesystem::is_regular_file(path)) { + vMD5.push_back(hashpp::MD::MD5().getHash(std::filesystem::path(path))); + } + else if (std::filesystem::exists(path) && std::filesystem::is_directory(path)) { + for (const std::filesystem::directory_entry& item : std::filesystem::recursive_directory_iterator(path)) { + if (item.is_regular_file()) { + vMD5.push_back(hashpp::MD::MD5().getHash(item.path())); + } + } + } + } + break; + } + case hashpp::ALGORITHMS::MD4: + { + for (const std::string& path : filePathSet.getData()) { + if (std::filesystem::exists(path) && std::filesystem::is_regular_file(path)) { + vMD4.push_back(hashpp::MD::MD4().getHash(std::filesystem::path(path))); + } + else if (std::filesystem::exists(path) && std::filesystem::is_directory(path)) { + for (const std::filesystem::directory_entry& item : std::filesystem::recursive_directory_iterator(path)) { + if (item.is_regular_file()) { + vMD4.push_back(hashpp::MD::MD4().getHash(item.path())); + } + } + } + } + break; + } + case hashpp::ALGORITHMS::MD2: + { + for (const std::string& path : filePathSet.getData()) { + if (std::filesystem::exists(path) && std::filesystem::is_regular_file(path)) { + vMD2.push_back(hashpp::MD::MD2().getHash(std::filesystem::path(path))); + } + else if (std::filesystem::exists(path) && std::filesystem::is_directory(path)) { + for (const std::filesystem::directory_entry& item : std::filesystem::recursive_directory_iterator(path)) { + if (item.is_regular_file()) { + vMD2.push_back(hashpp::MD::MD2().getHash(item.path())); + } + } + } + } + break; + } + case hashpp::ALGORITHMS::SHA1: + { + for (const std::string& path : filePathSet.getData()) { + if (std::filesystem::exists(path) && std::filesystem::is_regular_file(path)) { + vSHA1.push_back(hashpp::SHA::SHA1().getHash(std::filesystem::path(path))); + } + else if (std::filesystem::exists(path) && std::filesystem::is_directory(path)) { + for (const std::filesystem::directory_entry& item : std::filesystem::recursive_directory_iterator(path)) { + if (item.is_regular_file()) { + vSHA1.push_back(hashpp::SHA::SHA1().getHash(item.path())); + } + } + } + } + break; + } + case hashpp::ALGORITHMS::SHA2_224: + { + for (const std::string& path : filePathSet.getData()) { + if (std::filesystem::exists(path) && std::filesystem::is_regular_file(path)) { + vSHA2_224.push_back(hashpp::SHA::SHA2_224().getHash(std::filesystem::path(path))); + } + else if (std::filesystem::exists(path) && std::filesystem::is_directory(path)) { + for (const std::filesystem::directory_entry& item : std::filesystem::recursive_directory_iterator(path)) { + if (item.is_regular_file()) { + vSHA2_224.push_back(hashpp::SHA::SHA2_224().getHash(item.path())); + } + } + } + } + break; + } + case hashpp::ALGORITHMS::SHA2_256: + { + for (const std::string& path : filePathSet.getData()) { + if (std::filesystem::exists(path) && std::filesystem::is_regular_file(path)) { + vSHA2_256.push_back(hashpp::SHA::SHA2_256().getHash(std::filesystem::path(path))); + } + else if (std::filesystem::exists(path) && std::filesystem::is_directory(path)) { + for (const std::filesystem::directory_entry& item : std::filesystem::recursive_directory_iterator(path)) { + if (item.is_regular_file()) { + vSHA2_256.push_back(hashpp::SHA::SHA2_256().getHash(item.path())); + } + } + } + } + break; + } + case hashpp::ALGORITHMS::SHA2_384: + { + for (const std::string& path : filePathSet.getData()) { + if (std::filesystem::exists(path) && std::filesystem::is_regular_file(path)) { + vSHA2_384.push_back(hashpp::SHA::SHA2_384().getHash(std::filesystem::path(path))); + } + else if (std::filesystem::exists(path) && std::filesystem::is_directory(path)) { + for (const std::filesystem::directory_entry& item : std::filesystem::recursive_directory_iterator(path)) { + if (item.is_regular_file()) { + vSHA2_384.push_back(hashpp::SHA::SHA2_384().getHash(item.path())); + } + } + } + } + break; + } + case hashpp::ALGORITHMS::SHA2_512: + { + for (const std::string& path : filePathSet.getData()) { + if (std::filesystem::exists(path) && std::filesystem::is_regular_file(path)) { + vSHA2_512.push_back(hashpp::SHA::SHA2_512().getHash(std::filesystem::path(path))); + } + else if (std::filesystem::exists(path) && std::filesystem::is_directory(path)) { + for (const std::filesystem::directory_entry& item : std::filesystem::recursive_directory_iterator(path)) { + if (item.is_regular_file()) { + vSHA2_512.push_back(hashpp::SHA::SHA2_512().getHash(item.path())); + } + } + } + } + break; + } + case hashpp::ALGORITHMS::SHA2_512_224: + { + for (const std::string& path : filePathSet.getData()) { + if (std::filesystem::exists(path) && std::filesystem::is_regular_file(path)) { + vSHA2_512_224.push_back(hashpp::SHA::SHA2_512_224().getHash(std::filesystem::path(path))); + } + else if (std::filesystem::exists(path) && std::filesystem::is_directory(path)) { + for (const std::filesystem::directory_entry& item : std::filesystem::recursive_directory_iterator(path)) { + if (item.is_regular_file()) { + vSHA2_512_224.push_back(hashpp::SHA::SHA2_512_224().getHash(item.path())); + } + } + } + } + break; + } + case hashpp::ALGORITHMS::SHA2_512_256: + { + for (const std::string& path : filePathSet.getData()) { + if (std::filesystem::exists(path) && std::filesystem::is_regular_file(path)) { + vSHA2_512_256.push_back(hashpp::SHA::SHA2_512_256().getHash(std::filesystem::path(path))); + } + else if (std::filesystem::exists(path) && std::filesystem::is_directory(path)) { + for (const std::filesystem::directory_entry& item : std::filesystem::recursive_directory_iterator(path)) { + if (item.is_regular_file()) { + vSHA2_512_256.push_back(hashpp::SHA::SHA2_512_256().getHash(item.path())); + } + } + } + } + break; + } + } + } + return hashCollection{ + { + { "MD5", vMD5 }, + { "MD4", vMD4 }, + { "MD2", vMD2 }, + { "SHA1", vSHA1 }, + { "SHA2-224", vSHA2_224 }, + { "SHA2-256", vSHA2_256 }, + { "SHA2-384", vSHA2_384 }, + { "SHA2-512", vSHA2_512 }, + { "SHA2-512-224", vSHA2_512_224 }, + { "SHA2-512-256", vSHA2_512_256 } + } + }; + } + + // function to return a collection of resulting hashes from selected ALGORITHMS and passed file path container(s) (with recursive directory support) + static hashpp::hashCollection getFilesHashes(const std::initializer_list& filePathSets) { + std::vector vMD5, vMD4, vMD2, vSHA1, vSHA2_224, vSHA2_256, vSHA2_384, vSHA2_512, vSHA2_512_224, vSHA2_512_256; + + for (const FilePathsContainer& filePathSet : filePathSets) { + switch (filePathSet.getAlgorithm()) { + case hashpp::ALGORITHMS::MD5: + { + for (const std::string& path : filePathSet.getData()) { + if (std::filesystem::exists(path) && std::filesystem::is_regular_file(path)) { + vMD5.push_back(hashpp::MD::MD5().getHash(std::filesystem::path(path))); + } + else if (std::filesystem::exists(path) && std::filesystem::is_directory(path)) { + for (const std::filesystem::directory_entry& item : std::filesystem::recursive_directory_iterator(path)) { + if (item.is_regular_file()) { + vMD5.push_back(hashpp::MD::MD5().getHash(item.path())); + } + } + } + } + break; + } + case hashpp::ALGORITHMS::MD4: + { + for (const std::string& path : filePathSet.getData()) { + if (std::filesystem::exists(path) && std::filesystem::is_regular_file(path)) { + vMD4.push_back(hashpp::MD::MD4().getHash(std::filesystem::path(path))); + } + else if (std::filesystem::exists(path) && std::filesystem::is_directory(path)) { + for (const std::filesystem::directory_entry& item : std::filesystem::recursive_directory_iterator(path)) { + if (item.is_regular_file()) { + vMD4.push_back(hashpp::MD::MD4().getHash(item.path())); + } + } + } + } + break; + } + case hashpp::ALGORITHMS::MD2: + { + for (const std::string& path : filePathSet.getData()) { + if (std::filesystem::exists(path) && std::filesystem::is_regular_file(path)) { + vMD2.push_back(hashpp::MD::MD2().getHash(std::filesystem::path(path))); + } + else if (std::filesystem::exists(path) && std::filesystem::is_directory(path)) { + for (const std::filesystem::directory_entry& item : std::filesystem::recursive_directory_iterator(path)) { + if (item.is_regular_file()) { + vMD2.push_back(hashpp::MD::MD2().getHash(item.path())); + } + } + } + } + break; + } + case hashpp::ALGORITHMS::SHA1: + { + for (const std::string& path : filePathSet.getData()) { + if (std::filesystem::exists(path) && std::filesystem::is_regular_file(path)) { + vSHA1.push_back(hashpp::SHA::SHA1().getHash(std::filesystem::path(path))); + } + else if (std::filesystem::exists(path) && std::filesystem::is_directory(path)) { + for (const std::filesystem::directory_entry& item : std::filesystem::recursive_directory_iterator(path)) { + if (item.is_regular_file()) { + vSHA1.push_back(hashpp::SHA::SHA1().getHash(item.path())); + } + } + } + } + break; + } + case hashpp::ALGORITHMS::SHA2_224: + { + for (const std::string& path : filePathSet.getData()) { + if (std::filesystem::exists(path) && std::filesystem::is_regular_file(path)) { + vSHA2_224.push_back(hashpp::SHA::SHA2_224().getHash(std::filesystem::path(path))); + } + else if (std::filesystem::exists(path) && std::filesystem::is_directory(path)) { + for (const std::filesystem::directory_entry& item : std::filesystem::recursive_directory_iterator(path)) { + if (item.is_regular_file()) { + vSHA2_224.push_back(hashpp::SHA::SHA2_224().getHash(item.path())); + } + } + } + } + break; + } + case hashpp::ALGORITHMS::SHA2_256: + { + for (const std::string& path : filePathSet.getData()) { + if (std::filesystem::exists(path) && std::filesystem::is_regular_file(path)) { + vSHA2_256.push_back(hashpp::SHA::SHA2_256().getHash(std::filesystem::path(path))); + } + else if (std::filesystem::exists(path) && std::filesystem::is_directory(path)) { + for (const std::filesystem::directory_entry& item : std::filesystem::recursive_directory_iterator(path)) { + if (item.is_regular_file()) { + vSHA2_256.push_back(hashpp::SHA::SHA2_256().getHash(item.path())); + } + } + } + } + break; + } + case hashpp::ALGORITHMS::SHA2_384: + { + for (const std::string& path : filePathSet.getData()) { + if (std::filesystem::exists(path) && std::filesystem::is_regular_file(path)) { + vSHA2_384.push_back(hashpp::SHA::SHA2_384().getHash(std::filesystem::path(path))); + } + else if (std::filesystem::exists(path) && std::filesystem::is_directory(path)) { + for (const std::filesystem::directory_entry& item : std::filesystem::recursive_directory_iterator(path)) { + if (item.is_regular_file()) { + vSHA2_384.push_back(hashpp::SHA::SHA2_384().getHash(item.path())); + } + } + } + } + break; + } + case hashpp::ALGORITHMS::SHA2_512: + { + for (const std::string& path : filePathSet.getData()) { + if (std::filesystem::exists(path) && std::filesystem::is_regular_file(path)) { + vSHA2_512.push_back(hashpp::SHA::SHA2_512().getHash(std::filesystem::path(path))); + } + else if (std::filesystem::exists(path) && std::filesystem::is_directory(path)) { + for (const std::filesystem::directory_entry& item : std::filesystem::recursive_directory_iterator(path)) { + if (item.is_regular_file()) { + vSHA2_512.push_back(hashpp::SHA::SHA2_512().getHash(item.path())); + } + } + } + } + break; + } + case hashpp::ALGORITHMS::SHA2_512_224: + { + for (const std::string& path : filePathSet.getData()) { + if (std::filesystem::exists(path) && std::filesystem::is_regular_file(path)) { + vSHA2_512_224.push_back(hashpp::SHA::SHA2_512_224().getHash(std::filesystem::path(path))); + } + else if (std::filesystem::exists(path) && std::filesystem::is_directory(path)) { + for (const std::filesystem::directory_entry& item : std::filesystem::recursive_directory_iterator(path)) { + if (item.is_regular_file()) { + vSHA2_512_224.push_back(hashpp::SHA::SHA2_512_224().getHash(item.path())); + } + } + } + } + break; + } + case hashpp::ALGORITHMS::SHA2_512_256: + { + for (const std::string& path : filePathSet.getData()) { + if (std::filesystem::exists(path) && std::filesystem::is_regular_file(path)) { + vSHA2_512_256.push_back(hashpp::SHA::SHA2_512_256().getHash(std::filesystem::path(path))); + } + else if (std::filesystem::exists(path) && std::filesystem::is_directory(path)) { + for (const std::filesystem::directory_entry& item : std::filesystem::recursive_directory_iterator(path)) { + if (item.is_regular_file()) { + vSHA2_512_256.push_back(hashpp::SHA::SHA2_512_256().getHash(item.path())); + } + } + } + } + break; + } + } + } + return hashCollection{ + { + { "MD5", vMD5 }, + { "MD4", vMD4 }, + { "MD2", vMD2 }, + { "SHA1", vSHA1 }, + { "SHA2-224", vSHA2_224 }, + { "SHA2-256", vSHA2_256 }, + { "SHA2-384", vSHA2_384 }, + { "SHA2-512", vSHA2_512 }, + { "SHA2-512-224", vSHA2_512_224 }, + { "SHA2-512-256", vSHA2_512_256 } + } + }; + } + }; + +#if defined(HASHPP_INCLUDE_METRICS) + // well-defined timer class for use in metrics + template + class timer { + public: + void startTimer() { + this->_start = std::chrono::high_resolution_clock::now(); + } + + void stopTimer() { + this->_end = std::chrono::high_resolution_clock::now(); + } + + constexpr _Ty getTime() const { + return std::chrono::duration_cast<_Ty>(this->_end - this->_start); + } + + private: + std::chrono::steady_clock::time_point _start; + std::chrono::steady_clock::time_point _end; + }; + + template + class metrics : private timer<_Ty> { // optional class for algorithm metrics and benchmarking + public: + // Function to check each algorithm for correctness + void checkAlgorithms() const { + for (const hashpp::ALGORITHMS& algorithm : this->algorithms) { + if (hashpp::get::getHash(algorithm, "d").getString() == this->comparisons[static_cast(algorithm)].first) { + std::cout << this->comparisons[static_cast(algorithm)].second << " pass." << std::endl; + } + else { + std::cout << this->comparisons[static_cast(algorithm)].second << " fail." << std::endl; + } + } + } + + // Function to check each algorithm for HMAC correctness + void checkAlgorithms_HMAC() const { + for (const hashpp::ALGORITHMS& algorithm : this->algorithms) { + if (hashpp::get::getHMAC(algorithm, "k", "d").getString() == this->hmac_comparisons[static_cast(algorithm)].first) { + std::cout << this->hmac_comparisons[static_cast(algorithm)].second << " HMAC pass." << std::endl; + } + else { + std::cout << this->hmac_comparisons[static_cast(algorithm)].second << " HMAC fail." << std::endl; + } + } + } + + // Function to measure performance of all hashing algorithms when hashing 10 million + // repetitions of argument 'target.' + void benchmarkAlgorithms(const std::string& target) { + std::cout << "Testing 10m hashing repetitions of '" << target << "'.\n" << std::endl; + for (const hashpp::ALGORITHMS& algorithm : this->algorithms) { + if (algorithm == hashpp::ALGORITHMS::MD2 && !IncludeMD2) { + continue; + } + else { + this->startTimer(); + for (uint32_t i = 0; i < 10000000; i++) { + hashpp::get::getHash(algorithm, target); + } + this->stopTimer(); + std::cout << this->comparisons[static_cast(algorithm)].second << ": " << this->getTime().count() << std::endl; + } + } + } + + // Function to measure performance of all HMAC hashing algorithms when hashing 10 million + // repetitions of argument 'target' with key 'key.' + void benchmarkAlgorithms_HMAC(const std::string& key, const std::string& target) { + std::cout << "Testing 10m HMAC hashing repetitions of '" << target << "' with key '" << key << "'.\n" << std::endl; + for (const hashpp::ALGORITHMS& algorithm : this->algorithms) { + if (algorithm == hashpp::ALGORITHMS::MD2 && !IncludeMD2) { + continue; + } + else { + this->startTimer(); + for (uint32_t i = 0; i < 10000000; i++) { + hashpp::get::getHMAC(algorithm, key, target); + } + this->stopTimer(); + std::cout << this->hmac_comparisons[static_cast(algorithm)].second << ": " << this->getTime().count() << std::endl; + } + } + } + + // Function to measure performance of all hashing algorithms when hashing a given file + void benchmarkAlgorithms_File(const std::string& path) { + std::cout << "Testing algorithm speeds for hashing of file '" << path << "'.\n" << std::endl; + for (const hashpp::ALGORITHMS& algorithm : this->algorithms) { + if (algorithm == hashpp::ALGORITHMS::MD2 && !IncludeMD2) { + continue; + } + else { + this->startTimer(); + hashpp::get::getFileHash(algorithm, path); + this->stopTimer(); + std::cout << this->comparisons[static_cast(algorithm)].second << ": " << this->getTime().count() << std::endl; + } + } + } + + private: + const std::vector algorithms = { + hashpp::ALGORITHMS::MD5, + hashpp::ALGORITHMS::MD4, + hashpp::ALGORITHMS::MD2, + hashpp::ALGORITHMS::SHA1, + hashpp::ALGORITHMS::SHA2_224, + hashpp::ALGORITHMS::SHA2_256, + hashpp::ALGORITHMS::SHA2_384, + hashpp::ALGORITHMS::SHA2_512, + hashpp::ALGORITHMS::SHA2_512_224, + hashpp::ALGORITHMS::SHA2_512_256 + }; + + // All correct hashes of data 'd' for comparison + const std::vector> comparisons = { + { "8277e0910d750195b448797616e091ad", "MD5" }, + { "5d3f7ed29552c4ab4612fb7686bb52bb", "MD4" }, + { "96978c0796ce94f7beb31576946b6bed", "MD2" }, + { "3c363836cf4e16666669a25da280a1865c2d2874", "SHA1" }, + { "06c9f71496e24dec6acc44895648cf9ec40b5cebb7bc4858a3c69f25", "SHA2-224" }, + { "18ac3e7343f016890c510e93f935261169d9e3f565436429830faf0934f4f8e4", "SHA2-256" }, + { "8ac10705a78a2dcd15fa577bac70762708597a02e130d8a6192d73dababd2b14502dbeee29d0e22bc341a0c42af6a4fb", "SHA2-384" }, + { "48fb10b15f3d44a09dc82d02b06581e0c0c69478c9fd2cf8f9093659019a1687baecdbb38c9e72b12169dc4148690f87467f9154f5931c5df665c6496cbfd5f5", "SHA2-512" }, + { "a8c9aa3f45f2ada72e3ae9278407b4ade221490596c69b27af611dae", "SHA2-512/224" }, + { "9a895196448c0a9daa9769b48f29db5b41cfe2f6f65943a8ef2b8f446e388f7e", "SHA2-512/256" } + }; + + // All correct hashes of data 'd' with key 'k' for HMAC comparison + const std::vector> hmac_comparisons = { + { "7f330edb3a84f317f7ca433d6038ff9a", "MD5" }, + { "de693e9b565099e8fe8129b3833a702d", "MD4" }, + { "a10a9e7a2bcfa4cd38d0a1cab3f25816", "MD2" }, + { "2b90e41e7c0cc8e2f75c02910c3899cc468ba316", "SHA1" }, + { "c9b7d3a28728c8a0b10dd425247af65e00725f6e5d32131b0c9a4ac1", "SHA2-224" }, + { "e7ea21c3bcb63a4da3ad78503168d36bdca0be622382ea60a108fad4e4966679", "SHA2-256" }, + { "48da203588bac88ca21d843f0dd201e15e33fe08a4db11ff4f07d2b62e2e10dee4e55d49612a658a9e5ac2c0a6b8e945", "SHA2-384" }, + { "75e6621bf12000a13d8dae79fed84aadffbbceaefd36ae061493b34aef6a2988f0fb91b8ba4fef293ed0bd09e6bb7578858b8f2f7f70fe3ca7490d37f655fd38", "SHA2-512" }, + { "7882112b43ad00ad1a01bc1a8df3745aad04e27a999ceb60da32bb18", "SHA2-512/224" }, + { "df48fa6a1e87fc2ccdce7a79028b4cd891ce905ebf411898c9aba975f3a2f8ad", "SHA2-512/256" } + }; + }; +#endif +} + +#endif \ No newline at end of file diff --git a/src/Network/Core.cpp b/src/Network/Core.cpp index 1cd861d..2b21ea9 100755 --- a/src/Network/Core.cpp +++ b/src/Network/Core.cpp @@ -80,7 +80,9 @@ void Parse(std::string Data,SOCKET CSocket){ case 'O': //open default browser with URL if(IsAllowedLink(Data.substr(1))) { ShellExecuteA(nullptr, "open", Data.substr(1).c_str(), nullptr, nullptr,SW_SHOW); ///TODO: Look at when working on linux port + info("Opening Link \"" + Data.substr(1) + "\""); } + Data.clear(); break; case 'P': Data = Code + std::to_string(ProxyPort); diff --git a/src/Security/BeamNG.cpp b/src/Security/BeamNG.cpp index 0d2bef9..2595934 100755 --- a/src/Security/BeamNG.cpp +++ b/src/Security/BeamNG.cpp @@ -144,9 +144,9 @@ void FileList(std::vector&a,const std::string& Path){ for (const auto &entry : fs::directory_iterator(Path)) { const auto& DPath = entry.path(); if (!entry.is_directory()) { - a.emplace_back(DPath.u8string()); - }else if(NameValid(DPath.filename().u8string())){ - FileList(a, DPath.u8string()); + a.emplace_back(DPath.string()); + }else if(NameValid(DPath.filename().string())){ + FileList(a, DPath.string()); } } } @@ -165,7 +165,7 @@ bool Find(const std::string& FName,const std::string& Path){ bool FindHack(const std::string& Path){ bool s = true; for (const auto &entry : fs::directory_iterator(Path)) { - std::string Name = entry.path().filename().u8string(); + std::string Name = entry.path().filename().string(); for(char&c : Name)c = char(tolower(c)); if(Name == "steam.exe")s = false; if(Name.find("greenluma") != -1){ diff --git a/src/Startup.cpp b/src/Startup.cpp index c706c36..d276411 100755 --- a/src/Startup.cpp +++ b/src/Startup.cpp @@ -15,17 +15,46 @@ #include "Security/Init.h" #include #include "Startup.h" +#include "hashpp.h" #include "Logger.h" #include #include #include "Http.h" + extern int TraceBack; bool Dev = false; int ProxyPort = 0; namespace fs = std::filesystem; +VersionParser::VersionParser(const std::string& from_string) { + std::string token; + std::istringstream tokenStream(from_string); + while (std::getline(tokenStream, token, '.')) { + data.emplace_back(std::stol(token)); + split.emplace_back(token); + } +} + +std::strong_ordering VersionParser::operator<=>( + const VersionParser& rhs) const noexcept { + size_t const fields = std::min(data.size(), rhs.data.size()); + for (size_t i = 0; i != fields; ++i) { + if (data[i] == rhs.data[i]) continue; + else if (data[i] < rhs.data[i]) return std::strong_ordering::less; + else return std::strong_ordering::greater; + } + if (data.size() == rhs.data.size()) return std::strong_ordering::equal; + else if (data.size() > rhs.data.size()) return std::strong_ordering::greater; + else return std::strong_ordering::less; +} + +bool VersionParser::operator==(const VersionParser& rhs) const noexcept { + return std::is_eq(*this <=> rhs); +} + + std::string GetEN(){ return "BeamMP-Launcher.exe"; } @@ -75,44 +104,50 @@ void CheckName(int argc,char* args[]){ URelaunch(argc,args); } } +/* + * std::string LatestHash = HTTP::Get("https://backend.beammp.com/sha/launcher?branch=" + TargetBuild + "&pk=" + PublicKey); + std::string LatestVersion = HTTP::Get("https://backend.beammp.com/version/launcher?branch=" + TargetBuild + "&pk=" + PublicKey); -void CheckForUpdates(int argc,char*args[],const std::string& CV){ - std::string link; - std::string HTTP = HTTP::Get("https://beammp.com/builds/launcher?version=true"); - bool fallback = false; - if(HTTP.find_first_of("0123456789") == std::string::npos){ - HTTP = HTTP::Get("https://backup1.beammp.com/builds/launcher?version=true"); - fallback = true; - if(HTTP.find_first_of("0123456789") == std::string::npos) { - fatal("Primary Servers Offline! sorry for the inconvenience!"); - } - } - if(fallback){ - link = "https://backup1.beammp.com/builds/launcher?download=true"; - }else link = "https://beammp.com/builds/launcher?download=true"; + transform(LatestHash.begin(), LatestHash.end(), LatestHash.begin(), ::tolower); + std::string FileHash = hashpp::get::getFileHash(hashpp::ALGORITHMS::SHA2_256, (CurrentPath/"BeamMP-Launcher.exe").string()); std::string EP(GetEP() + GetEN()), Back(GetEP() + "BeamMP-Launcher.back"); - if(fs::exists(Back))remove(Back.c_str()); + if(FileHash != LatestHash && VersionParser(LatestVersion) > VersionParser(FullVersion)) { + LOG(INFO) << "Launcher update found!"; + fs::remove(CurrentPath/"BeamMP-Launcher.back"); + fs::rename(CurrentPath/"BeamMP-Launcher.exe", CurrentPath/"BeamMP-Launcher.back"); + LOG(INFO) << "Downloading Launcher update " << LatestHash; + HTTP::Download( + "https://backend.beammp.com/builds/launcher?download=true" + "&pk=" + + PublicKey + "&branch=" + TargetBuild, + (CurrentPath/"BeamMP-Launcher.exe").string()); + throw ShutdownException("Launcher update"); + } + */ +void CheckForUpdates(int argc, char* args[], const std::string& CV) { + std::string LatestHash = HTTP::Get("https://backend.beammp.com/sha/launcher?branch=" + Branch + "&pk=" + PublicKey); + std::string LatestVersion = HTTP::Get( + "https://backend.beammp.com/version/launcher?branch=" + Branch + "&pk=" + PublicKey); - if(HTTP > CV){ - system("cls"); - info("Update found!"); - info("Updating..."); - if(std::rename(EP.c_str(), Back.c_str()))error("failed creating a backup!"); + transform(LatestHash.begin(), LatestHash.end(), LatestHash.begin(), ::tolower); + std::string EP(GetEP() + GetEN()), Back(GetEP() + "BeamMP-Launcher.back"); - if(!HTTP::Download(link, EP)){ - error("Launcher Update failed! trying again..."); - std::this_thread::sleep_for(std::chrono::seconds(2)); + std::string FileHash = hashpp::get::getFileHash(hashpp::ALGORITHMS::SHA2_256, EP); - if(!HTTP::Download(link, EP)){ - error("Launcher Update failed!"); - std::this_thread::sleep_for(std::chrono::seconds(5)); - ReLaunch(argc,args); - } - } - URelaunch(argc,args); - }else info("Launcher version is up to date"); + if (FileHash != LatestHash && VersionParser(LatestVersion) > VersionParser(GetVer()+GetPatch())) { + info("Launcher update found!"); + fs::remove(Back); + fs::rename(EP, Back); + info("Downloading Launcher update " + LatestHash); + HTTP::Download( + "https://backend.beammp.com/builds/launcher?download=true" + "&pk=" + + PublicKey + "&branch=" + Branch, + EP); + URelaunch(argc, args); + } else info("Launcher version is up to date"); TraceBack++; } @@ -178,7 +213,7 @@ void CheckMP(const std::string& Path) { try { for (auto& p : fs::directory_iterator(Path)){ if(p.exists() && !p.is_directory()){ - std::string Name = p.path().filename().u8string(); + std::string Name = p.path().filename().string(); for(char&Ch : Name)Ch = char(tolower(Ch)); if(Name != "beammp.zip")fs::remove(p.path()); } @@ -224,7 +259,11 @@ void PreGame(const std::string& GamePath){ CheckMP(GetGamePath() + "mods/multiplayer"); if(!Dev) { - info("Downloading mod please wait..."); + std::string LatestHash = HTTP::Get("https://backend.beammp.com/sha/mod?branch=" + Branch + "&pk=" + PublicKey); + transform(LatestHash.begin(), LatestHash.end(), LatestHash.begin(), ::tolower); + LatestHash.erase(std::remove_if(LatestHash.begin(), LatestHash.end(), + [](auto const& c ) -> bool { return !std::isalnum(c); } ), LatestHash.end()); + try { if (!fs::exists(GetGamePath() + "mods/multiplayer")) { fs::create_directories(GetGamePath() + "mods/multiplayer"); @@ -233,20 +272,23 @@ void PreGame(const std::string& GamePath){ }catch(std::exception&e){ fatal(e.what()); } + std::string ZipPath(GetGamePath() + R"(mods\multiplayer\BeamMP.zip)"); - HTTP::Download("https://backend.beammp.com/builds/client?download=true" - "&pk=" + PublicKey + "&branch=" + Branch, ZipPath); + std::string FileHash = hashpp::get::getFileHash(hashpp::ALGORITHMS::SHA2_256, ZipPath); + + if (FileHash != LatestHash) { + info("Downloading BeamMP Update " + LatestHash); + HTTP::Download("https://backend.beammp.com/builds/client?download=true" + "&pk=" + PublicKey + "&branch=" + Branch, ZipPath); + } std::string Target(GetGamePath() + "mods/unpacked/beammp"); if(fs::is_directory(Target)) { fs::remove_all(Target); } - - //HTTP::Download("beammp.com/builds/client", GetGamePath() + R"(mods\multiplayer\BeamMP.zip)"); } - } void StartProxy() {