CryptAcquireContextA 函式 (wincrypt.h)

重要 此 API 已被取代。 新的和現有的軟體應該開始使用 密碼編譯新一代 API。 Microsoft 可能會在未來的版本中移除此 API。
 
CryptAcquireContext 函式可用來取得特定密碼編譯服務提供者內特定密鑰容器的句柄, (CSP) 。 此傳回的句柄用於呼叫使用所選 CSP 的 CryptoAPI 函式。

此函式會先嘗試尋找具有 dwProvTypepszProvider 參數中所述特性的 CSP。 如果找到 CSP,函式會嘗試在符合 pszContainer 參數所指定名稱的 CSP 內尋找密鑰容器。 若要取得與憑證公鑰相關聯之私鑰的內容金鑰容器,請使用 CryptAcquireCertificatePrivateKey

使用 dwFlags 的適當設定,此函式也可以建立和終結密鑰容器,而且如果不需要存取私鑰,可以使用暫存密鑰容器來提供 CSP 的存取權。

語法

BOOL CryptAcquireContextA(
  [out] HCRYPTPROV *phProv,
  [in]  LPCSTR     szContainer,
  [in]  LPCSTR     szProvider,
  [in]  DWORD      dwProvType,
  [in]  DWORD      dwFlags
);

參數

[out] phProv

CSP 句柄的指標。 當您完成使用 CSP 時,請呼叫 CryptReleaseContext 函式來釋放句柄。

[in] szContainer

金鑰容器名稱。 這是以 Null 結尾的字串,可識別 CSP 的密鑰容器。 此名稱與用來儲存金鑰的方法無關。 有些 CSP 會將其金鑰容器儲存在內部 (硬體) 、有些使用系統登錄,而其他則使用檔案系統。 在大部分情況下,當 dwFlags 設定為 CRYPT_VERIFYCONTEXT 時, pszContainer 必須設定為 NULL。 不過,對於硬體型 CSP,例如智慧卡 CSP,可以存取指定容器中的公開可用資訊。

如需 pszContainer 參數使用方式的詳細資訊,請參閱。

[in] szProvider

以 Null 結尾的字串,其中包含要使用的 CSP 名稱。

如果此參數為 NULL,則會使用用戶預設提供者。 如需詳細資訊,請參閱 密碼編譯服務提供者內容。 如需可用密碼編譯提供者的清單,請參閱 密碼編譯提供者名稱

應用程式可以使用 CryptGetProvParam 函式來讀取 dwParam 參數中的PP_NAME CSP 值,以取得使用中的 CSP 名稱。

預設 CSP 可以在作業系統版本之間變更。 為了確保不同操作系統平臺上的互操作性,應該使用此參數來明確設定 CSP,而不是使用預設 CSP。

[in] dwProvType

指定要取得的提供者類型。 密碼編譯提供者類型中會討論已定義的 提供者類型

[in] dwFlags

標幟值。 此參數通常會設定為零,但有些應用程式會設定下列一或多個旗標。

意義
CRYPT_VERIFYCONTEXT
此選項適用於使用暫時金鑰的應用程式,或不需要存取保存私鑰的應用程式,例如只執行 哈希加密數位簽名 驗證的應用程式。 只有建立簽章或解密訊息的應用程式需要 存取私鑰。 在大部分情況下,應該設定此旗標。

針對檔案型 CSP,當設定此旗標時, pszContainer 參數必須設定為 NULL。 應用程式無法存取公開/私鑰組的保存私鑰。 設定此旗標時,可以建立暫存 的公開/私鑰組 ,但不會保存它們。

對於硬體型 CSP,例如智慧卡 CSP,如果 pszContainer 參數為 NULL 或空白,則此旗標表示不需要存取任何密鑰,而且不應該向用戶顯示任何 UI。 此窗體用來連線到 CSP 來查詢其功能,但不會實際使用其密鑰。 如果 pszContainer 參數不是 NULL 且不是空白,則此旗標表示只需要存取指定容器內的公開可用資訊。 CSP 不應該要求 PIN。 例如,嘗試存取私用資訊 (,CryptSignHash 函式) 將會失敗。

呼叫 CryptAcquireContext 時,許多 CSP 需要來自擁有使用者的輸入,才能授與 密鑰容器中私鑰的存取權。 例如,私鑰可以加密,需要用戶的密碼才能使用。 不過,如果指定 CRYPT_VERIFYCONTEXT 旗標,就不需要存取私鑰,而且可以略過使用者介面。

