启动与系统组件

使用和排查 CryptAcquireContext 函数的问题 - Windows Server

· 52CE 我爱测

本文提供有关调用 CryptAcquireContext 时何时使用特定标志的信息以及使用这些标志的原因。 原始 KB 数: 238187 总结 对函数的 CryptAcquireContext 调用可以包括各种标志。 请务必了解何时使用这些标志。 本文提供有关调用 CryptAcquireContext 时何时使用特定标志以及使用这些标志的原因的信息。 详细信息 未执行私钥操作 如果不使用持久私钥,则调用 CryptAcquireContext 时,可以

本文提供有关调用 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可能会解决问题,具体取决于正在使用的提供程序。

资料来源与适用范围

资料来源
微软官方中文故障文档
适用范围
按正文的 Windows / Windows Server 适用版本;保留原文兼容性要求
内容语言
中文;命令、路径和错误标识保留技术原文
本地收录日期
2026-10-26
授权说明
CC BY 4.0

正文与所需资源由本站本地存储。查看来源及更新记录 ↗

请按适用版本和实际日志确认原因;本站没有对每一种系统或设备逐项执行文中的操作。