CryptAcquireContext() 사용 및 문제 해결

이 문서에서는 CryptAcquireContext를 호출할 때 특정 플래그를 사용하는 시기와 이러한 플래그를 사용하는 이유에 대한 정보를 제공합니다.

적용 대상: Windows Server 2012 R2
원본 KB 번호: 238187

요약

함수에 대한 호출에는 다양한 플래그가 CryptAcquireContext 포함될 수 있습니다. 이러한 플래그를 사용해야 하는 경우를 알아야 합니다. 이 문서에서는 호출 CryptAcquireContext 할 때 특정 플래그를 사용하는 시기와 이러한 플래그를 사용하는 이유에 대한 정보를 제공합니다.

추가 정보

프라이빗 키 작업이 수행되지 않음

지속형 프라이빗 키를 사용하지 않는 경우 CryptAcquireContext가 호출될 때 CRYPT_VERIFYCONTEXT(0xF0000000) 플래그를 사용할 수 있습니다. CryptoAPI에 CryptReleaseContext가 호출될 때 릴리스될 키 컨테이너를 메모리에 만들도록 지시합니다. 이 플래그를 사용하는 경우 pszContainer 매개 변수는 NULL이어야 합니다. CRYPT_VERIFYCONTEXT 플래그는 다음 시나리오에서 사용할 수 있습니다.

  • 해시를 만들고 있습니다.

  • 대칭 키를 생성하여 데이터를 암호화하거나 해독합니다.

  • 해시에서 대칭 키를 파생하여 데이터를 암호화하거나 암호 해독합니다.

  • 서명을 확인하고 있습니다. CryptImportKey 또는 CryptImportPublicKeyInfo를 사용하여 PUBLICKEYBLOB 또는 인증서에서 공개 키를 가져올 수 있습니다.

  • 대칭 키를 내보낼 계획이지만 암호화 컨텍스트의 수명 내에 가져오지는 않습니다.

    참고

    마지막 두 시나리오에 대한 공개 키만 가져오려는 경우 CRYPT_VERIFYCONTEXT 플래그를 사용하여 컨텍스트를 가져올 수 있습니다.

  • 프라이빗 키 작업을 수행하고 있지만 키 컨테이너에 저장된 지속형 프라이빗 키를 사용하지 않습니다.

프라이빗 키 작업이 수행됩니다.

프라이빗 키 작업을 수행하려는 경우 고려해야 할 많은 문제가 있습니다.

컨텍스트를 획득하는 가장 좋은 방법은 컨테이너를 여는 것입니다. 이 시도가 "NTE_BAD_KEYSET"와 함께 실패하는 경우 CRYPT_NEWKEYSET 플래그를 사용하여 컨테이너를 만듭니다.

참고

애플리케이션은 프라이빗 키를 저장하기 위해 컨테이너 이름에 NULL 을 전달하여 기본 키 컨테이너를 사용하면 안 됩니다. 여러 애플리케이션이 동일한 컨테이너를 사용하는 경우 한 애플리케이션은 다른 애플리케이션에서 사용할 수 있어야 하는 키를 변경하거나 삭제할 수 있습니다. 애플리케이션이 고유한 이름의 키 컨테이너를 사용하는 경우 적절한 기능에 필요한 키를 조작하는 다른 애플리케이션의 위험이 줄어듭니다.

// Acquire Context of container that is unique to each user.
if (!CryptAcquireContext(&hProv,  
 "Container",  
 NULL,  
 PROV_RSA_FULL,  
 0))
{
 if (GetLastError() == NTE_BAD_KEYSET)
 {
 if (!CryptAcquireContext(&hProv,  
 "Container",  
 NULL,  
 PROV_RSA_FULL,  
 CRYPT_NEWKEYSET))
 {
 // Error ...
 }
 }
}

