在C#中从x509证书字节中读取RSA公钥

4
在C#中,我正在从HTTP请求中检索RSA公钥,并且它以base64编码的形式给出。
WebClient webClient = new WebClient();
string rsaPublicKeyBase64 = webClient.DownloadString("http://localhost:8000/getkey");
// rsaPublicKeyBase64 = LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlHZk1BMEdDU3FHU0liM0RRRUJBUVVBQTRHTkFEQ0JpUUtCZ1FEdDAwcXQ2Zi9UUXdMQmVsVExRdVlXb05xSQoxbmRkcFpaOGh0WWs4d0NLbmFuRFJpWkJ1NVo5NnBNT01yNi84RS9JUzB0amV4WGdsVjh0WFlKK0NKc1lDUHhoCnBDUkduUW9rYkE2MnpOODVXNEROVUNMQ0cyMXlXcndscFhjSmxLYkY2dFhxdmd3TGRQb2RwZzUwY3RrWkI4R0UKbDBLS3VOV3JHZXRad045V0NRSURBUUFCCi0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLQo=

然后我解码Base64格式的RSA公钥。

byte[] rsaPublicKey = Convert.FromBase64String(rsaPublicKeyBase64);
/*
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDt00qt6f/TQwLBelTLQuYWoNqI
1nddpZZ8htYk8wCKnanDRiZBu5Z96pMOMr6/8E/IS0tjexXglV8tXYJ+CJsYCPxh
pCRGnQokbA62zN85W4DNUCLCG21yWrwlpXcJlKbF6tXqvgwLdPodpg50ctkZB8GE
l0KKuNWrGetZwN9WCQIDAQAB
-----END PUBLIC KEY-----
*/

我的下一步是将包含RSA公钥证书的byte[]转换为RSACryptoServiceProvider类型。我在网上找到了答案,但似乎都不适用于我。

这是我目前拥有的代码(不起作用):

string rsaPublicKeyFile = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
X509Certificate2 cert = null;
try {
    File.WriteAllBytes(rsaPublicKeyFile, rsaPublicKey);
    cert = new X509Certificate2(rsaPublicKeyFile);
} finally {
    File.Delete(rsaPublicKeyFile);
}

我收到了如下截图所示的未处理异常错误。 Unhandled Exception Error
System.Security.Cryptography.CryptographicException: 'Cannot find the requested object.

您不需要创建X509Certificate2对象。而且您无法仅从公钥创建它。您需要直接将密钥加载到“PublicKey”对象中。 - Crypt32
@Crypt32 你能提供一个例子吗? - Ari Seyhun
这里是:https://msdn.microsoft.com/zh-cn/library/system.security.cryptography.x509certificates.publickey(v=vs.110).aspx - Crypt32
@Crypt32这种情况没有示例。链接包含了如何使用证书*.crt和*.pfx文件的示例,但问题涉及到其他类型的数据。 如果我说错了,您能否提供更精确的答案? - Anatoliy
1个回答

3

感谢@Crypt32的帮助,我通过参考PublicKey类文档解决了这个问题。

我编写了一个函数GetCertificateFromBytes(byte[] cert),它会写入临时文件以便读取证书:

public static X509Certificate2 GetCertificateFromBytes(byte[] cert) {
    string certFile = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
    try {
        File.WriteAllBytes(certFile, cert);

        X509Store store = new X509Store(StoreLocation.CurrentUser);
        try {
            store.Open(OpenFlags.ReadOnly);
            X509Certificate2Collection certCollection = store.Certificates;
            return certCollection[0];
        } finally {
            store.Close();
        }
    } finally {
        File.Delete(certFile);
    }
}

加密步骤:

X509Certificate2 cert = GetCertificateFromBytes(rsaPublicKey);
RSACryptoServiceProvider publicKeyProvider = (RSACryptoServiceProvider)cert.PublicKey.Key;
byte[] encrypted = publicKeyProvider.Encrypt(data, false);

3
很奇怪:你从本地存储中得到了第一个证书,它与你保存在文件系统中的证书无关。这可以运行,因为证书是有效的且具有支持格式,但它并不是你的证书,而是完全不同的证书。不幸的是,我还没有找到好的解决方案。 - Anatoliy
6
这是不正确的:证书字节已保存,但从未读取。该示例继续通过加载当前用户存储中的第一个证书来进行。 - Carlo Bos

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接