I am writing a .Net Standard 2.1 class library that implements some cryptographic logic. I need to create a RSACryptoServiceProvider object from .pfx file to create a signature for my OpenIdConnect provider. I use the following code to do that.
X509Certificate2 certificate = new X509Certificate2(filePath, password,
X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.Exportable);
var privateKey = certificate.PrivateKey as RSACryptoServiceProvider;
RSACryptoServiceProvider rsaProvider = new RSACryptoServiceProvider();
rsaProvider.FromXmlString(privateKey .ToXmlString(true));
var rsaFormatter = new RSAPKCS1SignatureFormatter(rsaProvider);
rsaFormatter.SetHashAlgorithm("SHA256");
var sha256 = new SHA256Managed();
var hashSignatureBytes
=rsaFormatter.CreateSignature(sha256.ComputeHash(Encoding.UTF8.GetBytes(input)));
hashSignatureBase64 = Convert.ToBase64String(hashSignatureBytes);
return hashSignatureBase64;
This code is working in .Net 4.7 perfectly. But it does not work in .Net Standards 2.1 the reason is
var privateKey = certificate.PrivateKey as RSACryptoServiceProvider;
returns null
Does anyone know how to resolve this in .Net Standards? Thanks in advance
The cause of the problem is that the type of
certificate.PrivateKeydepends on the environment and is not necessarilyRSACryptoServiceProvider, so the cast fails andasreturnsnull.Example:
certificate.PrivateKeyis of typeRSACryptoServiceProvideron .NET Framework 4.7.2 (.NET Standard 2.0), of typeRSACngon .NET Core 3.0 or .NET 6.0 (.NET Standard 2.1) on Windows (10) and of typeRSAOpenSslon Linux/Ubuntu (for an overview of .NET Standard versions see here).To fix the issue, use
GetRSAPrivateKey()instead, which is supported in .NET Standard 2.0 and 2.1. This returns an RSA implementation supported by the respective environment (withRSAas base class), which can be passed directly to the formatter class:Note that
PrivateKeyshould be avoided because it is deprecated.Apart from that, signing is more convenient with
RSA#SignData()(though this is a matter of opinion):