【问题标题】:Verify JWT using public key in string使用字符串中的公钥验证 JWT
【发布时间】:2020-12-10 08:42:45
【问题描述】:

我有以下格式的公钥: ----- BEGIN RSA公钥----- MIIBCgKCAQEA1pjRK + cOnEsh5L1wrt1Tmx + FvyNRj4wuAotlqIWtHS8pIqRzsIOJg + tlbUtEXYju + KOcIohZnnmfj0cq28RcQ19HIohqUXypmUbNy9np / M + Aj9NcyKIaNyuEZ + UhcU / OIStHK4eTUJt + RWL + 0Q1 / rl49tg7h + toB9Y6Y3SeytXvZhMx3N5qqmHHNorpfb65bvvHsicGDB7vK5kn55o + C2LhRIxfnw87nKnhPBMRbZg + BKCTXD4svz4a2xiR / uM4rxebIBgB3Sm4X1w3yoRr0F3IDhAgXmEhSZ078wm3ohPfuuwymfVhvdzavm42NwzixZ7n52SowFE2v0DSJh3IbPwIDAQAB -----结束 RSA 公钥-----

如何实现 C# 以使用该字符串验证我的 JWT?我在Verifying JWT signed with the RS256 algorithm using public key in C# 找到了类似的主题,但没有一个解决方案适合我的情况。

这是我的代码:

        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();
        }

当我尝试初始化 asymmetricKeyParameter 对象时返回异常:

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)

在字符串类型中使用模数和指数编写可能有用的代码 sn-p:

RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
            rsa.ImportParameters(
              new RSAParameters()
              {
                  Modulus = FromBase64Url("w7Zdfmece8iaB0kiTY8pCtiBtzbptJmP28nSWwtdjRu0f2GFpajvWE4VhfJAjEsOcwYzay7XGN0b-X84BfC8hmCTOj2b2eHT7NsZegFPKRUQzJ9wW8ipn_aDJWMGDuB1XyqT1E7DYqjUCEOD1b4FLpy_xPn6oV_TYOfQ9fZdbE5HGxJUzekuGcOKqOQ8M7wfYHhHHLxGpQVgL0apWuP2gDDOdTtpuld4D2LK1MZK99s9gaSjRHE8JDb1Z4IGhEcEyzkxswVdPndUWzfvWBBWXWxtSUvQGBRkuy1BHOa4sP6FKjWEeeF7gm7UMs2Nm2QUgNZw6xvEDGaLk4KASdIxRQ"),
                  Exponent = FromBase64Url("AQAB")
              });

【问题讨论】:

  • 这是 PKCS#1 格式的公钥。它可以用 ASN.1 解析器读取,例如online,因此您可以了解它的结构。您可以手动轻松提取指数和模数。根据您的 .NET 版本(您尚未发布),也可以直接处理格式(但是在 DER 编码中),例如here.
  • 我在第一篇文章中添加了我的代码,但有异常。您知道为什么它不起作用吗?
  • Topaco,你能告诉我更多关于如何手动提取指数和模数的细节吗?
  • 您运行的是哪个 .NET 版本?
  • .Net 框架 4.7.2。我还在第一篇文章中包含了从我的角度来看可能很有趣的代码。

标签: c# jwt rsa public-key-encryption


【解决方案1】:

对于 .NET Framework(例如 4.7.2),可以使用 BouncyCastle(例如 v1.8.6.1)导入公共 PKCS#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);

...

可以使用 JWT 库(例如 System.IdentityModel.Tokens.Jwt)或纯加密 API 来验证 JWT。两者都在linked question 的答案中进行了详细描述。关于前者,另见here,第 2 段。

【讨论】:

  • 虽然您的评论已被删除,但仍然有以下信息:您当然可以将密钥写在一行中,\n 作为换行符。您也不需要所有换行符,但至少一个换行符紧接在标题(-----BEGIN RSA PUBLIC KEY-----\n)和一个紧接之前 页脚 (\n-----END RSA PUBLIC KEY-----)。
  • 是的,换行符给我带来了很多问题,因为我的代码与您相似,并且在将字符串传递给验证方法之前,我一直在从字符串中删除 \n。感谢您的帮助:)
猜你喜欢
  • 1970-01-01
  • 2021-08-21
  • 2017-11-22
  • 2016-04-17
  • 2019-08-25
  • 2019-08-12
  • 2021-08-14
  • 2020-08-19
  • 1970-01-01
相关资源
最近更新 更多