【问题标题】:How to create a snk from pfx / cer?如何从 pfx / cer 创建 snk?
【发布时间】:2011-11-17 21:00:11
【问题描述】:

微软似乎创造了一个难以理解的认证丛林。

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

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

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

非常感谢,

【问题讨论】:

    标签: c# .net x509certificate pfx snk


    【解决方案1】:

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

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

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

    您可以使用 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) 提取公钥! (例如,用于程序集的延迟签名)

    【讨论】:

    • 我已经发布了a command-line tool based on this in source code form on github。我是在 VB 中完成的。
    • 这对我不起作用我尝试在 VS2013 中使用时遇到加密错误。
    • 编辑队列已满,或者我会在上面添加: using System.Security.Cryptography.X509Certificates;使用 System.Security.Cryptography;
    【解决方案2】:

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

    sn -p keypair.pfx key.snk
    

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

    【讨论】:

    • 这在 VS2010 中给了我这个错误:密钥文件 'key.snk' 不包含公钥/私钥对。
    • 您使用的 pfk 可能不完整,我在使用 Verisign 提供的 .pfk 文件时遇到了这个问题,特别是它们分别提供 .pfk、.cer 和 .pfx 文件.
    • -p 使它只将证书的公共部分存储在 snk 中。由于您没有私钥,因此您无法使用生成的 snk 进行签名,除了延迟签名,它不会改变结尾...
    • 您可以使用sn -k keypair.snk 来生成公钥和私钥。我不知道它从哪里获取私钥,但至少它适用于我的目的。 (很抱歉破坏了这个线程)
    • @Slampisko 仅供参考,来自MSDN -k 选项“生成一个新的……密钥”。这就是为什么您不必引用现有的 .pfx
    【解决方案3】:

    这是@Sir Kill A Lot 在他的answer 中提供的相同方法,但已转换为 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;"
    

    【讨论】:

    • 谢谢!由于某种原因,最后一行没有为我输出文件,而是将其替换为:Set-Content -Path "$snkFilePath" -Value $snkBytes -Encoding Byte 修复了该问题。
    • 该文件似乎放在上面我运行脚本的目录中。我将脚本的最后一行更改为: [IO.File]::WriteAllBytes((Join-Path -Path (Get-Location) -ChildPath $snkFileName), $snkBytes);
    猜你喜欢
    • 1970-01-01
    • 2022-12-11
    • 2016-08-10
    • 1970-01-01
    • 2013-09-10
    • 2018-07-05
    • 2012-08-13
    • 1970-01-01
    相关资源
    最近更新 更多