// Or, acquire Context of container that is shared across the machine.
if (!CryptAcquireContext(&hProv,  
 "Container",  
 NULL,  
 PROV_RSA_FULL,  
 CRYPT_MACHINE_KEYSET))
{
 if (GetLastError() == NTE_BAD_KEYSET)
 {
 if (!CryptAcquireContext(&hProv,  
 "Container",  
 NULL,  
 PROV_RSA_FULL,  
 CRYPT_NEWKEYSET|CRYPT_MACHINE_KEYSET)
 {
 // Error ...
 }
 }
}

CRYPT_MACHINE_KEYSET 플래그 사용

사용자별로 프라이빗 키 작업을 수행하지 않고 전역 프라이빗 키 작업이 필요한 경우 CRYPT_MACHINE_KEYSET 사용해야 합니다. 이 메서드는 컴퓨터별로 프라이빗/퍼블릭 키 쌍을 만듭니다. CRYPT_MACHINE_KEYSET 사용해야 하는 몇 가지 특정 시나리오는 다음과 같습니다.

  • 서비스를 작성하고 있습니다.
  • 구성 요소가 ASP(활성 서버 페이지) 페이지에서 실행되고 있습니다.
  • 구성 요소는 MTS(Microsoft Transaction Server) 구성 요소입니다. 이러한 예제에서는 애플리케이션이 실행되는 보안 컨텍스트가 사용자 프로필에 액세스할 수 없기 때문에 CRYPT_MACHINE_KEYSET 사용됩니다. 예를 들어 MTS 클라이언트는 사용자를 가장할 수 있지만 사용자가 로그온하지 않았기 때문에 사용자의 프로필을 사용할 수 없습니다. ASP 페이지에서 실행되는 구성 요소도 마찬가지입니다.

컨테이너에 대한 액세스 제공

기본적으로 키 컨테이너를 만들 때 로컬 시스템과 작성자는 컨테이너에 액세스할 수 있는 유일한 사용자입니다. 관리자가 키 컨테이너를 만드는 경우는 예외입니다. 로컬 시스템과 다른 모든 관리자는 키 컨테이너에 액세스할 수 있습니다. 다른 보안 컨텍스트는 컨테이너를 열 수 없습니다.

코드가 둘 이상의 보안 컨텍스트에서 실행되는 경우 적절한 사용자에게 컨테이너에 대한 액세스 권한을 부여해야 합니다.

컨테이너에 대한 보안을 설정하려면 컨테이너를 만든 후 PP_KEYSET_SEC_DESCR 플래그를 사용하여 CryptSetProvParam 함수를 호출합니다. 이 메서드를 사용하면 컨테이너에서 보안 설명자를 설정할 수 있습니다.

다음 코드에서는 CryptSetProvParam을 호출하는 방법을 보여 줍니다. 이 작업은 키 컨테이너를 만든 직후에 수행됩니다.

// Acquire Context  
if (!CryptAcquireContext(&hProv,  
 "Container",  
 NULL,  
 PROV_RSA_FULL,  
 0))
{
 if (GetLastError() == NTE_BAD_KEYSET)
 {
 if (!CryptAcquireContext(&hProv,  
 "Container",  
 NULL,  
 PROV_RSA_FULL,  
 CRYPT_NEWKEYSET))
 {
 // Error ...
 }

// Create Security Descriptor (pSD)...

// Set the Security Descriptor on the container
 if (!CryptSetProvParam(hProv,
 PP_KEYSET_SEC_DESCR,
 pSD,
 DACL_SECURITY_INFORMATION))
 {
 // Error ...
 }
 }
}

CryptAcquireContext 오류

다음은 가장 일반적인 오류 코드와 오류의 가능한 이유입니다.

  • NTE_BAD_KEYSET(0x80090016)
    • 키 컨테이너가 없습니다.
    • 키 컨테이너에 액세스할 수 없습니다.
    • 보호된 스토리지 서비스가 실행되고 있지 않습니다.
  • NTE_EXISTS(0x8009000F)
    • 키 컨테이너가 이미 있지만 만들려고 합니다. NTE_BAD_KEYSET 키를 열려는 이전 시도가 실패한 경우 키 컨테이너에 대한 액세스가 거부되었음을 의미합니다.
  • NTE_KEYSET_NOT_DEF(0x80090019)
    • CSP(암호화 서비스 공급자)가 올바르게 설정되지 않을 수 있습니다. CSP DLL(Rsabase.dll 또는 Rsaenh.dll)에서 Regsvr32.exe 사용하면 사용 중인 공급자에 따라 문제가 해결될 수 있습니다.