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

#include <stdio.h>
#include <windows.h>
#include <Wincrypt.h>
#include <iostream>
#define MY_ENCODING_TYPE  (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
//this is keylength bit shifted, here we have keylength of 1024bits hence 1024 << 16;
#define KEYLENGTH 0x04000000

using namespace std;
int main()
{
	DWORD dwFlags = 0;
	HCRYPTPROV m_hProv;
	PBYTE pbKeyBlob;
	DWORD dwKeyBlobLen;
	DWORD m_dwBlockSize;
	DWORD dwLen;
	DWORD m_dwKeySizeInBits = 50;
	HCRYPTKEY hPubKey;
	DWORD dwBlockSize = 250;

	// Ok this initialises the Crypto stuff, here im using the enhanced provider
	if (!CryptAcquireContext(&m_hProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, dwFlags))
	{
	   // If cant get default provider the following creates one
	   DWORD err = GetLastError();
	   INT iReturn = 0;
	   LPSTR pszContainerName = NULL;
	   DWORD cbContainerName = 0;

	   if(GetLastError() != NTE_BAD_KEYSET)
	   {
		   printf("Error opening default key container!\r\n");
	   }

	   // Create default key container.
	   if(!CryptAcquireContext(&m_hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET))
	   {
			printf("Error creating default key container!\n");
	   }

	   // Get size of the name of the default key container name.
	   if(CryptGetProvParam(m_hProv, PP_CONTAINER, NULL, &cbContainerName, 0))
	   {
		  // Allocate buffer to receive default key container name.
		  pszContainerName = (char *)malloc(cbContainerName);
		  if(pszContainerName)
		  {
			 // Get name of default key container name.
			if(!CryptGetProvParam(m_hProv, PP_CONTAINER, (BYTE *)pszContainerName, &cbContainerName, 0))
			{
				// Error getting default key container name.
				pszContainerName[0] = 0;
			 }
		  }
	   }

	   // printf("Create key container '%s'\n", pszContainerName ? pszContainerName : "");

	   // Free container name buffer (if created)
	   if(pszContainerName)
	   {
		   free(pszContainerName);
	   }
	}
	BOOL bResult = CryptGenKey(m_hProv, CALG_RSA_KEYX,  KEYLENGTH | CRYPT_EXPORTABLE, &hPubKey);
	if(!CryptExportKey(hPubKey, NULL, PUBLICKEYBLOB, 0, NULL, &dwKeyBlobLen))
	{
	   //deal with errors (wrong types, not set to be exportable etc)
	}
	if((pbKeyBlob = (unsigned char *) malloc(dwKeyBlobLen)) == NULL)
	{
		//alloc prob
	}

	// Export session key into a simple key blob.
	if(!CryptExportKey(hPubKey, NULL, PUBLICKEYBLOB, 0, pbKeyBlob, &dwKeyBlobLen))
	{
	   // any probs
	}

	// Now this bit u would do on your client (after it arrived), you would init the client
	if(CryptImportKey(m_hProv,pbKeyBlob,dwKeyBlobLen,0,CRYPT_EXPORTABLE,&hPubKey) )
	{
		// now we get the block length as we can only encrypt up to that size, per pass
		// this can be done as soon as u generate the key u dont need to import/export 2 get it
		if(CryptGetKeyParam(hPubKey, KP_BLOCKLEN, (LPBYTE)&m_dwKeySizeInBits, &dwLen,0))
		{
			 m_dwBlockSize = m_dwKeySizeInBits/8;
		}
	}

	// now with RSA enc, it needs 11 bytes of padding at end, so this reduces the length further
	DWORD tempLen=m_dwBlockSize-11;
	BYTE* tempBuff = (BYTE*)"This is my datarffffffffffffffffffffffffffffffffffffgfhtrfhrthrthrthrthrthtrhrthrthrthrthrh";
	cout << *tempBuff << endl;
	if(!CryptEncrypt(hPubKey, NULL, FALSE, 0, tempBuff, &tempLen, dwBlockSize))
	{
		cout << GetLastError() << endl;
	}

	cout << endl << endl << endl;

	cout << "[encrypted buffer]: " << tempBuff;

	//now try and decrypt it, again we get length back of orig data
	if(!CryptDecrypt(hPubKey, NULL, FALSE, 0, tempBuff, &tempLen))
	{
		// if anything goes wrong
	}


	// obviously we need to cleanup nicely
	CryptDestroyKey(hPubKey);
	CryptReleaseContext(m_hProv,0); 
}

if(!CryptEncrypt(hPubKey, NULL, FALSE, 0, tempBuff, &tempLen, dwBlockSize))
is where it fails...

Edited 5 Years Ago by Tauren: n/a

The MSDN is very clear: the data buffer is an in/out parameter, that is

The plaintext in this buffer is overwritten with the ciphertext created by this function.

Your pointer is pointing to a read-only string literal. Besides, keep in mind that a ciphertext may take more space than the plaintext. It is always a good idea to call CryptEncrypt twice, first with a null data pointer to figure out how much space is required, then do an actual encryption with the buffer large enough.

This article has been dead for over six months. Start a new discussion instead.