CRYPT_NEWKEYSET
使用 pszContainer 所指定的名稱建立新的金鑰容器。 如果 pszContainerNULL,則會建立具有預設名稱的密鑰容器。
CRYPT_MACHINE_KEYSET
根據預設,金鑰和金鑰容器會儲存為使用者金鑰。 對於基底提供者,這表示使用者密鑰容器會儲存在使用者的配置檔中。 只有建立金鑰容器的使用者,以及具有系統管理許可權的使用者,才能存取系統管理員未建立此旗標的密鑰容器。

Windowsxp: 只有建立金鑰容器和本機系統帳戶的使用者,才能存取系統管理員未建立此旗標的密鑰容器。

只有建立金鑰容器和本機系統帳戶的使用者才能存取不是系統管理員的使用者所建立的密鑰容器,

CRYPT_MACHINE_KEYSET旗標可以與其他所有旗標結合,以指出感興趣的密鑰容器是計算機密鑰容器,而 CSP 會將它視為此類。 對於基底提供者,這表示密鑰會儲存在本機建立密鑰容器的計算機上。 如果密鑰容器是計算機容器,則CRYPT_MACHINE_KEYSET旗標必須與參考計算機容器之 CryptAcquireContext 的所有呼叫搭配使用。 除非使用 CryptSetProvParam 授與容器的訪問許可權,否則系統管理員只能由其建立者和具有系統管理員許可權的使用者存取以CRYPT_MACHINE_KEYSET建立的密鑰容器。

Windowsxp: 除非使用 CryptSetProvParam 授與容器的訪問許可權,否則系統管理員只能由其建立者和本機系統帳戶存取以CRYPT_MACHINE_KEYSET建立的密鑰容器。

除非使用 CryptSetProvParam 授與容器的存取權,否則不是系統管理員的使用者只能由其建立者和本機系統帳戶存取以CRYPT_MACHINE_KEYSET建立的密鑰容器。

當用戶從未以互動方式登入的服務或用戶帳戶存取時,CRYPT_MACHINE_KEYSET旗標很有用。 建立密鑰容器時,大部分的 CSP 不會自動建立任何 公開/私鑰組。 這些金鑰必須使用 CryptGenKey 函式建立為個別步驟。

CRYPT_DELETEKEYSET
刪除 pszContainer 指定的金鑰容器。 如果 pszContainerNULL,則會刪除具有預設名稱的密鑰容器。 金鑰容器中的所有 金鑰組 也會終結。

設定此旗標時, phProv 中傳回的值是未定義的,因此,之後不需要呼叫 CryptReleaseContext 函式。

CRYPT_SILENT
應用程式要求 CSP 不會針對此 內容顯示任何使用者介面 (UI) 。 如果 CSP 必須顯示要運作的 UI,呼叫會失敗,且NTE_SILENT_CONTEXT錯誤碼設定為最後一個錯誤。 此外,如果使用已使用 CRYPT_USER_PROTECTED CRYPT_SILENT 旗標取得的內容來呼叫 CryptGenKey ,則呼叫會失敗,而 CSP 會設定NTE_SILENT_CONTEXT。

CRYPT_SILENT適用於 CSP 無法顯示 UI 的應用程式。

CRYPT_DEFAULT_CONTAINER_OPTIONAL
取得智慧卡 CSP 的內容,可用於哈希和對稱密鑰作業,但不能用於任何需要使用 PIN 驗證智慧卡的作業。 這種類型的內容最常用來在空的智慧卡上執行作業,例如使用 CryptSetProvParam 設定 PIN。 此旗標只能與智慧卡 CSP 搭配使用。

Windows Server 2003 和 Windows XP: 不支援此旗標。

傳回值

如果函式成功,函式會傳回非零 (TRUE) 。

如果函式失敗,它會傳回零 (FALSE) 。 如需擴充的錯誤資訊,請呼叫 GetLastError

NTE 開頭的錯誤碼是由所使用的特定 CSP 所產生。 Winerror.h 中定義的一些可能錯誤碼如下。

