Code Example for CNG Provider

Learn how to index the registered cryptographic providers in Dedicated KMS to find the CNG provider installed with the Windows client installer using the provided example code.

The following example code shows how to index the registered cryptographic providers to find the CNG provider installed with the Windows client installer. The code also shows how to create an asymmetric key pair and how to use the key pair to sign data.

Note

Before you run this example, you must set up the HSM credentials. For more information, see Setting up the HSM Cluster Client in Windows.

#include <windows.h>
#include <stdio.h>
#include <bcrypt.h>


int testReturnStatus = 0;

BCRYPT_KEY_HANDLE GenerateKeyPair(
	BCRYPT_ALG_HANDLE   hAlg,
	ULONG				keyLen)
{
	NTSTATUS            status = -1;
	BCRYPT_KEY_HANDLE	keyHandle = NULL;

	print_debug("Generating Key Pair of size: %lu\n", keyLen);
	status = BCryptGenerateKeyPair(hAlg, &keyHandle, keyLen, 0);
	if (status)
	{
		ReportErrorStatus(status, "\t\t\t\t\t\t\t FAIL BCryptGenerateKeyPair");
		goto cleanup;
	}
	/* Finalize RSA keys generated */
	status = BCryptFinalizeKeyPair(keyHandle, 0);
	if (status)
	{
		ReportErrorStatus(status, "\t\t\t\t\t\t\t FAIL BCryptFinalizeKeyPair");
		goto cleanup;
	}
	print_debug("Keypair Gen Success\n");
	ReportErrorStatus(status, "\t\t PASS\n");
	return keyHandle;
cleanup:
	if (keyHandle) {
		status = BCryptDestroyKey(keyHandle);
		keyHandle = NULL;
		if (status)
			ReportErrorStatus(status, "BCryptDestroyKey");
	}

	return keyHandle;
}


static NTSTATUS testSignVerify(
	PBYTE				test,
	BCRYPT_KEY_HANDLE	signKey,
	BCRYPT_KEY_HANDLE	verifyKey,
	ULONG				keyLen,
	VOID				*pPaddingInfo)
{
	NTSTATUS			status = -1;
	BYTE                inbuf[CHUNK_SIZE];
	BYTE				hash[CHUNK_SIZE];
	DWORD				hash_size;
	PBYTE				sign = NULL;
	DWORD				i;
	DWORD               insize;
	DWORD				pcbResult = 0;
	ULONG				dwFlags = 0;

	if (signKey == NULL || verifyKey == NULL) {
		status = STATUS_INVALID_HANDLE;
		goto cleanup;
	}

	printf("%s", test);

	/* Fill input data; Alternatively can read from file */
	for (i = 0; i < CHUNK_SIZE; i++)
		inbuf[i] = (BYTE)i + 1;
	insize = i;/* Length of inbuf */
	if (pPaddingInfo)
		dwFlags = BCRYPT_PAD_PKCS1;
	// calculate the size of sign data needed
	status = BCryptSignHash(signKey,
		pPaddingInfo,
		hash,
		CHUNK_SIZE,
		NULL,
		0,
		&pcbResult,
		dwFlags
		);
	if (status)
	{
		ReportErrorStatus(status, "\t\t FAIL BCryptSignHash get-size");
		goto cleanup;
	}
	print_debug("required sign data size: %lu\n", pcbResult);

	status = CreateHash(BCRYPT_SHA1_ALGORITHM, MS_PRIMITIVE_PROVIDER, inbuf, insize, hash, &hash_size, NULL, 0, 0);
	if (status)
		goto cleanup;

	sign = (PBYTE)HEAPALLOC(pcbResult);
	if (sign == NULL) {
		status = STATUS_UNSUCCESSFUL;
		goto cleanup;
	}
	status = BCryptSignHash(signKey,
		pPaddingInfo,
		hash,
		hash_size,
		sign,
		pcbResult,
		&pcbResult,
		dwFlags
		);
	if (status)
	{
		ReportErrorStatus(status, "\t\t FAIL BCryptSignHash");
		goto cleanup;
	}
	print_debug("signed data size: %lu\n", pcbResult);
	print_debug("Created Signature from Hash using MS Key Success\n");

	/* Verify Signature with Cavium key*/
	status = BCryptVerifySignature(verifyKey,
		pPaddingInfo,
		hash,
		hash_size,
		sign,
		pcbResult,
		dwFlags);
	if (status)
	{
		ReportErrorStatus(status, "\t\t FAIL BCryptVerifySignature");
		goto cleanup;
	}
	print_debug("Verifying Signature SUCCESS\n");
	ReportErrorStatus(status, "\t\t PASS\n");
cleanup:
	if (sign)
		HeapFree(GetProcessHeap(), 0, sign);
	return status;
}


static void testRSA()
{
	NTSTATUS            status = STATUS_UNSUCCESSFUL;
	LPCWSTR				pszAlgId = NULL;
	BCRYPT_ALG_HANDLE   caviumAlg = NULL;
	BCRYPT_ALG_HANDLE   msAlg = NULL;
	EncDecPriv			priv = { 0 };
	ULONG				keyLen = 2048;
	

	pszAlgId = BCRYPT_RSA_ALGORITHM;

	//open Cavium CNG Provider
	caviumAlg = OpenAlgorithmProvider(pszAlgId, CAVIUM_PROVIDER_NAME, 0);
	if (caviumAlg == NULL)
		goto cleanup;
	//open Microsoft Primitive Provider
	msAlg = OpenAlgorithmProvider(pszAlgId, MS_PRIMITIVE_PROVIDER, 0);
	if (msAlg == NULL)
		goto cleanup;

	// fill priv structure
	priv.alg = RSA;
	priv.blockSize = 1;

	printf("\n\n############################# %ls Unit Testing ########################################\n\n", pszAlgId);
	printf("KeyLen\t   Test\t\t      Info\t\t\t Result\n");
	printf("=======================================================================================\n");
	for (keyLen = 2048; keyLen <= 4096; keyLen = keyLen + 256) {
		printf("\n%lu\n", keyLen);
		priv.keyLen = keyLen;
		status = testRSACommon(caviumAlg, msAlg, &priv);
#ifdef RUN_MINIMAL_TEST
		/* To test functionality with RSA 2048 key size only, break now. */
		break; /* This will be suitable if we are running these tests in PR checker kind of build.*/
#endif
	}

cleanup:
	if (caviumAlg)
		CloseAlgorithmProvider(caviumAlg, 0);
	if (msAlg)
		CloseAlgorithmProvider(msAlg, 0);
	return;
}