2

I have public key in following format: -----BEGIN RSA PUBLIC KEY-----MIIBCgKCAQEA1pjRK+cOnEsh5L1wrt1Tmx+FvyNRj4wuAotlqIWtHS8pIqRzsIOJg+tlbUtEXYju+KOcIohZnnmfj0cq28RcQ19HIohqUXypmUbNy9np/M+Aj9NcyKIaNyuEZ+UhcU/OIStHK4eTUJt+RWL+0Q1/rl49tg7h+toB9Y6Y3SeytXvZhMx3N5qqmHHNorpfb65bvvHsicGDB7vK5kn55o+C2LhRIxfnw87nKnhPBMRbZg+BKCTXD4svz4a2xiR/uM4rxebIBgB3Sm4X1w3yoRr0F3IDhAgXmEhSZ078wm3ohPfuuwymfVhvdzavm42NwzixZ7n52SowFE2v0DSJh3IbPwIDAQAB-----END RSA PUBLIC KEY-----

How can I implement C# to verify my JWT using that string? I have found similar topic at Verifying JWT signed with the RS256 algorithm using public key in C# but none of solutions suits my case.

There is my code:

        public static bool TransformKey(string fullKey)
        {
            try
            {
                var publicKey = fullKey.Replace("-----BEGIN RSA PUBLIC KEY-----", "");
                publicKey = publicKey.Replace("-----END RSA PUBLIC KEY-----", "");
                publicKey = publicKey.Replace("\n", "");

                var keyBytes = Convert.FromBase64String(publicKey); // your key here 
                AsymmetricKeyParameter asymmetricKeyParameter = PublicKeyFactory.CreateKey(keyBytes);
                RsaKeyParameters rsaKeyParameters = (RsaKeyParameters)asymmetricKeyParameter;
                RSAParameters rsaParameters = new RSAParameters
                {
                    Modulus = rsaKeyParameters.Modulus.ToByteArrayUnsigned(),
                    Exponent = rsaKeyParameters.Exponent.ToByteArrayUnsigned()
                };
                return true;
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                return false;
            }
        }
      
        static void Main(string[] args)
        {
            // The code provided will print ‘Hello World’ to the console.
            // Press Ctrl+F5 (or go to Debug > Start Without Debugging) to run your app.
            string key = "-----BEGIN RSA PUBLIC KEY-----MIIBCgKCAQEA1pjRK+cOnEsh5L1wrt1Tmx+FvyNRj4wuAotlqIWtHS8pIqRzsIOJg+tlbUtEXYju+KOcIohZnnmfj0cq28RcQ19HIohqUXypmUbNy9np/M+Aj9NcyKIaNyuEZ+UhcU/OIStHK4eTUJt+RWL+0Q1/rl49tg7h+toB9Y6Y3SeytXvZhMx3N5qqmHHNorpfb65bvvHsicGDB7vK5kn55o+C2LhRIxfnw87nKnhPBMRbZg+BKCTXD4svz4a2xiR/uM4rxebIBgB3Sm4X1w3yoRr0F3IDhAgXmEhSZ078wm3ohPfuuwymfVhvdzavm42NwzixZ7n52SowFE2v0DSJh3IbPwIDAQAB-----END RSA PUBLIC KEY-----";
            bool test = TransformKey(key);
            Console.ReadKey();
        }

It returns exception when I try to initialize asymmetricKeyParameter object:

System.ArgumentException: Unknown object in GetInstance: Org.BouncyCastle.Asn1.DerInteger
Parameter name: obj
   w Org.BouncyCastle.Asn1.Asn1Sequence.GetInstance(Object obj)
   w Org.BouncyCastle.Asn1.X509.AlgorithmIdentifier.GetInstance(Object obj)
   w Org.BouncyCastle.Asn1.X509.SubjectPublicKeyInfo..ctor(Asn1Sequence seq)
   w Org.BouncyCastle.Asn1.X509.SubjectPublicKeyInfo.GetInstance(Object obj)
   w Org.BouncyCastle.Security.PublicKeyFactory.CreateKey(Byte[] keyInfoData)

Code snippet with Modulus and Exponent in string type that can be useful:

RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
            rsa.ImportParameters(
              new RSAParameters()
              {
                  Modulus = FromBase64Url("w7Zdfmece8iaB0kiTY8pCtiBtzbptJmP28nSWwtdjRu0f2GFpajvWE4VhfJAjEsOcwYzay7XGN0b-X84BfC8hmCTOj2b2eHT7NsZegFPKRUQzJ9wW8ipn_aDJWMGDuB1XyqT1E7DYqjUCEOD1b4FLpy_xPn6oV_TYOfQ9fZdbE5HGxJUzekuGcOKqOQ8M7wfYHhHHLxGpQVgL0apWuP2gDDOdTtpuld4D2LK1MZK99s9gaSjRHE8JDb1Z4IGhEcEyzkxswVdPndUWzfvWBBWXWxtSUvQGBRkuy1BHOa4sP6FKjWEeeF7gm7UMs2Nm2QUgNZw6xvEDGaLk4KASdIxRQ"),
                  Exponent = FromBase64Url("AQAB")
              });
Vaurine
  • 65
  • 7
  • 1
    This is a public key in PKCS#1 format. It can be read with an ASN.1 parser, e.g. [online](https://lapo.it/asn1js/), so you can get an impression how it is structured. You can easily extract exponent and modulus _manually_. Depending on your .NET version (which you haven't posted), the format may also be processed _directly_ (however in DER encoding), e.g. [here](https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.rsa.importrsapublickey?view=netcore-3.0). – Topaco Aug 21 '20 at 08:51
  • I have added my code snipped with exception in first post. Have you got any idea why it is not working? – Vaurine Aug 21 '20 at 10:19
  • Topaco, can you provide me more details how to extract exponent and modulus manually? – Vaurine Aug 21 '20 at 14:52
  • Which .NET version are you running? – Topaco Aug 21 '20 at 15:24
  • .Net Framework 4.7.2. I have also included code that can be interesting from my point of view in first post. – Vaurine Aug 21 '20 at 15:55

1 Answers1

2

In the case of the .NET Framework (e.g. 4.7.2), a public PKCS#1 key can be imported for example using BouncyCastle (e.g. v1.8.6.1):

using System.IO;
using System.Security.Cryptography;

using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Security;

...

string publicPKCS1 = @"-----BEGIN RSA PUBLIC KEY-----
                       MIIBCgKCAQEA1pjRK+cOnEsh5L1wrt1Tmx+FvyNRj4wuAotlqIWtHS8pIqRzsIOJ
                       g+tlbUtEXYju+KOcIohZnnmfj0cq28RcQ19HIohqUXypmUbNy9np/M+Aj9NcyKIa
                       NyuEZ+UhcU/OIStHK4eTUJt+RWL+0Q1/rl49tg7h+toB9Y6Y3SeytXvZhMx3N5qq
                       mHHNorpfb65bvvHsicGDB7vK5kn55o+C2LhRIxfnw87nKnhPBMRbZg+BKCTXD4sv
                       z4a2xiR/uM4rxebIBgB3Sm4X1w3yoRr0F3IDhAgXmEhSZ078wm3ohPfuuwymfVhv
                       dzavm42NwzixZ7n52SowFE2v0DSJh3IbPwIDAQAB
                       -----END RSA PUBLIC KEY-----";

PemReader pemReader = new PemReader(new StringReader(publicPKCS1));
AsymmetricKeyParameter asymmetricKeyParameter = (AsymmetricKeyParameter)pemReader.ReadObject();
RSAParameters rsaParameters = DotNetUtilities.ToRSAParameters((RsaKeyParameters)asymmetricKeyParameter);

RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.ImportParameters(rsaParameters);

...

The validation of the JWT can be done with a JWT library (e.g. System.IdentityModel.Tokens.Jwt) or with a pure cryptography API. Both are described in detail in the answers to the linked question. Regarding the former, see also here, 2nd paragraph.

Topaco
  • 40,594
  • 4
  • 35
  • 62
  • Your comment has been removed though, but nevertheless the following information: You can of course write the key in one line with `\n` as a line break. You don't need all the line breaks either, but there must be _at least_ one line break _immediately after_ the header (`-----BEGIN RSA PUBLIC KEY-----\n`) and one _immediately before_ the footer (`\n-----END RSA PUBLIC KEY-----`). – Topaco Aug 21 '20 at 17:41
  • Yes, line breaks generated a lot of issue of me, because I had similar code to you and I had been removing \n from my string before passing it to verify methods. Thanks for your assistance :) – Vaurine Aug 22 '20 at 20:51