#include "common/Crypto.h" #include #include #include #include #include #include #include namespace visione::crypto { namespace { constexpr int passwordIterations = 210000; constexpr size_t passwordHashBytes = 32; std::string toHex(const unsigned char *data, size_t size) { std::ostringstream stream; stream << std::hex << std::uppercase << std::setfill('0'); for (size_t i = 0; i < size; ++i) { stream << std::setw(2) << static_cast(data[i]); } return stream.str(); } std::string pbkdf2(const std::string &password, const std::string &salt, int iterations) { std::array output{}; PKCS5_PBKDF2_HMAC(password.c_str(), static_cast(password.size()), reinterpret_cast(salt.data()), static_cast(salt.size()), iterations, EVP_sha256(), static_cast(output.size()), output.data()); return toHex(output.data(), output.size()); } } // namespace std::string sha256(const std::string &value) { return drogon::utils::getSha256(value); } std::string randomNumericCode(int digits) { std::random_device device; std::mt19937 generator(device()); std::uniform_int_distribution distribution(0, 9); std::string code; code.reserve(static_cast(digits)); for (int i = 0; i < digits; ++i) { code.push_back(static_cast('0' + distribution(generator))); } return code; } std::string randomToken() { return drogon::utils::getUuid() + drogon::utils::getUuid(); } std::string hashPassword(const std::string &password) { const auto salt = drogon::utils::getUuid() + drogon::utils::getUuid(); return "pbkdf2_sha256$" + std::to_string(passwordIterations) + "$" + salt + "$" + pbkdf2(password, salt, passwordIterations); } bool verifyPassword(const std::string &password, const std::string &hash) { constexpr std::string_view pbkdf2Prefix = "pbkdf2_sha256$"; if (!hash.starts_with(pbkdf2Prefix)) { return false; } const auto iterationsStart = pbkdf2Prefix.size(); const auto saltStart = hash.find('$', iterationsStart); if (saltStart == std::string::npos) { return false; } const auto digestStart = hash.find('$', saltStart + 1); if (digestStart == std::string::npos) { return false; } const auto iterations = std::stoi(hash.substr(iterationsStart, saltStart - iterationsStart)); const auto salt = hash.substr(saltStart + 1, digestStart - saltStart - 1); const auto expected = "pbkdf2_sha256$" + std::to_string(iterations) + "$" + salt + "$" + pbkdf2(password, salt, iterations); return expected == hash; } std::string hashSecret(const std::string &secret) { return sha256("visione:" + secret); } } // namespace visione::crypto