billchaison / wincrypt

File encryption using WinCrypt API

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

wincrypt

File encryption using WinCrypt API

Windows executable that encrypts a source file with a randomly generated AES-256 key. The key is encrypted using a PEM-encoded RSA public key. This can be used for secure archiving. The RSA private key is needed to recover the encrypted file.

Example of generating a password-protected RSA key pair

openssl genrsa -out rsakey.key -aes256 4096

(extract the public key, which will be used by the Windows executable)
openssl rsa -in rsakey.key -pubout -out rsakey.pub -outform pem

Windows executable C source

Source file is secureblob.c compile using i686-w64-mingw32-gcc -mconsole ./secureblob.c -o ./secureblob.exe -lshlwapi -lcrypt32

/*
   Windows executable that encrypts a source file with a randomly generated
   AES-256 key which is stored within the secure blob using a PEM-encoded
   RSA public key.  This can be used for secure archival.  Use the RSA
   private key to recover the original source file.  The secure blob contains
   four ASCIIZ headers that can be used to decrypt the file.

   (output file structure)
   hdr[0]        = original filename
   hdr[1]        = SHA-256 hash of original file as hex string
   hdr[2]        = SHA-256 hash of public key as hex string
   hdr[3]        = AES-256 key encrypted with public key as hex string
   [binary blob] = encrypted file data

   Program:
   input: an RSA public key PEM file, a source file to encrypt
   output: an encrypted version of the source file with headers

   Example usage:
   secureblob.exe public.pem source.doc \\10.1.2.3\archives\000001.enc

   Compile:
   i686-w64-mingw32-gcc -mconsole ./secureblob.c -o ./secureblob.exe -lshlwapi -lcrypt32
*/

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

#define PEMBUF 1048576
#define SHA256BYTES 32
#define AES256KEYBYTES 32
#define AESBLOCKBYTES 16
#define BLOCKMULT 256

void Byte2Hex(BYTE *pIn, DWORD dwInLen, char *pOut);
void Etyb2Hex(BYTE *pIn, DWORD dwInLen, char *pOut);

