CryptAcquireContextW 函数 (wincrypt.h)

重要 此 API 已弃用。 新的和现有的软件应开始使用 加密下一代 API。 Microsoft可能会在将来的版本中删除此 API。
 
CryptAcquireContext 函数用于获取特定 密钥容器的句柄, 特定 加密服务提供商(CSP)。 此返回的句柄用于调用 CryptoAPI 使用所选 CSP 的函数。

此函数首先尝试查找具有 dwProvTypepszProvider 参数中描述的特征的 CSP。 如果找到 CSP,该函数将尝试在 CSP 中找到与 pszContainer 参数指定的名称匹配的密钥容器。 若要获取与证书 公钥 关联的 私钥的 上下文 和密钥容器,请使用 CryptAcquireCertificatePrivateKey

使用 dwFlags的相应设置,此函数还可以创建和销毁密钥容器,并且可以在不需要访问私钥时使用临时密钥容器提供对 CSP 的访问权限。

语法

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

参数

[out] phProv

指向 CSP 句柄的指针。 使用完 CSP 后,通过调用 CryptReleaseContext 函数释放句柄。

[in] szContainer

密钥容器名称。 这是一个以 null 结尾的字符串,用于标识 CSP 的密钥容器。 此名称与用于存储密钥的方法无关。 某些 CSP 将其密钥容器存储在内部(硬件中),一些 CSP 使用系统注册表,而另一些则使用文件系统。 在大多数情况下,当 dwFlags 设置为CRYPT_VERIFYCONTEXT时,pszContainer 必须设置为 NULL。 但是,对于基于硬件的 CSP(例如智能卡 CSP),可以访问规范容器中的公开可用信息。

有关 pszContainer 参数用法的详细信息,请参阅“备注”。

[in] szProvider

一个以 null 结尾的字符串,其中包含要使用的 CSP 的名称。

如果此参数 NULL,则使用用户默认提供程序。 有关详细信息,请参阅 加密服务提供程序上下文。 有关可用加密提供程序的列表,请参阅 加密提供程序名称

应用程序可以使用 CryptGetProvParam 函数来获取正在使用的 CSP 的名称,以读取 dwParam 参数中的 PP_NAME CSP 值。

默认 CSP 可以在操作系统版本之间更改。 为了确保不同操作系统平台上的互操作性,应使用此参数而不是使用默认 CSP 显式设置 CSP。

[in] dwProvType

指定要获取的提供程序的类型。 加密提供程序类型中讨论了定义的提供程序类型。

[in] dwFlags

以下一个或多个标志。 请注意,大多数应用程序应设置 CRYPT_VERIFYCONTEXT 标志,除非它们需要创建数字签名或解密消息。

价值 意义
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
默认情况下,密钥和密钥容器存储为用户密钥。 对于基本提供程序,这意味着用户密钥容器存储在用户的配置文件中。 管理员创建没有此标志的密钥容器只能由创建密钥容器的用户和具有管理权限的用户访问。

Windows XP:只有创建密钥容器和本地系统帐户的用户才能访问管理员创建没有此标志的密钥容器。

没有此标志的用户创建的密钥容器不能由创建密钥容器和本地系统帐户的用户访问。

CRYPT_MACHINE_KEYSET标志可以与其他所有标志结合使用,以指示感兴趣的密钥容器是计算机密钥容器,CSP 将它视为此类容器。 对于基础提供程序,这意味着密钥存储在创建密钥容器的计算机上。 如果密钥容器是计算机容器,则CRYPT_MACHINE_KEYSET标志必须与引用计算机容器 CryptAcquireContext 的所有调用一起使用。 管理员使用CRYPT_MACHINE_KEYSET创建的密钥容器只能由其创建者和具有管理员 权限的用户访问,除非使用 CryptSetProvParam授予对容器的访问权限。

Windows XP:管理员使用CRYPT_MACHINE_KEYSET创建的密钥容器只能由其创建者和本地系统帐户访问,除非 使用 cryptSetProvParam授予对容器的访问权限。

由不是管理员的用户创建的密钥容器只能由其创建者和本地系统帐户访问,除非使用 CRYPT_MACHINE_KEYSET CryptSetProvParam授予对容器的访问权限。

当用户从未以交互方式登录的服务或用户帐户进行访问时,CRYPT_MACHINE_KEYSET标志非常有用。 创建密钥容器时,大多数 CSP 不会自动创建任何 公钥/私钥对。 必须使用 CryptGenKey 函数将这些密钥创建为单独的步骤。

CRYPT_DELETEKEYSET
删除由 pszContainer指定的 密钥容器。 如果 pszContainer为 NULL,则会删除具有默认名称的密钥容器。 密钥容器中 的所有 密钥对也会销毁。

设置此标志时,phProv 中返回的值是未定义的,因此,以后无需调用 CryptReleaseContext 函数。

CRYPT_SILENT
应用程序请求 CSP 不为此 上下文显示任何用户界面(UI)。 如果 CSP 必须显示要运行的 UI,则调用将失败,并将NTE_SILENT_CONTEXT错误代码设置为最后一个错误。 此外,如果调用使用CRYPT_SILENT标志获取的上下文 CryptGenKey CRYPT_USER_PROTECTED,则调用将失败,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 中定义的一些可能的错误代码遵循。

返回代码/值 描述
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 参数设置为 NULLdwFlags 参数在不需要持久密钥的所有情况下 CRYPT_VERIFYCONTEXT。 具体而言,请考虑将 pszContainer 参数设置为 NULL,并将 dwFlags 参数设置为以下方案 CRYPT_VERIFYCONTEXT

  • 正在创建哈希。
  • 你正在生成对称密钥来加密或解密数据。
  • 从哈希派生对称密钥以加密或解密数据。
  • 正在验证签名。 可以使用 CryptImportKeyCryptImportPublicKeyInfo从 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 [仅限桌面应用]
目标平台 窗户
标头 wincrypt.h
Advapi32.lib
DLL Advapi32.dll

另请参阅

CryptGenKey

CryptGetProvParam

CryptReleaseContext

服务提供程序函数

加密服务提供商的线程处理问题