I'm reading a certificate from a X509Store, that I want to get it's CngKey using GetCngPrivateKey. But all I'm getting is the following error.
at Security.Cryptography.X509Certificates.X509Native.AcquireCngPrivateKey(SafeCertContextHandle certificateContext)\r\n at Security.Cryptography.X509Certificates.X509Certificate2ExtensionMethods.GetCngPrivateKey(X509Certificate2 certificate)\r\n
The certificate is passing the validation HasCngKey, but I'm not able to get its value. Is there any other way to get the CngKey?
byte[] digest = null;
using (var hmac = SHA256.Create())
{
digest = hmac.ComputeHash(System.Text.Encoding.UTF8.GetBytes(data));
}
var certificate = collection[0];
byte[] firmadigital = null;
CngKey privateKey = null;
AsymmetricAlgorithm privateKey1 = null;
var hasCng = certificate.HasCngKey();
if (hasCng)
{
privateKey = certificate.GetCngPrivateKey();
Console.WriteLine("tiene CNG");
var key = new Security.Cryptography.RSACng(privateKey);
key.SignatureHashAlgorithm = CngAlgorithm.Sha1;
var p = key.SignData(digest);
return Convert.ToBase64String(p);
}
I'm using c# net core 2.0
Thanks
You seem to be using an extra library, since neither .NET Framework nor .NET Core has HasCngKey
, GetCngPrivateKey()
, or a property-based RSACng
class. I'm guessing you're using the cryptography library from the clrsecurity
CodePlex prototype.
The functionality you're using is in .NET Framework (as of 4.6) and .NET Core (all versions), but under different names.
Instead of
var hasCng = certificate.HasCngKey();
if (hasCng)
{
privateKey = certificate.GetCngPrivateKey();
Console.WriteLine("tiene CNG");
var key = new Security.Cryptography.RSACng(privateKey);
key.SignatureHashAlgorithm = CngAlgorithm.Sha1;
var p = key.SignData(digest);
return Convert.ToBase64String(p);
}
you want
using (RSA rsa = certificate.GetRSAPrivateKey())
{
Console.WriteLine("tiene RSA. Que tipo no es importante.");
var p = rsa.SignData(digest, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1);
return Convert.ToBase64String(p);
}
It is correct to put the object from GetRSAPrivateKey()
into a using block, because the method returns a distinct object every call.
The reason that GetRSAPrivateKey()
was chosen (along with fixing up the RSA base class to be more useful) was so the same code works for Windows CNG, Windows CAPI, Linux, and macOS. The only reason to ever inspect the returned object and cast further is to do pointer-based interop with the OS/cryptolib. (But since Windows can return CNG or CAPI as necessary, it's tough to get even that right)