int main(int argc, char **argv)
{
   char *pPemFile, *pInFile, *pOutFile, *pInFileName;
   BYTE *pPemBuf, *pPubKey, *pPubKeySHA256, *pAESKey, *pAESKeyEnc, *pReadBuf, *pFileSHA256;
   DWORD dwPemSize, dwTemp, dwDiff, dwAESLen;
   HANDLE hRead, hWrite;
   CERT_PUBLIC_KEY_INFO *pPubKeyInfo;
   HCRYPTPROV hProv = 0;
   HCRYPTKEY hPubKey = 0, hAESKey = 0;
   HCRYPTHASH hFileSHA256;
   char szSHA256Hex[(SHA256BYTES * 2) + 1];
   char szAESKeyHex[(AES256KEYBYTES * 2) + 1];
   char szFileSHA256Hex[(SHA256BYTES * 2) + 1];
   char *pAESKeyEncHex;
   char szBlank[] = "0000000000000000000000000000000000000000000000000000000000000000";
   BOOL bEOF = FALSE;

   if(argc != 4)
   {
      fprintf(stderr, "You must provide 3 parameters:\n<public key pem file> <input file> <output file>\n");
      return -1;
   }
   if(!strcmp(argv[2], argv[3]))
   {
      fprintf(stderr, "The output file cannot be the same as the input file.\n");
      return -1;
   }
   pPemFile = argv[1];
   pInFile = argv[2];
   pOutFile = argv[3];
   if((hRead = CreateFile(pPemFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL)) == INVALID_HANDLE_VALUE)
   {
      fprintf(stderr, "Error opening PEM file, %d\n", GetLastError());
      return -1;
   }
   dwPemSize = GetFileSize(hRead, &dwTemp);
   if(dwPemSize == INVALID_FILE_SIZE || dwPemSize == 0 || dwPemSize >= PEMBUF || dwTemp > 0)
   {
      fprintf(stderr, "Error bad PEM file size, %d, %d\n", GetLastError(), dwPemSize);
      CloseHandle(hRead);
      return -1;
   }
   if(!(pPemBuf = (BYTE *)malloc(PEMBUF)))
   {
      fprintf(stderr, "Error allocating PEM file buffer.\n");
      CloseHandle(hRead);
      return -1;
   }
   memset(pPemBuf, 0, PEMBUF);
   if(!ReadFile(hRead, pPemBuf, dwPemSize, &dwPemSize, NULL))
   {
      fprintf(stderr, "Error reading PEM file, %d\n", GetLastError());
      CloseHandle(hRead);
      free(pPemBuf);
      return -1;
   }
   CloseHandle(hRead);
   dwPemSize = 0;
   if(!CryptStringToBinary(pPemBuf, 0, CRYPT_STRING_BASE64HEADER, NULL, &dwPemSize, NULL, NULL))
   {
      fprintf(stderr, "Error determining PEM buffer size, %d\n", GetLastError());
      free(pPemBuf);
      return -1;
   }
   if(dwPemSize < 1)
   {
      fprintf(stderr, "Error PEM buffer value.\n");
      free(pPemBuf);
      return -1;
   }
   if(!(pPubKey = (BYTE *)malloc(dwPemSize)))
   {
      fprintf(stderr, "Error allocating public key buffer.\n");
      free(pPemBuf);
      return -1;
   }
   if(!CryptStringToBinary(pPemBuf, 0, CRYPT_STRING_BASE64HEADER, pPubKey, &dwPemSize, NULL, NULL))
   {
      fprintf(stderr, "Error retrieving public key, %d\n", GetLastError());
      free(pPemBuf);
      free(pPubKey);
      return -1;
   }
   if(!CryptDecodeObjectEx(X509_ASN_ENCODING, X509_PUBLIC_KEY_INFO, pPubKey, dwPemSize, CRYPT_ENCODE_ALLOC_FLAG, NULL, &pPubKeyInfo, &dwTemp))
   {
      fprintf(stderr, "Error CryptDecodeObjectEx, %d\n", GetLastError());
      free(pPemBuf);
      free(pPubKey);
      return -1;
   }
   dwTemp = 0;
   if(!CryptHashPublicKeyInfo(0, CALG_SHA_256, 0, X509_ASN_ENCODING, pPubKeyInfo, NULL, &dwTemp))
   {
      fprintf(stderr, "Error CryptHashPublicKeyInfo determine length, %d\n", GetLastError());
      free(pPemBuf);
      free(pPubKey);
      LocalFree(pPubKeyInfo);
      return -1;
   }
   if(dwTemp != SHA256BYTES)
   {
      fprintf(stderr, "Error public key SHA-256 length.\n");
      free(pPemBuf);
      free(pPubKey);
      LocalFree(pPubKeyInfo);
      return -1;
   }
   if(!(pPubKeySHA256 = (BYTE *)malloc(SHA256BYTES)))
   {
      fprintf(stderr, "Error allocating public key SHA-256 buffer.\n");
      free(pPemBuf);
      free(pPubKey);
      LocalFree(pPubKeyInfo);
      return -1;
   }
   if(!CryptHashPublicKeyInfo(0, CALG_SHA_256, 0, X509_ASN_ENCODING, pPubKeyInfo, pPubKeySHA256, &dwTemp))
   {
      fprintf(stderr, "Error CryptHashPublicKeyInfo, %d\n", GetLastError());
      free(pPemBuf);
      free(pPubKey);
      free(pPubKeySHA256);
      LocalFree(pPubKeyInfo);
      return -1;
   }
   if(!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT))
   {
      fprintf(stderr, "Error CryptAcquireContext, %d\n", GetLastError());
      free(pPemBuf);
      free(pPubKey);
      free(pPubKeySHA256);
      LocalFree(pPubKeyInfo);
      return -1;
   }
   if(!CryptImportPublicKeyInfo(hProv, X509_ASN_ENCODING, pPubKeyInfo, &hPubKey))
   {
      fprintf(stderr, "Error CryptImportPublicKeyInfo, %d\n", GetLastError());
      free(pPemBuf);
      free(pPubKey);
      free(pPubKeySHA256);
      LocalFree(pPubKeyInfo);
      CryptReleaseContext(hProv, 0);
      return -1;
   }
   if(!CryptGenKey(hProv, CALG_AES_256, CRYPT_EXPORTABLE, &hAESKey))
   {
      fprintf(stderr, "Error CryptGenKey, %d\n", GetLastError());
      free(pPemBuf);
      free(pPubKey);
      free(pPubKeySHA256);
      LocalFree(pPubKeyInfo);
      CryptDestroyKey(hPubKey);
      CryptReleaseContext(hProv, 0);
      return -1;
   }
   if(!CryptExportKey(hAESKey, 0, PLAINTEXTKEYBLOB, 0, NULL, &dwTemp))
   {
      fprintf(stderr, "Error CryptExportKey determine length, %d\n", GetLastError());
      free(pPemBuf);
      free(pPubKey);
      free(pPubKeySHA256);
      LocalFree(pPubKeyInfo);
      CryptDestroyKey(hPubKey);
      CryptDestroyKey(hAESKey);
      CryptReleaseContext(hProv, 0);
      return -1;
   }
   if(!(pAESKey = (BYTE *)malloc(dwTemp)))
   {
      fprintf(stderr, "Error allocating AES key buffer.\n");
      free(pPemBuf);
      free(pPubKey);
      free(pPubKeySHA256);
      LocalFree(pPubKeyInfo);
      CryptDestroyKey(hPubKey);
      CryptDestroyKey(hAESKey);
      CryptReleaseContext(hProv, 0);
      return -1;
   }
   if(!CryptExportKey(hAESKey, 0, PLAINTEXTKEYBLOB, 0, pAESKey, &dwTemp))
   {
      fprintf(stderr, "Error CryptExportKey, %d\n", GetLastError());
      free(pPemBuf);
      free(pPubKey);
      free(pPubKeySHA256);
      free(pAESKey);
      LocalFree(pPubKeyInfo);
      CryptDestroyKey(hPubKey);
      CryptDestroyKey(hAESKey);
      CryptReleaseContext(hProv, 0);
      return -1;
   }
   dwDiff = sizeof(BLOBHEADER) + sizeof(DWORD);
   dwAESLen = dwTemp - dwDiff;
   if(dwAESLen != AES256KEYBYTES)
   {
      fprintf(stderr, "Error CryptExportKey length.\n");
      free(pPemBuf);
      free(pPubKey);
      free(pPubKeySHA256);
      free(pAESKey);
      LocalFree(pPubKeyInfo);
      CryptDestroyKey(hPubKey);
      CryptDestroyKey(hAESKey);
      CryptReleaseContext(hProv, 0);
      return -1;
   }
   Byte2Hex(pPubKeySHA256, SHA256BYTES, szSHA256Hex);
   Byte2Hex(pAESKey + dwDiff, AES256KEYBYTES, szAESKeyHex);
   dwTemp = AES256KEYBYTES;
   if(!CryptEncrypt(hPubKey, 0, TRUE, 0, 0, &dwTemp, 0))
   {
      fprintf(stderr, "Error CryptEncrypt RSA determine length, %d\n", GetLastError());
      free(pPemBuf);
      free(pPubKey);
      free(pPubKeySHA256);
      free(pAESKey);
      LocalFree(pPubKeyInfo);
      CryptDestroyKey(hPubKey);
      CryptDestroyKey(hAESKey);
      CryptReleaseContext(hProv, 0);
      return -1;
   }
   if(!(pAESKeyEnc = (BYTE *)malloc(dwTemp)))
   {
      fprintf(stderr, "Error allocating encrypted key buffer.\n");
      free(pPemBuf);
      free(pPubKey);
      free(pPubKeySHA256);
      free(pAESKey);
      LocalFree(pPubKeyInfo);
      CryptDestroyKey(hPubKey);
      CryptDestroyKey(hAESKey);
      CryptReleaseContext(hProv, 0);
      return -1;
   }
   memcpy(pAESKeyEnc, pAESKey + dwDiff, AES256KEYBYTES);
   if(!CryptEncrypt(hPubKey, 0, TRUE, 0, pAESKeyEnc, &dwAESLen, dwTemp))
   {
      fprintf(stderr, "Error CryptEncrypt RSA, %d\n", GetLastError());
      free(pPemBuf);
      free(pPubKey);
      free(pPubKeySHA256);
      free(pAESKey);
      free(pAESKeyEnc);
      LocalFree(pPubKeyInfo);
      CryptDestroyKey(hPubKey);
      CryptDestroyKey(hAESKey);
      CryptReleaseContext(hProv, 0);
      return -1;
   }
   if(!(pAESKeyEncHex = (BYTE *)malloc((dwAESLen * 2) + 1)))
   {
      fprintf(stderr, "Error allocating encrypted AES key string buffer.\n");
      free(pPemBuf);
      free(pPubKey);
      free(pPubKeySHA256);
      free(pAESKey);
      free(pAESKeyEnc);
      LocalFree(pPubKeyInfo);
      CryptDestroyKey(hPubKey);
      CryptDestroyKey(hAESKey);
      CryptReleaseContext(hProv, 0);
      return -1;
   }
   Etyb2Hex(pAESKeyEnc, dwAESLen, pAESKeyEncHex);
   if(!CryptCreateHash(hProv, CALG_SHA_256, 0, 0, &hFileSHA256))
   {
      fprintf(stderr, "Error CryptCreateHash, %d\n", GetLastError());
      free(pPemBuf);
      free(pPubKey);
      free(pPubKeySHA256);
      free(pAESKey);
      free(pAESKeyEnc);
      LocalFree(pPubKeyInfo);
      CryptDestroyKey(hPubKey);
      CryptDestroyKey(hAESKey);
      CryptReleaseContext(hProv, 0);
      return -1;
   }
   pInFileName = PathFindFileName(pInFile);
   if(!strlen(pInFileName))
   {
      fprintf(stderr, "Error source file name length.\n");
      free(pPemBuf);
      free(pPubKey);
      free(pPubKeySHA256);
      free(pAESKey);
      free(pAESKeyEnc);
      LocalFree(pPubKeyInfo);
      CryptDestroyKey(hPubKey);
      CryptDestroyKey(hAESKey);
      CryptReleaseContext(hProv, 0);
      return -1;
   }
   if((hRead = CreateFile(pInFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL)) == INVALID_HANDLE_VALUE)
   {
      fprintf(stderr, "Error opening source file, %d\n", GetLastError());
      free(pPemBuf);
      free(pPubKey);
      free(pPubKeySHA256);
      free(pAESKey);
      free(pAESKeyEnc);
      LocalFree(pPubKeyInfo);
      CryptDestroyKey(hPubKey);
      CryptDestroyKey(hAESKey);
      CryptReleaseContext(hProv, 0);
      return -1;
   }
   if(!GetFileSize(hRead, &dwTemp))
   {
      if(dwTemp == 0)
      {
         fprintf(stderr, "Source file is empty, nothing to do.\n");
         free(pPemBuf);
         free(pPubKey);
         free(pPubKeySHA256);
         free(pAESKey);
         free(pAESKeyEnc);
         LocalFree(pPubKeyInfo);
         CryptDestroyKey(hPubKey);
         CryptDestroyKey(hAESKey);
         CryptReleaseContext(hProv, 0);
         return -1;
      }
   }
   if((hWrite = CreateFile(pOutFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE)
   {
      fprintf(stderr, "Error creating destination file, %d\n", GetLastError());
      free(pPemBuf);
      free(pPubKey);
      free(pPubKeySHA256);
      free(pAESKey);
      free(pAESKeyEnc);
      LocalFree(pPubKeyInfo);
      CryptDestroyKey(hPubKey);
      CryptDestroyKey(hAESKey);
      CryptReleaseContext(hProv, 0);
      CloseHandle(hRead);
      return -1;
   }
   if(!(pReadBuf = (BYTE *)malloc(AESBLOCKBYTES * BLOCKMULT)))
   {
      fprintf(stderr, "Error allocating file buffer.\n");
      free(pPemBuf);
      free(pPubKey);
      free(pPubKeySHA256);
      free(pAESKey);
      free(pAESKeyEnc);
      LocalFree(pPubKeyInfo);
      CryptDestroyKey(hPubKey);
      CryptDestroyKey(hAESKey);
      CryptReleaseContext(hProv, 0);
      CloseHandle(hRead);
      CloseHandle(hWrite);
      DeleteFile(pOutFile);
      return -1;
   }
   dwTemp = strlen(pInFileName) + 1;
   if(!WriteFile(hWrite, pInFileName, dwTemp, &dwTemp, NULL))
   {
      fprintf(stderr, "Error WriteFile, %d\n", GetLastError());
      free(pPemBuf);
      free(pPubKey);
      free(pPubKeySHA256);
      free(pAESKey);
      free(pAESKeyEnc);
      free(pReadBuf);
      LocalFree(pPubKeyInfo);
      CryptDestroyKey(hPubKey);
      CryptDestroyKey(hAESKey);
      CryptReleaseContext(hProv, 0);
      CloseHandle(hRead);
      CloseHandle(hWrite);
      DeleteFile(pOutFile);
      return -1;
   }
   dwTemp = strlen(szBlank) + 1;
   if(!WriteFile(hWrite, szBlank, dwTemp, &dwTemp, NULL))
   {
      fprintf(stderr, "Error WriteFile, %d\n", GetLastError());
      free(pPemBuf);
      free(pPubKey);
      free(pPubKeySHA256);
      free(pAESKey);
      free(pAESKeyEnc);
      free(pReadBuf);
      LocalFree(pPubKeyInfo);
      CryptDestroyKey(hPubKey);
      CryptDestroyKey(hAESKey);
      CryptReleaseContext(hProv, 0);
      CloseHandle(hRead);
      CloseHandle(hWrite);
      DeleteFile(pOutFile);
      return -1;
   }
   dwTemp = strlen(szSHA256Hex) + 1;
   if(!WriteFile(hWrite, szSHA256Hex, dwTemp, &dwTemp, NULL))
   {
      fprintf(stderr, "Error WriteFile, %d\n", GetLastError());
      free(pPemBuf);
      free(pPubKey);
      free(pPubKeySHA256);
      free(pAESKey);
      free(pAESKeyEnc);
      free(pReadBuf);
      LocalFree(pPubKeyInfo);
      CryptDestroyKey(hPubKey);
      CryptDestroyKey(hAESKey);
      CryptReleaseContext(hProv, 0);
      CloseHandle(hRead);
      CloseHandle(hWrite);
      DeleteFile(pOutFile);
      return -1;
   }
   dwTemp = strlen(pAESKeyEncHex) + 1;
   if(!WriteFile(hWrite, pAESKeyEncHex, dwTemp, &dwTemp, NULL))
   {
      fprintf(stderr, "Error WriteFile, %d\n", GetLastError());
      free(pPemBuf);
      free(pPubKey);
      free(pPubKeySHA256);
      free(pAESKey);
      free(pAESKeyEnc);
      free(pReadBuf);
      LocalFree(pPubKeyInfo);
      CryptDestroyKey(hPubKey);
      CryptDestroyKey(hAESKey);
      CryptReleaseContext(hProv, 0);
      CloseHandle(hRead);
      CloseHandle(hWrite);
      DeleteFile(pOutFile);
      return -1;
   }
   while(!bEOF)
   {
      if(!ReadFile(hRead, pReadBuf, (AESBLOCKBYTES * BLOCKMULT), &dwTemp, NULL))
      {
         fprintf(stderr, "Error ReadFile, %d\n", GetLastError());
         free(pPemBuf);
         free(pPubKey);
         free(pPubKeySHA256);
         free(pAESKey);
         free(pAESKeyEnc);
         free(pReadBuf);
         LocalFree(pPubKeyInfo);
         CryptDestroyKey(hPubKey);
         CryptDestroyKey(hAESKey);
         CryptReleaseContext(hProv, 0);
         CloseHandle(hRead);
         CloseHandle(hWrite);
         DeleteFile(pOutFile);
         return -1;
      }
      if(!CryptHashData(hFileSHA256, pReadBuf, dwTemp, 0))
      {
         fprintf(stderr, "Error CryptHashData, %d\n", GetLastError());
         free(pPemBuf);
         free(pPubKey);
         free(pPubKeySHA256);
         free(pAESKey);
         free(pAESKeyEnc);
         free(pReadBuf);
         LocalFree(pPubKeyInfo);
         CryptDestroyKey(hPubKey);
         CryptDestroyKey(hAESKey);
         CryptReleaseContext(hProv, 0);
         CloseHandle(hRead);
         CloseHandle(hWrite);
         DeleteFile(pOutFile);
         return -1;
      }
      if(dwTemp != (AESBLOCKBYTES * BLOCKMULT)) bEOF = TRUE;
      if(!CryptEncrypt(hAESKey, 0, bEOF, 0, pReadBuf, &dwTemp, (AESBLOCKBYTES * BLOCKMULT)))
      {
         fprintf(stderr, "Error CryptEncrypt AES, %d\n", GetLastError());
         free(pPemBuf);
         free(pPubKey);
         free(pPubKeySHA256);
         free(pAESKey);
         free(pAESKeyEnc);
         free(pReadBuf);
         LocalFree(pPubKeyInfo);
         CryptDestroyKey(hPubKey);
         CryptDestroyKey(hAESKey);
         CryptReleaseContext(hProv, 0);
         CloseHandle(hRead);
         CloseHandle(hWrite);
         DeleteFile(pOutFile);
         return -1;
      }
      if(!WriteFile(hWrite, pReadBuf, dwTemp, &dwTemp, NULL))
      {
         fprintf(stderr, "Error WriteFile, %d\n", GetLastError());
         free(pPemBuf);
         free(pPubKey);
         free(pPubKeySHA256);
         free(pAESKey);
         free(pAESKeyEnc);
         free(pReadBuf);
         LocalFree(pPubKeyInfo);
         CryptDestroyKey(hPubKey);
         CryptDestroyKey(hAESKey);
         CryptReleaseContext(hProv, 0);
         CloseHandle(hRead);
         CloseHandle(hWrite);
         DeleteFile(pOutFile);
         return -1;
      }
   }
   if(!(pFileSHA256 = (BYTE *)malloc(SHA256BYTES)))
   {
      fprintf(stderr, "Error allocating file hash buffer.\n");
      free(pPemBuf);
      free(pPubKey);
      free(pPubKeySHA256);
      free(pAESKey);
      free(pAESKeyEnc);
      free(pReadBuf);
      LocalFree(pPubKeyInfo);
      CryptDestroyKey(hPubKey);
      CryptDestroyKey(hAESKey);
      CryptReleaseContext(hProv, 0);
      CloseHandle(hRead);
      CloseHandle(hWrite);
      DeleteFile(pOutFile);
      return -1;
   }
   dwTemp = SHA256BYTES;
   if(!CryptGetHashParam(hFileSHA256, HP_HASHVAL, pFileSHA256, &dwTemp, 0))
   {
      fprintf(stderr, "Error CryptGetHashParam, %d\n", GetLastError());
      free(pPemBuf);
      free(pPubKey);
      free(pPubKeySHA256);
      free(pAESKey);
      free(pAESKeyEnc);
      free(pReadBuf);
      free(pFileSHA256);
      LocalFree(pPubKeyInfo);
      CryptDestroyKey(hPubKey);
      CryptDestroyKey(hAESKey);
      CryptReleaseContext(hProv, 0);
      CloseHandle(hRead);
      CloseHandle(hWrite);
      DeleteFile(pOutFile);
      return -1;
   }
   if(dwTemp != SHA256BYTES)
   {
      fprintf(stderr, "Error CryptGetHashParam length, %d\n", GetLastError());
      free(pPemBuf);
      free(pPubKey);
      free(pPubKeySHA256);
      free(pAESKey);
      free(pAESKeyEnc);
      free(pReadBuf);
      free(pFileSHA256);
      LocalFree(pPubKeyInfo);
      CryptDestroyKey(hPubKey);
      CryptDestroyKey(hAESKey);
      CryptReleaseContext(hProv, 0);
      CloseHandle(hRead);
      CloseHandle(hWrite);
      DeleteFile(pOutFile);
      return -1;
   }
   Byte2Hex(pFileSHA256, dwTemp, szFileSHA256Hex);
   if(SetFilePointer(hWrite, strlen(pInFileName) + 1, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
   {
      fprintf(stderr, "Error SetFilePointer, %d\n", GetLastError());
      free(pPemBuf);
      free(pPubKey);
      free(pPubKeySHA256);
      free(pAESKey);
      free(pAESKeyEnc);
      free(pReadBuf);
      free(pFileSHA256);
      LocalFree(pPubKeyInfo);
      CryptDestroyKey(hPubKey);
      CryptDestroyKey(hAESKey);
      CryptReleaseContext(hProv, 0);
      CloseHandle(hRead);
      CloseHandle(hWrite);
      DeleteFile(pOutFile);
      return -1;
   }
   dwTemp = SHA256BYTES * 2;
   if(!WriteFile(hWrite, szFileSHA256Hex, dwTemp, &dwTemp, NULL))
   {
      fprintf(stderr, "Error WriteFile, %d\n", GetLastError());
      free(pPemBuf);
      free(pPubKey);
      free(pPubKeySHA256);
      free(pAESKey);
      free(pAESKeyEnc);
      free(pReadBuf);
      free(pFileSHA256);
      LocalFree(pPubKeyInfo);
      CryptDestroyKey(hPubKey);
      CryptDestroyKey(hAESKey);
      CryptReleaseContext(hProv, 0);
      CloseHandle(hRead);
      CloseHandle(hWrite);
      DeleteFile(pOutFile);
      return -1;
   }

   free(pPemBuf);
   free(pPubKey);
   free(pPubKeySHA256);
   free(pAESKey);
   free(pAESKeyEnc);
   free(pReadBuf);
   free(pFileSHA256);
   LocalFree(pPubKeyInfo);
   CryptDestroyKey(hPubKey);
   CryptDestroyKey(hAESKey);
   CryptReleaseContext(hProv, 0);
   CloseHandle(hRead);
   CloseHandle(hWrite);

   return 0;
}

void Byte2Hex(BYTE *pIn, DWORD dwInLen, char *pOut)
{
   DWORD dwTemp;

   for(dwTemp = 0; dwTemp < dwInLen; dwTemp++)
   {
      sprintf(pOut + (dwTemp * 2), "%02x", pIn[dwTemp]);
   }
}

void Etyb2Hex(BYTE *pIn, DWORD dwInLen, char *pOut)
{
   int nTemp;
   char *pChar = pOut;

   for(nTemp = dwInLen - 1; nTemp > -1; nTemp--, pChar += 2)
   {
      sprintf(pChar, "%02x", pIn[nTemp]);
   }
}

Linux bash script to decrypt the file

Script name secure_blob_recover.sh

#!/usr/bin/bash

read -p 'Enter the file to decrypt: ' infile
read -p 'Enter the private key PEM file: ' keyfile

pubhash=$(openssl rsa -in "$keyfile" -pubout -out - -outform der | sha256sum | cut -d " " -f 1)

headers=( $(strings -n 1 "$infile" 2>/dev/null | head -n 4) )
for i in {1..3}
do
   echo "${headers[$i]}" | egrep '^[0-9a-f]{64,}$' >/dev/null
   if [ $? -ne 0 ]
   then
      echo "Header check failed."
      exit -1
   fi
done

if [ "${headers[2]}" != "$pubhash" ]
then
   echo "Public key fingerprint does not match."
   exit -1
fi

aeskey=$(echo "${headers[3]}" | xxd -r -p | openssl rsautl -decrypt -in - -out - -inkey "$keyfile" | xxd -p -c 256)
skip=$((${#headers[0]}+${#headers[1]}+${#headers[2]}+${#headers[3]}+4))
enctmp=$(mktemp)
dd if=$infile bs=$skip skip=1 >$enctmp 2>/dev/null
cat $enctmp | openssl enc -aes-256-cbc -nosalt -K $aeskey -iv 00000000000000000000000000000000 -d >"/tmp/${headers[0]}"

rm $enctmp
filehash=$(sha256sum "/tmp/${headers[0]}" | cut -d " " -f 1)
if [ "${headers[1]}" != "$filehash" ]
then
   echo "Decrypted file SHA-256 check failed"
   rm "/tmp/${headers[0]}"
   exit -1
else
   echo "Decrypted file saved to: /tmp/${headers[0]}"
fi

Example encryption and decryption

Encrypt on Windows
alt text

Decrypt on Linux
alt text

About

File encryption using WinCrypt API