37#ifndef ENCRYPTION_UTILS_HPP
38#define ENCRYPTION_UTILS_HPP
51#if defined(_WIN64) || defined(WIN64) || defined(WIN32) || defined(_WIN32)
55#pragma comment(lib, "bcrypt")
56#pragma comment(lib, "crypt32")
62#include "siddiqsoft/RunOnEnd.hpp"
77 template <
typename T =
char>
78 requires std::same_as<T, char> || std::same_as<T, wchar_t>
79 static std::string
MD5(
const std::basic_string<T>& source)
81 constexpr char rgbDigits[] {
"0123456789abcdef"};
83 if constexpr (std::is_same_v<T, char>) {
86 RunOnEnd cleanUpOnEnd {[&hProv, &hHash] {
88 if (hHash != NULL) CryptDestroyHash(hHash);
89 if (hProv != NULL) CryptReleaseContext(hProv, 0);
93 if (TRUE == CryptAcquireContext(&hProv,
nullptr,
nullptr, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) {
95 if (TRUE == CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash)) {
99 hHash,
reinterpret_cast<const BYTE*
>(source.data()),
static_cast<DWORD
>(source.length()), 0)) {
100 BYTE rgbHash[
sizeof(rgbDigits)] {};
101 DWORD rgbHashSize =
sizeof(rgbDigits);
103 if (TRUE == CryptGetHashParam(hHash, HP_HASHVAL, rgbHash, &rgbHashSize, 0)) {
104 std::string result {};
106 for (DWORD i = 0; i < rgbHashSize; i++) {
107 std::format_to(std::back_inserter(result),
109 rgbDigits[rgbHash[i] >> 4],
110 rgbDigits[rgbHash[i] & 0xf]);
134 template <
typename T =
char>
135 requires std::same_as<T, char> || std::same_as<T, wchar_t>
136 static std::string
HMAC(
const std::basic_string<T>& message,
const std::string& key)
138 if constexpr (std::is_same_v<T, char>) {
139 BCRYPT_ALG_HANDLE hAlg {};
140 BCRYPT_HASH_HANDLE hHash {};
142 RunOnEnd cleanupOnEnd {[&hAlg, &hHash] {
144 if (hAlg) BCryptCloseAlgorithmProvider(hAlg, 0);
145 if (hHash) BCryptDestroyHash(hHash);
149 if (status = BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_SHA256_ALGORITHM,
nullptr, BCRYPT_ALG_HANDLE_HMAC_FLAG);
154 if (status = BCryptCreateHash(hAlg,
158 reinterpret_cast<UCHAR*
>(
const_cast<char*
>(key.data())),
159 static_cast<DWORD
>(key.length()),
164 if (status = BCryptHashData(hHash,
165 reinterpret_cast<UCHAR*
>(
const_cast<char*
>(message.data())),
166 static_cast<DWORD
>(message.length()),
173 if (status = BCryptGetProperty(
174 hAlg, BCRYPT_HASH_LENGTH,
reinterpret_cast<UCHAR*
>(&cbHash),
sizeof(DWORD), &cbData, 0);
176 std::vector<BYTE> pbHash(cbHash);
178 if (status = BCryptFinishHash(hHash,
reinterpret_cast<UCHAR*
>(pbHash.data()), cbHash, 0);
181 return std::string {
reinterpret_cast<char*
>(pbHash.data()), cbHash};
203 template <
typename T =
char>
204 requires std::same_as<T, char> || std::same_as<T, wchar_t>
205 static std::basic_string<T>
206 JWTHMAC256(
const std::string& key,
const std::basic_string<T>& header,
const std::basic_string<T>& payload)
208 if constexpr (std::is_same_v<T, char>) {
209 auto s1 = Base64Utils::urlEscape<char>(Base64Utils::encode<char>(header));
210 auto s2 = Base64Utils::urlEscape<char>(Base64Utils::encode<char>(payload));
211 auto a3 = std::format(
"{}.{}", s1, s2);
212 auto a4 = HMAC<char>(a3, key);
213 auto signature = Base64Utils::urlEscape<char>(Base64Utils::encode<char>(a4));
215 return std::format(
"{}.{}.{}", s1, s2, signature);
232 template <
typename T =
char>
233 requires std::same_as<T, char> || std::same_as<T, wchar_t>
234 static std::basic_string<T>
SASToken(
const std::string& key,
235 const std::basic_string<T>& url,
236 const std::basic_string<T>& keyName,
237 const std::chrono::seconds& timeout)
243 if constexpr (std::is_same_v<T, wchar_t>) {
244 return SASToken<wchar_t>(key, url, keyName, std::to_wstring(int64_t(epoch) + timeout.count()));
246 else if constexpr (std::is_same_v<T, char>) {
247 return SASToken<char>(key, url, keyName, std::to_string(int64_t(epoch) + timeout.count()));
259 template <
typename T =
char>
260 requires std::same_as<T, char> || std::same_as<T, wchar_t>
261 static std::basic_string<T>
SASToken(
const std::string& key,
262 const std::basic_string<T>& url,
263 const std::basic_string<T>& keyName,
264 const std::basic_string<T>& expiry)
266 if (url.empty())
throw std::invalid_argument(
"SASToken: url may not be empty");
267 if (keyName.empty())
throw std::invalid_argument(
"SASToken: keyName may not be empty");
268 if (key.empty())
throw std::invalid_argument(
"SASToken: key may not be empty");
269 if (expiry.empty())
throw std::invalid_argument(
"SASToken: expiry may not be empty");
271 if constexpr (std::is_same_v<T, char>) {
272 auto s1 = UrlUtils::encode<char>(url,
true);
273 auto sig = HMAC<char>(std::format(
"{}\n{}", s1, expiry), key);
274 auto esign = Base64Utils::encode<char>(sig);
275 esign = UrlUtils::encode<char>(esign,
true);
277 return std::format(
"SharedAccessSignature sr={}&sig={}&se={}&skn={}", s1, esign, expiry, keyName);
296 template <
typename T =
char>
297 requires std::same_as<T, char> || std::same_as<T, wchar_t>
299 const std::basic_string<T>& verb,
300 const std::basic_string<T>& type,
301 const std::basic_string<T>& resourceLink,
302 const std::basic_string<T>& date)
304 if (key.empty())
throw std::invalid_argument(
"CosmosToken: key may not be empty");
305 if (date.empty())
throw std::invalid_argument(
"CosmosToken: date may not be empty");
306 if (verb.empty())
throw std::invalid_argument(
"CosmosToken: verb may not be empty");
308 if constexpr (std::is_same_v<T, char>) {
311 std::string strToHash {};
313 std::ranges::transform(verb, std::back_inserter(strToHash), [](
auto& ch) {
return std::tolower(ch); });
314 std::format_to(std::back_inserter(strToHash),
"\n");
315 std::ranges::transform(type, std::back_inserter(strToHash), [](
auto& ch) {
return std::tolower(ch); });
316 std::format_to(std::back_inserter(strToHash),
"\n{}\n", resourceLink);
317 std::ranges::transform(date, std::back_inserter(strToHash), [](
auto& ch) {
return std::tolower(ch); });
318 std::format_to(std::back_inserter(strToHash),
"\n\n");
320 if (!strToHash.empty()) {
322 if (
auto hmacBase64UrlEscaped = UrlUtils::encode<char>(
323 Base64Utils::encode<char>(EncryptionUtils::HMAC<char>(strToHash, key)),
true);
324 !hmacBase64UrlEscaped.empty())
326 return std::format(
"type%3dmaster%26ver%3d1.0%26sig%3d{}", hmacBase64UrlEscaped);
static std::wstring wideFromAscii(const std::string &src)
Given an ascii encoded string returns a utf-16 in std::wstring.
static std::wstring wideFromUtf8(const std::string &src)
Given a utf-8 encoded string returns a utf-16 in std::wstring.
static std::string utf8FromWide(const std::wstring &src)
Convert given wide string to utf8 encoded string.
static std::string asciiFromWide(const std::wstring &src)
Convert given wide string to ascii encoded string.
Encryption utility functions for ServiceBus, Cosmos, EventGrid, EventHub Implementation Note!...
static std::basic_string< T > SASToken(const std::string &key, const std::basic_string< T > &url, const std::basic_string< T > &keyName, const std::chrono::seconds &timeout)
Create a Shared Access Signature for Azure storage https://docs.microsoft.com/en-us/rest/api/eventhub...
static std::basic_string< T > SASToken(const std::string &key, const std::basic_string< T > &url, const std::basic_string< T > &keyName, const std::basic_string< T > &expiry)
Create a Shared Access Signature for Azure storage https://docs.microsoft.com/en-us/rest/api/eventhub...
static std::string MD5(const std::basic_string< T > &source)
Create a MD5 hash for the given source as a string.
static std::basic_string< T > JWTHMAC256(const std::string &key, const std::basic_string< T > &header, const std::basic_string< T > &payload)
Create a JsonWebToken authorization with HMAC 256.
static std::string HMAC(const std::basic_string< T > &message, const std::string &key)
Returns binary HMAC using SHA-256. https://www.liavaag.org/English/SHA-Generator/HMAC/.
static std::basic_string< T > CosmosToken(const std::string &key, const std::basic_string< T > &verb, const std::basic_string< T > &type, const std::basic_string< T > &resourceLink, const std::basic_string< T > &date)
Create the Cosmos Authorization Token using the Key for this connection.