傳回碼/值 Description
ERROR_BUSY
107L
如果已設定CRYPT_DELETEKEYSET旗標值,而另一個線程或 進程 使用此 密鑰容器,則某些 CSP 會設定此錯誤。
ERROR_FILE_NOT_FOUND
2L
不會載入使用者的配置檔,而且找不到。 當應用程式模擬使用者時,就會發生這種情況,例如IUSR_ComputerName 帳戶。
ERROR_INVALID_PARAMETER
87L
其中一個參數包含無效的值。 這通常是無效的指標。
ERROR_NOT_ENOUGH_MEMORY
8L
操作系統在作業期間記憶體不足。
NTE_BAD_FLAGS
0x80090009L
dwFlags 參數的值無效。
NTE_BAD_KEY_STATE
0x8009000BL
自私鑰加密后,用戶密碼已變更。
NTE_BAD_KEYSET
0x80090016L
無法開啟金鑰容器。 此錯誤的常見原因是金鑰容器不存在。 若要建立密鑰容器,請使用 CRYPT_NEWKEYSET 旗標呼叫 CryptAcquireContext 。 此錯誤碼也可以指出存取現有的金鑰容器遭到拒絕。 密鑰集建立者可以使用 CryptSetProvParam 授與容器的訪問許可權。
NTE_BAD_KEYSET_PARAM
0x8009001FL
pszContainerpszProvider 參數設定為無效的值。
NTE_BAD_PROV_TYPE
0x80090014L
dwProvType 參數的值超出範圍。 所有提供者類型都必須從 1 到 999,包含。
NTE_BAD_SIGNATURE
0x80090006L
無法驗證提供者 DLL 簽章。 DLL 或數位簽名已遭竄改。
NTE_EXISTS
0x8009000FL
dwFlags 參數CRYPT_NEWKEYSET,但密鑰容器已經存在。
NTE_KEYSET_ENTRY_BAD
0x8009001AL
找到 pszContainer 密鑰容器,但已損毀。
NTE_KEYSET_NOT_DEF
0x80090019L
要求的提供者不存在。
NTE_NO_MEMORY
0x8009000EL
CSP 在作業期間記憶體不足。
NTE_PROV_DLL_NOT_FOUND
0x8009001EL
提供者 DLL 檔案不存在或不在目前路徑上。
NTE_PROV_TYPE_ENTRY_BAD
0x80090018L
dwProvType 指定的提供者類型已損毀。 此錯誤可能會與用戶預設 CSP 清單或電腦預設 CSP 列表有關。
NTE_PROV_TYPE_NO_MATCH
0x8009001BL
dwProvType 指定的提供者類型不符合找到的提供者類型。 請注意,只有在 pszProvider 指定實際的 CSP 名稱時,才會發生此錯誤。
NTE_PROV_TYPE_NOT_DEF
0x80090017L
dwProvType 所指定的提供者類型沒有專案存在。
NTE_PROVIDER_DLL_FAIL
0x8009001DL
無法載入提供者 DLL 檔案或無法初始化。
NTE_SIGNATURE_FILE_BAD
0x8009001CL
在驗證 DLL 檔案映像之前,載入 DLL 檔案映像時發生錯誤。

備註

pszContainer 參數會指定用來保存密鑰的容器名稱。 每個容器可以包含一個金鑰。 如果您在建立金鑰時指定現有容器的名稱,新的金鑰將會覆寫先前的金鑰。

CSP 名稱和金鑰容器名稱的組合可唯一識別系統上的單一密鑰。 如果某個應用程式嘗試在另一個應用程式使用它時修改密鑰容器,則可能會導致無法預期的行為。

如果您將 pszContainer 參數設定為 NULL,則會使用預設密鑰容器名稱。 以這種方式呼叫 Microsoft 軟體 CSP 時,每次呼叫 CryptAcquireContext 函式時都會建立新的容器。 不過,不同的 CSP 在此方面可能會有不同的行為。 特別是,CSP 可能會有單一預設容器,由所有存取 CSP 的應用程式共用。 因此,應用程式不得使用預設密鑰容器來儲存私鑰。 相反地,請在 dwFlags 參數中傳遞 CRYPT_VERIFYCONTEXT 旗標,或使用其他應用程式不太可能使用的應用程式特定容器,來防止密鑰記憶體。

應用程式可以使用 CryptGetProvParam 函式來讀取PP_CONTAINER值,以取得使用中的密鑰容器名稱。

