#ifndef HELPERS_H #define HELPERS_H #include #include #include #include #include #include #include // Include OpenSSL headers we need extern "C" { #include #include #include #include #include } std::ostream& operator<<(std::ostream& os, const std::vector& v) { using namespace std; copy(v.begin(), v.end(), std::ostream_iterator(os, "\n")); return os; } std::string to_string(const std::vector& vec) { std::ostringstream oss; oss << vec; return oss.str(); } std::string operator+(const std::string& str, const std::vector& vec) { return str + to_string(vec); } std::string operator+(const std::vector& vec, const std::string& str) { return to_string(vec) + str; } namespace RspCrypto { struct BIODeleter { void operator()(BIO* bio) const { BIO_free_all(bio); } }; struct X509Deleter { void operator()(X509* cert) const { X509_free(cert); } }; struct EVP_PKEY_Deleter { void operator()(EVP_PKEY* key) const { EVP_PKEY_free(key); } }; struct X509_STORE_Deleter { void operator()(X509_STORE* store) const { X509_STORE_free(store); } }; struct X509_STORE_CTX_Deleter { void operator()(X509_STORE_CTX* ctx) const { X509_STORE_CTX_free(ctx); } }; struct EVP_MD_CTX_Deleter { void operator()(EVP_MD_CTX* ctx) const { EVP_MD_CTX_free(ctx); } }; class Base64 { public: static std::vector decode(const std::string& b64message) { if (b64message.empty()) { return {}; } int padding = 0; if (b64message.size() > 0) { if (b64message[b64message.size() - 1] == '=' && b64message[b64message.size() - 2] == '=') { padding = 2; } else if (b64message[b64message.size() - 1] == '=') { padding = 1; } } size_t decodeLen = (b64message.size() * 3) / 4 - padding; std::vector buffer(decodeLen); BIO* b64 = BIO_new(BIO_f_base64()); BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); // No newlines BIO* mem = BIO_new_mem_buf(b64message.c_str(), -1); BIO* bioChain = BIO_push(b64, mem); std::unique_ptr bioPtr(bioChain); int length = BIO_read(bioChain, buffer.data(), b64message.size()); if (length <= 0) { throw std::runtime_error("Failed to decode base64 data"); } buffer.resize(length); // Resize to actual decoded length return buffer; } static std::string encode(const std::vector& data) { if (data.empty()) { return {}; } BIO* b64 = BIO_new(BIO_f_base64()); BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); // No newlines BIO* mem = BIO_new(BIO_s_mem()); BIO* bioChain = BIO_push(b64, mem); std::unique_ptr bioPtr(bioChain); BIO_write(bioChain, data.data(), data.size()); BIO_flush(bioChain); BUF_MEM* bufferPtr; BIO_get_mem_ptr(mem, &bufferPtr); return std::string(bufferPtr->data, bufferPtr->length); } }; class HexUtil { public: static std::vector hexToBytes(const std::string& hex) { if (hex.length() % 2 != 0) { throw std::runtime_error("Invalid hex string length"); } std::vector bytes(hex.length() / 2); for (size_t i = 0; i < bytes.size(); ++i) { sscanf(hex.c_str() + (i * 2), "%2hhx", &bytes[i]); } return bytes; } static std::string bytesToHex(const std::vector& bytes) { return bytesToHex(bytes.data(), bytes.size()); } static std::string bytesToHex(const uint8_t* data, size_t length) { std::stringstream ss; ss << std::hex << std::uppercase << std::setfill('0'); for (size_t i = 0; i < length; ++i) { ss << std::setw(2) << static_cast(data[i]); } return ss.str(); } }; } // namespace RspCrypto #endif // HELPERS_H