42

微软似乎创造了一个认证丛林,这很难理解。

  • Microsoft X.509 证书 (.cer)
  • 个人信息交换 (.pfx)
  • 程序集签名密钥属性 (.snk)

    1. 是否建议基于 pfx 或 cer 创建一个 snk 文件?(不确定它是否可能,如果可能,它是如何完成的?)

    2. 虽然可以使用受密码保护的 pfx 对程序集进行签名,但它似乎不是强命名的,除非它使用 snk 进行签名。但是snk没有密码保护。使用哪一种更安全?由于我是我项目中唯一的开发人员,我没有多开发人员安全环境问题,但仍然想知道什么是最好的方法。

非常感谢,

4

3 回答 3

41

关于您提到的文件类型的一点说明:

  • .cer文件是 X.509 证书
  • .pfx文件是使用基于密码的对称密钥加密的 X.509 证书,另请参阅PKCS #12(维基百科)
  • .snk -文件仅包含 RSA 密钥(仅公共/私有或公共)

使用.pfx -files 或.snk -files 对程序集进行签名都没关系,无论哪种方式,它都会得到强命名。将 RSA 密钥存储为加密证书 ( .pfx ) 当然比仅存储未加密密钥 ( .snk ) 更安全。

您可以使用 class 轻松地从代码中的这些文件中提取密钥System.Security.Cryptography.X509Certificates.X509Certificate2

要从.pfx中提取密钥:

/// <summary>
/// Converts .pfx file to .snk file.
/// </summary>
/// <param name="pfxData">.pfx file data.</param>
/// <param name="pfxPassword">.pfx file password.</param>
/// <returns>.snk file data.</returns>
public static byte[] Pfx2Snk(byte[] pfxData, string pfxPassword)
{
    // load .pfx
    var cert = new X509Certificate2(pfxData, pfxPassword, X509KeyStorageFlags.Exportable);

    // create .snk
    var privateKey = (RSACryptoServiceProvider)cert.PrivateKey;
    return privateKey.ExportCspBlob(true);
}

仅用于privateKey.ExportCspBlob(false)提取公钥!(例如,对于程序集的延迟签名)

于 2012-07-12T22:09:21.690 回答
32

要仅使用来自 pfx 的公钥生成 snk 文件:

sn -p keypair.pfx key.snk

我一直喜欢使用 snk 文件而不是 .pfx 文件,它们看起来不那么容易出错。

于 2012-03-27T22:34:21.483 回答
18

这是@Sir Kill A Lot在他的回答中提供的相同方法,但已转换为 PowerShell 脚本 ( pfx2snk.ps1 )。

Param(
    [Parameter(Mandatory=$True,Position=1)]
    [string] $pfxFilePath,
    [string] $pfxPassword
)

# The path to the snk file we're creating
[string] $snkFilePath = [IO.Path]::GetFileNameWithoutExtension($pfxFilePath) + ".snk";

# Read in the bytes of the pfx file
[byte[]] $pfxBytes = Get-Content $pfxFilePath -Encoding Byte;

# Get a cert object from the pfx bytes with the private key marked as exportable
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2(
    $pfxBytes,
    $pfxPassword,
    [Security.Cryptography.X509Certificates.X509KeyStorageFlags]::Exportable);

# Export a CSP blob from the cert (which is the same format as an SNK file)
[byte[]] $snkBytes = ([Security.Cryptography.RSACryptoServiceProvider]$cert.PrivateKey).ExportCspBlob($true);

# Write the CSP blob/SNK bytes to the snk file
[IO.File]::WriteAllBytes($snkFilePath, $snkBytes);

只需运行提供 pfx 文件路径和密码的脚本,它就会在与 pfx 文件相同的目录中创建一个 snk 文件(除了扩展名之外具有相同的名称)。

powershell.exe -File pfx2snk.ps1 -pfxFilePath cert.pfx -pfxPassword "pfx password"

或者,如果您的 pfx 没有密码(可耻,可耻):

powershell.exe -File pfx2snk.ps1 cert.pfx

而且,如果您不幸在不允许执行 PowerShell 脚本的环境中工作(即仅交互式 PowerShell 会话),那么您可以从标准 cmd.exe 命令行(根据需要替换文件路径和 pfx 密码)。

powershell.exe -Command "[IO.File]::WriteAllBytes('SnkFilePath.snk', ([Security.Cryptography.RSACryptoServiceProvider](New-Object System.Security.Cryptography.X509Certificates.X509Certificate2((Get-Content 'PfxFilePath.pfx' -Encoding Byte), 'PfxPassword', [Security.Cryptography.X509Certificates.X509KeyStorageFlags]::Exportable)).PrivateKey).ExportCspBlob($true));"

实际上,我使用该单行代码作为我的 Visual Studio 预构建过程的标准部分,以自动化使用来自我们的身份验证签名证书(pfx 文件)的相同密钥进行强名称签名的过程。这不是一个要求,但对我来说,它们应该是相同的似乎是有道理的,并且它助长了我的强迫症倾向。

(我使用 snk 文件而不是原始 pfx,因为我有使用 pfx 文件进行强名称签名的“错误”经验,@punkcoder在他的回答中提到)

而且,如果您有兴趣,我在 Visual Studio 中的后期构建过程中有类似以下内容的内容,以将身份验证签名添加到项目输出中(无论如何在“发布”项目配置中)。

powershell.exe -Command "Set-AuthenticodeSignature -FilePath '$(TargetPath)' -Certificate '$(SolutionDir)MyCert.pfx' -TimestampServer http://timestamp.verisign.com/scripts/timstamp.dll -HashAlgorithm sha256;"
于 2016-09-17T17:45:13.763 回答