

기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.

# 암호화 API: 용 차세대(CNG) 및 키 스토리지 공급자(KSP) AWS CloudHSM
<a name="ksp-v3-library"></a>

Windows용 AWS CloudHSM 클라이언트에는 CNG 및 KSP 공급자가 포함됩니다.

*KSP(Key Storage Provider)*를 사용하여 키를 저장하고 검색할 수 있습니다. 예를 들어 Microsoft Active Directory Certificate Services(AD CS) 역할을 Windows 서버에 추가하고 인증 기관(CA)용 프라이빗 키를 새로 만들기로 한 경우, 키 저장을 관리할 KSP를 선택할 수 있습니다. AD CS 역할을 구성할 때 이 KSP를 선택할 수 있습니다. 자세한 내용은 [Windows Server CA 생성](win-ca-overview-sdk5.md#win-ca-setup-sdk5) 단원을 참조하십시오.

*CNG(Cryptography API: Next Generation)*는 Microsoft Windows 운영 체제 전용 암호화 API입니다. 개발자들은 CNG를 통해 Windows 기반 애플리케이션을 보호하는 암호화 기법을 사용할 수 있습니다. 개괄적으로 CNG AWS CloudHSM 구현은 다음과 같은 기능을 제공합니다.
+ **암호화 프리미티브** - 기본 암호화 작업을 수행할 수 있습니다.
+ **키 가져오기 및 내보내기** - 비대칭 키를 가져오고 내보낼 수 있습니다.
+ **데이터 보호 API(CNG DPAPI)** - 데이터를 쉽게 암호화하고 암호화를 해독할 수 있습니다.
+ **키 저장 및 검색** - 비대칭 키 페어의 프라이빗 키를 안전하게 보관하고 격리할 수 있습니다.

**Topics**
+ [에 대한 KSP 및 CNG 공급자 확인 AWS CloudHSM](ksp-v3-library-install.md)
+ [AWS CloudHSM Windows 클라이언트를 사용하기 위한 사전 조건](ksp-library-prereq.md)
+ [AWS CloudHSM 키를 인증서와 연결](ksp-library-associate-key-certificate.md)
+ [용 CNG 공급자의 코드 샘플 AWS CloudHSM](ksp-library-sample.md)

# 에 대한 KSP 및 CNG 공급자 확인 AWS CloudHSM
<a name="ksp-v3-library-install"></a>

KSP 및 CNG 공급자는 Windows AWS CloudHSM 클라이언트를 설치할 때 설치됩니다. [클라이언트 설치(Windows)](kmu-install-and-configure-client-win.md)의 단계에 따라 클라이언트를 설치할 수 있습니다.

다음 섹션을 사용하여 공급자의 설치를 확인합니다.

## Windows AWS CloudHSM 클라이언트 구성 및 실행
<a name="ksp-configure-client-windows"></a>

Windows CloudHSM 클라이언트를 시작하려면 먼저 [사전 조건](ksp-library-prereq.md)의 조건을 충족해야 합니다. 그런 다음 공급자가 사용하는 구성 파일을 업데이트하고 아래 단계를 완료하여 클라이언트를 시작합니다. KSP 및 CNG 공급자를 처음 사용할 때와 클러스터에서 HSM을 추가하거나 제거한 후 이러한 단계를 수행해야 합니다. 이렇게 하면 AWS CloudHSM 가 데이터를 동기화하고 클러스터의 모든 HSMs에서 일관성을 유지할 수 있습니다.

### 1단계: AWS CloudHSM 클라이언트 중지
<a name="ksp-stop-cloudhsm-client"></a>

공급자가 사용하는 구성 파일을 업데이트하기 전에 AWS CloudHSM 클라이언트를 중지합니다. 클라이언트가 이미 중지된 경우 중지 명령을 실행해도 아무 영향이 없습니다.
+ Windows 클라이언트 1.1.2\$1의 경우:

  ```
  C:\Program Files\Amazon\CloudHSM>net.exe stop AWSCloudHSMClient
  ```
+ Windows 클라이언트 1.1.1 이상의 경우:

   AWS CloudHSM 클라이언트를 시작한 명령 창에서 **Ctrl**\$1**C**를 사용합니다.

### 2단계: AWS CloudHSM 구성 파일 업데이트
<a name="ksp-config-a"></a>

이 단계에서는 [구성 도구](configure-tool.md)의 `-a` 파라미터를 사용하여 클러스터에 있는 HSM 중 하나의 탄력적 네트워크 인터페이스(ENI) IP 주소를 구성 파일에 추가합니다.

```
PS C:\> & "C:\Program Files\Amazon\CloudHSM\configure.exe" -a <HSM ENI IP>
```

클러스터에 있는 HSM의 ENI IP 주소를 가져오려면 AWS CloudHSM 콘솔로 이동하여 **클러스터**를 선택하고 원하는 클러스터를 선택합니다. [DescribeClusters](https://docs.aws.amazon.com/cloudhsm/latest/APIReference/API_DescribeClusters.html) 작업, [describe-clusters](https://docs.aws.amazon.com/cli/latest/reference/cloudhsmv2/describe-clusters.html) 명령 또는 [Get-HSM2Cluster](https://docs.aws.amazon.com/powershell/latest/reference/items/Get-HSM2Cluster.html) PowerShell cmdlet를 사용할 수도 있습니다. 오직 한 개의 ENI IP 주소만 입력하십시오. 어떤 ENI IP 주소를 사용해도 상관은 없습니다.

### 3단계: AWS CloudHSM 클라이언트 시작
<a name="ksp-start-cloudhsm-client"></a>

그런 다음 AWS CloudHSM 클라이언트를 시작하거나 다시 시작합니다. AWS CloudHSM 클라이언트가 시작되면 구성 파일의 ENI IP 주소를 사용하여 클러스터를 쿼리합니다. 그런 다음 클러스터 정보 파일에 모든 HSM의 ENI IP 주소를 추가합니다.
+ Windows 클라이언트 1.1.2\$1의 경우:

  ```
  C:\Program Files\Amazon\CloudHSM>net.exe start AWSCloudHSMClient
  ```
+ Windows 클라이언트 1.1.1 이상의 경우:

  ```
  C:\Program Files\Amazon\CloudHSM>start "cloudhsm_client" cloudhsm_client.exe C:\ProgramData\Amazon\CloudHSM\data\cloudhsm_client.cfg
  ```

## KSP 및 CNG 공급자 확인
<a name="ksp-check-providers"></a>

다음 명령 중 하나를 사용하여 시스템에 어떤 공급자가 설치되었는지 확인할 수 있습니다. 이 명령은 등록된 KSP 공급자와 CNG 공급자를 나열합니다. AWS CloudHSM 클라이언트를 실행할 필요는 없습니다.

```
PS C:\> & "C:\Program Files\Amazon\CloudHSM\ksp_config.exe" -enum
```

```
PS C:\> & "C:\Program Files\Amazon\CloudHSM\cng_config.exe" -enum
```

Windows Server EC2 인스턴스에 KSP 및 CNG 공급자가 설치되어 있는지 확인하려면 목록에 다음 항목이 표시되어야 합니다.

```
Cavium CNG Provider
Cavium Key Storage Provider
```

CNG 공급자가 없으면 다음 명령을 실행합니다.

```
PS C:\> & "C:\Program Files\Amazon\CloudHSM\cng_config.exe" -register
```

KSP 공급자가 없으면 다음 명령을 실행합니다.

```
PS C:\> & "C:\Program Files\Amazon\CloudHSM\ksp_config.exe" -register
```

# AWS CloudHSM Windows 클라이언트를 사용하기 위한 사전 조건
<a name="ksp-library-prereq"></a>

Windows AWS CloudHSM 클라이언트를 시작하고 KSP 및 CNG 공급자를 사용하려면 먼저 시스템의 HSM에 대한 로그인 자격 증명을 설정해야 합니다. Windows 자격 증명 관리자 또는 시스템 환경 변수를 통해 자격 증명을 설정할 수 있습니다. 자격 증명 저장에는 Windows 자격 증명 관리자를 사용하는 것이 좋습니다. 이 옵션은 AWS CloudHSM 클라이언트 버전 2.0.4 이상에서 사용할 수 있습니다. 환경 변수를 사용하면 더 쉽게 설정할 수 있지만 Windows 자격 증명 관리자를 사용할 때보다 안전하지 않습니다.

## Windows 자격 증명 관리자
<a name="wcm"></a>

`set_cloudhsm_credentials` 유틸리티 또는 Windows 자격 증명 관리자 인터페이스를 사용할 수 있습니다.
+ **`set_cloudhsm_credentials` 유틸리티 사용**:

  `set_cloudhsm_credentials` 유틸리티는 Windows 설치 관리자에 포함되어 있습니다. 이 유틸리티를 사용하여 HSM 로그인 자격 증명을 Windows 자격 증명 관리자에 편리하게 전달할 수 있습니다. 소스에서 이 유틸리티를 컴파일하려는 경우 설치 관리자에 포함된 Python 코드를 사용할 수 있습니다.

  1. `C:\Program Files\Amazon\CloudHSM\tools\` 폴더로 이동합니다.

  1. CU 사용자 이름 및 암호 파라미터를 사용하여 `set_cloudhsm_credentials.exe` 파일을 실행합니다.

     ```
     set_cloudhsm_credentials.exe --username <CU USER> --password <CU PASSWORD>
     ```
+ **자격 증명 관리자 인터페이스 사용**:

  자격 증명 관리자 인터페이스를 사용하여 자격 증명을 수동으로 관리할 수 있습니다.

  1. 자격 증명 관리자를 열려면 작업 표시줄의 검색 상자에 `credential manager`를 입력하고 **자격 증명 관리자**를 선택합니다.

  1. **Windows 자격 증명**을 선택하여 Windows 자격 증명을 관리합니다.

  1. **일반 자격 증명 추가**를 선택하고 다음과 같이 세부 정보를 채웁니다.
     + **인터넷 또는 네트워크 주소**에 대상 이름을 `cloudhsm_client`로 입력합니다.
     + **사용자 이름** 및 **암호**에 CU 자격 증명을 입력합니다.
     + **확인**을 클릭합니다.

## 시스템 환경 변수
<a name="enviorn-var"></a>

Windows 애플리케이션용 HSM 및 [CU(Crypto User)](understanding-users-cmu.md#crypto-user-cmu)를 식별하는 시스템 환경 변수를 설정할 수 있습니다. [**setx**명령](https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/setx)을 사용하여 시스템 환경 변수를 설정하거나, [프로그래밍 방식](https://msdn.microsoft.com/en-us/library/system.environment.setenvironmentvariable(v=vs.110).aspx)으로 또는 Windows **시스템 속성** 제어판의 **고급** 탭에서 영구 시스템 환경 변수를 설정할 수 있습니다.

**주의**  
시스템 환경 변수를 통해 자격 증명을 설정하면 사용자의 시스템에서 일반 텍스트로 암호를 사용할 수 있습니다. 이 문제를 해결하려면 Windows 자격 증명 관리자를 사용하십시오.

다음 시스템 환경 변수를 설정합니다.

**`n3fips_password=<CU USERNAME>:<CU PASSWORD>`**  
HSM의 [CU(Crypto User)](understanding-users-cmu.md#crypto-user-cmu)를 식별하고 필요한 모든 로그인 정보를 제공합니다. 애플리케이션에서는 해당 CU로 인증하고 실행합니다. 애플리케이션은 이 CU의 권한을 가지며 CU가 소유하고 공유하는 키만 보고 관리할 수 있습니다. 새 CU를 생성하려면 [createUser](cloudhsm_mgmt_util-createUser.md)를 사용하십시오 기존 CU를 찾으려면 [listUsers](cloudhsm_mgmt_util-listUsers.md)를 사용하십시오.  
예제:  

```
setx /m n3fips_password test_user:password123
```

# AWS CloudHSM 키를 인증서와 연결
<a name="ksp-library-associate-key-certificate"></a>

Microsoft의 [SignTool](https://docs.microsoft.com/en-us/windows/win32/seccrypto/signtool)과 같은 타사 도구와 함께 AWS CloudHSM 키를 사용하려면 먼저 키의 메타데이터를 로컬 인증서 스토어로 가져오고 메타데이터를 인증서와 연결해야 합니다. 키의 메타데이터를 가져오려면 CloudHSM 버전 3.0 이상에 포함된 import\$1key.exe 유틸리티를 사용합니다. 다음 단계에서는 추가 정보와 샘플 출력을 제공합니다.

## 1단계: 인증서 가져오기
<a name="import-cert"></a>

Windows에서는 인증서를 두 번 클릭하여 로컬 인증서 스토어로 가져올 수 있습니다.

그러나 두 번 클릭해도 작동하지 않는다면 [Microsoft Certreq 도구](https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2012-R2-and-2012/dn296456%28v%3dws.11%29)를 사용하여 인증서를 Certificate Manager로 가져옵니다. 예제: 

```
certreq -accept <certificatename>
```

이 작업이 실패하고 `Key not found` 오류가 표시되는 경우 2단계를 진행합니다. 인증서가 키 스토어에 나타나면 작업이 완료된 것이므로 추가 작업이 필요하지 않습니다.

## 2단계: 인증서 식별 정보 수집
<a name="cert-identifier"></a>

이전 단계가 성공하지 못한 경우 프라이빗 키를 인증서와 연결해야 합니다. 그러나 연결을 생성하려면 먼저 인증서의 고유 컨테이너 이름 및 일련번호를 찾아야 합니다. 필요한 인증서 정보를 표시하려면 **certutil**과 같은 유틸리티를 사용합니다. **certutil**의 다음 샘플 출력은 컨테이너 이름과 일련 번호를 보여줍니다.

```
================ Certificate 1 ================ Serial Number:
			72000000047f7f7a9d41851b4e000000000004Issuer: CN=Enterprise-CANotBefore: 10/8/2019 11:50
			AM NotAfter: 11/8/2020 12:00 PMSubject: CN=www.example.com, OU=Certificate Management,
			O=Information Technology, L=Seattle, S=Washington, C=USNon-root CertificateCert
			Hash(sha1): 7f d8 5c 00 27 bf 37 74 3d 71 5b 54 4e c0 94 20 45 75 bc 65No key provider
			information Simple container name: CertReq-39c04db0-6aa9-4310-93db-db0d9669f42c Unique
			container name: CertReq-39c04db0-6aa9-4310-93db-db0d9669f42c
```



## 3단계: AWS CloudHSM 프라이빗 키를 인증서와 연결
<a name="associate-key-certificate"></a>

키를 인증서와 연결하려면 먼저 [AWS CloudHSM 클라이언트 데몬을 시작해야](key_mgmt_util-setup.md#key_mgmt_util-start-cloudhsm-client) 합니다. 그런 다음 import\$1key.exe(CloudHSM 버전 3.0 이상에 포함되어 있음)를 사용하여 프라이빗 키를 인증서와 연결합니다. 인증서를 지정할 때 간단한 컨테이너 이름을 사용하십시오. 다음 예제에서는 명령과 응답을 보여줍니다. 이 작업은 키의 메타데이터만 복사하므로 키는 HSM에 남아 있습니다.

```
$> import_key.exe –RSA CertReq-39c04db0-6aa9-4310-93db-db0d9669f42c

Successfully opened Microsoft Software Key Storage Provider : 0NCryptOpenKey failed : 80090016
```

## 4단계: 인증서 스토어 업데이트
<a name="update-certificate-store"></a>

 AWS CloudHSM 클라이언트 데몬이 여전히 실행 중인지 확인합니다. 그런 다음 **certutil** 동사, **-repairstore**를 사용하여 인증서 일련 번호를 업데이트합니다. 다음 샘플은 명령 및 출력을 보여줍니다. [**-repairstore** 동사](https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2012-R2-and-2012/cc732443(v=ws.11)?redirectedfrom=MSDN#-repairstore)에 대한 자세한 내용은 Microsoft 설명서를 참조하십시오.

```
C:\Program Files\Amazon\CloudHSM>certutil -f -csp "Cavium Key Storage Provider"-repairstore my "72000000047f7f7a9d41851b4e000000000004"
my "Personal"
================ Certificate 1 ================
Serial Number: 72000000047f7f7a9d41851b4e000000000004
Issuer: CN=Enterprise-CA
NotBefore: 10/8/2019 11:50 AM
NotAfter: 11/8/2020 12:00 PM
Subject: CN=www.example.com, OU=Certificate Management, O=Information Technology, L=Seattle, S=Washington, C=US
Non-root CertificateCert Hash(sha1): 7f d8 5c 00 27 bf 37 74 3d 71 5b 54 4e c0 94 20 45 75 bc 65       
SDK Version: 3.0 
Key Container = CertReq-39c04db0-6aa9-4310-93db-db0d9669f42c 
Provider = "Cavium Key Storage Provider"
Private key is NOT exportableEncryption test passedCertUtil: -repairstore command completed successfully.
```

인증서 일련 번호를 업데이트한 후이 인증서와 해당 AWS CloudHSM 프라이빗 키를 Windows의 타사 서명 도구와 함께 사용할 수 있습니다.

# 용 CNG 공급자의 코드 샘플 AWS CloudHSM
<a name="ksp-library-sample"></a>

****  
\$1\$1 예제 코드 전용 - 프로덕션용으로 사용 불가 \$1\$1  
이 샘플 코드는 설명 목적으로만 제공됩니다. 이 코드를 프로덕션용으로 사용하지 마십시오.

다음 샘플은 Windows용 CloudHSM 클라이언트와 함께 설치된 CNG 공급자를 찾기 위해 시스템에 등록된 암호화 공급자를 열거하는 방법을 보여줍니다. 또한 비대칭 키 페어를 생성하는 방법과 키 페어를 사용하여 데이터에 서명하는 방법을 보여 줍니다.

**중요**  
이 예제를 실행하기 전에 사전 조건의 설명에 따라 HSM 보안 인증을 설정해야 합니다. 자세한 내용은 [AWS CloudHSM Windows 클라이언트를 사용하기 위한 사전 조건](ksp-library-prereq.md) 단원을 참조하십시오.

```
// CloudHsmCngExampleConsole.cpp : Console application that demonstrates CNG capabilities.
// This example contains the following functions.
//
//   VerifyProvider()          - Enumerate the registered providers and retrieve Cavium KSP and CNG providers.
//   GenerateKeyPair()         - Create an RSA key pair.
//   SignData()                - Sign and verify data.
//

#include "stdafx.h"
#include <Windows.h>

#ifndef NT_SUCCESS
#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)
#endif

#define CAVIUM_CNG_PROVIDER L"Cavium CNG Provider"
#define CAVIUM_KEYSTORE_PROVIDER L"Cavium Key Storage Provider"

// Enumerate the registered providers and determine whether the Cavium CNG provider
// and the Cavium KSP provider exist.
//
bool VerifyProvider()
{
  NTSTATUS status;
  ULONG cbBuffer = 0;
  PCRYPT_PROVIDERS pBuffer = NULL;
  bool foundCng = false;
  bool foundKeystore = false;

  // Retrieve information about the registered providers.
  //   cbBuffer - the size, in bytes, of the buffer pointed to by pBuffer.
  //   pBuffer - pointer to a buffer that contains a CRYPT_PROVIDERS structure.
  status = BCryptEnumRegisteredProviders(&cbBuffer, &pBuffer);

  // If registered providers exist, enumerate them and determine whether the
  // Cavium CNG provider and Cavium KSP provider have been registered.
  if (NT_SUCCESS(status))
  {
    if (pBuffer != NULL)
    {
      for (ULONG i = 0; i < pBuffer->cProviders; i++)
      {
        // Determine whether the Cavium CNG provider exists.
        if (wcscmp(CAVIUM_CNG_PROVIDER, pBuffer->rgpszProviders[i]) == 0)
        {
          printf("Found %S\n", CAVIUM_CNG_PROVIDER);
          foundCng = true;
        }

        // Determine whether the Cavium KSP provider exists.
        else if (wcscmp(CAVIUM_KEYSTORE_PROVIDER, pBuffer->rgpszProviders[i]) == 0)
        {
          printf("Found %S\n", CAVIUM_KEYSTORE_PROVIDER);
          foundKeystore = true;
        }
      }
    }
  }
  else
  {
    printf("BCryptEnumRegisteredProviders failed with error code 0x%08x\n", status);
  }

  // Free memory allocated for the CRYPT_PROVIDERS structure.
  if (NULL != pBuffer)
  {
    BCryptFreeBuffer(pBuffer);
  }

  return foundCng == foundKeystore == true;
}

// Generate an asymmetric key pair. As used here, this example generates an RSA key pair 
// and returns a handle. The handle is used in subsequent operations that use the key pair. 
// The key material is not available.
//
// The key pair is used in the SignData function.
//
NTSTATUS GenerateKeyPair(BCRYPT_ALG_HANDLE hAlgorithm, BCRYPT_KEY_HANDLE *hKey)
{
  NTSTATUS status;

  // Generate the key pair.
  status = BCryptGenerateKeyPair(hAlgorithm, hKey, 2048, 0);
  if (!NT_SUCCESS(status))
  {
    printf("BCryptGenerateKeyPair failed with code 0x%08x\n", status);
    return status;
  }

  // Finalize the key pair. The public/private key pair cannot be used until this 
  // function is called.
  status = BCryptFinalizeKeyPair(*hKey, 0);
  if (!NT_SUCCESS(status))
  {
    printf("BCryptFinalizeKeyPair failed with code 0x%08x\n", status);
    return status;
  }

  return status;
}

// Sign and verify data using the RSA key pair. The data in this function is hardcoded
// and is for example purposes only.
//
NTSTATUS SignData(BCRYPT_KEY_HANDLE hKey)
{
  NTSTATUS status;
  PBYTE sig;
  ULONG sigLen;
  ULONG resLen;
  BCRYPT_PKCS1_PADDING_INFO pInfo;

  // Hardcode the data to be signed (for demonstration purposes only).
  PBYTE message = (PBYTE)"d83e7716bed8a20343d8dc6845e57447";
  ULONG messageLen = strlen((char*)message);

  // Retrieve the size of the buffer needed for the signature.
  status = BCryptSignHash(hKey, NULL, message, messageLen, NULL, 0, &sigLen, 0);
  if (!NT_SUCCESS(status))
  {
    printf("BCryptSignHash failed with code 0x%08x\n", status);
    return status;
  }

  // Allocate a buffer for the signature.
  sig = (PBYTE)HeapAlloc(GetProcessHeap(), 0, sigLen);
  if (sig == NULL)
  {
    return -1;
  }

  // Use the SHA256 algorithm to create padding information.
  pInfo.pszAlgId = BCRYPT_SHA256_ALGORITHM;

  // Create a signature.
  status = BCryptSignHash(hKey, &pInfo, message, messageLen, sig, sigLen, &resLen, BCRYPT_PAD_PKCS1);
  if (!NT_SUCCESS(status))
  {
    printf("BCryptSignHash failed with code 0x%08x\n", status);
    return status;
  }

  // Verify the signature.
  status = BCryptVerifySignature(hKey, &pInfo, message, messageLen, sig, sigLen, BCRYPT_PAD_PKCS1);
  if (!NT_SUCCESS(status))
  {
    printf("BCryptVerifySignature failed with code 0x%08x\n", status);
    return status;
  }

  // Free the memory allocated for the signature.
  if (sig != NULL)
  {
    HeapFree(GetProcessHeap(), 0, sig);
    sig = NULL;
  }

  return 0;
}

// Main function.
//
int main()
{
  NTSTATUS status;
  BCRYPT_ALG_HANDLE hRsaAlg;
  BCRYPT_KEY_HANDLE hKey = NULL;

  // Enumerate the registered providers.
  printf("Searching for Cavium providers...\n");
  if (VerifyProvider() == false) {
    printf("Could not find the CNG and Keystore providers\n");
    return 1;
  }

  // Get the RSA algorithm provider from the Cavium CNG provider.
  printf("Opening RSA algorithm\n");
  status = BCryptOpenAlgorithmProvider(&hRsaAlg, BCRYPT_RSA_ALGORITHM, CAVIUM_CNG_PROVIDER, 0);
  if (!NT_SUCCESS(status))
  {
    printf("BCryptOpenAlgorithmProvider RSA failed with code 0x%08x\n", status);
    return status;
  }

  // Generate an asymmetric key pair using the RSA algorithm.
  printf("Generating RSA Keypair\n");
  GenerateKeyPair(hRsaAlg, &hKey);
  if (hKey == NULL)
  {
    printf("Invalid key handle returned\n");
    return 0;
  }
  printf("Done!\n");

  // Sign and verify [hardcoded] data using the RSA key pair.
  printf("Sign/Verify data with key\n");
  SignData(hKey);
  printf("Done!\n");

  // Remove the key handle from memory.
  status = BCryptDestroyKey(hKey);
  if (!NT_SUCCESS(status))
  {
    printf("BCryptDestroyKey failed with code 0x%08x\n", status);
    return status;
  }

  // Close the RSA algorithm provider.
  status = BCryptCloseAlgorithmProvider(hRsaAlg, NULL);
  if (!NT_SUCCESS(status))
  {
    printf("BCryptCloseAlgorithmProvider RSA failed with code 0x%08x\n", status);
    return status;
  }

  return 0;
}
```