5

I am trying to run code from this sample

https://learn.microsoft.com/en-us/dotnet/standard/security/how-to-store-asymmetric-keys-in-a-key-container

Under .NetCore 2.0 (Web application).

However when I try to execute any line using

CspParameters

I get the following error

'CspParameters' requires Windows Cryptographic API (CAPI), which is not available on this platform.

Suggestions please on how I work around this. Thanks.

MHugh
  • 455
  • 1
  • 7
  • 20

4 Answers4

12

.NET does not store cryptographic keys, that's ultimately a feature that is (or isn't) provided by the cryptographic platform it builds on top of.

To use CspParameters with .NET Core you have to run on Windows; because that's a very thin wrapper over the (old) Windows Cryptographic API. You can't use it in UAP, because UAP only allows the newer Cryptography: Next Generation (CNG) API.

macOS can store keys in a Keychain, but .NET Core doesn't provide API to read them out.

Linux (OpenSSL) does not have any key storage mechanism other than "save this to a file and load it again", but .NET Core does not support loading asymmetric keys from files.

The only way to accomplish your goal in a cross-platform mechanism is to have your asymmetric key associated with an X.509 certificate. If you build the X509Certificate2 object for which HasPrivateKey returns true you can save it to a PFX/PKCS#12 file and then load from that file; or you can add it to an X509Store instance (the "My" store for CurrentUser is the one that works best across the platforms) and then read it back from the X509Store instance.

Despite the page you referenced claiming to be written in 2017, what it really means is the content was moved from its previous location on msdn.microsoft.com on that date. The original page was written in 2008 (at least, that's the first hit on web.archive.org), so it long predated .NET Core.

bartonjs
  • 30,352
  • 2
  • 71
  • 111
1

You can now do it cross-platform and it works as long as you are on .netcore 3.0 or higher and you add the latest System.Security.Cryptography.Cng nuget package (NB! this will ONLY work if your project is NOT multi-targeted - it can ONLY target netcoreapp3.0) :

using (ECDsa key = ECDsa.Create())
            {
                key.ImportPkcs8PrivateKey(Convert.FromBase64String(privateKey), out _);

                return Jose.JWT.Encode
                    (
                    payload: payload,
                    key: key,
                    algorithm: JwsAlgorithm.ES256,
                    extraHeaders: extraHeader
                    );
            }
Matthew Joughin
  • 111
  • 1
  • 4
0

So just wanted to offer another option we found once we encountered this error. That CSP Parameters error is related to the RSACryptoServiceProvider . This has some issues with cross platform .NET Core. We found a Github issue that mentioned to use RSA.Create() method instead. I was using a Bouncy Castle library that still uses the RSACryptoServiceProvider. At the time of writing this answer, it looked like this.

        public static RSA ToRSA(RsaPrivateCrtKeyParameters privKey)
    {
        RSAParameters rp = ToRSAParameters(privKey);
        RSACryptoServiceProvider rsaCsp = new RSACryptoServiceProvider();
        rsaCsp.ImportParameters(rp);
        return rsaCsp;
    } 

So we just replaced it with a private method in the class that looked like this.

            private RSA ToRSA(RsaPrivateCrtKeyParameters parameters)
        {
            RSAParameters rp = DotNetUtilities.ToRSAParameters(parameters);
            return RSA.Create(rp);
        }

This ran in linux, no errors. Bouncy probably just needs to update their libs.

Puerto
  • 1,072
  • 3
  • 11
  • 32
0

Use this method to import public key from the Key string make sure to install BouncyCastle.NetCore nuget package

  public static RSACryptoServiceProvider ImportPublicKey(string pem)
    {
        PemReader pr = new PemReader(new StringReader(pem));
        AsymmetricKeyParameter publicKey = (AsymmetricKeyParameter)pr.ReadObject();
        RSAParameters rsaParams = DotNetUtilities.ToRSAParameters((RsaKeyParameters)publicKey);

        RSACryptoServiceProvider csp = new RSACryptoServiceProvider();// cspParams);
        csp.ImportParameters(rsaParams);
        return csp;
    }

And then you can encrypt your data as shown below

 public static string Encryption(string data,string publickey)
    {
        var testData = Encoding.GetEncoding("iso-8859-1").GetBytes(strText);

        using (var rsa = ImportPublicKey(publickey))
        {
            try
            {
                var encryptedData = rsa.Encrypt(testData, false);
                var base64Encrypted = Convert.ToBase64String(encryptedData);
                return base64Encrypted;
            }
            finally
            {
                rsa.PersistKeyInCsp = false;
            }
        }
    }
Cyril
  • 1
  • 2
  • I have tried this solution but this is producing exception at this line: var encryptedData = rsa.Encrypt(testData, false); Internal.Cryptography.CryptoThrowHelper.WindowsCryptographicException: 'Bad Length' – Ala Aga Sep 12 '19 at 11:09
  • Increase Key length size possibly use Public key with key size of more than 4096 – Cyril Sep 13 '19 at 14:09