Search code examples
c#encryptionrsax509certificatex509certificate2

Read RSA Public Key from x509 Certificate Bytes in C#


In C#, I'm retrieving an RSA public key from a HTTP request and it gives me the key encoded in base64.

WebClient webClient = new WebClient();
string rsaPublicKeyBase64 = webClient.DownloadString("http://localhost:8000/getkey");
// rsaPublicKeyBase64 = LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlHZk1BMEdDU3FHU0liM0RRRUJBUVVBQTRHTkFEQ0JpUUtCZ1FEdDAwcXQ2Zi9UUXdMQmVsVExRdVlXb05xSQoxbmRkcFpaOGh0WWs4d0NLbmFuRFJpWkJ1NVo5NnBNT01yNi84RS9JUzB0amV4WGdsVjh0WFlKK0NKc1lDUHhoCnBDUkduUW9rYkE2MnpOODVXNEROVUNMQ0cyMXlXcndscFhjSmxLYkY2dFhxdmd3TGRQb2RwZzUwY3RrWkI4R0UKbDBLS3VOV3JHZXRad045V0NRSURBUUFCCi0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLQo=

I then decode the base 64 RSA public key.

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

My next step is to convert this byte[] containing my RSA public key certificate into type RSACryptoServiceProvider. I've found answers online, but none seem to work for me.

Here's what I currently have (which does not work).

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);
}

I receive an unhandled exception error shown in the screenshot below.

Unhandled Exception Error

System.Security.Cryptography.CryptographicException: 'Cannot find the requested object.

Solution

  • Thanks to @Crypt32, I managed to solve it by referencing the PublicKey Class documentation

    I wrote a function GetCertificateFromBytes(byte[] cert) which writes to a temporary file in order to read the certificate:

    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);
        }
    }
    

    Then to Encrypt:

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