如何使用带有RSA私钥的RS256在C#中创建加密的JWT

问题描述:

我正在使用 jose-jwt库,并希望使用C#在C#中创建签名的JWT RS256加密算法.我没有密码学的经验,所以请原谅我的无知.我在文档中看到以下示例:

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", "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);

其中显示了p12文件的用法,但是如何使用下面形式的RSA密钥文件?我正在查看 X509Certificate2 ,但是我看不到RSA私钥的选项.它似乎只接受PKCS7,我认为这是公共密钥.

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?

--------------------------选项1 ------------------- -------

-------------------------- OPTION 1 --------------------------

RS- *和PS- *系列

RS-* and PS-* family

CLR:

RS256,RS384,RS512和PS256,PS384,PS512签名需要 对应的RSACryptoServiceProvider(通常为私有)密钥 长度.需要强制CSP使用Microsoft增强的RSA和AES 加密提供者.通常可以重新导入 RSAParameters.参见 http://clrsecurity.codeplex.com/discussions/243156 有关详细信息.

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.

--------------------------选项2 ------------------- -------

-------------------------- OPTION 2 --------------------------

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

CORECLR: RS256, RS384, RS512 signatures require RSA (usually private) key of corresponding length.

我知道这篇文章很旧,但是花了我很多时间才弄清楚这一点,所以我想分享一下.

I know this post is old, but it took me forever to figure this out, so I thought I would share.

要测试,我使用OpenSSL创建了RSA密钥:

To test I created RSA keys using OpenSSL:

openssl genrsa -out privateKey.pem 512
openssl rsa -in privateKey.pem -pubout -out publicKey.pem

您将需要以下2个nuget程序包:

You will need the following 2 nuget packages:

  1. https://github.com/dvsekhvalnov/jose-jwt
  2. http://www.bouncycastle.org/csharp/
  1. https://github.com/dvsekhvalnov/jose-jwt
  2. http://www.bouncycastle.org/csharp/

测试代码

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

创建令牌

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

解码令牌

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

我发现 https://jwt.io/是测试令牌的绝佳资源

I found https://jwt.io/ a great resource to test your tokens