I tried implementing Jwt authentication with RSA encryption in .NET Core, but I ran into this issue.
Below is a snippet
[Fact]
public void RSATest()
{
var privateKeyBytes = Convert.FromBase64String(@"MIIEoQIBAAKCAQBqjE6Z9ZNNy7Fp5WgtUH2rRq9/m8DSZ3nbqm5aySFtd2kSaDYX
YemqumnE0nfYvwKL+gd+uG6459guN0rz+diMVNaIfst0FEiMJ0yekm/zNwiIsf4m
Lkiw/NOQpg0PiPdulsZcu7MNST02BPyS3aOgRmysofxbtcYgMQp3qEwoOAV0xTXo
XW0X2TSEddKRdeZuSkdyM4WaeEWQpfTRmLgA2952Ggd0NYhMDfU5cLBIAdKJ48/l
rH+81T8MNgiuBwWM0LhmM7VnVOglaO1s/2xXKVAJBwd8wbMnwBJGT+0sCfeRf0Q8
0552thSs8BThYYpy/UWeOtdkwELFAimPmmqvAgMBAAECggEAMwMD6uBRazC3uzyT
WQatdCA+i/j1I4dZJ1t8xEiBkZhXHPH5284MAqqHUy11Jbelr4DAr+H7WNnffZkJ
cK/RBrbjk6wpGmVPqpJyM4Vmxeo2UsPtKziDowEZBasKm8J2vGLBi8pt2lGTVdaj
Wml1Gpo9E5Xmbb4komr4WPuhoqs5CwskhNJFaYf7YDDdXtcSleyFQ0LAAHP0QMjp
qP0CVo6x3JLHv0Q/AOKPyhQYzR6XtDwflRiIgjqK2whopzazrljVJL0ZmvM9jv2b
XcXguZ+RCe2SwomH9Z60YMDuXOwghtSiHFM0ZP+zJuDHu4+blZILNtsA5BQcnh3E
GpPrUQKBgQCydC/hCsHLUVn8itAhC8vp5V0nXKbFoxYfKhRajZQcNoh40cmK2lh+
XI50bQ1776cXfwu2NBPATNe94Ci2vD+TgIL6u65XvyoJ9iQk2/xE78TFtYlsZdms
1Gb+nGl8SN0hZGzRcKJZg30LZJinFbPz9wfbxxamczJwFD7R4ygNOQKBgQCY2ROi
Sxnv48ab+glycLujg4Y1SnGHotNU9Qdpo8oIl4+puacXGLNrGR6vToWgqxcL22sP
FeBFfTtMiOGVRjhfdjnJ2+FFvBnLo0DhcI3wnw7iJuwL5IoYl4zrCXyUO5J75hjU
QV3/lxFiD/j+U6R091sjv6RijoviORozIJqfJwKBgEHhuSdo9EDeqM0eZlY856xT
PD/i6cL/QZSB0X/Y0vxTebC5KqHzmEYWX5VGCXte754yDh3XPg95jxCPaBiGiSYo
hLKShXvpnFiPIarl+E1vA4NGURTOyT0QMXIARsVWlSTV0YLFBXrsm0aQffb5gTUp
VyJhbtBGqTFNmB+esFOpAoGAXV+fYvHGMopPdlHVG5hKyKU8g6mqmVWbDLdzg9GP
RphwJxtHPBDW6oI6AJZTg8eBGLk+OcT/cPQEGck1Jd/z6D1tKCevAs7aY1Cj/hSo
YWqJyRZF9S30Pvm2GI9/D38lCZOTb3dPWSiMcf+X+KZYPSwu/TPB1IOIaPbBTqKI
UtkCgYBGc+yZjHWhO8qW0JMG6yql2BZYF4OIJ/+o4KoHD6N539lRWDel3Vv4vhQS
4Yl3TUI4pGm72BOCLnPLjGcScll1Fg287OP9wLKcKzn1rFZZp+KWGUUtf/KJ7kJP
ZQXT0CHxhIyhBANEYXatnrhoDNGxpTmJ8+INDIuHn/Ss8rrEew==");
var publicKeyBytes = Convert.FromBase64String(@"MIIBITANBgkqhkiG9w0BAQEFAAOCAQ4AMIIBCQKCAQBqjE6Z9ZNNy7Fp5WgtUH2r
Rq9/m8DSZ3nbqm5aySFtd2kSaDYXYemqumnE0nfYvwKL+gd+uG6459guN0rz+diM
VNaIfst0FEiMJ0yekm/zNwiIsf4mLkiw/NOQpg0PiPdulsZcu7MNST02BPyS3aOg
RmysofxbtcYgMQp3qEwoOAV0xTXoXW0X2TSEddKRdeZuSkdyM4WaeEWQpfTRmLgA
2952Ggd0NYhMDfU5cLBIAdKJ48/lrH+81T8MNgiuBwWM0LhmM7VnVOglaO1s/2xX
KVAJBwd8wbMnwBJGT+0sCfeRf0Q80552thSs8BThYYpy/UWeOtdkwELFAimPmmqv
AgMBAAE=");
using (var rsa = RSA.Create())
{
rsa.ImportRSAPrivateKey(privateKeyBytes, out _);
rsa.ImportSubjectPublicKeyInfo(publicKeyBytes, out _);
var key = new RsaSecurityKey(rsa);
var handler = new JsonWebTokenHandler();
var now = DateTime.UtcNow;
var descriptor = new SecurityTokenDescriptor
{
Issuer = "me",
Audience = "you",
IssuedAt = now,
NotBefore = now,
Expires = now.AddMinutes(5),
SigningCredentials = new SigningCredentials(key, SecurityAlgorithms.RsaSha256)
};
string jwt = handler.CreateToken(descriptor);
TokenValidationResult result = handler.ValidateToken(jwt,
new TokenValidationParameters
{
ValidIssuer = "me",
ValidAudience = "you",
IssuerSigningKey = new RsaSecurityKey(key.Rsa.ExportParameters(false))
});
}
}
It throws a CryptographicException on string jwt = handler.CreateToken(descriptor); with the following message

My workspace specifications:
OS: macOS Catalina 10.15.3
.NET Core SDK Version: 3.1.101
Other things to note
Private key looks like
-----BEGIN RSA PRIVATE KEY-----
-----END RSA PRIVATE KEY-----
and public key like
-----BEGIN PUBLIC KEY-----
-----END PUBLIC KEY-----
I also tried using RSA.create(2048), but it did not yield any difference.
cc: @bartonjs
I couldn't add an area label to this Issue.
Checkout this page to find out which area owner to ping, or please add exactly one area label to help train me in the future.
You probably don't need to import the private key and the public key. The moment you import the public key you loose the private key.
The documentation says about RSA.ImportSubjectPublicKeyInfo:
Imports the public key from an X.509 SubjectPublicKeyInfo structure after decryption, replacing the keys for this object.
You probably don't need to import the private key and the public key.
Correct. The private key contains the public key.
Any of the Import methods forget the current key data and take their totality from the provided data, as already suggested by @InlineAsm.
If you remove the call to ImportSubjectPublicKeyInfo everything should work fine.
Thanks @InlineAsm, @vcsjones, and @bartonjs.
It works.
Most helpful comment
You probably don't need to import the private key and the public key. The moment you import the public key you loose the private key.
The documentation says about RSA.ImportSubjectPublicKeyInfo: