diff --git a/support/include/utils/base64.hpp b/support/include/utils/base64.hpp index b5099d69..2c63569a 100644 --- a/support/include/utils/base64.hpp +++ b/support/include/utils/base64.hpp @@ -1,174 +1,174 @@ -// NOLINTBEGIN -#ifndef _MACARON_BASE64_H_ -#define _MACARON_BASE64_H_ - -/** - * The MIT License (MIT) - * Copyright (c) 2016 tomykaira - * - * 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. - */ - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunknown-warning-option" -#endif - -#ifdef __GNUC__ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wconversion" -#pragma GCC diagnostic ignored "-Wold-style-cast" -#pragma GCC diagnostic ignored "-Wuseless-cast" -#endif - -#include -#include -#include - -namespace macaron::Base64 { -static std::string Encode(const unsigned char *data, std::size_t len) { - static constexpr std::array sEncodingTable{ - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', - 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', - 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', - 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', - }; - - auto in_len{len}; - std::string ret; - if (in_len > 0) { - std::size_t out_len{4U * ((in_len + 2U) / 3U)}; - ret = std::string(out_len, '\0'); - std::size_t i; - auto *p = reinterpret_cast(ret.data()); - - for (i = 0U; i < in_len - 2U; i += 3U) { - *p++ = sEncodingTable[(data[i] >> 2U) & 0x3F]; - *p++ = sEncodingTable[((data[i] & 0x3) << 4U) | - ((int)(data[i + 1U] & 0xF0) >> 4U)]; - *p++ = sEncodingTable[((data[i + 1] & 0xF) << 2) | - ((int)(data[i + 2U] & 0xC0) >> 6U)]; - *p++ = sEncodingTable[data[i + 2U] & 0x3F]; - } - if (i < in_len) { - *p++ = sEncodingTable[(data[i] >> 2U) & 0x3F]; - if (i == (in_len - 1U)) { - *p++ = sEncodingTable[((data[i] & 0x3) << 4U)]; - *p++ = '='; - } else { - *p++ = sEncodingTable[((data[i] & 0x3) << 4U) | - ((int)(data[i + 1U] & 0xF0) >> 4U)]; - *p++ = sEncodingTable[((data[i + 1U] & 0xF) << 2U)]; - } - *p++ = '='; - } - } - - return ret; -} - -[[maybe_unused]] static std::string Encode(std::string_view data) { - return Encode(reinterpret_cast(data.data()), - data.size()); -} - -[[maybe_unused]] static std::vector -Decode(std::string_view input) { - static constexpr std::array kDecodingTable{ - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63, 52, 53, 54, 55, 56, 57, - 58, 59, 60, 61, 64, 64, 64, 64, 64, 64, 64, 0, 1, 2, 3, 4, 5, 6, - 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 64, 64, 64, 64, 64, 64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, - 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, - }; - - std::vector out; - if (not input.empty()) { - auto in_len{input.size()}; - if (in_len % 4U != 0U) { - throw std::runtime_error("Input data size is not a multiple of 4"); - } - - std::size_t out_len{in_len / 4U * 3U}; - if (input[in_len - 1U] == '=') { - out_len--; - } - if (input[in_len - 2U] == '=') { - out_len--; - } - - out.resize(out_len); - - for (std::size_t i = 0U, j = 0U; i < in_len;) { - std::uint32_t a = - input.at(i) == '=' - ? 0U & i++ - : kDecodingTable[static_cast(input.at(i++))]; - std::uint32_t b = - input.at(i) == '=' - ? 0U & i++ - : kDecodingTable[static_cast(input.at(i++))]; - std::uint32_t c = - input.at(i) == '=' - ? 0U & i++ - : kDecodingTable[static_cast(input.at(i++))]; - std::uint32_t d = - input.at(i) == '=' - ? 0U & i++ - : kDecodingTable[static_cast(input.at(i++))]; - - std::uint32_t triple = - (a << 3U * 6U) + (b << 2U * 6U) + (c << 1U * 6U) + (d << 0U * 6U); - - if (j < out_len) - out[j++] = (triple >> 2U * 8U) & 0xFF; - if (j < out_len) - out[j++] = (triple >> 1U * 8U) & 0xFF; - if (j < out_len) - out[j++] = (triple >> 0U * 8U) & 0xFF; - } - } - - return out; -} -} // namespace macaron::Base64 - -#ifdef __GNUC__ -#pragma GCC diagnostic pop -#endif - -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - -#endif /* _MACARON_BASE64_H_ */ - -// NOLINTEND +// NOLINTBEGIN +#ifndef _MACARON_BASE64_H_ +#define _MACARON_BASE64_H_ + +/** + * The MIT License (MIT) + * Copyright (c) 2016 tomykaira + * + * 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. + */ + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunknown-warning-option" +#endif + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#pragma GCC diagnostic ignored "-Wold-style-cast" +#pragma GCC diagnostic ignored "-Wuseless-cast" +#endif + +#include +#include +#include + +namespace macaron::Base64 { +static std::string Encode(const unsigned char *data, std::size_t len) { + static constexpr std::array sEncodingTable{ + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', + }; + + auto in_len{len}; + std::string ret; + if (in_len > 0) { + std::size_t out_len{4U * ((in_len + 2U) / 3U)}; + ret = std::string(out_len, '\0'); + std::size_t i; + auto *p = reinterpret_cast(ret.data()); + + for (i = 0U; i < in_len - 2U; i += 3U) { + *p++ = sEncodingTable[(data[i] >> 2U) & 0x3F]; + *p++ = sEncodingTable[((data[i] & 0x3) << 4U) | + ((int)(data[i + 1U] & 0xF0) >> 4U)]; + *p++ = sEncodingTable[((data[i + 1] & 0xF) << 2) | + ((int)(data[i + 2U] & 0xC0) >> 6U)]; + *p++ = sEncodingTable[data[i + 2U] & 0x3F]; + } + if (i < in_len) { + *p++ = sEncodingTable[(data[i] >> 2U) & 0x3F]; + if (i == (in_len - 1U)) { + *p++ = sEncodingTable[((data[i] & 0x3) << 4U)]; + *p++ = '='; + } else { + *p++ = sEncodingTable[((data[i] & 0x3) << 4U) | + ((int)(data[i + 1U] & 0xF0) >> 4U)]; + *p++ = sEncodingTable[((data[i + 1U] & 0xF) << 2U)]; + } + *p++ = '='; + } + } + + return ret; +} + +[[maybe_unused]] static std::string Encode(std::string_view data) { + return Encode(reinterpret_cast(data.data()), + data.size()); +} + +[[maybe_unused]] static std::vector +Decode(std::string_view input) { + static constexpr std::array kDecodingTable{ + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 64, 64, 64, 64, 64, 64, 64, 0, 1, 2, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 64, 64, 64, 64, 64, 64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, + }; + + std::vector out; + if (not input.empty()) { + auto in_len{input.size()}; + if (in_len % 4U != 0U) { + throw std::runtime_error("Input data size is not a multiple of 4"); + } + + std::size_t out_len{in_len / 4U * 3U}; + if (input[in_len - 1U] == '=') { + out_len--; + } + if (input[in_len - 2U] == '=') { + out_len--; + } + + out.resize(out_len); + + for (std::size_t i = 0U, j = 0U; i < in_len;) { + std::uint32_t a = + input.at(i) == '=' + ? 0U & i++ + : kDecodingTable[static_cast(input.at(i++))]; + std::uint32_t b = + input.at(i) == '=' + ? 0U & i++ + : kDecodingTable[static_cast(input.at(i++))]; + std::uint32_t c = + input.at(i) == '=' + ? 0U & i++ + : kDecodingTable[static_cast(input.at(i++))]; + std::uint32_t d = + input.at(i) == '=' + ? 0U & i++ + : kDecodingTable[static_cast(input.at(i++))]; + + std::uint32_t triple = + (a << 3U * 6U) + (b << 2U * 6U) + (c << 1U * 6U) + (d << 0U * 6U); + + if (j < out_len) + out[j++] = (triple >> 2U * 8U) & 0xFF; + if (j < out_len) + out[j++] = (triple >> 1U * 8U) & 0xFF; + if (j < out_len) + out[j++] = (triple >> 0U * 8U) & 0xFF; + } + } + + return out; +} +} // namespace macaron::Base64 + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +#endif /* _MACARON_BASE64_H_ */ + +// NOLINTEND diff --git a/support/include/utils/collection.hpp b/support/include/utils/collection.hpp index ad46600c..61ea7e11 100644 --- a/support/include/utils/collection.hpp +++ b/support/include/utils/collection.hpp @@ -24,6 +24,8 @@ #include "utils/config.hpp" +#include "utils/string.hpp" + namespace repertory::utils::collection { template [[nodiscard]] inline auto @@ -94,21 +96,6 @@ inline auto remove_element(col_t &collection, return collection; } -template -[[nodiscard]] inline auto to_hex_string_t(const col_t &collection) -> string_t { - static_assert(sizeof(typename col_t::value_type) == 1U, - "value_type must be 1 byte in size"); - static constexpr const auto mask = 0xFF; - - std::basic_stringstream stream{}; - for (auto &&val : collection) { - stream << std::setfill('0') << std::setw(2) << std::hex - << (static_cast(val) & mask); - } - - return stream.str(); -} - template inline auto from_hex_string(std::string_view str, val_t &val) -> bool { return from_hex_string_t(str, val); @@ -121,12 +108,22 @@ inline auto from_hex_string(std::wstring_view str, val_t &val) -> bool { template inline auto to_hex_string(const col_t &collection) -> std::string { - return to_hex_string_t(collection); + static_assert(sizeof(typename col_t::value_type) == 1U, + "value_type must be 1 byte in size"); + static constexpr const auto mask = 0xFF; + + std::stringstream stream{}; + for (auto &&val : collection) { + stream << std::setfill('0') << std::setw(2) << std::hex + << (static_cast(val) & mask); + } + + return stream.str(); } template inline auto to_hex_wstring(const col_t &collection) -> std::wstring { - return to_hex_string_t(collection); + return utils::string::from_utf8(to_hex_string(collection)); } } // namespace repertory::utils::collection diff --git a/support/include/utils/common.hpp b/support/include/utils/common.hpp index fd670173..952e426e 100644 --- a/support/include/utils/common.hpp +++ b/support/include/utils/common.hpp @@ -90,10 +90,6 @@ get_next_available_port(std::uint16_t first_port, std::uint16_t &available_port) -> bool; #endif // defined(PROJECT_ENABLE_BOOST) -[[nodiscard]] auto resolve_variables(std::string str) -> std::string; - -[[nodiscard]] auto resolve_variables(std::wstring_view str) -> std::wstring; - template inline constexpr auto divide_with_ceiling(result_t numerator, data_t denominator) -> result_t { diff --git a/support/include/utils/encryption.hpp b/support/include/utils/encryption.hpp index 445e294f..28e55ca0 100644 --- a/support/include/utils/encryption.hpp +++ b/support/include/utils/encryption.hpp @@ -25,31 +25,46 @@ #include "utils/config.hpp" -namespace repertory::utils::encryption { -using hash_256_t = std::array; -using hash_256_func_t = std::function; -using key_type = std::array; +#include "utils/hash.hpp" +namespace repertory::utils::encryption { inline constexpr const std::uint32_t encryption_header_size{ crypto_aead_xchacha20poly1305_IETF_NPUBBYTES + crypto_aead_xchacha20poly1305_IETF_ABYTES, }; -[[nodiscard]] auto generate_key(std::string_view encryption_token) -> key_type; +template +[[nodiscard]] inline auto default_create_hash(std::string_view) -> hash_t; + +template +[[nodiscard]] inline auto default_create_hash(std::wstring_view) -> hash_t; + +template +inline auto generate_key( + std::string_view password, + std::optional< + std::function> + hasher = std::nullopt) -> hash_t; + +template +inline auto generate_key( + std::wstring_view password, + std::optional< + std::function> + hasher = std::nullopt) -> hash_t; #if defined(PROJECT_ENABLE_BOOST) -[[nodiscard]] auto decrypt_data( - std::string_view data, std::string_view password, - std::optional hasher = std::nullopt) -> data_buffer; +[[nodiscard]] auto decrypt_data(std::string_view password, + std::string_view data) -> data_buffer; -[[nodiscard]] auto encrypt_data( - std::string_view data, std::string_view password, - std::optional hasher = std::nullopt) -> data_buffer; +[[nodiscard]] auto encrypt_data(std::string_view password, + std::string_view data) -> data_buffer; -template -[[nodiscard]] inline auto -decrypt_data(const key_type &key, const unsigned char *buffer, - std::size_t buffer_size, result &res) -> bool { +template +[[nodiscard]] inline auto decrypt_data(const std::array &key, + const unsigned char *buffer, + std::size_t buffer_size, + result &res) -> bool { if (buffer_size > encryption_header_size) { const std::uint32_t size = boost::endian::native_to_big(static_cast(buffer_size)); @@ -65,34 +80,43 @@ decrypt_data(const key_type &key, const unsigned char *buffer, return false; } -template -[[nodiscard]] inline auto decrypt_data(const key_type &key, const buffer &buf, - result &res) -> bool { +template +[[nodiscard]] inline auto decrypt_data(const std::array &key, + const buffer &buf, result &res) -> bool { return decrypt_data( key, reinterpret_cast(buf.data()), buf.size(), res); } -template -[[nodiscard]] inline auto decrypt_data(std::string_view encryption_token, - const buffer &buf, result &res) -> bool { - return decrypt_data(generate_key(encryption_token), buf, res); +template +[[nodiscard]] inline auto decrypt_data( + std::string_view password, const buffer &buf, result &res, + std::optional< + std::function> + hasher = std::nullopt) -> bool { + return decrypt_data(generate_key(password, hasher), buf, res); } -template -[[nodiscard]] inline auto -decrypt_data(std::string_view encryption_token, const unsigned char *buffer, - std::size_t buffer_size, result &res) -> bool { - return decrypt_data(generate_key(encryption_token), buffer, +template +[[nodiscard]] inline auto decrypt_data( + std::string_view password, const unsigned char *buffer, + std::size_t buffer_size, result &res, + + std::optional< + std::function> + hasher = std::nullopt) -> bool { + return decrypt_data(generate_key(password, hasher), buffer, buffer_size, res); } -template +template inline void encrypt_data(const std::array &iv, - const key_type &key, const unsigned char *buffer, - std::size_t buffer_size, result &res) { + const std::array &key, + const unsigned char *buffer, std::size_t buffer_size, + result &res) { std::array mac{}; const std::uint32_t size = boost::endian::native_to_big( @@ -113,47 +137,116 @@ encrypt_data(const std::array -inline void encrypt_data(const key_type &key, const unsigned char *buffer, - std::size_t buffer_size, result &res) { +template +inline void encrypt_data(const std::array &key, + const unsigned char *buffer, std::size_t buffer_size, + result &res) { std::array iv{}; randombytes_buf(iv.data(), iv.size()); encrypt_data(iv, key, buffer, buffer_size, res); } -template -inline void encrypt_data(std::string_view encryption_token, - const unsigned char *buffer, std::size_t buffer_size, - result &res) { - encrypt_data(generate_key(encryption_token), buffer, buffer_size, +template +inline void encrypt_data( + std::string_view password, const unsigned char *buffer, + std::size_t buffer_size, result &res, + std::optional< + std::function> + hasher = std::nullopt) { + encrypt_data(generate_key(password, hasher), buffer, buffer_size, res); } -template -inline void encrypt_data(std::string_view encryption_token, const buffer &buf, - result &res) { - encrypt_data(generate_key(encryption_token), +template +inline void encrypt_data( + std::string_view password, const buffer &buf, result &res, + std::optional< + std::function> + hasher = std::nullopt) { + encrypt_data(generate_key(password, hasher), reinterpret_cast(buf.data()), buf.size(), res); } -template -inline void encrypt_data(const key_type &key, const buffer &buf, result &res) { +template +inline void encrypt_data(const std::array &key, const buffer &buf, + result &res) { encrypt_data(key, reinterpret_cast(buf.data()), buf.size(), res); } -template +template inline void encrypt_data(const std::array &iv, - const key_type &key, const buffer &buf, result &res) { + const std::array &key, const buffer &buf, result &res) { encrypt_data(iv, key, reinterpret_cast(buf.data()), buf.size(), res); } #endif // defined(PROJECT_ENABLE_BOOST) + +template <> +inline auto +default_create_hash(std::string_view data) -> hash_256_t { + return create_hash_sha256(data); +} + +template <> +inline auto +default_create_hash(std::wstring_view data) -> hash_256_t { + return create_hash_sha256(data); +} + +template <> +inline auto +default_create_hash(std::string_view data) -> hash_384_t { + return create_hash_blake2b_384(data); +} + +template <> +inline auto +default_create_hash(std::wstring_view data) -> hash_384_t { + return create_hash_blake2b_384(data); +} + +template <> +inline auto +default_create_hash(std::string_view data) -> hash_512_t { + return create_hash_sha512(data); +} + +template <> +inline auto +default_create_hash(std::wstring_view data) -> hash_512_t { + return create_hash_sha512(data); +} + +template +inline auto generate_key( + std::string_view password, + std::optional< + std::function> + hasher) -> hash_t { + return hasher.has_value() ? (*hasher)(reinterpret_cast( + password.data()), + password.size()) + : default_create_hash(password); +} + +template +inline auto generate_key( + std::wstring_view password, + std::optional< + std::function> + hasher) -> hash_t { + return hasher.has_value() + ? (*hasher)( + reinterpret_cast(password.data()), + password.size() * sizeof(std::wstring_view::value_type)) + : default_create_hash(password); +} } // namespace repertory::utils::encryption #endif // defined(PROJECT_ENABLE_LIBSODIUM) diff --git a/support/include/utils/file.hpp b/support/include/utils/file.hpp index 1d059125..3f5c3df2 100644 --- a/support/include/utils/file.hpp +++ b/support/include/utils/file.hpp @@ -74,21 +74,21 @@ public: [[nodiscard]] auto truncate(std::size_t size) -> bool; -#if defined(PROJECT_ENABLE_JSON) - [[nodiscard]] auto write(const nlohmann::json &data, - std::size_t *total_written = nullptr) -> bool { - auto str_data = data.dump(); - return write_(reinterpret_cast(str_data.c_str()), - str_data.size(), 0U, total_written); - } -#endif // defined(PROJECT_ENABLE_JSON) - [[nodiscard]] auto write(const data_buffer &data, std::uint64_t offset, std::size_t *total_written = nullptr) -> bool { return write_(reinterpret_cast(data.data()), data.size(), offset, total_written); } +#if defined(PROJECT_ENABLE_JSON) + [[nodiscard]] auto write_json(const nlohmann::json &data, + std::size_t *total_written = nullptr) -> bool { + auto str_data = data.dump(); + return write_(reinterpret_cast(str_data.c_str()), + str_data.size(), 0U, total_written); + } +#endif // defined(PROJECT_ENABLE_JSON) + [[nodiscard]] operator bool() const { return stream_.is_open(); } private: diff --git a/support/include/utils/hash.hpp b/support/include/utils/hash.hpp new file mode 100644 index 00000000..9c74f216 --- /dev/null +++ b/support/include/utils/hash.hpp @@ -0,0 +1,255 @@ +/* + Copyright <2018-2024> + + 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. +*/ +#ifndef REPERTORY_INCLUDE_UTILS_HASH_HPP_ +#define REPERTORY_INCLUDE_UTILS_HASH_HPP_ +#if defined(PROJECT_ENABLE_LIBSODIUM) + +#include "utils/config.hpp" + +namespace repertory::utils::encryption { +using hash_256_t = std::array; +using hash_384_t = std::array; +using hash_512_t = std::array; + +[[nodiscard]] auto create_hash_blake2b_256(std::string_view data) -> hash_256_t; + +[[nodiscard]] auto +create_hash_blake2b_256(std::wstring_view data) -> hash_256_t; + +[[nodiscard]] auto create_hash_blake2b_384(std::string_view data) -> hash_384_t; + +[[nodiscard]] auto +create_hash_blake2b_384(std::wstring_view data) -> hash_384_t; + +[[nodiscard]] auto create_hash_blake2b_512(std::string_view data) -> hash_512_t; + +[[nodiscard]] auto +create_hash_blake2b_512(std::wstring_view data) -> hash_512_t; + +template +[[nodiscard]] auto +create_hash_blake2b_t(std::basic_string_view data) -> hash_t; + +template +[[nodiscard]] auto create_hash_blake2b_t(const data_buffer &data) -> hash_t; + +template +[[nodiscard]] auto create_hash_blake2b_t( + const std::vector> &data) -> hash_t; + +template +[[nodiscard]] auto +create_hash_blake2b_t(const std::vector> &data) + -> std::array; + +[[nodiscard]] auto create_hash_sha256(std::string_view data) -> hash_256_t; + +[[nodiscard]] auto create_hash_sha256(std::wstring_view data) -> hash_256_t; + +[[nodiscard]] auto create_hash_sha512(std::string_view data) -> hash_512_t; + +[[nodiscard]] auto create_hash_sha512(std::wstring_view data) -> hash_512_t; + +template +[[nodiscard]] auto +create_hash_sha256_t(std::basic_string_view data) -> hash_256_t; + +template +[[nodiscard]] auto create_hash_sha512_t(std::basic_string_view data) + -> repertory::utils::encryption::hash_512_t; + +template +auto create_hash_blake2b_t(const data_buffer &data) -> hash_t { + hash_t hash{}; + + crypto_generichash_blake2b_state state{}; + auto res = crypto_generichash_blake2b_init(&state, nullptr, 0U, hash.size()); + if (res != 0) { + throw std::runtime_error("failed to initialize blake2b|" + + std::to_string(res)); + } + + res = crypto_generichash_blake2b_update( + &state, reinterpret_cast(data.data()), + data.size() * sizeof(data_buffer::value_type)); + if (res != 0) { + throw std::runtime_error("failed to update blake2b|" + std::to_string(res)); + } + + res = crypto_generichash_blake2b_final(&state, hash.data(), hash.size()); + if (res != 0) { + throw std::runtime_error("failed to finalize blake2b|" + + std::to_string(res)); + } + + return hash; +} + +template +auto create_hash_blake2b_t(const std::vector> &data) + -> std::array { + using hash_t = std::array; + hash_t hash{}; + + crypto_generichash_blake2b_state state{}; + auto res = crypto_generichash_blake2b_init(&state, nullptr, 0U, hash.size()); + if (res != 0) { + throw std::runtime_error("failed to initialize blake2b|" + + std::to_string(res)); + } + + for (const auto &item : data) { + res = crypto_generichash_blake2b_update( + &state, reinterpret_cast(item.data()), + item.size()); + if (res != 0) { + throw std::runtime_error("failed to update blake2b|" + + std::to_string(res)); + } + } + + res = crypto_generichash_blake2b_final(&state, hash.data(), hash.size()); + if (res != 0) { + throw std::runtime_error("failed to finalize blake2b|" + + std::to_string(res)); + } + + return hash; +} + +template +auto create_hash_blake2b_t(const std::vector> &data) + -> hash_t { + hash_t hash{}; + + crypto_generichash_blake2b_state state{}; + auto res = crypto_generichash_blake2b_init(&state, nullptr, 0U, hash.size()); + if (res != 0) { + throw std::runtime_error("failed to initialize blake2b|" + + std::to_string(res)); + } + + for (const auto &item : data) { + res = crypto_generichash_blake2b_update( + &state, reinterpret_cast(item.data()), + item.size() * sizeof(char_t)); + if (res != 0) { + throw std::runtime_error("failed to update blake2b|" + + std::to_string(res)); + } + } + + res = crypto_generichash_blake2b_final(&state, hash.data(), hash.size()); + if (res != 0) { + throw std::runtime_error("failed to finalize blake2b|" + + std::to_string(res)); + } + + return hash; +} + +template +auto create_hash_blake2b_t(std::basic_string_view data) -> hash_t { + hash_t hash{}; + + crypto_generichash_blake2b_state state{}; + auto res = crypto_generichash_blake2b_init(&state, nullptr, 0U, hash.size()); + if (res != 0) { + throw std::runtime_error("failed to initialize blake2b|" + + std::to_string(res)); + } + + res = crypto_generichash_blake2b_update( + &state, reinterpret_cast(data.data()), + data.size() * sizeof(char_t)); + if (res != 0) { + throw std::runtime_error("failed to update blake2b|" + std::to_string(res)); + } + + res = crypto_generichash_blake2b_final(&state, hash.data(), hash.size()); + if (res != 0) { + throw std::runtime_error("failed to finalize blake2b|" + + std::to_string(res)); + } + + return hash; +} + +template +auto create_hash_sha256_t(std::basic_string_view data) + -> repertory::utils::encryption::hash_256_t { + repertory::utils::encryption::hash_256_t hash{}; + + crypto_hash_sha256_state state{}; + auto res = crypto_hash_sha256_init(&state); + if (res != 0) { + throw std::runtime_error("failed to initialize sha256|" + + std::to_string(res)); + } + + res = crypto_hash_sha256_update( + &state, reinterpret_cast(data.data()), + data.size() * sizeof(char_t)); + if (res != 0) { + throw std::runtime_error("failed to update sha256|" + std::to_string(res)); + } + + res = crypto_hash_sha256_final(&state, hash.data()); + if (res != 0) { + throw std::runtime_error("failed to finalize sha256|" + + std::to_string(res)); + } + + return hash; +} + +template +auto create_hash_sha512_t(std::basic_string_view data) + -> repertory::utils::encryption::hash_512_t { + repertory::utils::encryption::hash_512_t hash{}; + + crypto_hash_sha512_state state{}; + auto res = crypto_hash_sha512_init(&state); + if (res != 0) { + throw std::runtime_error("failed to initialize sha512|" + + std::to_string(res)); + } + + res = crypto_hash_sha512_update( + &state, reinterpret_cast(data.data()), + data.size() * sizeof(char_t)); + if (res != 0) { + throw std::runtime_error("failed to update sha512|" + std::to_string(res)); + } + + res = crypto_hash_sha512_final(&state, hash.data()); + if (res != 0) { + throw std::runtime_error("failed to finalize sha512|" + + std::to_string(res)); + } + + return hash; +} +} // namespace repertory::utils::encryption + +#endif // defined(PROJECT_ENABLE_LIBSODIUM) +#endif // REPERTORY_INCLUDE_UTILS_HASH_HPP_ diff --git a/support/src/utils/common.cpp b/support/src/utils/common.cpp index 79dd536b..72b926e6 100644 --- a/support/src/utils/common.cpp +++ b/support/src/utils/common.cpp @@ -86,12 +86,21 @@ auto create_uuid_wstring() -> std::wstring { #if defined(PROJECT_ENABLE_LIBSODIUM) auto generate_random_string(std::size_t length) -> std::string { std::string ret; + if (length == 0U) { + return ret; + } + ret.resize(length); - for (std::size_t i = 0U; i < length; i++) { - do { - ret[i] = static_cast(generate_random() % 74 + 48); - } while (((ret.at(i) >= 91) && (ret.at(i) <= 96)) || - ((ret.at(i) >= 58) && (ret.at(i) <= 64))); + for (auto &ch : ret) { + std::array random_list{ + generate_random_between(0U, 57U), + generate_random_between(65U, 90U), + generate_random_between(97U, 255U), + }; + ch = static_cast( + random_list.at(repertory::utils::generate_random_between(0U, 2U)) % + 74U + + 48U); } return ret; @@ -118,6 +127,10 @@ auto get_environment_variable(std::wstring_view variable) -> std::wstring { #if defined(PROJECT_ENABLE_BOOST) auto get_next_available_port(std::uint16_t first_port, std::uint16_t &available_port) -> bool { + if (first_port == 0U) { + return false; + } + using namespace boost::asio; using ip::tcp; @@ -141,13 +154,4 @@ auto get_next_available_port(std::uint16_t first_port, return not error_code; } #endif // defined(PROJECT_ENABLE_BOOST) - -auto resolve_variables(std::string str) -> std::string { - return utils::path::absolute(str); -} - -auto resolve_variables(std::wstring_view str) -> std::wstring { - return utils::string::from_utf8( - resolve_variables(utils::string::to_utf8(str))); -} } // namespace repertory::utils diff --git a/support/src/utils/encryption.cpp b/support/src/utils/encryption.cpp index a67cd20c..cb146c69 100644 --- a/support/src/utils/encryption.cpp +++ b/support/src/utils/encryption.cpp @@ -22,33 +22,11 @@ #include "utils/encryption.hpp" #if defined(PROJECT_ENABLE_LIBSODIUM) -namespace { -using nonce_t = - std::array; - -static constexpr const auto nonce_size{sizeof(nonce_t)}; - -[[nodiscard]] static auto create_hash_256(std::string_view data) - -> repertory::utils::encryption::hash_256_t { - repertory::utils::encryption::hash_256_t hash{}; - - crypto_generichash_blake2b_state state{}; - crypto_generichash_blake2b_init(&state, nullptr, 0U, hash.size()); - crypto_generichash_blake2b_update( - &state, reinterpret_cast(data.data()), - data.size()); - crypto_generichash_blake2b_final(&state, hash.data(), hash.size()); - - return hash; -} -} // namespace - namespace repertory::utils::encryption { #if defined(PROJECT_ENABLE_BOOST) -auto decrypt_data(std::string_view data, std::string_view password, - std::optional hasher) -> data_buffer { - auto key = - hasher.has_value() ? (*hasher)(password) : create_hash_256(password); +auto decrypt_data(std::string_view password, + std::string_view data) -> data_buffer { + auto key = generate_key(password); data_buffer buf{}; if (not decrypt_data(key, @@ -60,10 +38,9 @@ auto decrypt_data(std::string_view data, std::string_view password, return buf; } -auto encrypt_data(std::string_view data, std::string_view password, - std::optional hasher) -> data_buffer { - auto key = - hasher.has_value() ? (*hasher)(password) : create_hash_256(password); +auto encrypt_data(std::string_view password, + std::string_view data) -> data_buffer { + auto key = generate_key(password); data_buffer buf{}; encrypt_data(key, reinterpret_cast(data.data()), @@ -72,30 +49,6 @@ auto encrypt_data(std::string_view data, std::string_view password, return buf; } #endif // defined(PROJECT_ENABLE_BOOST) - -auto generate_key(std::string_view encryption_token) -> key_type { - crypto_hash_sha256_state state{}; - auto res = crypto_hash_sha256_init(&state); - if (res != 0) { - throw std::runtime_error("failed to initialize sha256|" + - std::to_string(res)); - } - res = crypto_hash_sha256_update( - &state, reinterpret_cast(encryption_token.data()), - encryption_token.size()); - if (res != 0) { - throw std::runtime_error("failed to update sha256|" + std::to_string(res)); - } - - key_type ret{}; - res = crypto_hash_sha256_final(&state, ret.data()); - if (res != 0) { - throw std::runtime_error("failed to finalize sha256|" + - std::to_string(res)); - } - - return ret; -} } // namespace repertory::utils::encryption #endif // defined(PROJECT_ENABLE_LIBSODIUM) diff --git a/support/src/utils/file.cpp b/support/src/utils/file.cpp index a938454e..1657e842 100644 --- a/support/src/utils/file.cpp +++ b/support/src/utils/file.cpp @@ -276,7 +276,7 @@ auto read_json_file(std::string_view path, nlohmann::json &data) -> bool { #if defined(PROJECT_ENABLE_LIBSODIUM) && defined(PROJECT_ENABLE_BOOST) if (password.has_value()) { auto decrypted_data = - utils::encryption::decrypt_data(json_text, *password); + utils::encryption::decrypt_data(*password, json_text); json_text = {decrypted_data.begin(), decrypted_data.end()}; } #endif // defined(PROJECT_ENABLE_LIBSODIUM) && defined(PROJECT_ENABLE_BOOST) @@ -322,7 +322,7 @@ auto write_json_file(std::string_view path, #if defined(PROJECT_ENABLE_LIBSODIUM) && defined(PROJECT_ENABLE_BOOST) if (password.has_value()) { - return file.write(utils::encryption::encrypt_data(data.dump(), *password), + return file.write(utils::encryption::encrypt_data(*password, data.dump()), 0U); } #endif // defined(PROJECT_ENABLE_LIBSODIUM) && defined(PROJECT_ENABLE_BOOST) diff --git a/support/src/utils/hash.cpp b/support/src/utils/hash.cpp new file mode 100644 index 00000000..7cc2fe52 --- /dev/null +++ b/support/src/utils/hash.cpp @@ -0,0 +1,70 @@ +/* + Copyright <2018-2024> + + 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. +*/ +#include "utils/hash.hpp" + +#if defined(PROJECT_ENABLE_LIBSODIUM) + +namespace {} // namespace + +namespace repertory::utils::encryption { +auto create_hash_blake2b_256(std::string_view data) -> hash_256_t { + return create_hash_blake2b_t(data); +} + +auto create_hash_blake2b_256(std::wstring_view data) -> hash_256_t { + return create_hash_blake2b_t(data); +} + +auto create_hash_blake2b_384(std::string_view data) -> hash_384_t { + return create_hash_blake2b_t(data); +} + +auto create_hash_blake2b_384(std::wstring_view data) -> hash_384_t { + return create_hash_blake2b_t(data); +} + +auto create_hash_blake2b_512(std::string_view data) -> hash_512_t { + return create_hash_blake2b_t(data); +} + +auto create_hash_blake2b_512(std::wstring_view data) -> hash_512_t { + return create_hash_blake2b_t(data); +} + +auto create_hash_sha256(std::string_view data) -> hash_256_t { + return create_hash_sha256_t(data); +} + +auto create_hash_sha256(std::wstring_view data) -> hash_256_t { + return create_hash_sha256_t(data); +} + +auto create_hash_sha512(std::string_view data) -> hash_512_t { + return create_hash_sha512_t(data); +} + +auto create_hash_sha512(std::wstring_view data) -> hash_512_t { + return create_hash_sha512_t(data); +} +} // namespace repertory::utils::encryption + +#endif // defined(PROJECT_ENABLE_LIBSODIUM) diff --git a/support/test/src/utils/common_test.cpp b/support/test/src/utils/common_test.cpp index d1ed808a..0d1d822d 100644 --- a/support/test/src/utils/common_test.cpp +++ b/support/test/src/utils/common_test.cpp @@ -20,10 +20,12 @@ SOFTWARE. */ #include "gtest/gtest.h" -#include #include "utils/common.hpp" +#include "utils/collection.hpp" +#include "utils/string.hpp" + namespace repertory { TEST(utils_common, calculate_read_size) { auto read_size = utils::calculate_read_size(0U, 0U, 0U); @@ -240,4 +242,72 @@ TEST(utils_common, generate_random_between_throws_error_on_invalid_range) { }, std::range_error); } + +#if defined(PROJECT_ENABLE_LIBSODIUM) +TEST(utils_common, generate_random_string) { + static constexpr const auto max_iterations{10000L}; + + const auto test_string = [](auto str) { + static std::vector list{}; + + EXPECT_FALSE(utils::collection::includes(list, str)); + list.push_back(str); + + EXPECT_EQ(16U, str.size()); + for (auto &&ch : str) { + auto ch_int = static_cast(ch); + EXPECT_GE(ch_int, 48U); + EXPECT_LE(ch_int, 73U + 48U); + } + }; + + for (std::size_t idx = 0U; idx < max_iterations; ++idx) { + test_string(utils::generate_random_string(16U)); + test_string(utils::generate_random_wstring(16U)); + } +} + +TEST(utils_common, generate_random_string_for_zero_length) { + EXPECT_TRUE(utils::generate_random_string(0U).empty()); + EXPECT_TRUE(utils::generate_random_wstring(0U).empty()); +} +#endif // defined(PROJECT_ENABLE_LIBSODIUM) + +TEST(utils_common, get_environment_variable) { + static constexpr const std::string path_env{"PATH"}; + std::string path; + +#if defined(_WIN32) + path.resize(MAX_PATH + 1U); + auto size = ::GetEnvironmentVariableA(path_env.c_str(), path.data(), 0U); + + path.resize(size); + ::GetEnvironmentVariableA(path_env.c_str(), path.data(), + static_cast(path.size())); +#else // !defined(_WIN32) + path = std::getenv(path_env.c_str()); +#endif // defined(_WIN32) + + EXPECT_STREQ(path.c_str(), utils::get_environment_variable(path_env).c_str()); + EXPECT_STREQ( + utils::string::from_utf8(path).c_str(), + utils::get_environment_variable(utils::string::from_utf8(path_env)) + .c_str()); +} + +#if defined(PROJECT_ENABLE_BOOST) +TEST(utils_common, get_next_available_port) { + std::uint16_t available_port{}; + for (std::uint16_t port = 1U; port < 65535; ++port) { + EXPECT_TRUE(utils::get_next_available_port(port, available_port)); + EXPECT_GE(available_port, port); + } +} + +TEST(utils_common, get_next_available_port_fails_if_starting_point_is_zero) { + std::uint16_t available_port{}; + EXPECT_FALSE(utils::get_next_available_port(0U, available_port)); + EXPECT_EQ(0U, available_port); +} +#endif // defined(PROJECT_ENABLE_BOOST) } // namespace repertory diff --git a/support/test/src/utils/encryption_test.cpp b/support/test/src/utils/encryption_test.cpp index 6e04a841..73c1dec7 100644 --- a/support/test/src/utils/encryption_test.cpp +++ b/support/test/src/utils/encryption_test.cpp @@ -19,7 +19,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#if defined(PROJECT_ENABLE_LIBSODIUM) && defined(PROJECT_ENABLE_BOOST) +#if defined(PROJECT_ENABLE_LIBSODIUM) #include "gtest/gtest.h" @@ -27,8 +27,117 @@ #include "utils/encryption.hpp" namespace repertory { +static const std::string token{"moose"}; +static const std::wstring token_w{L"moose"}; + +TEST(utils_encryption, generate_key) { + auto key1 = + utils::encryption::generate_key(token); + EXPECT_STREQ( + "182072537ada59e4d6b18034a80302ebae935f66adbdf0f271d3d36309c2d481", + utils::collection::to_hex_string(key1).c_str()); + + auto key2 = + utils::encryption::generate_key("moose"); + auto key3 = + utils::encryption::generate_key("moose"); + EXPECT_EQ(key2, key3); + + auto key4 = + utils::encryption::generate_key("moose2"); + EXPECT_NE(key2, key4); + + auto key1_w = + utils::encryption::generate_key(token_w); + EXPECT_NE(key1, key1_w); + EXPECT_STREQ( + L"590ac70125bec4501172937f6a2cbdeb22a87b5e40d5595eccd06b2b20548d8f", + utils::collection::to_hex_wstring(key1_w).c_str()); + + auto key2_w = + utils::encryption::generate_key(L"moose"); + auto key3_w = + utils::encryption::generate_key(L"moose"); + EXPECT_EQ(key2_w, key3_w); + EXPECT_NE(key2_w, key2); + EXPECT_NE(key3_w, key3); + + auto key4_w = + utils::encryption::generate_key(L"moose2"); + EXPECT_NE(key2_w, key4_w); + EXPECT_NE(key4_w, key4); +} + +TEST(utils_encryption, generate_key_default_hasher_is_sha256) { + auto key1 = + utils::encryption::generate_key(token); + auto key2 = utils::encryption::generate_key( + token, [](auto &&data, auto &&size) -> auto { + return utils::encryption::create_hash_sha256( + std::string_view(reinterpret_cast(data), size)); + }); + EXPECT_EQ(key1, key2); + + auto key1_w = + utils::encryption::generate_key(token_w); + auto key2_w = utils::encryption::generate_key( + token_w, [](auto &&data, auto &&size) -> auto { + return utils::encryption::create_hash_sha256(std::wstring_view( + reinterpret_cast(data), size / sizeof(wchar_t))); + }); + EXPECT_EQ(key1_w, key2_w); + + EXPECT_NE(key1_w, key1); + EXPECT_NE(key2_w, key2); +} + +TEST(utils_encryption, generate_key_with_hasher) { + auto key1 = utils::encryption::generate_key( + token, [](auto &&data, auto &&size) -> auto { + return utils::encryption::create_hash_sha256( + std::string_view(reinterpret_cast(data), size)); + }); + EXPECT_STREQ( + "182072537ada59e4d6b18034a80302ebae935f66adbdf0f271d3d36309c2d481", + utils::collection::to_hex_string(key1).c_str()); + + auto key2 = utils::encryption::generate_key( + token, [](auto &&data, auto &&size) -> auto { + return utils::encryption::create_hash_blake2b_256( + std::string_view(reinterpret_cast(data), size)); + }); + EXPECT_NE(key1, key2); + + EXPECT_STREQ( + "ab4a0b004e824962913f7c0f79582b6ec7a3b8726426ca61d1a0a28ce5049e96", + utils::collection::to_hex_string(key2).c_str()); + + auto key1_w = utils::encryption::generate_key( + token_w, [](auto &&data, auto &&size) -> auto { + return utils::encryption::create_hash_sha256(std::wstring_view( + reinterpret_cast(data), size / sizeof(wchar_t))); + }); + EXPECT_STREQ( + L"590ac70125bec4501172937f6a2cbdeb22a87b5e40d5595eccd06b2b20548d8f", + utils::collection::to_hex_wstring(key1_w).c_str()); + + auto key2_w = utils::encryption::generate_key( + token_w, [](auto &&data, auto &&size) -> auto { + return utils::encryption::create_hash_blake2b_256(std::wstring_view( + reinterpret_cast(data), size / sizeof(wchar_t))); + }); + EXPECT_NE(key1_w, key2_w); + + EXPECT_STREQ( + L"0392d95ed3eee9772fbb9af68fedf829a8eb0adbe8575d9691cc9a752196766a", + utils::collection::to_hex_wstring(key2_w).c_str()); + + EXPECT_NE(key1_w, key1); + EXPECT_NE(key2_w, key2); +} + +#if defined(PROJECT_ENABLE_BOOST) static const std::string buffer = "cow moose dog chicken"; -static const std::string token = "moose"; static void test_encrypted_result(const data_buffer &result) { EXPECT_EQ(buffer.size() + utils::encryption::encryption_header_size, @@ -39,14 +148,6 @@ static void test_encrypted_result(const data_buffer &result) { EXPECT_STREQ(buffer.c_str(), data.c_str()); } -TEST(utils_encryption, generate_key) { - const auto key = utils::encryption::generate_key(token); - const auto str = utils::collection::to_hex_string(key); - EXPECT_STREQ( - "182072537ada59e4d6b18034a80302ebae935f66adbdf0f271d3d36309c2d481", - str.c_str()); -} - TEST(utils_encryption, encrypt_data_buffer) { data_buffer result; utils::encryption::encrypt_data(token, buffer, result); @@ -54,7 +155,8 @@ TEST(utils_encryption, encrypt_data_buffer) { } TEST(utils_encryption, encrypt_data_buffer_with_key) { - const auto key = utils::encryption::generate_key(token); + const auto key = + utils::encryption::generate_key(token); data_buffer result; utils::encryption::encrypt_data(key, buffer, result); test_encrypted_result(result); @@ -69,7 +171,8 @@ TEST(utils_encryption, encrypt_data_pointer) { } TEST(utils_encryption, encrypt_data_pointer_with_key) { - const auto key = utils::encryption::generate_key(token); + const auto key = + utils::encryption::generate_key(token); data_buffer result; utils::encryption::encrypt_data( key, reinterpret_cast(buffer.data()), @@ -78,7 +181,8 @@ TEST(utils_encryption, encrypt_data_pointer_with_key) { } TEST(utils_encryption, decrypt_data_pointer) { - const auto key = utils::encryption::generate_key(token); + const auto key = + utils::encryption::generate_key(token); data_buffer result; utils::encryption::encrypt_data( key, reinterpret_cast(buffer.data()), @@ -93,7 +197,8 @@ TEST(utils_encryption, decrypt_data_pointer) { } TEST(utils_encryption, decrypt_data_buffer_with_key) { - const auto key = utils::encryption::generate_key(token); + const auto key = + utils::encryption::generate_key(token); data_buffer result; utils::encryption::encrypt_data( key, reinterpret_cast(buffer.data()), @@ -107,7 +212,8 @@ TEST(utils_encryption, decrypt_data_buffer_with_key) { } TEST(utils_encryption, decrypt_data_pointer_with_key) { - const auto key = utils::encryption::generate_key(token); + const auto key = + utils::encryption::generate_key(token); data_buffer result; utils::encryption::encrypt_data( key, reinterpret_cast(buffer.data()), @@ -122,7 +228,8 @@ TEST(utils_encryption, decrypt_data_pointer_with_key) { } TEST(utils_encryption, decryption_failure) { - const auto key = utils::encryption::generate_key(token); + const auto key = + utils::encryption::generate_key(token); data_buffer result; utils::encryption::encrypt_data( key, reinterpret_cast(buffer.data()), @@ -134,6 +241,7 @@ TEST(utils_encryption, decryption_failure) { std::string data; EXPECT_FALSE(utils::encryption::decrypt_data(key, result, data)); } +#endif // defined(PROJECT_ENABLE_BOOST) } // namespace repertory -#endif // defined(PROJECT_ENABLE_LIBSODIUM) && defined(PROJECT_ENABLE_BOOST) +#endif // defined(PROJECT_ENABLE_LIBSODIUM) diff --git a/support/test/src/utils/path_test.cpp b/support/test/src/utils/path_test.cpp index ff1b7a99..da767ab3 100644 --- a/support/test/src/utils/path_test.cpp +++ b/support/test/src/utils/path_test.cpp @@ -304,4 +304,31 @@ TEST(utils_path, absolute) { // path = utils::path::absolute("~/.local"); } + +TEST(utils_path, absolute_can_resolve_path_variables) { + std::string home{}; + +#if defined(_WIN32) + home.resize(MAX_PATH + 1U); + auto size = ::GetEnvironmentVariableA("USERPROFILE", home.data(), 0U); + + home.resize(size); + ::GetEnvironmentVariableA("USERPROFILE", home.data(), + static_cast(home.size())); + home = utils::path::absolute(home); + + auto expanded_str = utils::path::absolute("%USERPROFILE%"); + EXPECT_STREQ(home.c_str(), expanded_str.c_str()); + + expanded_str = utils::path::absolute("~"); + EXPECT_STREQ(home.c_str(), expanded_str.c_str()); + EXPECT_STREQ((home + home).c_str(), expanded_str.c_str()); +#else // !defined(_WIN32) + home = std::getenv("HOME"); + home = utils::path::absolute(home); + + auto expanded_str = utils::path::absolute("~"); + EXPECT_STREQ(home.c_str(), expanded_str.c_str()); +#endif // defined(_WIN32) +} } // namespace repertory