Here is an example that works in .net core:
Use openssl tool. Open your terminal and type the following commands:
openssl genrsa -out private.pem 2048
openssl rsa -in private.pem -outform PEM -pubout -out public.pem
It will result in creating 2 files.
There’s one more thing before we can actually use our RSA keys within .NET Core application. We need to convert them into XML. Use a "RSA PEM to XML Converter".
It can be done here: Online rsa key converter
Before copying XML into private-rsa-key.xml and public-rsa-key.xml files, format them using: XML Formatter
The private key is required only for the service responsible for generating the token. This must not be shared outside of this project.
Startup.cs :
public class Startup
{
public IConfiguration Configuration { get; }
private SigningCredentials _signingCredentials;
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public void ConfigureServices(IServiceCollection services)
{
// other code
services
.AddIdentityServer()
.AddSigningCredential(_signingCredentials)
.AddInMemoryApiResources(_identityConfig.GetApiResources())
.AddInMemoryClients(_identityConfig.GetClients());
// other code
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseMvc();
app.UseIdentityServer();
}
private void InitializeRsaKey()
{
try
{
RSACryptoServiceProvider rsaProvider = new RSACryptoServiceProvider(2048);
var rsaParametersPrivate = RSAExtensions.RSAParametersFromXmlFile(Configuration.GetSection("JwtSettings:rsaPrivateKeyXml").Value);
rsaProvider.ImportParameters(rsaParametersPrivate);
var securityKey = new RsaSecurityKey(rsaProvider);
_signingCredentials = new SigningCredentials(securityKey, SecurityAlgorithms.RsaSha256);
}
catch(Exception ex)
{
throw new Exception("Identity Server RSA Key initialization failed. " + ex.ToString());
}
}
}
The RSAExtensions class:
public static class RSAExtensions
{
/// <summary>
/// Gets RSA Parameters from XML file.
/// </summary>
/// <param name="xmlFilePath">The XML file path.</param>
/// <returns>RSAParameters.</returns>
/// <exception cref="Exception">Invalid XML RSA key.</exception>
public static RSAParameters RSAParametersFromXmlFile(string xmlFilePath)
{
RSAParameters parameters = new RSAParameters();
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(File.ReadAllText(xmlFilePath));
if (xmlDoc.DocumentElement.Name.Equals("RSAKeyValue"))
{
foreach (XmlNode node in xmlDoc.DocumentElement.ChildNodes)
{
switch (node.Name)
{
case "Modulus": parameters.Modulus = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
case "Exponent": parameters.Exponent = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
case "P": parameters.P = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
case "Q": parameters.Q = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
case "DP": parameters.DP = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
case "DQ": parameters.DQ = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
case "InverseQ": parameters.InverseQ = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
case "D": parameters.D = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
}
}
}
else
{
throw new Exception("Invalid XML RSA key.");
}
return parameters;
}
}
In appsettings.json add the following:
"JwtSettings": {
"rsaPrivateKeyXml": "RSAKeys/private-rsa-key.xml",
},
I don't know if you can store raw XML in appsettings.json. If not you can write a helper method to convert pem to xml and store the raw pem content inside a configuration variable.
I found a sample project in GitHub that may help you on the conversion: Rsa-Dotnet-Core