Crypt(API) any data WITHOUT password



Click here for larger image

Environment: VC6 NT5 SP2

By default the NT4+ offers to you CryptoAPI. This is a set of complex functions for crypting, decrypting, hashing, signing and so on. Sometimes you need want two functions such as Crypt() and Decrypt() to work with the data. Here you'll find them! A password isn't required because you enter it in the login procedure. Only the current logged user can decrypt crypted data. This is pretty useful for the user since there is no need to remember a NEW password!

Updates:
Crypto API is based on CSP - this means Cryptographic Service Providers. The strenght of crypted data depends of CSP. The following table shows the differences between the Base Provider, and the Enhanced Provider. The key lengths shown are the default keylengths.

Algorithm Base Provider Enhanced Provider
RSA public-key signature algorithm Key length: 512 bits. Key length: 1,024 bits.
RSA public-key exchange algorithm Key length: 512 bits. Key length: 1,024 bits.
RC2 block encryption algorithm Key length: 40 bits. Key length: 128 bits.
Salt length: settable.
RC4 stream encryption algorithm Key length: 40 bits. Key length: 128 bits.
Salt length: settable.
DES Not supported. Key length: 56 bits.
Triple DES (2 key) Not supported. Key length: 112 bits.
Triple DES (3 key) Not supported. Key length: 168 bits.

Crypted data has got almost the same size as source data (in brackets you can find size if you will use my functions to convert data to ASCII from BIN) :

119[B]  -> 200 [B] (400[B])
244[kB] -> 246[kB] (493[kB])

In the code below you can find also two functions to convert data from/to ASCII or binary. This can be useful to save the crypted data for example to INI files. At the end you can find simple example of usage (in the main() function)

This code is written for simplicity, so there aren't proper error handling mechanisms. You'll need to add that! I didn't tested the functions on NT4, only on Win2k (NT5); however, there shouldn't be any problems on NT4.

This code after compile you should link with advapi32.lib and user32.lib.


#define _CRYPT32_
#define _WIN32_WINNT 0x0500

#include "stdafx.h"
#include <stdio.h>
#include <objbase.h>
#include <wincrypt.h>


