Anonymous275 3b479abf64 v2.0.84
- add hash check
- new routes for updates
- use C++ 20
2023-12-15 18:16:12 +00:00

4642 lines
224 KiB
C++

#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 <iostream>
#include <fstream>
#include <filesystem>
#include <vector>
#if defined(HASHPP_INCLUDE_METRICS)
#include <chrono>
#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<uint8_t*>(const_cast<char*>(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<char> buf(1024 * 1024, 0);
this->ctx_init();
while (file) {
file.read(buf.data(), buf.size());
this->ctx_update(reinterpret_cast<uint8_t*>(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<uint8_t> 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<uint8_t> fromHex(const std::string& hex) {
std::vector<uint8_t> bytes;
for (size_t i = 0; i < hex.length(); i += 2) {
std::string byteString = hex.substr(i, 2);
uint8_t byte = static_cast<uint8_t>(strtol(byteString.c_str(), NULL, 16));
bytes.push_back(byte);
}
return bytes;
}
private:
std::string bytesToHexString() {
const std::vector<uint8_t> 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<uint8_t> getBytes() override {
return std::vector<uint8_t>(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<uint8_t> 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<uint8_t> 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<uint8_t> getBytes() override {
return std::vector<uint8_t>(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<uint8_t> 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<uint8_t> 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<uint8_t> getBytes() override {
return std::vector<uint8_t>(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<uint8_t> 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<uint8_t> 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<uint64_t>(len);
for (uint32_t i = 0; i < len; ++i) {
this->context.in[offset++] = static_cast<uint8_t>(*(data + i));
if (offset % 64 == 0) {
for (uint32_t j = 0; j < 16; ++j) {
input[j] = static_cast<uint32_t>(this->context.in[(j * 4) + 3]) << 24 |
static_cast<uint32_t>(this->context.in[(j * 4) + 2]) << 16 |
static_cast<uint32_t>(this->context.in[(j * 4) + 1]) << 8 |
static_cast<uint32_t>(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<uint64_t>(plen);
for (uint32_t j = 0; j < 14; ++j) {
input[j] = static_cast<uint32_t>(this->context.in[(j * 4) + 3]) << 24 |
static_cast<uint32_t>(this->context.in[(j * 4) + 2]) << 16 |
static_cast<uint32_t>(this->context.in[(j * 4) + 1]) << 8 |
static_cast<uint32_t>(this->context.in[(j * 4)]);
}
input[14] = static_cast<uint32_t>(this->context.size * 8);
input[15] = static_cast<uint32_t>((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<uint8_t>((this->context.buf[i] & 0x000000FF));
this->context.digest[(i * 4) + 1] = static_cast<uint8_t>((this->context.buf[i] & 0x0000FF00) >> 8);
this->context.digest[(i * 4) + 2] = static_cast<uint8_t>((this->context.buf[i] & 0x00FF0000) >> 16);
this->context.digest[(i * 4) + 3] = static_cast<uint8_t>((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<uint8_t> 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<uint8_t> 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<uint64_t>(len);
for (uint32_t i = 0; i < len; ++i) {
this->context.in[offset++] = static_cast<uint8_t>(*(data + i));
if (offset % 64 == 0) {
for (uint32_t j = 0; j < 16; ++j) {
input[j] = static_cast<uint32_t>(this->context.in[(j * 4) + 3]) << 24 |
static_cast<uint32_t>(this->context.in[(j * 4) + 2]) << 16 |
static_cast<uint32_t>(this->context.in[(j * 4) + 1]) << 8 |
static_cast<uint32_t>(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<uint64_t>(plen);
for (uint32_t j = 0; j < 14; ++j) {
input[j] = static_cast<uint32_t>(this->context.in[(j * 4) + 3]) << 24 |
static_cast<uint32_t>(this->context.in[(j * 4) + 2]) << 16 |
static_cast<uint32_t>(this->context.in[(j * 4) + 1]) << 8 |
static_cast<uint32_t>(this->context.in[(j * 4)]);
}
input[14] = static_cast<uint32_t>(this->context.size * 8);
input[15] = static_cast<uint32_t>((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<uint8_t>((this->context.buf[i] & 0x000000FF));
this->context.digest[(i * 4) + 1] = static_cast<uint8_t>((this->context.buf[i] & 0x0000FF00) >> 8);
this->context.digest[(i * 4) + 2] = static_cast<uint8_t>((this->context.buf[i] & 0x00FF0000) >> 16);
this->context.digest[(i * 4) + 3] = static_cast<uint8_t>((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<uint8_t> 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<uint8_t> 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<uint32_t>(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<uint32_t>(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<uint8_t> 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<uint8_t> 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<uint8_t> getBytes() override {
return std::vector<uint8_t>(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<uint8_t> 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<uint8_t> 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<uint8_t> getBytes() override {
return std::vector<uint8_t>(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<uint8_t> 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<uint8_t> 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<uint8_t> getBytes() override {
return std::vector<uint8_t>(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<uint8_t> 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<uint8_t> 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<uint8_t> getBytes() override {
return std::vector<uint8_t>(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<uint8_t> 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<uint8_t> 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<uint8_t> getBytes() override {
return std::vector<uint8_t>(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<uint8_t> 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<uint8_t> 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<uint8_t> getBytes() override {
return std::vector<uint8_t>(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<uint8_t> 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<uint8_t> 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<uint8_t> getBytes() override {
return std::vector<uint8_t>(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<uint8_t> 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<uint8_t> 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<uint64_t>(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<uint8_t> 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<uint8_t> 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<uint64_t>(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<uint8_t> 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<uint8_t> 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<uint64_t>(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<uint8_t> 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<uint8_t> 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<uint8_t> 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<uint8_t> 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<uint8_t> 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<uint8_t> 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<uint8_t> 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<uint8_t> 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<uint8_t> 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<uint8_t> 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 <class _Ty, std::enable_if_t<std::is_constructible_v<std::string, _Ty>, 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<std::pair<std::string, std::vector<std::string>>>& data) noexcept : collection(data) {}
hashCollection(std::vector<std::pair<std::string, std::vector<std::string>>>&& data) noexcept : collection(std::move(data)) {}
// operator[] overload to access collections of hashpp
// by their specific algorithm
std::vector<std::string> 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<std::pair<std::string, std::vector<std::string>>>::const_iterator begin() const noexcept {
return this->collection.begin();
}
std::vector<std::pair<std::string, std::vector<std::string>>>::const_iterator end() const noexcept {
return this->collection.end();
}
private:
std::vector<std::pair<std::string, std::vector<std::string>>> collection;
std::vector<std::string> getHashesFromID(const std::string& algoID) const {
for (const std::pair<std::string, std::vector<std::string>>& 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<std::string>();
}
};
// 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<std::string>& data
) noexcept : algorithm(algorithm), data(data) {
}
Container(
ALGORITHMS algorithm,
std::vector<std::string>&& data
) noexcept : algorithm(algorithm), data(std::move(data)) {
}
Container(
ALGORITHMS algorithm,
const std::vector<std::string>& data,
const std::string& key
) noexcept : algorithm(algorithm), data(data), key(key) {
}
Container(
ALGORITHMS algorithm,
std::vector<std::string>&& data,
const std::string& key
) noexcept : algorithm(algorithm), data(std::move(data)), key(key) {
}
Container(
ALGORITHMS algorithm,
const std::vector<std::string>& data,
std::string&& key
) noexcept : algorithm(algorithm), data(data), key(std::move(key)) {
}
Container(
ALGORITHMS algorithm,
std::vector<std::string>&& data,
std::string&& key
) noexcept : algorithm(algorithm), data(std::move(data)), key(std::move(key)) {
}
template <class... _Ts,
std::enable_if_t<std::conjunction_v<std::is_constructible<std::string, _Ts>...>, int> = 0>
Container(
ALGORITHMS algorithm,
const _Ts&... data
) noexcept : algorithm(algorithm), data({ data... }) {
}
template <class... _Ts,
std::enable_if_t<std::conjunction_v<std::is_constructible<std::string, _Ts>..., std::negation<std::is_lvalue_reference<_Ts>>...>, 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<std::string>& 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<std::string>& data) noexcept { this->data = data; }
void setData(std::vector<std::string>&& data) noexcept { this->data = std::move(data); }
template <class... _Ts> void setData(const _Ts&... data) noexcept { this->data = { data... }; }
template <class... _Ts,
std::enable_if_t<std::conjunction_v<std::negation<std::is_lvalue_reference<_Ts>>...>, int> = 0>
void setData(_Ts&&... data) noexcept { this->data = { std::forward<_Ts>(data)... }; }
void appendData(const std::vector<std::string>& data) noexcept { this->data.insert(this->data.end(), data.begin(), data.end()); }
void appendData(std::vector<std::string>&& data) noexcept { this->data.insert(this->data.end(), std::make_move_iterator(data.begin()), std::make_move_iterator(data.end())); }
template <class... _Ts> void appendData(const _Ts&... data) noexcept { (this->data.push_back(data), ...); }
template <class... _Ts,
std::enable_if_t<std::conjunction_v<std::negation<std::is_lvalue_reference<_Ts>>...>, 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<std::string> 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<std::string> 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<DataContainer>& dataSets) {
std::vector<std::string> 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<DataContainer>& dataSets) {
std::vector<std::string> 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 <class... _Ts,
std::enable_if_t<std::conjunction_v<std::is_constructible<std::string, _Ts>...>, int> = 0>
static hashpp::hashCollection getHashes(hashpp::ALGORITHMS algorithm, const _Ts&... data) {
switch (algorithm) {
case hashpp::ALGORITHMS::MD5:
{
std::vector<std::string> vMD5;
(vMD5.push_back(hashpp::MD::MD5().getHash(static_cast<std::string>(data))), ...);
return hashCollection{ {{ "MD5", vMD5 }} };
}
case hashpp::ALGORITHMS::MD4:
{
std::vector<std::string> vMD4;
(vMD4.push_back(hashpp::MD::MD4().getHash(static_cast<std::string>(data))), ...);
return hashCollection{ {{ "MD4", vMD4 }} };
}
case hashpp::ALGORITHMS::MD2:
{
std::vector<std::string> vMD2;
(vMD2.push_back(hashpp::MD::MD2().getHash(static_cast<std::string>(data))), ...);
return hashCollection{ {{ "MD2", vMD2 }} };
}
case hashpp::ALGORITHMS::SHA1:
{
std::vector<std::string> vSHA1;
(vSHA1.push_back(hashpp::SHA::SHA1().getHash(static_cast<std::string>(data))), ...);
return hashCollection{ {{ "SHA1", vSHA1 }} };
}
case hashpp::ALGORITHMS::SHA2_224:
{
std::vector<std::string> vSHA2_224;
(vSHA2_224.push_back(hashpp::SHA::SHA2_224().getHash(static_cast<std::string>(data))), ...);
return hashCollection{ {{ "SHA2-224", vSHA2_224 }} };
}
case hashpp::ALGORITHMS::SHA2_256:
{
std::vector<std::string> vSHA2_256;
(vSHA2_256.push_back(hashpp::SHA::SHA2_256().getHash(static_cast<std::string>(data))), ...);
return hashCollection{ {{ "SHA2-256", vSHA2_256 }} };
}
case hashpp::ALGORITHMS::SHA2_384:
{
std::vector<std::string> vSHA_384;
(vSHA_384.push_back(hashpp::SHA::SHA2_384().getHash(static_cast<std::string>(data))), ...);
return hashCollection{ {{ "SHA2-384", vSHA_384 }} };
}
case hashpp::ALGORITHMS::SHA2_512:
{
std::vector<std::string> vSHA2_512;
(vSHA2_512.push_back(hashpp::SHA::SHA2_512().getHash(static_cast<std::string>(data))), ...);
return hashCollection{ {{ "SHA2-512", vSHA2_512 }} };
}
case hashpp::ALGORITHMS::SHA2_512_224:
{
std::vector<std::string> vSHA2_512_224;
(vSHA2_512_224.push_back(hashpp::SHA::SHA2_512_224().getHash(static_cast<std::string>(data))), ...);
return hashCollection{ {{ "SHA2-512-224", vSHA2_512_224 }} };
}
case hashpp::ALGORITHMS::SHA2_512_256:
{
std::vector<std::string> vSHA2_512_256;
(vSHA2_512_256.push_back(hashpp::SHA::SHA2_512_256().getHash(static_cast<std::string>(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<std::string> 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<HMAC_DataContainer>& keyDataSets) {
std::vector<std::string> 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<HMAC_DataContainer>& keyDataSets) {
std::vector<std::string> 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 <class... _Ts,
std::enable_if_t<std::conjunction_v<std::is_constructible<std::string, _Ts>...>, int> = 0>
static hashpp::hashCollection getHMACs(hashpp::ALGORITHMS algorithm, const std::string& key, const _Ts&... data) {
switch (algorithm) {
case hashpp::ALGORITHMS::MD5:
{
std::vector<std::string> vMD5;
(vMD5.push_back(hashpp::MD::MD5().getHMAC(key, data)), ...);
return hashCollection{ {{ "MD5", vMD5 }} };
}
case hashpp::ALGORITHMS::MD4:
{
std::vector<std::string> vMD4;
(vMD4.push_back(hashpp::MD::MD4().getHMAC(key, data)), ...);
return hashCollection{ {{ "MD4", vMD4 }} };
}
case hashpp::ALGORITHMS::MD2:
{
std::vector<std::string> vMD2;
(vMD2.push_back(hashpp::MD::MD2().getHMAC(key, data)), ...);
return hashCollection{ {{ "MD2", vMD2 }} };
}
case hashpp::ALGORITHMS::SHA1:
{
std::vector<std::string> vSHA1;
(vSHA1.push_back(hashpp::SHA::SHA1().getHMAC(key, data)), ...);
return hashCollection{ {{ "SHA1", vSHA1 }} };
}
case hashpp::ALGORITHMS::SHA2_224:
{
std::vector<std::string> 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<std::string> 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<std::string> 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<std::string> 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<std::string> 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<std::string> 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<std::string> 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<FilePathsContainer>& filePathSets) {
std::vector<std::string> 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<FilePathsContainer>& filePathSets) {
std::vector<std::string> 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 _Ty>
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 <bool IncludeMD2 = true, class _Ty = std::chrono::milliseconds>
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<uint8_t>(algorithm)].first) {
std::cout << this->comparisons[static_cast<uint8_t>(algorithm)].second << " pass." << std::endl;
}
else {
std::cout << this->comparisons[static_cast<uint8_t>(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<uint8_t>(algorithm)].first) {
std::cout << this->hmac_comparisons[static_cast<uint8_t>(algorithm)].second << " HMAC pass." << std::endl;
}
else {
std::cout << this->hmac_comparisons[static_cast<uint8_t>(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<uint8_t>(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<uint8_t>(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<uint8_t>(algorithm)].second << ": " << this->getTime().count() << std::endl;
}
}
}
private:
const std::vector<hashpp::ALGORITHMS> 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<std::pair<std::string, std::string>> 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<std::pair<std::string, std::string>> 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