I am using the jose-jwt library and want to create a signed JWT in C# using the RS256 algorithm for encryption. I have no experience with cryptography, so please excuse my ignorance. I see the following example in the docs:
var payload = new Dictionary<string, object>() { { "sub", "[email protected]" }, { "exp", 1300819380 } }; var privateKey=new X509Certificate2("my-key.p12", "password", X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet).PrivateKey as RSACryptoServiceProvider; string token=Jose.JWT.Encode(payload, privateKey, JwsAlgorithm.RS256);
which shows the use of a p12
file, but how do I use an RSA key file of the form below? I am looking at the docs for X509Certificate2, but I see no option for RSA private keys. It appears to only accept PKCS7
, which I understand to be public keys.
-----BEGIN RSA PRIVATE KEY----- MIICXAIBAAKBgQCqGKukO1De7zhZj6+H0qtjTkVxwTCpvKe4eCZ0FPqri0cb2JZfXJ/DgYSF6vUp wmJG8wVQZKjeGcjDOL5UlsuusFncCzWBQ7RKNUSesmQRMSGkVb1/3j+skZ6UtW+5u09lHNsj6tQ5 1s1SPrCBkedbNf0Tp0GbMJDyR4e9T04ZZwIDAQABAoGAFijko56+qGyN8M0RVyaRAXz++xTqHBLh 3tx4VgMtrQ+WEgCjhoTwo23KMBAuJGSYnRmoBZM3lMfTKevIkAidPExvYCdm5dYq3XToLkkLv5L2 pIIVOFMDG+KESnAFV7l2c+cnzRMW0+b6f8mR1CJzZuxVLL6Q02fvLi55/mbSYxECQQDeAw6fiIQX GukBI4eMZZt4nscy2o12KyYner3VpoeE+Np2q+Z3pvAMd/aNzQ/W9WaI+NRfcxUJrmfPwIGm63il AkEAxCL5HQb2bQr4ByorcMWm/hEP2MZzROV73yF41hPsRC9m66KrheO9HPTJuo3/9s5p+sqGxOlF L0NDt4SkosjgGwJAFklyR1uZ/wPJjj611cdBcztlPdqoxssQGnh85BzCj/u3WqBpE2vjvyyvyI5k X6zk7S0ljKtt2jny2+00VsBerQJBAJGC1Mg5Oydo5NwD6BiROrPxGo2bpTbu/fhrT8ebHkTz2epl U9VQQSQzY1oZMVX8i1m5WUTLPz2yLJIBQVdXqhMCQBGoiuSoSjafUhV7i1cEGpb88h5NBYZzWXGZ 37sJ5QsW+sJyoNde3xH8vdXhzU7eT82D6X/scw9RZz+/6rCJ4p0= -----END RSA PRIVATE KEY-----
Finally, what is the difference between the two options listed in the docs, and how do I choose between the two?
-------------------------- OPTION 1 --------------------------
RS-* and PS-* family
CLR:
RS256, RS384, RS512 and PS256, PS384, PS512 signatures require RSACryptoServiceProvider (usually private) key of corresponding length. CSP need to be forced to use Microsoft Enhanced RSA and AES Cryptographic Provider. Which usually can be done be re-importing RSAParameters. See http://clrsecurity.codeplex.com/discussions/243156 for details.
-------------------------- OPTION 2 --------------------------
CORECLR: RS256, RS384, RS512 signatures require RSA (usually private) key of corresponding length.
RSA is a popular algorithm for asymmetric (public key) encryption that was established more than 40 years ago. Encrypting a JWT for a given recipient requires their public RSA key. The decryption takes place with the corresponding private RSA key, which the recipient must keep secret at all times.
RS256 algorithm is an asymmetric algorithm that uses a private key to sign a JWT and a public key to verification that signature. RS256 is the recommended algorithm when signing your JWTs. It is more secure, and you can rotate keys quickly if they are compromised. (Auth0 signs JWTs with RS256 by default).
I know this post is old, but it took me forever to figure this out, so I thought I would share.
To test I created RSA keys using OpenSSL:
openssl genrsa -out privateKey.pem 512 openssl rsa -in privateKey.pem -pubout -out publicKey.pem
You will need the following 2 nuget packages:
Test Code
public static void Test() { string publicKey = File.ReadAllText(@"W:\Dev\Temp\rsa_keys\publicKey.pem"); string privateKey = File.ReadAllText(@"W:\Dev\Temp\rsa_keys\privateKey.pem"); var claims = new List<Claim>(); claims.Add(new Claim("claim1", "value1")); claims.Add(new Claim("claim2", "value2")); claims.Add(new Claim("claim3", "value3")); var token = CreateToken(claims, privateKey); var payload = DecodeToken(token, publicKey); }
Create Token
public static string CreateToken(List<Claim> claims, string privateRsaKey) { RSAParameters rsaParams; using (var tr = new StringReader(privateRsaKey)) { var pemReader = new PemReader(tr); var keyPair = pemReader.ReadObject() as AsymmetricCipherKeyPair; if (keyPair == null) { throw new Exception("Could not read RSA private key"); } var privateRsaParams = keyPair.Private as RsaPrivateCrtKeyParameters; rsaParams = DotNetUtilities.ToRSAParameters(privateRsaParams); } using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider()) { rsa.ImportParameters(rsaParams); Dictionary<string, object> payload = claims.ToDictionary(k => k.Type, v => (object)v.Value); return Jose.JWT.Encode(payload, rsa, Jose.JwsAlgorithm.RS256); } }
Decode Token
public static string DecodeToken(string token, string publicRsaKey) { RSAParameters rsaParams; using (var tr = new StringReader(publicRsaKey)) { var pemReader = new PemReader(tr); var publicKeyParams = pemReader.ReadObject() as RsaKeyParameters; if (publicKeyParams == null) { throw new Exception("Could not read RSA public key"); } rsaParams = DotNetUtilities.ToRSAParameters(publicKeyParams); } using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider()) { rsa.ImportParameters(rsaParams); // This will throw if the signature is invalid return Jose.JWT.Decode(token, rsa, Jose.JwsAlgorithm.RS256); } }
I found https://jwt.io/ a great resource to test your tokens
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With