C# 如何从pfx/cer创建snk?

C# 如何从pfx/cer创建snk?,c#,.net,x509certificate,pfx,snk,C#,.net,X509certificate,Pfx,Snk,微软似乎创造了一个难以理解的认证丛林 Microsoft X.509证书(.cer) 个人信息交换(.pfx) 程序集签名密钥属性(.snk) 是否建议基于pfx或cer创建snk文件? (不确定这是否可能,如果可能,怎么做?) 虽然可以使用受密码保护的pfx对程序集进行签名,但是 但似乎不是很有名,除非是与snk签署的 相反但是snk没有密码保护。哪个更安全 使用?因为我是我项目中唯一的开发者,所以我没有 多开发者安全环境问题,但仍希望 知道什么是最好的方法 非常感谢,要从pfx生成sn

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

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

  • 是否建议基于pfx或cer创建snk文件? (不确定这是否可能,如果可能,怎么做?)

  • 虽然可以使用受密码保护的pfx对程序集进行签名,但是 但似乎不是很有名,除非是与snk签署的 相反但是snk没有密码保护。哪个更安全 使用?因为我是我项目中唯一的开发者,所以我没有 多开发者安全环境问题,但仍希望 知道什么是最好的方法


非常感谢,

要从pfx生成snk文件:

sn -p keypair.pfx key.snk

我一直非常喜欢使用snk文件而不是.pfx文件,因为它们似乎没有那么多问题。

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

  • .cer文件是X.509证书
  • .pfx文件是使用基于密码的对称密钥加密的X.509证书,另请参见
  • .snk文件仅包含RSA密钥(公用/专用或仅公用)
不管您是使用.pfx文件还是.snk文件对程序集进行签名,它都会以强名称命名。 将RSA密钥存储为加密证书(.pfx)当然比仅存储未加密密钥(.snk)更安全

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

要从.pfx中提取密钥,请执行以下操作:
//
///将.pfx文件转换为.snk文件。
/// 
///.pfx文件数据。
///.pfx文件密码。
///.snk文件数据。
公共静态字节[]Pfx2Snk(字节[]pfxData,字符串pfxPassword)
{
//加载.pfx
var cert=新的X509Certificate2(pfxData、pfxPassword、X509keystrageFlags.Exportable);
//创建.snk
var privateKey=(rsacyptoserviceprovider)cert.privateKey;
返回privateKey.ExportCspBlob(true);
}

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

以下是his中提供的相同方法,但已转换为PowerShell脚本(pfx2snk.ps1)。

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

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

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

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

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

而且,如果您感兴趣,我在VisualStudio中的后期构建过程中有如下内容,可以将authenticode签名添加到项目输出中(无论如何,在“发布”项目配置中)


这在VS2010中给了我一个错误:密钥文件“key.snk”不包含公钥/私钥对。您正在使用的pfk可能不完整,我在使用Verisign提供的.pfk文件时遇到了这个问题,特别是在它们提供.pfk、.cer、,和.pfx文件分开。p使其仅在snk中存储证书的公共部分。由于您没有私钥,因此不能使用生成的snk进行签名,除了延迟签名,延迟签名不会改变结束…您可以使用
sn-k keypair.snk
生成公钥和私钥。我一点也不知道私钥是从哪里来的,但至少它对我来说是有用的。(很抱歉死掉了这个线程)@Slampisko-FYI,来自
-k
选项“生成一个新的…密钥”。这就是为什么您不必引用已发布的现有.pfxI。我在VB中这样做是为了见鬼。这对我不起作用。我在尝试在VS2013中使用时出现加密错误。编辑队列已满,或者我要在上面添加:使用System.Security.Cryptography.X509Certificates;使用System.Security.Cryptography;谢谢出于某种原因,最后一行没有为我输出文件,而是将其替换为:
Set Content-Path“$snkFilePath”-Value$snkBytes-Encoding Byte
修复了该问题。该文件似乎放在我运行脚本的上方目录中。我将脚本的最后一行更改为:[IO.File]::writealBytes((Join Path-Path(Get Location)-ChildPath$snkFileName),$snkBytes);
/// <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);
}
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);
powershell.exe -File pfx2snk.ps1 -pfxFilePath cert.pfx -pfxPassword "pfx password"
powershell.exe -File pfx2snk.ps1 cert.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));"
powershell.exe -Command "Set-AuthenticodeSignature -FilePath '$(TargetPath)' -Certificate '$(SolutionDir)MyCert.pfx' -TimestampServer http://timestamp.verisign.com/scripts/timstamp.dll -HashAlgorithm sha256;"