cryptAcquireContextA 函数 (wincrypt.h)

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

此函数首先尝试查找具有 dwProvTypepszProvider 参数中描述的特征的 CSP。 如果找到 CSP,该函数将尝试在 CSP 中查找与 pszContainer 参数指定的名称匹配的密钥容器。 若要获取与证书公钥关联的私钥上下文密钥容器,请使用 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 将其密钥容器存储在硬件) 内部 (中,有些 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 的所有调用。 管理员使用 CRYPT_MACHINE_KEYSET 创建的密钥容器只能由其创建者和具有管理员 特权 的用户访问,除非使用 CryptSetProvParam 授予对容器的访问权限。

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

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

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

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

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

CRYPT_SILENT
应用程序请求 CSP 不为此 上下文显示任何用户界面 (UI) 。 如果 CSP 必须显示 UI 才能运行,则调用会失败,并且NTE_SILENT_CONTEXT错误代码设置为最后一个错误。 此外,如果使用 CRYPT_USER_PROTECTED 标志对 CryptGenKey 进行调用,并且该标志具有已使用 CRYPT_SILENT 标志获取的上下文,则调用将失败,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 之间(包括 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
Library Advapi32.lib
DLL Advapi32.dll

另请参阅

CryptGenKey

CryptGetProvParam

CryptReleaseContext

服务提供程序函数

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