CryptAcquireContextA 函数 (wincrypt.h)
此函数首先尝试查找具有 dwProvType 和 szProvider 参数中所述特征的 CSP。 如果找到 CSP,函数会尝试在 CSP 中查找与 szContainer 参数指定的名称匹配的密钥容器。 若要获取与证书公钥关联的私钥的上下文和密钥容器,请使用 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 时, szContainer 必须设置为 NULL。 但是,对于基于硬件的 CSP,例如智能卡 CSP,可以访问指定容器中的公开可用信息。
有关 szContainer 参数用法的详细信息,请参阅备注。
[in] szProvider
一个以 null 结尾的字符串,包含要使用的 CSP 的名称。
如果此参数为 NULL,则使用用户默认提供程序。 有关详细信息,请参阅 加密服务提供程序上下文。 有关可用加密提供程序的列表,请参阅 加密提供程序名称。
应用程序可以使用 CryptGetProvParam 函数读取 dwParam 参数中的PP_NAME CSP 值,从而获取正在使用的 CSP 的名称。
默认 CSP 可以在操作系统版本之间更改。 若要确保不同操作系统平台上的互操作性,应使用此参数而不是默认 CSP 显式设置 CSP。
[in] dwProvType
指定要获取的提供程序的类型。 加密提供程序类型中讨论了定义的 提供程序类型。
[in] dwFlags
标记值。 此参数通常设置为零,但某些应用程序会设置以下一个或多个标志。
值 | 含义 |
---|---|
|
此选项适用于使用临时密钥的应用程序,或不需要访问持久化私钥的应用程序,例如仅执行 哈希、 加密和 数字签名 验证的应用程序。 只有创建签名或解密消息的应用程序需要访问 私钥。 在大多数情况下,应设置此标志。
对于基于文件的 CSP,设置此标志时, 必须将 szContainer 参数设置为 NULL。 应用程序无法访问公钥/私钥对的持久私钥。 设置此标志后,可以创建临时 公钥/私钥对 ,但不会保留它们。 对于基于硬件的 CSP(例如智能卡 CSP),如果 szContainer 参数为 NULL 或空白,则此标志表示不需要访问任何密钥,并且不应向用户显示 UI。 此表单用于连接到 CSP 以查询其功能,但不能实际使用其密钥。 如果 szContainer 参数不是 NULL 且不为空,则此标志意味着需要仅访问指定容器中的公开可用信息。 CSP 不应要求输入 PIN。 尝试访问私人信息 (例如, CryptSignHash 函数) 将失败。 调用 CryptAcquireContext 时,许多 CSP 在授予对密钥 容器中的私钥的访问权限之前,都需要拥有用户的输入。 例如,可以加密私钥,要求用户提供密码才能使用。 但是,如果指定 了CRYPT_VERIFYCONTEXT 标志,则不需要访问私钥,并且可以绕过用户界面。 |
|
使用 szContainer 指定的名称创建新的密钥容器。 如果 szContainer 为 NULL,则会创建具有默认名称的密钥容器。 |
|
默认情况下,密钥和密钥容器存储为用户密钥。 对于基本提供程序,这意味着用户密钥容器存储在用户的配置文件中。 只有创建密钥容器的用户和具有管理权限的用户才能访问管理员创建的不带此标志的密钥容器。
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 函数的单独步骤创建。 |
|
删除 szContainer 指定的密钥容器。 如果 szContainer 为 NULL,则删除具有默认名称的密钥容器。 密钥容器中的所有 密钥对 也会被销毁。
设置此标志时, phProv 中返回的值未定义,因此以后无需调用 CryptReleaseContext 函数。 |
|
应用程序请求 CSP 不显示此 上下文的任何用户界面 (UI) 。 如果 CSP 必须显示要运行的 UI,则调用会失败,并且NTE_SILENT_CONTEXT错误代码设置为最后一个错误。 此外,如果使用 CRYPT_USER_PROTECTED 标志对 CryptGenKey 进行调用,其上下文是使用 CRYPT_SILENT 标志获取的,则调用会失败,CSP 设置NTE_SILENT_CONTEXT。
CRYPT_SILENT适用于 CSP 无法显示 UI 的应用程序。 |
|
获取智能卡 CSP 的上下文,该上下文可用于哈希和对称密钥操作,但不能用于需要使用 PIN 对智能卡进行身份验证的任何操作。 这种类型的上下文最常用于对空智能卡执行操作,例如使用 CryptSetProvParam 设置 PIN。 此标志只能与智能卡 CSP 一起使用。
Windows Server 2003 和 Windows XP: 不支持此标志。 |
返回值
如果函数成功,则函数) 返回非零 (TRUE 。
如果函数失败,则返回零 (FALSE) 。 有关扩展的错误信息,请调用 GetLastError。
NTE 开头的错误代码由使用的特定 CSP 生成。 Winerror.h 中定义的一些可能的错误代码如下所示。
返回代码/值 | 说明 |
---|---|
|
如果设置了CRYPT_DELETEKEYSET标志值并且另一个线程或 进程 使用此 密钥容器,则某些 CSP 会设置此错误。 |
|
未加载用户的配置文件,并且找不到。 当应用程序模拟用户(例如,IUSR_ComputerName 帐户)时,就会发生这种情况。 |
|
其中一个参数包含无效的值。 这通常是无效的指针。 |
|
操作系统在操作期间内存不足。 |
|
dwFlags 参数的值无效。 |
|
自私钥加密以来,用户密码已更改。 |
|
无法打开密钥容器。 此错误的常见原因是密钥容器不存在。 若要创建密钥容器,请使用 CRYPT_NEWKEYSET 标志调用 CryptAcquireContext 。 此错误代码也可能指示拒绝访问现有密钥容器。 密钥集创建者可以使用 CryptSetProvParam 授予对容器的访问权限。 |
|
szContainer 或 szProvider 参数设置为无效的值。 |
|
dwProvType 参数的值在范围外。 所有提供程序类型都必须介于 1 到 999 之间(包括 1 到 999)。 |
|
无法验证提供程序 DLL 签名。 DLL 或数字签名已被篡改。 |
|
dwFlags 参数CRYPT_NEWKEYSET,但密钥容器已存在。 |
|
找到 szContainer 密钥容器,但已损坏。 |
|
请求的提供程序不存在。 |
|
CSP 在操作期间内存不足。 |
|
提供程序 DLL 文件不存在或不在当前路径中。 |
|
dwProvType 指定的提供程序类型已损坏。 此错误可能与用户默认 CSP 列表或计算机默认 CSP 列表有关。 |
|
dwProvType 指定的提供程序类型与找到的提供程序类型不匹配。 请注意,只有在 szProvider 指定实际的 CSP 名称时,才会发生此错误。 |
|
dwProvType 指定的提供程序类型不存在任何条目。 |
|
提供程序 DLL 文件无法加载或初始化失败。 |
|
在验证 DLL 文件映像签名之前加载 DLL 文件映像时出错。 |
注解
szContainer 参数指定用于保存密钥的容器的名称。 每个容器可以包含一个密钥。 如果在创建密钥时指定现有容器的名称,则新密钥将覆盖以前的密钥。
CSP 名称和密钥容器名称的组合唯一标识系统上的单个密钥。 如果一个应用程序尝试修改密钥容器,而另一个应用程序正在使用密钥容器,可能会导致不可预知的行为。
如果将 szContainer 参数设置为 NULL,则使用默认密钥容器名称。 以这种方式调用 Microsoft 软件 CSP 时,每次调用 CryptAcquireContext 函数时,都会创建一个新容器。 但是,不同的 CSP 在这方面的行为可能不同。 具体而言,CSP 可能有一个默认容器,该容器由访问 CSP 的所有应用程序共享。 因此,应用程序不得使用默认密钥容器来存储私钥。 相反,可以通过在 dwFlags 参数中传递 CRYPT_VERIFYCONTEXT 标志来阻止密钥存储,或者使用其他应用程序不太可能使用的应用程序特定容器。
应用程序可以通过使用 CryptGetProvParam 函数读取PP_CONTAINER值来获取正在使用的密钥容器的名称。
出于性能原因,建议在不需要持久密钥的所有情况下,将 szContainer 参数设置为 NULL ,并将 dwFlags 参数设置为 CRYPT_VERIFYCONTEXT 。 具体而言,请考虑将 szContainer 参数设置为 NULL ,将 dwFlags 参数设置为 CRYPT_VERIFYCONTEXT 以下方案:
- 正在创建哈希。
- 你正在生成对称密钥来加密或解密数据。
- 你要从哈希派生对称密钥来加密或解密数据。
- 正在验证签名。 可以使用 CryptImportKey 或 CryptImportPublicKeyInfo 从 PUBLICKEYBLOB 或证书导入公钥。 如果仅计划导入公钥,则可以使用 CRYPT_VERIFYCONTEXT 标志获取上下文。
- 你计划导出对称密钥,但不在加密上下文的生存期内导入它。 如果只计划为最后两个方案导入公钥,则可以使用 CRYPT_VERIFYCONTEXT 标志获取上下文。
- 你正在执行私钥操作,但未使用存储在密钥容器中的持久化私钥。
示例
以下示例演示如何获取加密上下文并访问密钥容器中的公钥/私钥对。 如果请求的密钥容器不存在,则会创建它。
有关包含此示例的完整上下文的示例,请参阅 示例 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 |