C# 如何使用RS256和RSA私钥对JWT进行签名

C# 如何使用RS256和RSA私钥对JWT进行签名,c#,encryption,rsa,jwt,sha256,C#,Encryption,Rsa,Jwt,Sha256,我正在使用,希望使用RS256加密算法在C#中创建一个签名JWT。我没有密码学方面的经验,请原谅我的无知。我在文档中看到以下示例: var payload = new Dictionary<string, object>() { { "sub", "mr.x@contoso.com" }, { "exp", 1300819380 } }; var privateKey=new X509Certificate2("my-key.p12", "password", X5

我正在使用,希望使用RS256加密算法在C#中创建一个签名JWT。我没有密码学方面的经验,请原谅我的无知。我在文档中看到以下示例:

var payload = new Dictionary<string, object>()
{
    { "sub", "mr.x@contoso.com" },
    { "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);
最后,中列出的两个选项之间有什么区别,我如何在这两个选项之间进行选择

--------------------------备选方案1------------------

RS-*和PS-*系列

CLR:

RS256、RS384、RS512和PS256、PS384、PS512签名需要 RSACryptServiceProvider(通常为私钥)对应的 长度。CSP需要强制使用Microsoft增强的RSA和AES 加密提供者。这通常可以通过重新导入来完成 RSA参数。看见 详情请参阅

--------------------------备选案文2------------------

CORECLR:RS256、RS384、RS512签名需要相应长度的RSA(通常是私钥)密钥


GetRSAPrivateKey仅在.NET 4.6中可用。请参阅下面的URL


我知道这篇文章很旧,但我花了很长时间才弄明白,所以我想我会与大家分享

要测试我使用OpenSSL创建的RSA密钥,请执行以下操作:

openssl genrsa -out privateKey.pem 512
openssl rsa -in privateKey.pem -pubout -out publicKey.pem
您将需要以下2个nuget软件包:

  • 测试代码

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

    我发现了一个很好的资源来测试您的令牌

    如果您使用公共证书和.NET 4.6进行解码,您可以使用:

    string token = "eyJhbGciOiJSUzI1NiIsInR....";
    string certificate = "MIICnzCCAYcCBgFd2yEPx....";
    var publicKey = new X509Certificate2(Convert.FromBase64String(certificate )).GetRSAPublicKey();
    string decoded = JWT.Decode(token, publicKey, JwsAlgorithm.RS256);
    
  • RS256是一种签名算法而不是加密算法
  • 加密是用公钥完成的
  • 以下是创建加密JWT的代码:

    var cert = new X509Certificate2(".\\key.cer");
    var rsa = (RSACryptoServiceProvider) cert.PublicKey.Key;
    
    var payload = new Dictionary<string, object>()
    {
      {"sub", "mr.x@contoso.com"},
      {"exp", 1300819380}
    };
    
    var encryptedToken =
      JWT.Encode(
        payload,
        rsa,
        JweAlgorithm.RSA_OAEP,
        JweEncryption.A256CBC_HS512,
        null);
    
    var cert=new X509Certificate2(“.\\key.cer”);
    var rsa=(rsacyptoserviceprovider)cert.PublicKey.Key;
    var payload=newdictionary()
    {
    {“sub”,“mr。x@contoso.com"},
    {“exp”,1300819380}
    };
    var encryptedToken=
    编码(
    有效载荷,
    rsa,
    JweAlgorithm.RSA_OAEP,
    JweEncryption.A256CBChs512,
    无效);
    

  • 如果要使用证书,可以使用此方法通过其指纹检索证书

    private X509Certificate2 GetByThumbprint(string Thumbprint)
    {
        var localStore = new X509Store(StoreName.My, StoreLocation.LocalMachine);
        localStore.Open(OpenFlags.ReadOnly);
        return localStore.Certificates//.Find(X509FindType.FindByKeyUsage, X509KeyUsageFlags.DigitalSignature, false)
            .Find(X509FindType.FindByThumbprint, Thumbprint, false)
            .OfType<X509Certificate2>().First();
    }
    

    这个问题的关键是使用JWT和Bouncy castle库分别对令牌进行编码和签名

  • 用于编码和解码JWT令牌
  • 支持加密和解密,尤其是RS256
  • 首先,您需要将私钥转换为RSA参数的形式。然后需要将RSA参数作为私钥传递给RSA算法。最后,使用JWT库对令牌进行编码和签名

        public string GenerateJWTToken(string rsaPrivateKey)
        {
            var rsaParams = GetRsaParameters(rsaPrivateKey);
            var encoder = GetRS256JWTEncoder(rsaParams);
    
            // create the payload according to your need
            var payload = new Dictionary<string, object>
            {
                { "iss", ""},
                { "sub", "" },
                // and other key-values 
            };
    
            // add headers. 'alg' and 'typ' key-values are added automatically.
            var header = new Dictionary<string, object>
            {
                { "{header_key}", "{your_private_key_id}" },
            };
    
            var token = encoder.Encode(header,payload, new byte[0]);
    
            return token;
        }
    
        private static IJwtEncoder GetRS256JWTEncoder(RSAParameters rsaParams)
        {
            var csp = new RSACryptoServiceProvider();
            csp.ImportParameters(rsaParams);
    
            var algorithm = new RS256Algorithm(csp, csp);
            var serializer = new JsonNetSerializer();
            var urlEncoder = new JwtBase64UrlEncoder();
            var encoder = new JwtEncoder(algorithm, serializer, urlEncoder);
    
            return encoder;
        }
    
        private static RSAParameters GetRsaParameters(string rsaPrivateKey)
        {
            var byteArray = Encoding.ASCII.GetBytes(rsaPrivateKey);
            using (var ms = new MemoryStream(byteArray))
            {
                using (var sr = new StreamReader(ms))
                {
                    // use Bouncy Castle to convert the private key to RSA parameters
                    var pemReader = new PemReader(sr);
                    var keyPair = pemReader.ReadObject() as AsymmetricCipherKeyPair;
                    return DotNetUtilities.ToRSAParameters(keyPair.Private as RsaPrivateCrtKeyParameters);
                }
            }
        }
    
    公共字符串GenerateJWTToken(字符串rsaPrivateKey)
    {
    var rsaparms=getrsaparmeters(rsaPrivateKey);
    var编码器=GetRS256JWTEncoder(rsaParams);
    //根据需要创建有效负载
    var payload=新字典
    {
    {“iss”,“},
    {“sub”,“”},
    //和其他关键值
    };
    //添加标题。自动添加“alg”和“typ”键值。
    var header=新字典
    {
    {{header\u key},{your\u private\u key\u id},
    };
    var token=encoder.Encode(头,有效载荷,新字节[0]);
    返回令牌;
    }
    专用静态IJwtEncoder GetRS256JWTEncoder(RSAParameters rsaParams)
    {
    var csp=新的RSACryptServiceProvider();
    csp.进口参数(rsaParams);
    var算法=新的RS256算法(csp,csp);
    var serializer=new JsonNetSerializer();
    var urlEncoder=new JwtBase64UrlEncoder();
    var编码器=新的JwtEncoder(算法、序列化程序、URLCoder);
    返回编码器;
    }
    私有静态RSAPERAMETERS GetRSAPERAMETERS(字符串rsaPrivateKey)
    {
    var byteArray=Encoding.ASCII.GetBytes(rsaPrivateKey);
    使用(var ms=新内存流(byteArray))
    {
    使用(var sr=新的StreamReader(ms))
    {
    //使用Bouncy Castle将私钥转换为RSA参数
    var pemReader=新pemReader(sr);
    var keyPair=pemReader.ReadObject()作为非对称密码密钥对;
    返回DotNetUtilities.ToRSAParameters(keyPair.Private作为rsaprovatecrtkeyparameters);
    }
    }
    }
    
    ps:RSA私钥应具有以下格式:

    -----开始RSA私钥-----

    {base64格式化值}

    -----结束RSA私钥------

    使用和nuget包,下面的代码对我有用

    public static string CreateToken(Dictionary<string, object> payload)
    {
      string jwt = string.Empty;
      RsaPrivateCrtKeyParameters keyPair;
    
      var cert = ConfigurationManager.AppSettings["cert"];
      /// cert begins -----BEGIN PRIVATE KEY----- and ends with -END PRIVATE KEY-----";
    
      using (var sr = new StringReader(cert))
      {
        PemReader pr = new PemReader(sr);
        keyPair = (RsaPrivateCrtKeyParameters)pr.ReadObject();
      }
    
      RSAParameters rsaParams = DotNetUtilities.ToRSAParameters(keyPair);
    
      using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
      {
        rsa.ImportParameters(rsaParams);
    
        jwt = Jose.JWT.Encode(payload, rsa, Jose.JwsAlgorithm.RS256);
      }
    
      return jwt;
    }
    
    公共静态字符串CreateToken(字典负载)
    {
    string jwt=string.Empty;
    RsaPrivateCrtKeyParameters密钥对;
    var cert=ConfigurationManager.AppSettings[“cert”];
    ///证书开始------开始私钥------结束于-结束私钥------”;
    使用(var sr=新的StringReader(证书))
    {
    PemReader pr=新PemReader(sr);
    keyPair=(RsaPrivateCrtKeyParameters)pr.ReadObject();
    }
    RSAParameters rsaParams=DotNetUtilities.ToRSAParameters(密钥对);
    使用(rsacryptserviceprovider rsa=new rsacryptserviceprovider())
    {
    rsa.输入参数(rsaparms);
    jwt=Jose.jwt.Encode(有效载荷,rsa,Jose.JwsAlgorithm.RS256);
    }
    返回jwt;
    }
    
    发布代码,使用服务帐户JSON键为GCP OAuth令牌API调用创建RS256 JWT令牌-:

    using JWT;
    using JWT.Algorithms;
    using JWT.Serializers;
    using Org.BouncyCastle.Crypto.Parameters;
    using Org.BouncyCastle.Security;
    using System;
    using System.Collections.Generic;
    using System.Security.Cryptography;
    
    namespace GCP
    {
        class JWTTokenGenerationForGCPOAuthTokenAPI
        {
    
    
            public static string GenerateJWTToken()
            {
                var rsaParams = ReadAsymmetricKeyParameter();
                var encoder = GetRS256JWTEncoder(rsaParams);
                var iat = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
                var exp = DateTimeOffset.UtcNow.AddMinutes(60).ToUnixTimeSeconds();
    
                // create the payload according to your need 
                // iss is the Service Account Email ID
                var payload = new Dictionary<string, object>
                {
                    { "iss",   "<service-account>@<project-id>.iam.gserviceaccount.com"},
                    { "scope", "https://www.googleapis.com/auth/cloud-platform" },
                    { "aud",   "https://oauth2.googleapis.com/token" },
                    { "exp",    exp},
                    { "iat",    iat}
                };
                //Final token
                var token = encoder.Encode(payload, new byte[0]);
    
                return token;
            }
    
            private static IJwtEncoder GetRS256JWTEncoder(RSAParameters rsaParams)
            {
                var csp = new RSACryptoServiceProvider();
                csp.ImportParameters(rsaParams);
                var algorithm = new RS256Algorithm(csp, csp);
                var serializer = new JsonNetSerializer();
                var urlEncoder = new JwtBase64UrlEncoder();
                var encoder = new JwtEncoder(algorithm, serializer, urlEncoder);
    
                return encoder;
            }
    
    
    
            public static RSAParameters ReadAsymmetricKeyParameter()
    
    
            {
    
    \\ This key is fetched from the GCP Service Account JSON File. 
    \\"private_key": "-----BEGIN PRIVATE KEY-----\n<long-code>-----END PRIVATE KEY-----\n",
    \\ pick <long-code> from above. Replace all \n with actual new line like shown below.
    
                    string pkey = @"MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDSoGKK/Dzb8MBy
    ################################################################
    ################################################################
    ################################################################
    ################################################################
    twySMqKKWnIC/zZljrvp4w==";
    
    
    
                RsaPrivateCrtKeyParameters rsaPrivateCrtKeyParameters1;
                var keyBytes = Convert.FromBase64String(pkey);
                var asymmetricKeyParameter = PrivateKeyFactory.CreateKey(keyBytes);
    
    
                rsaPrivateCrtKeyParameters1 = (RsaPrivateCrtKeyParameters)asymmetricKeyParameter;
    
                RSAParameters r = DotNetUtilities.ToRSAParameters(rsaPrivateCrtKeyParameters1);
    
                return r;
    
    
            }
        }
    
    }
    
    使用JWT;
    使用JWT.算法;
    使用JWT.serializer;
    使用Org.BouncyCastle.Crypto.Parameters;
    使用Org.BouncyCastle.Security;
    使用制度;
    使用System.Collections.Generic;
    使用System.Security.Cryptography;
    名称空间GCP
    {
    类JWTTokenGenerationForGCPOAuthTokenAPI
    {
    公共静态字符串GenerateJWTToken()
    {
    var rsaparms=ReadAsymmetricKeyParameter();
    var编码器=GetRS256JWTEncoder(rsaParams);
    var iat=DateTimeOffset.UtcNow.ToUnixTimeSeconds();
    var exp=DateTimeOffset.UtcNow.AddMinutes(60).ToUnixTimeSeconds();
    //根据需要创建有效负载
    //iss是Se
    
    private JwtSecurityToken GenerateJWT()
    {
        var securityKey = new Microsoft.IdentityModel.Tokens.X509SecurityKey(GetByThumbprint("YOUR-CERT-THUMBPRINT-HERE"));
    
        var credentials = new Microsoft.IdentityModel.Tokens.SigningCredentials(securityKey, "RS256");
    
        var JWTHeader = new JwtHeader(credentials);
    
        var payload = new JwtPayload
        {
            { "iss", "Issuer-here"},
            { "exp", (Int32)(DateTime.UtcNow.AddHours(1).Subtract(new DateTime(1970, 1, 1))).TotalSeconds},
            { "iat", (Int32)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds}
        };
    
        var token = new JwtSecurityToken(JWTHeader, payload);
        return token;
    }
    
        public string GenerateJWTToken(string rsaPrivateKey)
        {
            var rsaParams = GetRsaParameters(rsaPrivateKey);
            var encoder = GetRS256JWTEncoder(rsaParams);
    
            // create the payload according to your need
            var payload = new Dictionary<string, object>
            {
                { "iss", ""},
                { "sub", "" },
                // and other key-values 
            };
    
            // add headers. 'alg' and 'typ' key-values are added automatically.
            var header = new Dictionary<string, object>
            {
                { "{header_key}", "{your_private_key_id}" },
            };
    
            var token = encoder.Encode(header,payload, new byte[0]);
    
            return token;
        }
    
        private static IJwtEncoder GetRS256JWTEncoder(RSAParameters rsaParams)
        {
            var csp = new RSACryptoServiceProvider();
            csp.ImportParameters(rsaParams);
    
            var algorithm = new RS256Algorithm(csp, csp);
            var serializer = new JsonNetSerializer();
            var urlEncoder = new JwtBase64UrlEncoder();
            var encoder = new JwtEncoder(algorithm, serializer, urlEncoder);
    
            return encoder;
        }
    
        private static RSAParameters GetRsaParameters(string rsaPrivateKey)
        {
            var byteArray = Encoding.ASCII.GetBytes(rsaPrivateKey);
            using (var ms = new MemoryStream(byteArray))
            {
                using (var sr = new StreamReader(ms))
                {
                    // use Bouncy Castle to convert the private key to RSA parameters
                    var pemReader = new PemReader(sr);
                    var keyPair = pemReader.ReadObject() as AsymmetricCipherKeyPair;
                    return DotNetUtilities.ToRSAParameters(keyPair.Private as RsaPrivateCrtKeyParameters);
                }
            }
        }
    
    public static string CreateToken(Dictionary<string, object> payload)
    {
      string jwt = string.Empty;
      RsaPrivateCrtKeyParameters keyPair;
    
      var cert = ConfigurationManager.AppSettings["cert"];
      /// cert begins -----BEGIN PRIVATE KEY----- and ends with -END PRIVATE KEY-----";
    
      using (var sr = new StringReader(cert))
      {
        PemReader pr = new PemReader(sr);
        keyPair = (RsaPrivateCrtKeyParameters)pr.ReadObject();
      }
    
      RSAParameters rsaParams = DotNetUtilities.ToRSAParameters(keyPair);
    
      using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
      {
        rsa.ImportParameters(rsaParams);
    
        jwt = Jose.JWT.Encode(payload, rsa, Jose.JwsAlgorithm.RS256);
      }
    
      return jwt;
    }
    
    using JWT;
    using JWT.Algorithms;
    using JWT.Serializers;
    using Org.BouncyCastle.Crypto.Parameters;
    using Org.BouncyCastle.Security;
    using System;
    using System.Collections.Generic;
    using System.Security.Cryptography;
    
    namespace GCP
    {
        class JWTTokenGenerationForGCPOAuthTokenAPI
        {
    
    
            public static string GenerateJWTToken()
            {
                var rsaParams = ReadAsymmetricKeyParameter();
                var encoder = GetRS256JWTEncoder(rsaParams);
                var iat = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
                var exp = DateTimeOffset.UtcNow.AddMinutes(60).ToUnixTimeSeconds();
    
                // create the payload according to your need 
                // iss is the Service Account Email ID
                var payload = new Dictionary<string, object>
                {
                    { "iss",   "<service-account>@<project-id>.iam.gserviceaccount.com"},
                    { "scope", "https://www.googleapis.com/auth/cloud-platform" },
                    { "aud",   "https://oauth2.googleapis.com/token" },
                    { "exp",    exp},
                    { "iat",    iat}
                };
                //Final token
                var token = encoder.Encode(payload, new byte[0]);
    
                return token;
            }
    
            private static IJwtEncoder GetRS256JWTEncoder(RSAParameters rsaParams)
            {
                var csp = new RSACryptoServiceProvider();
                csp.ImportParameters(rsaParams);
                var algorithm = new RS256Algorithm(csp, csp);
                var serializer = new JsonNetSerializer();
                var urlEncoder = new JwtBase64UrlEncoder();
                var encoder = new JwtEncoder(algorithm, serializer, urlEncoder);
    
                return encoder;
            }
    
    
    
            public static RSAParameters ReadAsymmetricKeyParameter()
    
    
            {
    
    \\ This key is fetched from the GCP Service Account JSON File. 
    \\"private_key": "-----BEGIN PRIVATE KEY-----\n<long-code>-----END PRIVATE KEY-----\n",
    \\ pick <long-code> from above. Replace all \n with actual new line like shown below.
    
                    string pkey = @"MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDSoGKK/Dzb8MBy
    ################################################################
    ################################################################
    ################################################################
    ################################################################
    twySMqKKWnIC/zZljrvp4w==";
    
    
    
                RsaPrivateCrtKeyParameters rsaPrivateCrtKeyParameters1;
                var keyBytes = Convert.FromBase64String(pkey);
                var asymmetricKeyParameter = PrivateKeyFactory.CreateKey(keyBytes);
    
    
                rsaPrivateCrtKeyParameters1 = (RsaPrivateCrtKeyParameters)asymmetricKeyParameter;
    
                RSAParameters r = DotNetUtilities.ToRSAParameters(rsaPrivateCrtKeyParameters1);
    
                return r;
    
    
            }
        }
    
    }