I'm currently using this link to store my RSA key in windows Key Container (machine-level) and it works fine, but I'm looking for a way that works for both Linux and windows because I will definitely deploy this project on Linux.
public static void StoreRSAKey(string containerName, string xmlKey)
{
#pragma warning disable CA1416 // Validate platform compatibility
var parameters = new CspParameters
{
KeyContainerName = containerName
};
#pragma warning restore CA1416 // Validate platform compatibility
parameters.Flags = CspProviderFlags.UseMachineKeyStore;
using RSACryptoServiceProvider? rsa = new RSACryptoServiceProvider(parameters);
rsa.FromXmlString(xmlKey);
}
I have found several recommendations on the web but I need a more precise solution.
I'd be glad if anyone can help me through this.
Best way to store RSA key and use it in .Net core(looking for a cross-platform solution)
IMO, the question should be, is it possible to use the RSA key in .net core for cross-platform?
I have recently built an open-source encryption and decryption library, spending hours investigating the same question you asked. The short answer is that it is not possible to use CspParameters with Linux, it is for Windows OS (as this answer mentions). And because the answer is not possible, there is no best way.
So to start with, let's see if we can answer the question of using the RSA key in the .net core for cross-platform.
To do that it is straightforward, you need to do the following:
Rsa = RSA.Create();
Rsa.KeySize = 2048;
This part does not require installing the library, it is part of netstandard2.0.
That is it, now to export and import a key that you generate, you can do the following.
When you RSA.Create()
first you can export the key and store it anywhere safe for later usage.
To export the private key it should be kept safe
Rsa.ToXmlString(true);
To export public key, to encrypt with
Rsa.ToXmlString(false);
When you need to import the key from a local store, you can do the following:
Rsa.FromXmlString(asymmetricKey);
This is a cross-platform compatible solution for Windows, Linux, or Mac computers.
It is also possible to import certificates from a local computer using X509Certificate2
and use its public key for encryption and private key for decryption.
It is also possible to import private key parameters to RSAParameters
, which requires a helper method to translate XML tags from private key files:
<RSAKeyValue>
<Modulus>xxxx...</Modulus>
<Exponent>xxxx</Exponent>
<P>xxxx...</P>
<Q>xxxx...</Q>
<DP>xxxx...</DP>
<DQ>xxxx...</DQ>
<InverseQ>xxxx...</InverseQ>
<D>xxxx...</D>
</RSAKeyValue>
But I find it easier to use FromXmlString
and it is part of RSA
class when creating RSA.Create()
, so there is no need for a helper method, that said if performance means a lot for your project, you need to make a performance test to compare the results.
So finally I provide a simple example of how to store and load keys:
public static void Main(string[] args)
{
var rsa = RSA.Create();
rsa.KeySize = 2048;
// public key for decrypting
var privateKey = rsa.ToXmlString(true);
SaveKey(@"privateKey", privateKey);
// public key for encrypting
var publicKey = rsa.ToXmlString(false);
SaveKey(@"publicKey", publicKey);
// initialize the private for use on another instance
var rsaAnotherPlace = RSA.Create();
rsaAnotherPlace.KeySize = 2048;
rsaAnotherPlace.FromXmlString(LoadKey(@"privateKey"));
}
// store my keys
public static void SaveKey(string filename, string content)
{
var bytes = Encoding.ASCII.GetBytes(content);
using var fs = new FileStream(filename, FileMode.Create, FileAccess.Write);
fs.Write(bytes, 0, bytes.Length);
}
// load key
public static string LoadKey(string filename)
{
var bytes = File.ReadAllBytes(filename);
return Encoding.ASCII.GetString(bytes);
}
I have tested the solution on Windows and Linux OS and it passes the macOS test on GitHub actions, but I have not tested it yet on macOS.
Disclaimer: this is the open-source library I am working on.