CryptAcquireContext() 失败,返回代码 0x8009000B NTE_BAD_KEY_STATE - 但用户密码尚未更改

use*_*443 4 vb6 encryption winapi handle

我的公司有一个用vb6编译的程序,在使用该软件之前需要验证加密的许可证代码。最近,有客户打电话说许可证代码验证失败,程序被锁定。经过一番调查,我发现代码在调用 CryptAcquireContext 时失败,错误代码为 0x8009000B (NTE_BAD_KEY_STATE)。CryptAcquireContext 的 Microsoft 支持页面指出,此错误意味着“自私钥加密以来,用户密码已更改”。

客户最近电脑出现问题,所以安装了新的固态硬盘并重新安装了Win7。但是,他确信他的用户密码没有更改,服务器密码也没有更改(用户计算机包含指向服务器上可执行文件的快捷方式,没有其他用户遇到此问题)。在搜索了一些 Microsoft 论坛后,很明显其他人也遇到过此错误(也具有相同的密码),并且在每种情况下,它都是高度偶发的,并且对于使用相同程序的机器系统中的一台计算机来说通常是唯一的。我所审查的每一个案例都走向了死胡同;微软对这个错误非常无助,我已经用尽了我在谷歌上的研究能力。

这是失败的代码片段。对于我在这个特定领域缺乏知识,我深表歉意,我们的程序用于加密/解密的类来自开源项目(cCrypt 类模块 - Kevin Wilson)

If CryptAcquireContext(lngCryptProv, 0, p_CSP_String, p_CSP_Type, 0) = 0 Then
    
    ' If there is no default key container then create one using Flags field'

    CheckGetLastError Err.LastDllError, Return_ErrNum, Return_ErrDesc, "CryptAcquireContext", False

    If Return_ErrNum = -2146893802 Then
      Return_ErrNum = 0
      Return_ErrDesc = ""
        
      If CryptAcquireContext(lngCryptProv, 0, p_CSP_String, p_CSP_Type, CRYPT_NEWKEYSET) = 0 Then

        CheckGetLastError Err.LastDllError, Return_ErrNum, Return_ErrDesc, "CryptAcquireContext", False
        Exit Function

      End If
    Else
      Exit Function
    End If
  End If
Run Code Online (Sandbox Code Playgroud)

这是对 CryptAcquireContext 的第一次调用失败。我尝试绕过第一个调用并直接使用标志 CRYPT_NEWKEYSET 进入第二个调用,但该调用也失败了。

附言。这是 Microsoft 论坛上的一个很好的例子,其中有人在没有更改密码的情况下遇到了同样的问题,并且 Microsoft 代表最终停止回复(可以为您提供一些额外的信息):

https://groups.google.com/forum/#!topic/microsoft.public.platformsdk.security/XhzsN9HQWjk

use*_*443 5

我通过将 CryptAcquireContext (0) 中的最后一个参数更改为 CRYPT_VERIFYCONTEXT 标志来修复此问题。看起来现在工作正常!