web-dev-qa-db-ja.com

RSA秘密鍵でRS256を使用してC#で暗号化されたJWTを作成する方法

jose-jwtライブラリ を使用しており、暗号化にRS256アルゴリズムを使用してC#で署名付きJWTを作成したいと考えています。私は暗号化の経験がないので、私の無知を許してください。ドキュメントに次の例が表示されます。

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

これはp12ファイルの使用を示していますが、以下の形式のRSAキーファイルをどのように使用しますか? X509Certificate2 のドキュメントを見ていますが、RSA秘密鍵のオプションがありません。 PKCS7のみを受け入れるようです。これは私が公開鍵であると理解しています。

-----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-----

最後に、 docs にリストされている2つのオプションの違いは何ですか?2つのオプションをどのように選択すればよいですか?

- - - - - - - - - - - - - オプション1 - - - - - - - - - - - ----

RS- *およびPS- *ファミリー

CLR:

RS256、RS384、RS512およびPS256、PS384、PS512署名には、対応する長さのRSACryptoServiceProvider(通常はプライベート)キーが必要です。 CSPは、Microsoft Enhanced RSAおよびAES Cryptographic Providerの使用を強制する必要があります。これは通常、RSAParametersを再インポートすることで実行できます。詳細は http://clrsecurity.codeplex.com/discussions/243156 を参照してください。

--------------------------オプション2 ---------------------- ----

CORECLR:RS256、RS384、RS512署名には、対応する長さのRSA(通常はプライベート)キーが必要です。

13
FullStack

この投稿が古いことは知っていますが、これを理解するのに永遠にかかったので、共有したいと思いました。

OpenSSLを使用してRSAキーを作成したことをテストするには:

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

次の2つのnugetパッケージが必要です。

  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/ トークンをテストするのに最適なリソースです

20
Roche

証明書を使用する場合は、このメソッドを使用して拇印で取得できます

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

その後:

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;
}
1
Enrico

この質問の鍵は、トークンのエンコードと署名にそれぞれJWTとBouncy Castleライブラリを使用することです。

  1. [〜#〜] jwt [〜#〜] JWTトークンのエンコードおよびデコード用
  2. Bouncy Castle 暗号化と復号化、特に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);
            }
        }
    }

ps:RSA秘密鍵の形式は次のとおりです。

----- RSAプライベートキーの開始-----

{base64形式の値}

----- RSAプライベートキーの終了-----

0
Ehsan Mirsaeedi
  1. RS256は暗号化アルゴリズムではなく署名アルゴリズムです
  2. 暗号化は公開鍵で行われます
  3. 暗号化されたJWTを作成するコードは次のとおりです。

    var cert = new X509Certificate2(".\\key.cer");
    var rsa = (RSACryptoServiceProvider) cert.PublicKey.Key;
    
    var payload = new Dictionary<string, object>()
    {
      {"sub", "[email protected]"},
      {"exp", 1300819380}
    };
    
    var encryptedToken =
      JWT.Encode(
        payload,
        rsa,
        JweAlgorithm.RSA_OAEP,
        JweEncryption.A256CBC_HS512,
        null);
    
0
Broken Link

公開証明書と.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);
0
rubiktubik