// decrypt buffer
//
// IN:
// pIn     - pointer to memory to decrypt
// plSize  - pointer to long which hold pIn size in bytes
//
// OUT:
// pIn     - decrypted memory block
// plSize  - size of decrypted memory
BOOL Decrypt(unsigned char *pIn, long *plSize)
{
   HCRYPTPROV hProv = 0;
   HCRYPTKEY hKey = 0;
   DWORD dwCount;

   BYTE *pbKeyBlob = NULL;
   DWORD dwBlobLen;

   // Get a handle to the default provider.
   if (!CryptAcquireContext(&hProv, 
NULL,
NULL,
PROV_RSA_FULL,
0)) return FALSE; // Read the key blob length from the source and
// init pointer
memcpy(&dwBlobLen, pIn, sizeof(DWORD)); pbKeyBlob = (BYTE *)&pIn[sizeof(DWORD)]; // Import the key blob into the CSP. if (!CryptImportKey(hProv,
pbKeyBlob,
dwBlobLen,
0, 0,
&hKey)) return FALSE; // decrypt all dwCount =*plSize - (sizeof(DWORD)+dwBlobLen); if (!CryptDecrypt(hKey,
0,
TRUE,
0,
&pIn[sizeof(DWORD)+dwBlobLen],
&dwCount)) return FALSE; // inform user about the lenght of decrypted data memmove(pIn, &pIn[sizeof(DWORD)+dwBlobLen], dwCount); *plSize = dwCount; // Destroy the session key. if(hKey != 0) CryptDestroyKey(hKey); // Release the provider handle. if(hProv != 0) CryptReleaseContext(hProv, 0); return TRUE; } // crypt memory block via random key (generated every time) // this key is also crypted and saved with the body BUT! // you dont neede password! why? // becouse you enter the password in login procedure! // yes this function takes the logged user key to crypt. // // IN: // pIn - buffer to crypt // plSize - size of data to crypt (buffer) // // OUT: // ppOut - pointer to pointer which will hold crypted
// data (bigger than data at in!)
// plSize - size of crypted data BOOL Crypt(unsigned char *pIn,
long *plSize,
unsigned char **ppOut) { HCRYPTPROV hProv = 0; HCRYPTKEY hKey = 0; HCRYPTKEY hXchgKey = 0; DWORD dwCount, dwNewBufLen; BYTE *pbKeyBlob = NULL; DWORD dwBlobLen; // Get a handle to the default provider. if(!CryptAcquireContext(&hProv,
NULL,
NULL,
PROV_RSA_FULL,
0)) // Some sort of error occured, create default key container. if (!CryptAcquireContext( &hProv,
NULL,
MS_DEF_PROV,
PROV_RSA_FULL,
CRYPT_NEWKEYSET)) // Error creating key container! return FALSE; // Get a handle to key exchange key. if (!CryptGetUserKey(hProv, AT_KEYEXCHANGE, &hXchgKey)) if (GetLastError()==NTE_NO_KEY) { // Create key exchange key pair. if (!CryptGenKey(hProv,AT_KEYEXCHANGE,0,&hKey)) { // Error during CryptGenKey! CryptReleaseContext(hProv, 0); return FALSE; } else { CryptDestroyKey(hKey); CryptGetUserKey(hProv, AT_KEYEXCHANGE, &hXchgKey); } } else return FALSE; // Create a random block cipher session key. if (!CryptGenKey(hProv,
CALG_RC2,
CRYPT_EXPORTABLE,
&hKey)) return FALSE; // Determine the size of the key blob and allocate memory. if (!CryptExportKey( hKey,
hXchgKey,
SIMPLEBLOB,
0,
NULL,
&dwBlobLen)) return FALSE; if ((pbKeyBlob =
(unsigned char *)malloc(dwBlobLen)) == NULL) return FALSE; // Export the key into a simple key blob. if (!CryptExportKey(hKey,
hXchgKey,
SIMPLEBLOB,
0,
pbKeyBlob,
&dwBlobLen)) { free(pbKeyBlob); return FALSE; } // how much memory neede for ciphered block? dwCount = *plSize; if (!CryptEncrypt(hKey, 0, TRUE, 0, NULL, &dwCount, 0)) return FALSE; // put on output the len, key blob, and alloc memory *ppOut = (unsigned char *)malloc(sizeof(dwBlobLen) +
dwBlobLen + dwCount); if (!*ppOut) return FALSE; memcpy(*ppOut, &dwBlobLen, sizeof(dwBlobLen)); memcpy(&(*ppOut)[sizeof(dwBlobLen)],
pbKeyBlob,
dwBlobLen); // Free memory. free(pbKeyBlob); // finally crypt! memcpy(&(*ppOut)[sizeof(dwBlobLen)+dwBlobLen], pIn, *plSize); dwNewBufLen = dwCount; dwCount = *plSize; if (!CryptEncrypt(hKey,
0,
TRUE,
0,
&(*ppOut)[sizeof(dwBlobLen)+dwBlobLen],
&dwCount,
dwNewBufLen)) return FALSE; // update output size *plSize = sizeof(dwBlobLen) + dwBlobLen + dwCount; // Destroy the session key. if(hKey != 0) CryptDestroyKey(hKey); // Destroy the key exchange key. if(hXchgKey != 0) CryptDestroyKey(hXchgKey); // Release the provider handle. if(hProv != 0) CryptReleaseContext(hProv, 0); return TRUE; } // conver binary data to ASCII string // // IN: // pIn - binary data // lSize - size of those data // // OUT: // ppOut - new allocated string with data
// (twice bigger than binary)
BOOL Bin2ASCII(unsigned char *pIn,
long lSize,
unsigned char **ppOut) { // alloc memory (lSize *2) *ppOut = (unsigned char *)malloc((lSize*2)+1); if (!*ppOut) return FALSE; for (long l=0; l<lSize; l++) wsprintf((char *)&(*ppOut)[l*2], "%02X", pIn[l]); return TRUE; } // convert ASCII string generated by Bin2ASCII() to binary data // // IN: // pIn - string of data // lSize - string len // // OUT: // ppOut - binary data (twice smaller than string) BOOL ASCII2Bin(unsigned char *pIn,
long lSize,
unsigned char **ppOut) { char szBuf[3]; // alloc memory (lSize/2) + one for zero at end *ppOut = (unsigned char *)malloc((lSize/2)+1); if (!*ppOut) return FALSE; szBuf[2] = NULL; for (long l=0; l<lSize; l++) { szBuf[0] = pIn[l*2]; szBuf[1] = pIn[(l*2)+1]; (*ppOut)[l] = (unsigned char)strtoul(szBuf, NULL, 16); } return TRUE; } int main(int argc, char* argv[]) { FILE *fIn, *fOut; unsigned char Buf[1024], *pBuf, *pOut; // decrypt the file fIn = fopen("test1.xxx", "rb"); long l = fread(Buf, 1, sizeof(Buf), fIn); ASCII2Bin(Buf, l, &pBuf); l/=2; Decrypt(pBuf, &l); pBuf[l]=0; fclose(fIn); // encrypt file fIn = fopen("test1.txt", "rb"); fOut = fopen("test1.xxx", "wb"); l = fread(Buf, 1, sizeof(Buf), fIn); Crypt(Buf, &l, &pBuf); Bin2ASCII(pBuf, l, &pOut); fwrite(pOut, l*2, 1, fOut); free(pBuf); fclose(fIn); fclose(fOut); return 0; }