为什么我在重新启动时丢失了我的密钥容器?

Why do I lose my key container when I reboot?

多年来,我们一直将强名称密钥保存在密钥容器中。 Visual Studio 不直接支持它,但是,如果您只编辑 .csproj 文件并添加:

,它就可以正常工作
<KeyContainerName>MyKeyName</KeyContainerName>

我们通过以下方式将密钥安装到密钥库中:

sn -m Y
sn -i MyKeyFile.snk MyKeyName

然后我们可以从那台机器上删除 MyKeyFile.snk,这样密钥就更安全了。

最近重启后出现这个问题。我们怀疑这个问题是由 VS 2015 引入的,但它可能是由 Windows 8 and/or 10 引起的。我们将密钥安装到密钥容器中,一切正常。然后,我们重新启动那台机器,构建失败并显示:

CSC : error CS7028: Error signing output with public key from container 'MyKeyName' -- Keyset does not exist (Exception from HRESULT: 0x80090016)

看起来密钥容器在重新启动时丢失了,但是,如果我们这样做:

sn -m Y
sn -i MyKeyFile.snk MyKeyName

它失败了:

Failed to install key pair -- Object already exists.

我们必须使用 sn -d 删除密钥容器,然后再将其添加回来,Visual Studio 很高兴。

这是怎么回事?为什么在 sn 可以看到的情况下 Visual Studio 重启后看不到我们的密钥容器?密钥容器实际存放在哪里?

首先,使用"sn -m"命令在基于机器的密钥和基于用户的密钥之间切换时需要小心。该命令区分大小写,无效值的处理就像未指定值一样,显示当前设置。因此,"sn -m Y" 不启用基于机器的密钥,您必须说 "sn -m y"(小写 y 或 n)。

CSC.exe 的当前版本似乎只使用基于机器的密钥。我不知道这是否是最近的更改,但这是我在使用 .NET V4.6 和 VS 2015 时观察到的行为。

机器密钥保存在 C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys。当您执行 "sn -i file.snk name" 安装密钥时,会在该目录中创建一个文件。该文件以几个 GUID 命名,因此您必须查看修改日期才能确定刚刚创建的文件。

如果您检查新文件的属性并查看 "Security" 选项卡,您将看到一个 "LogonSessionId_n_nnn" 条目。 ACL 中的该条目授予您的登录会话访问权限,但如果您重新启动,您将获得不同的登录会话,因此该条目不再授予您访问权限。这就是为什么我们可以安装强名称密钥并使用它们直到我们重新启动。它还解释了为什么在重新安装之前需要删除密钥,密钥仍然存在,但我们无法访问它。

您可以编辑该文件的 ACL 并授予自己 "Read, Read & Execute" 使用 AD 用户名或组的访问权限,强名称密钥即使在重新启动后也可以使用。