AES 256 and Base64 using CryptoAPI and C

The Advanced Encryption Standard (AES), also known as Rijndael (its original name), is a specification for the encryption of electronic data established by the U.S. National Institute of Standards and Technology (NIST) in 2001.

AES is based on the Rijndael cipher developed by two Belgian cryptographers, Joan Daemen and Vincent Rijmen, who submitted a proposal to NIST during the AES selection process. Rijndael is a family of ciphers with different key and block sizes.

For AES, NIST selected three members of the Rijndael family, each with a block size of 128 bits, but three different key lengths: 128, 192 and 256 bits.

AES has been adopted by the U.S. government and is now used worldwide. It supersedes the Data Encryption Standard (DES), which was published in 1977. The algorithm described by AES is a symmetric-key algorithm, meaning the same key is used for both encrypting and decrypting the data.

In the United States, AES was announced by the NIST as U.S. FIPS PUB 197 (FIPS 197) on November 26, 2001. This announcement followed a five-year standardization process in which fifteen competing designs were presented and evaluated, before the Rijndael cipher was selected as the most suitable (see Advanced Encryption Standard process for more details).

AES became effective as a federal government standard on May 26, 2002 after approval by the Secretary of Commerce. AES is included in the ISO/IEC 18033-3 standard. AES is available in many different encryption packages, and is the first (and only) publicly accessible cipher approved by the National Security Agency (NSA) for top secret information when used in an NSA approved cryptographic module (see Security of AES, below).

The name Rijndael is a play on the names of the two inventors (Joan Daemen and Vincent Rijmen). – Wikipedia

AES 256 (CBC crypt mode) and Base64 encoding

Generate Key and IV

bool CryptoInit(HCRYPTKEY *key, HCRYPTPROV *provider, unsigned char **iv, const unsigned char *password, unsigned long pLen)
{
	unsigned long mode = CRYPT_MODE_CBC;
	unsigned long blockSize, blockSizeLen = sizeof(unsigned long);
 
	if (!CryptAcquireContextW(provider, NULL, NULL, PROV_RSA_AES, 0))
	{
		if (GetLastError() == NTE_BAD_KEYSET)
		{
			if (!CryptAcquireContextW(provider, NULL, NULL, PROV_RSA_AES, CRYPT_NEWKEYSET))
			{
				printf("Error: %d\n", GetLastError());
				return false;
			}
		}
		else
		{
			printf("Error: %d\n", GetLastError());
			return false;
		}
	}
 
	if (!generateKey(key, *provider, CALG_AES_256, password, pLen))
	{
		printf("Error: %d\n", GetLastError());
		if (*provider) CryptReleaseContext(*provider, 0);
		return false;
	}
 
	if (!CryptSetKeyParam(*key, KP_MODE, (BYTE *)&mode, 0))
	{
		printf("Error: %d\n", GetLastError());
		if (*key) CryptDestroyKey(*key);
		if (*provider) CryptReleaseContext(*provider, 0);
		return false;
	}
 
	if (!CryptGetKeyParam(*key, KP_BLOCKLEN, (BYTE *)&blockSize, &blockSizeLen, 0))
	{
		printf("Error: %d\n", GetLastError());
		if (*key) CryptDestroyKey(*key);
		if (*provider) CryptReleaseContext(*provider, 0);
		return false;
	}
 
	blockSize /= 8;
 
	*iv = (unsigned char *)malloc(blockSize * sizeof(unsigned char));
	if (*iv == NULL)
	{
		if (*key) CryptDestroyKey(*key);
		if (*provider) CryptReleaseContext(*provider, 0);
		return false;
	}
	SecureZeroMemory(*iv, blockSize * sizeof(unsigned char));
 
	if (!CryptGenRandom(*provider, blockSize, *iv))
	{
		printf("Error: %d\n", GetLastError());
		SAFE_FREE(*iv);
		if (*key) CryptDestroyKey(*key);
		if (*provider) CryptReleaseContext(*provider, 0);
		return false;
	}
 
	if (!CryptSetKeyParam(*key, KP_IV, *iv, 0))
	{
		printf("Error: %d\n", GetLastError());
		SAFE_FREE(*iv);
		if (*key) CryptDestroyKey(*key);
		if (*provider) CryptReleaseContext(*provider, 0);
		return false;
	}
 
	return true;
}

Encrypt

bool Encrypt(HCRYPTKEY key, char **cipherText, unsigned long *cLen, unsigned char *plainText, unsigned long pLen)
{
	unsigned long len = 0;
	unsigned char *encrypted = 0;
	unsigned long enLen = 0;
 
	len = pLen + 1;
 
	if (!CryptEncrypt(key, 0, TRUE, 0, NULL, &len, 0))
	{
		if (key) CryptDestroyKey(key);
		return false;
	}
 
	enLen = len;
 
	encrypted = (unsigned char *)malloc(len * sizeof(unsigned char));
	if (encrypted == NULL)
	{
		if (key) CryptDestroyKey(key);
		return false;
	}
	SecureZeroMemory(encrypted, len * sizeof(unsigned char));
 
	memcpy_s(encrypted, len, plainText, pLen + 1);
 
	len = pLen + 1;
	if (!CryptEncrypt(key, 0, TRUE, 0, encrypted, &len, enLen))
	{
		SAFE_FREE(encrypted);
		if (key) CryptDestroyKey(key);
		return false;
	}
 
	if (!Base64EncodeA(cipherText, cLen, encrypted, enLen))
	{
		SAFE_FREE(encrypted);
		if (key) CryptDestroyKey(key);
		return false;
	}
 
	SAFE_FREE(encrypted);
 
	return true;
}

Decrypt

bool Decrypt(HCRYPTKEY key, unsigned char **plainText, char *cipherText, unsigned long cLen)
{
	unsigned long len = 0;
	unsigned long decodedLen = 0;
	char *decoded = 0;
 
	if (!Base64DecodeA(&decoded, &decodedLen, cipherText, cLen))
	{
		if (key) CryptDestroyKey(key);
		return false;
	}
 
	*plainText = (unsigned char *)malloc(decodedLen * sizeof(unsigned char));
	if (*plainText == NULL)
	{
		if (key) CryptDestroyKey(key);
		return false;
	}
	SecureZeroMemory(*plainText, decodedLen * sizeof(unsigned char));
 
	memcpy_s(*plainText, decodedLen, decoded, decodedLen);
 
	SAFE_FREE(decoded);
 
	len = decodedLen;
	if (!CryptDecrypt(key, 0, TRUE, 0, *plainText, &len))
	{
		SAFE_FREE(*plainText);
		if (key) CryptDestroyKey(key);
		return false;
	}
 
	return true;
}

Download full source code from GitHub.

git clone https://github.com/maldevel/AES256
Categories: C, Programming Tags: , ,
%d bloggers like this: