#include <stdio.h>
#include <windows.h>
#include <wincrypt.h>

#pragma comment(lib, "advapi32.lib")

// Function to compute SHA-256 hash using WinCrypt
BOOL calcSHA256(const BYTE* data, DWORD dataSize, BYTE* hash, DWORD hashSize) {
  HCRYPTPROV hProv = 0;
  HCRYPTHASH hHash = 0;

  if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) {
    printf("Error: CryptAcquireContext failed - %08x\n", GetLastError());
    return FALSE;
  }

  if (!CryptCreateHash(hProv, CALG_SHA_256, 0, 0, &hHash)) {
    printf("Error: CryptCreateHash failed - %08x\n", GetLastError());
    CryptReleaseContext(hProv, 0);
    return FALSE;
  }

  if (!CryptHashData(hHash, data, dataSize, 0)) {
    printf("Error: CryptHashData failed - %08x\n", GetLastError());
    CryptDestroyHash(hHash);
    CryptReleaseContext(hProv, 0);
    return FALSE;
  }

  DWORD hashLen = hashSize;
  if (!CryptGetHashParam(hHash, HP_HASHVAL, hash, &hashLen, 0)) {
    printf("Error: CryptGetHashParam failed - %08x\n", GetLastError());
    CryptDestroyHash(hHash);
    CryptReleaseContext(hProv, 0);
    return FALSE;
  }

  CryptDestroyHash(hHash);
  CryptReleaseContext(hProv, 0);
  return TRUE;
}

int main() {
  // Example: Hashing an ASCII string using SHA-256
  const char* inputString = "Hello, Packt!";

  // Convert string to bytes
  const BYTE* inputData = (const BYTE*)inputString;
  DWORD dataSize = lstrlenA(inputString);

  // Allocate space for the hash (SHA-256 produces a 256-bit hash, i.e., 32 bytes)
  BYTE hash[32];

  // Compute the SHA-256 hash
  if (calcSHA256(inputData, dataSize, hash, sizeof(hash))) {
    printf("SHA-256 Hash:\n");
    for (DWORD i = 0; i < sizeof(hash); ++i) {
      printf("%02x", hash[i]);
    }
    printf("\n");
  }

  return 0;
}
