diff --git a/CMakeLists.txt b/CMakeLists.txt index 9b607b6..be4feb3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,6 +51,7 @@ set(EHS_SOURCES src/Color3.cpp include/ehs/Color3.h src/Version.cpp include/ehs/Version.h src/Base64.cpp include/ehs/Base64.h + src/SHA256.cpp include/ehs/SHA256.h src/Data.cpp include/ehs/Data.h src/Range.cpp include/ehs/Range.h src/Util.cpp include/ehs/Util.h diff --git a/include/ehs/Base64.h b/include/ehs/Base64.h index 71fcf35..ee0f0c9 100644 --- a/include/ehs/Base64.h +++ b/include/ehs/Base64.h @@ -8,17 +8,26 @@ namespace ehs class EHS_LIB_IO Base64 { private: - static const char ascii[]; + static constexpr UInt_8 asciiUrl[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; + static constexpr UInt_8 ascii[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; public: + static Str_8 EncodeURL(const Str_8 &input); + static Str_8 Encode(const Str_8 &input); - + + static Str_8 DecodeURL(const Str_8 &input); + static Str_8 Decode(const Str_8 &input); private: - static char Find(char c); - - static bool IsBase64(char c); + static UInt_8 FindURL(const UInt_8 &c); + + static UInt_8 Find(const UInt_8 &c); + + static bool IsBase64URL(const UInt_8 &c); + + static bool IsBase64(const UInt_8 &c); }; } \ No newline at end of file diff --git a/include/ehs/SHA256.h b/include/ehs/SHA256.h new file mode 100644 index 0000000..a823d23 --- /dev/null +++ b/include/ehs/SHA256.h @@ -0,0 +1,59 @@ +#pragma once +#include "Types.h" + +namespace ehs +{ + class SHA256 + { + private: + static UInt_32 ROTR(UInt_32 x, UInt_32 n); + + static UInt_32 CH(UInt_32 x, UInt_32 y, UInt_32 z); + + static UInt_32 MAJ(UInt_32 x, UInt_32 y, UInt_32 z); + + static UInt_32 EP0(UInt_32 x); + + static UInt_32 EP1(UInt_32 x); + + static UInt_32 SIG0(UInt_32 x); + + static UInt_32 SIG1(UInt_32 x); + + static constexpr UInt_32 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 + }; + + UInt_32 state[8]; + UInt_64 bitLen; + Byte data[64]; + UInt_64 dataLen; + + public: + SHA256(); + + SHA256(SHA256 &&other) noexcept; + + SHA256(const SHA256 &other); + + SHA256 &operator=(SHA256 &&other) noexcept; + + SHA256 &operator=(const SHA256 &other); + + void Update(const Byte *data, UInt_64 len); + + void Final(Byte hash[32]); + + void Hash(const Byte *data, UInt_64 len, Byte hash[32]); + + private: + void Transform(const Byte data[64]); + }; +} diff --git a/include/ehs/system/BaseSystem.h b/include/ehs/system/BaseSystem.h index c3e54ab..713af91 100644 --- a/include/ehs/system/BaseSystem.h +++ b/include/ehs/system/BaseSystem.h @@ -8,7 +8,7 @@ namespace ehs class EHS_LIB_IO BaseSystem { public: - static void OpenURI(const Str_8& uri); + static void OpenURI(Str_8 uri); static Str_8 OpenFileDialog(const Str_8 &dir, const Str_8 &filters); diff --git a/include/ehs/system/System_LNX.h b/include/ehs/system/System_LNX.h index 144019c..c468697 100644 --- a/include/ehs/system/System_LNX.h +++ b/include/ehs/system/System_LNX.h @@ -8,7 +8,7 @@ namespace ehs class EHS_LIB_IO System : public BaseSystem { public: - static void OpenURI(const Str_8& uri); + static void OpenURI(Str_8 uri); static Str_8 OpenFileDialog(const Str_8 &dir, const Str_8 &filters); diff --git a/include/ehs/system/System_W32.h b/include/ehs/system/System_W32.h index 148aa20..9e814d0 100644 --- a/include/ehs/system/System_W32.h +++ b/include/ehs/system/System_W32.h @@ -7,6 +7,6 @@ namespace ehs class EHS_LIB_IO System : public BaseSystem { public: - static void OpenURI(const Str_8& uri); + static void OpenURI(Str_8 uri); }; } \ No newline at end of file diff --git a/src/Base64.cpp b/src/Base64.cpp index 0e07821..8235cbd 100644 --- a/src/Base64.cpp +++ b/src/Base64.cpp @@ -2,8 +2,36 @@ namespace ehs { - const char Base64::ascii[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - + Str_8 Base64::EncodeURL(const Str_8 &input) + { + UInt_64 input_length = input.Size(); + + // Calculate the output length + UInt_64 output_length = (input_length * 4 + 2) / 3; + + // Allocate memory for the output + Str_8 result(output_length); + + // Loop through the input and fill the output + for (int i = 0, j = 0; i < input_length;) { + + // Take first byte and shift right by 2 bits + UInt_32 octet_a = (UInt_8)input[i++]; + UInt_32 octet_b = i < input_length ? (UInt_8)input[i++] : 0; + UInt_32 octet_c = i < input_length ? (UInt_8)input[i++] : 0; + + UInt_32 triple = (octet_a << 16) + (octet_b << 8) + octet_c; + + // Encode the 24-bits into four 6-bits integers + result[j++] = asciiUrl[(triple >> 3 * 6) & 0x3F]; + result[j++] = asciiUrl[(triple >> 2 * 6) & 0x3F]; + result[j++] = asciiUrl[(triple >> 1 * 6) & 0x3F]; + result[j++] = asciiUrl[(triple >> 0 * 6) & 0x3F]; + } + + return result; + } + Str_8 Base64::Encode(const Str_8 &input) { UInt_64 input_length = input.Size(); @@ -18,9 +46,9 @@ namespace ehs for (int i = 0, j = 0; i < input_length;) { // Take first byte and shift right by 2 bits - UInt_32 octet_a = i < input_length ? input[i++] : 0; - UInt_32 octet_b = i < input_length ? input[i++] : 0; - UInt_32 octet_c = i < input_length ? input[i++] : 0; + UInt_32 octet_a = i < input_length ? (UInt_8)input[i++] : 0; + UInt_32 octet_b = i < input_length ? (UInt_8)input[i++] : 0; + UInt_32 octet_c = i < input_length ? (UInt_8)input[i++] : 0; UInt_32 triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c; @@ -41,64 +69,152 @@ namespace ehs return result; } - - Str_8 Base64::Decode(const Str_8 &input) + + Str_8 Base64::DecodeURL(const Str_8 &input) { - UInt_64 in_len = input.Size(); - int i = 0; - int j = 0; - int in_ = 0; - char char_array_4[4], char_array_3[3]; - Str_8 ret; + Str_8 result(input.Size() * 3 / 4); - while (in_len-- && ( input[in_] != '=') && IsBase64(input[in_])) + UInt_64 remaining = input.Size(); + UInt_64 offsetIn = 0; + UInt_64 offsetOut = 0; + UInt_8 quartet[4]; + + while (remaining) { - char_array_4[i++] = input[in_]; in_++; - - if (i ==4) + if (remaining >= 4) { - for (i = 0; i <4; i++) - char_array_4[i] = Find(char_array_4[i]); + for (UInt_8 i = 0; i < 4; ++i) + { + if (!IsBase64URL(input[offsetIn + i])) + return {}; - char_array_3[0] = ( char_array_4[0] << 2 ) + ((char_array_4[1] & 0x30) >> 4); - char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); - char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; + quartet[i] = FindURL(input[offsetIn + i]); + if (quartet[i] == EHS_UINT_8_MAX) + return {}; + } - for (i = 0; (i < 3); i++) - ret += char_array_3[i]; + result[offsetOut++] = (Char_8)((((UInt_8*)&quartet)[0] << 2) | (((UInt_8*)&quartet)[1] >> 4)); + result[offsetOut++] = (Char_8)((((UInt_8*)&quartet)[1] << 4) | (((UInt_8*)&quartet)[2] >> 2)); + result[offsetOut++] = (Char_8)((((UInt_8*)&quartet)[2] << 6) | ((UInt_8*)&quartet)[3]); - i = 0; + offsetIn += 4; + remaining -= 4; + } + else + { + for (UInt_8 i = 0; i < 4; ++i) + { + if (i < remaining) + { + if (!IsBase64URL(input[offsetIn + i])) + return {}; + + quartet[i] = FindURL(input[offsetIn + i]); + if (quartet[i] == EHS_UINT_8_MAX) + return {}; + } + else + quartet[i] = 0; + } + + result[offsetOut++] = (Char_8)((quartet[0] << 2) | (quartet[1] >> 4)); + + if (remaining == 3) + result[offsetOut++] = (Char_8)((quartet[1] << 4) | (quartet[2] >> 2)); + + offsetIn += remaining; + remaining = 0; } } - if (i) + return result; + } + + Str_8 Base64::Decode(const Str_8 &input) + { + Str_8 result(input.Size() * 3 / 4); + + UInt_64 remaining = input.Size(); + UInt_64 offsetIn = 0; + UInt_64 offsetOut = 0; + UInt_8 quartet[4]; + + while (remaining) { - for (j = 0; j < i; j++) - char_array_4[j] = Find(char_array_4[j]); + if (remaining >= 4) + { + for (UInt_8 i = 0; i < 4; ++i) + { + if (!IsBase64(input[offsetIn + i])) + return {}; - char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); - char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); + quartet[i] = Find(input[offsetIn + i]); + if (quartet[i] == EHS_UINT_8_MAX) + return {}; + } - for (j = 0; (j < i - 1); j++) - ret += char_array_3[j]; + result[offsetOut++] = (Char_8)((((UInt_8*)&quartet)[0] << 2) | (((UInt_8*)&quartet)[1] >> 4)); + result[offsetOut++] = (Char_8)((((UInt_8*)&quartet)[1] << 4) | (((UInt_8*)&quartet)[2] >> 2)); + result[offsetOut++] = (Char_8)((((UInt_8*)&quartet)[2] << 6) | ((UInt_8*)&quartet)[3]); + + offsetIn += 4; + remaining -= 4; + } + else + { + for (UInt_8 i = 0; i < 4; ++i) + { + if (i < remaining) + { + if (!IsBase64(input[offsetIn + i])) + return {}; + + quartet[i] = Find(input[offsetIn + i]); + if (quartet[i] == EHS_UINT_8_MAX) + return {}; + } + else + quartet[i] = 0; + } + + result[offsetOut++] = (Char_8)((quartet[0] << 2) | (quartet[1] >> 4)); + + if (remaining == 3) + result[offsetOut++] = (Char_8)((quartet[1] << 4) | (quartet[2] >> 2)); + + offsetIn += remaining; + remaining = 0; + } } - return ret; + return result; } - - char Base64::Find(const char c) + + UInt_8 Base64::FindURL(const UInt_8 &c) { - for (char i = 0; i < (char)sizeof(ascii); ++i) - { + for (UInt_8 i = 0; i < (UInt_8)sizeof(asciiUrl) - 1; ++i) + if (asciiUrl[i] == c) + return i; + + return EHS_UINT_8_MAX;; + } + + UInt_8 Base64::Find(const UInt_8 &c) + { + for (UInt_8 i = 0; i < (UInt_8)sizeof(ascii) - 1; ++i) if (ascii[i] == c) return i; - } return EHS_SINT_8_MAX; } - - bool Base64::IsBase64(const char c) + + bool Base64::IsBase64URL(const UInt_8 &c) { - return (c > 47 && c < 58) || (c > 64 && c < 91) || (c > 96 && c < 123) || (c == '+') || (c == '/'); + return (c > 47 && c < 58) || (c > 64 && c < 91) || (c > 96 && c < 123) || c == '-' || c == '_'; + } + + bool Base64::IsBase64(const UInt_8 &c) + { + return (c > 47 && c < 58) || (c > 64 && c < 91) || (c > 96 && c < 123) || c == '+' || c == '/'; } } \ No newline at end of file diff --git a/src/SHA256.cpp b/src/SHA256.cpp new file mode 100644 index 0000000..4fb52ff --- /dev/null +++ b/src/SHA256.cpp @@ -0,0 +1,209 @@ +#include "ehs/SHA256.h" + +#include "ehs/Util.h" + +namespace ehs +{ + UInt_32 SHA256::ROTR(const UInt_32 x, const UInt_32 n) + { + return (x >> n) | (x << (32 - n)); + } + + UInt_32 SHA256::CH(const UInt_32 x, const UInt_32 y, const UInt_32 z) + { + return (x & y) ^ (~x & z); + } + + UInt_32 SHA256::MAJ(const UInt_32 x, const UInt_32 y, const UInt_32 z) + { + return (x & y) ^ (x & z) ^ (y & z); + } + + UInt_32 SHA256::EP0(const UInt_32 x) + { + return ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22); + } + + UInt_32 SHA256::EP1(const UInt_32 x) + { + return ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25); + } + + UInt_32 SHA256::SIG0(const UInt_32 x) + { + return ROTR(x, 7) ^ ROTR(x, 18) ^ (x >> 3); + } + + UInt_32 SHA256::SIG1(const UInt_32 x) + { + return ROTR(x,17) ^ ROTR(x, 19) ^ (x >> 10); + } + + SHA256::SHA256() + : state{0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19}, + bitLen(0), data{}, dataLen(0) + { + } + + SHA256::SHA256(SHA256&& other) noexcept + : state{}, bitLen(0), data{}, dataLen(0) + { + Util::Copy(state, other.state, sizeof(state) / sizeof(UInt_32)); + bitLen = other.bitLen; + Util::Copy(data, other.data, sizeof(data)); + dataLen = other.dataLen; + + Util::Zero(other.state, sizeof(state) / sizeof(UInt_32)); + other.bitLen = 0; + Util::Zero(other.data, sizeof(data)); + other.dataLen = 0; + } + + SHA256::SHA256(const SHA256& other) + : state{}, bitLen(0), data{}, dataLen(0) + { + Util::Copy(state, other.state, sizeof(state) / sizeof(UInt_32)); + bitLen = other.bitLen; + Util::Copy(data, other.data, sizeof(data)); + dataLen = other.dataLen; + } + + SHA256& SHA256::operator=(SHA256&& other) noexcept + { + if (this == &other) + return *this; + + Util::Copy(state, other.state, sizeof(state) / sizeof(UInt_32)); + bitLen = other.bitLen; + Util::Copy(data, other.data, sizeof(data)); + dataLen = other.dataLen; + + Util::Zero(other.state, sizeof(state) / sizeof(UInt_32)); + other.bitLen = 0; + Util::Zero(other.data, sizeof(data)); + other.dataLen = 0; + + return *this; + } + + SHA256& SHA256::operator=(const SHA256& other) + { + if (this == &other) + return *this; + + Util::Copy(state, other.state, sizeof(state) / sizeof(UInt_32)); + bitLen = other.bitLen; + Util::Copy(data, other.data, sizeof(data)); + dataLen = other.dataLen; + + return *this; + } + + void SHA256::Update(const Byte* data, const UInt_64 len) + { + for(UInt_64 i = 0; i < len; ++i) + { + this->data[dataLen++] = data[i]; + + if(dataLen == 64) + { + Transform(this->data); + bitLen += 512; + dataLen = 0; + } + } + } + + void SHA256::Final(Byte hash[32]) + { + UInt_32 i = dataLen; + + /* Pad */ + data[i++] = 0x80; + if(i > 56) + { + while(i < 64) + data[i++] = 0x00; + + Transform(data); + + i = 0; + } + + while(i < 56) + data[i++] = 0x00; + + /* Length in bits */ + bitLen += dataLen * 8ULL; + data[63] = bitLen; + data[62] = bitLen >> 8; + data[61] = bitLen >> 16; + data[60] = bitLen >> 24; + data[59] = bitLen >> 32; + data[58] = bitLen >> 40; + data[57] = bitLen >> 48; + data[56] = bitLen >> 56; + Transform(data); + + /* big‑endian output */ + for(i = 0; i < 4; ++i) { + hash[i] = (state[0] >> (24 - i * 8)) & 0xff; + hash[i + 4] = (state[1] >> (24 - i * 8)) & 0xff; + hash[i + 8] = (state[2] >> (24 - i * 8)) & 0xff; + hash[i + 12] = (state[3] >> (24 - i * 8)) & 0xff; + hash[i + 16] = (state[4] >> (24 - i * 8)) & 0xff; + hash[i + 20] = (state[5] >> (24 - i * 8)) & 0xff; + hash[i + 24] = (state[6] >> (24 - i * 8)) & 0xff; + hash[i + 28] = (state[7] >> (24 - i * 8)) & 0xff; + } + } + + void SHA256::Hash(const Byte* data, const UInt_64 len, Byte hash[32]) + { + Update(data, len); + Final(hash); + } + + void SHA256::Transform(const Byte data[64]) + { + UInt_32 m[64]; + UInt_32 a = state[0]; + UInt_32 b = state[1]; + UInt_32 c = state[2]; + UInt_32 d = state[3]; + UInt_32 e = state[4]; + UInt_32 f = state[5]; + UInt_32 g = state[6]; + UInt_32 h = state[7]; + UInt_32 i, t1, t2; + + for (i = 0; i < 16; ++i) + m[i] = (UInt_32)data[i * 4] << 24 | (UInt_32)data[i * 4 + 1] << 16 | (UInt_32)data[i * 4 + 2] << 8 | (UInt_32)data[i * 4 + 3]; + + for (; i < 64; ++i) + m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16]; + + for(i = 0; i < 64; ++i) + { + t1 = h + EP1(e) + CH(e,f,g) + k[i] + m[i]; + t2 = EP0(a) + MAJ(a,b,c); + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + } + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + state[5] += f; + state[6] += g; + state[7] += h; + } +} diff --git a/src/io/socket/SSL.cpp b/src/io/socket/SSL.cpp index 87de809..a2fd4e3 100644 --- a/src/io/socket/SSL.cpp +++ b/src/io/socket/SSL.cpp @@ -102,9 +102,21 @@ namespace ehs if (bound) return; - OpenSSL_add_all_algorithms(); + OpenSSL_add_ssl_algorithms(); SSL_load_error_strings(); - ctx = SSL_CTX_new(SSLv23_server_method()); + ctx = SSL_CTX_new(TLS_server_method()); + + SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION); + + SSL_CTX_set_cipher_list(ctx, "HIGH:!aNULL:!MD5"); + SSL_CTX_set_ciphersuites(ctx, + "TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256:" + "TLS_CHACHA20_POLY1305_SHA256:ECDHE-RSA-AES128-GCM-SHA256" + ); + + #if OPENSSL_VERSION_NUMBER < 0x10101000L + SSL_CTX_set_ecdh_auto(ctx, 1); + #endif sslHdl = SSL_new(ctx); SSL_set_fd(sslHdl, hdl); @@ -143,12 +155,35 @@ namespace ehs return; TCP::Connect(address, port); - OpenSSL_add_all_algorithms(); + + OpenSSL_add_ssl_algorithms(); SSL_load_error_strings(); - ctx = SSL_CTX_new(SSLv23_client_method()); + + ctx = SSL_CTX_new(TLS_client_method()); + if (!ctx) + { + EHS_LOG_INT(LogType::ERR, 0, "Failed to creat SSL context."); + return; + } + + SSL_CTX_set_default_verify_paths(ctx); + SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, nullptr); + SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION); + sslHdl = SSL_new(ctx); SSL_set_fd(sslHdl, hdl); - SSL_connect(sslHdl); + + SSL_set_tlsext_host_name(sslHdl, &address[0]); + + SInt_32 rc = SSL_connect(sslHdl); + if (rc != 1) + { + EHS_LOG_INT(LogType::ERR, 1, "Failed to connect with error #" + Str_8::FromNum(SSL_get_error(sslHdl, rc)) + "."); + + return; + } + + EHS_LOG_SUCCESS(); } UInt_64 SSL::Send(const Byte* const buffer, const UInt_32 size) diff --git a/src/system/BaseSystem.cpp b/src/system/BaseSystem.cpp index c963082..2bcd747 100644 --- a/src/system/BaseSystem.cpp +++ b/src/system/BaseSystem.cpp @@ -2,7 +2,7 @@ namespace ehs { - void BaseSystem::OpenURI(const Str_8& uri) + void BaseSystem::OpenURI(Str_8 uri) { } diff --git a/src/system/System_LNX.cpp b/src/system/System_LNX.cpp index dfaff88..016c2ab 100644 --- a/src/system/System_LNX.cpp +++ b/src/system/System_LNX.cpp @@ -13,13 +13,17 @@ namespace ehs system("xdg-open \"" + *uri + "\""); + delete uri; + return 0; } - void System::OpenURI(const Str_8& uri) + void System::OpenURI(Str_8 uri) { + Str_8 *arg = new Str_8((Str_8&&)uri); + Thread xdg; - xdg.Start(XDG_Thread, (void*)&uri); + xdg.Start(XDG_Thread, arg); xdg.Detach(); } diff --git a/src/system/System_W32.cpp b/src/system/System_W32.cpp index 1029f1d..ccc0b18 100644 --- a/src/system/System_W32.cpp +++ b/src/system/System_W32.cpp @@ -4,7 +4,7 @@ namespace ehs { - void System::OpenURI(const Str_8& uri) + void System::OpenURI(Str_8 uri) { ShellExecuteA(nullptr, "open", uri, nullptr, nullptr, SW_SHOW); }