首页 文章

从PFX文件中读取私钥

提问于
浏览
4

我知道,有很多关于此的帖子,但我仍然无法找到解决方案来实现这一点 . 我在我的机器上生成了一个带有 openssl 的PFX文件,如下所示:

openssl x509 -req -days 365 -in "myReqest.csr" -signkey "myPrivateKey.pem" -out "myCertificate.crt"
openssl pkcs12 -export -out "myCertificate.pfx" -inkey "myPrivateKey.pem" -in "myCertificate.crt" -certfile "myCertificate.crt"

在我的C#应用程序中,我像这样访问私钥:

var cert = new X509Certificate2("myCertificate.pfx", "myPassword");
cert.HasPrivateKey; // This is always true!
cert.PrivateKey; // Works on my machine (only)

这完全正常(在我的机器上),但是当我在另一台机器上运行相同的代码时,它会抛出: "Key set not found" ,即使 HasPrivateKey 返回 true !私钥不应该包含在* .pfx文件中吗?你能告诉我吗:

  • 创建时,openssl是否以某种方式自动在我的机器上安装了证书/私钥?

  • 如何从* .PFX文件中读取私钥(或者从* .PEM文件中读取)?

StackTrace异常:

at System.Security.Cryptography.Utils.CreateProvHandle(CspParameters parameters, Boolean randomKeyContaier)
at System.Security.Cryptography.Utils.GetKeyPairHelper(CspAlgorithmType keyType, CspParameters parameters, Boolean randomKeyContaier, Int32 dwKeySize, SafeProvHandle& safeProvHandle, SafeKeyHandle& safeKeyHandle)
at System.Security.Cryptography.RSACryptoServiceProvider.GetKeyPair()
at System.Security.Cryptography.RSACryptoServiceProvider..ctor(Int32 dwKeySize, CspParameters parameters, Boolean useDefaultKeySize)
at System.Security.Cryptography.RSACryptoServiceProvider..ctor(CspParameters parameter)
at System.Security.Cryptography.X509Certificates.X509Certificate2.get_PrivateKey()

Update:

我发现,以下确实有效:

// on my machine
// read certificate from file (exportable!)
X509Certificate2 cert = new X509Certificate2("filename.pfx", "password", X509KeyStorageFlags.Exportable)
// sign data etc.
((RSACryptoServiceProvider)cert.PrivateKey).SignData(...
// export private key to XML-file
File.WriteAllText("filename.xml", cert.PrivateKey.ToXmlString(true));

// on the other machine
// create new RSA object
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
// import private key from xml
rsa.FromXmlString(File.ReadAllText("filename.xml"));
// verify data etc.
rsa.VerifyData(...

但是,对我来说,这只是一种解决方法,我想以更传统/标准的方式做到这一点!

5 回答

  • 2

    你必须像这样加载证书:

    X509Certificate2 cert = new X509Certificate2("a.pfx", "password", X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet)

    这篇文章解释了为什么http://paulstovell.com/blog/x509certificate2

  • 1

    也许您可以告诉我们更多关于您为什么要这样做的信息 . 当然有充分的理由想要这样做,例如编写一个程序,该程序将位于公司的内部服务器上以自动化产品构建 .

    但是,如果您打算在高信任区域之外分发此应用程序(例如,向客户),则答案是 DO NOT DO IT! 您永远不应该泄露您的私钥文件 . 这会打开你的密码暴力攻击(这肯定比私钥本身弱得多) . 如果您分发您的应用程序,那么您的密码将包含在MSIL代码的 plain text 中 . 在那里,可以使用任何托管代码反汇编程序(例如Reflector)轻松查看,甚至可以使用文本或十六进制编辑器查看它 .

    总之,将您的私钥文件与您的应用程序一起分发给某人允许他们使用您的证书轻松签署他们想要的任何内容 . 私钥的重点是将其安全地锁定在除了您(或您的组织等)之外的任何人都无法访问的位置 .

  • 3

    看起来,在.NET中没有直接的方法来做到这一点 . 因此,我现在决定直接从证书存储区加载证书:

    X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
    store.Open(OpenFlags.OpenExistingOnly | OpenFlags.ReadOnly);
    X509Certificate2Collection certificates = store.Certificates.Find(X509FindType.FindByThumbprint, CERTIFICATE_THUMB_PRINT, false);
    if (certificates.Count == 0)
    {
        // "Certificate not installed."
    }
    else
    {
        certificate = certificates[0];
    }
    store.Close();
    

    当然,如果必须在机器上安装 .

    我认为这是解决这个问题的一个很好的解决方案,因为它为它添加了额外的安全层(应用程序必须在安装证书的机器上运行,并且作为安装证书的用户,文件本身也可以存放在其他地方的安全地方) .

  • 2

    默认密钥集不是一个asp.net应用程序(即它没有用户配置文件) . 如果将X509KeyStorageFlags.MachineKeySet作为第三个参数传递给 X509Certificate2 构造函数,那么它应该在两台机器上以相同的方式工作 .

    它仅在访问 PrivateKey 属性时发生的原因是它是创建实际CSP对象以使用密钥的第一个位置 .

  • 0

    您也可以通过以下方法获取私人 .

    System.Security.Cryptography.X509Certificates.X509Certificate2 certificate = LoadCertificate("Certificate.pfx", "PasswordofCertificate");
    
    RSACryptoServiceProvider key = certificate.PrivateKey as RSACryptoServiceProvider;
    

    从证书变量,您还可以获取其他信息,如公钥等 .

相关问题