基於效能考慮,我們建議您將 pszContainer 參數設定為 NULL ,並將 dwFlags 參數設定為 CRYPT_VERIFYCONTEXT 在所有不需要保存密鑰的情況下。 特別是,請考慮將 pszContainer 參數設定為 NULL ,並將 dwFlags 參數設定為 下列案例CRYPT_VERIFYCONTEXT

  • 您正在建立哈希。
  • 您正在產生對稱金鑰來加密或解密資料。
  • 您要從哈希衍生對稱密鑰,以加密或解密數據。
  • 您正在驗證簽章。 您可以使用 CryptImportKey 或 CryptImportPublicKeyInfo,從 PUBLICKEYBLOB 或憑證匯入公鑰。 如果您只打算匯入公鑰,可以使用 CRYPT_VERIFYCONTEXT 旗標來取得內容。
  • 您計劃匯出對稱密鑰,但不在密碼編譯內容的存留期內匯入。 如果您只打算匯入最後兩個案例的公鑰,則可以使用 CRYPT_VERIFYCONTEXT 旗標來取得內容。
  • 您正在執行私鑰作業,但未使用儲存在金鑰容器中的保存私鑰。
如果您打算執行私鑰作業,取得內容的最佳方式是嘗試開啟容器。 如果嘗試失敗並出現NTE_BAD_KEYSET,請使用 CRYPT_NEWKEYSET 旗標建立容器。

範例

下列範例顯示取得密鑰容器中公開/私鑰組的密碼編譯內容和存取權。 如果要求的金鑰容器不存在,則會建立它。

如需包含此範例完整內容的範例,請參閱 範例 C 程式:建立密鑰容器和產生金鑰。 如需其他範例,請參閱 範例 C 程式:使用 CryptAcquireContext

//-------------------------------------------------------------------
// Declare and initialize variables.

HCRYPTPROV hCryptProv = NULL;        // handle for a cryptographic
                                     // provider context
LPCSTR UserName = "MyKeyContainer";  // name of the key container
                                     // to be used
//-------------------------------------------------------------------
// Attempt to acquire a context and a key
// container. The context will use the default CSP
// for the RSA_FULL provider type. DwFlags is set to zero
// to attempt to open an existing key container.

if(CryptAcquireContext(
   &hCryptProv,               // handle to the CSP
   UserName,                  // container name 
   NULL,                      // use the default provider
   PROV_RSA_FULL,             // provider type
   0))                        // flag values
{
    printf("A cryptographic context with the %s key container \n", 
  UserName);
    printf("has been acquired.\n\n");
}
else
{ 
//-------------------------------------------------------------------
// An error occurred in acquiring the context. This could mean
// that the key container requested does not exist. In this case,
// the function can be called again to attempt to create a new key 
// container. Error codes are defined in Winerror.h.
 if (GetLastError() == NTE_BAD_KEYSET)
 {
   if(CryptAcquireContext(
      &hCryptProv, 
      UserName, 
      NULL, 
      PROV_RSA_FULL, 
      CRYPT_NEWKEYSET)) 
    {
      printf("A new key container has been created.\n");
    }
    else
    {
      printf("Could not create a new key container.\n");
      exit(1);
    }
  }
  else
  {
      printf("A cryptographic service handle could not be "
          "acquired.\n");
      exit(1);
   }
  
} // End of else.
//-------------------------------------------------------------------
// A cryptographic context and a key container are available. Perform
// any functions that require a cryptographic provider handle.

//-------------------------------------------------------------------
// When the handle is no longer needed, it must be released.

if (CryptReleaseContext(hCryptProv,0))
{
  printf("The handle has been released.\n");
}
else
{
  printf("The handle could not be released.\n");
}

注意

wincrypt.h 標頭會將 CryptAcquireContext 定義為別名,根據 UNICODE 預處理器常數的定義,自動選取此函式的 ANSI 或 Unicode 版本。 混合使用編碼中性別名與非編碼中性的程序代碼,可能會導致編譯或運行時間錯誤不符。 如需詳細資訊,請參閱 函式原型的慣例

規格需求

需求
最低支援的用戶端 Windows XP [僅限傳統型應用程式]
最低支援的伺服器 Windows Server 2003 [僅限傳統型應用程式]
目標平台 Windows
標頭 wincrypt.h
程式庫 Advapi32.lib
Dll Advapi32.dll

另請參閱

CryptGenKey

CryptGetProvParam

CryptReleaseContext

服務提供者函式

密碼編譯服務提供者的線程問題