RSA 2048 and Base64 using CryptoAPI and C

RSA is one of the first practical public-key cryptosystems and is widely used for secure data transmission. In such a cryptosystem, the encryption key is public and differs from the decryption key which is kept secret. In RSA, this asymmetry is based on the practical difficulty of factoring the product of two large prime numbers, the factoring problem. RSA is made of the initial letters of the surnames of Ron Rivest, Adi Shamir, and Leonard Adleman, who first publicly described the algorithm in 1977. Clifford Cocks, an English mathematician working for the UK intelligence agency GCHQ, had developed an equivalent system in 1973, but it was not declassified until 1997.

A user of RSA creates and then publishes a public key based on two large prime numbers, along with an auxiliary value. The prime numbers must be kept secret. Anyone can use the public key to encrypt a message, but with currently published methods, if the public key is large enough, only someone with knowledge of the prime numbers can feasibly decode the message. Breaking RSA encryption is known as the RSA problem; whether it is as hard as the factoring problem remains an open question.

RSA is a relatively slow algorithm, and because of this it is less commonly used to directly encrypt user data. More often, RSA passes encrypted shared keys for symmetric key cryptography which in turn can perform bulk encryption-decryption operations at much higher speed. – wikipedia

Generate Public and Private Keys

static bool generateKeys(HCRYPTKEY *key, HCRYPTPROV provider, unsigned char **publicKey, unsigned char **privateKey)
{
	unsigned long publicKeyLen = 0;
	unsigned long privateKeyLen = 0;
 
	if (!provider)
		return false;
 
	if (!CryptGenKey(provider, AT_KEYEXCHANGE, RSA2048BIT_KEY | CRYPT_EXPORTABLE, key))
	{
		return false;
	}
 
	if (!CryptExportKey(*key, 0, PUBLICKEYBLOB, 0, NULL, &publicKeyLen))
	{
		if (*key) CryptDestroyKey(*key);
		return false;
	}
 
	*publicKey = (unsigned char *)malloc(publicKeyLen * sizeof(unsigned char));
	if (*publicKey == NULL)
	{
		if (*key) CryptDestroyKey(*key);
		return false;
	}
	SecureZeroMemory(*publicKey, publicKeyLen * sizeof(unsigned char));
 
	if (!CryptExportKey(*key, 0, PUBLICKEYBLOB, 0, *publicKey, &publicKeyLen))
	{
		SAFE_FREE(*publicKey);
		if (*key) CryptDestroyKey(*key);
		return false;
	}
 
	if (!CryptExportKey(*key, 0, PRIVATEKEYBLOB, 0, NULL, &privateKeyLen))
	{
		SAFE_FREE(*publicKey);
		if (*key) CryptDestroyKey(*key);
		return false;
	}
 
	*privateKey = (unsigned char *)malloc(privateKeyLen * sizeof(unsigned char));
	if (*privateKey == NULL)
	{
		SAFE_FREE(*publicKey);
		if (*key) CryptDestroyKey(*key);
		return false;
	}
	SecureZeroMemory(*privateKey, privateKeyLen * sizeof(unsigned char));
 
	if (!CryptExportKey(*key, 0, PRIVATEKEYBLOB, 0, *privateKey, &privateKeyLen))
	{
		SAFE_FREE(*publicKey);
		SAFE_FREE(*privateKey);
		if (*key) CryptDestroyKey(*key);
		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/RSA2048
%d bloggers like this: