本文提供有关调用 CryptAcquireContext 时何时使用特定标志的信息以及使用这些标志的原因。
原始 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)页下运行。
- 组件是Microsoft事务服务器(MTS)组件。 对于这些示例,将使用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可能会解决问题,具体取决于正在使用的提供程序。