web-dev-qa-db-fra.com

Comment créer un JWT chiffré en C # en utilisant RS256 avec une clé privée RSA

J'utilise la bibliothèque jose-jwt et je veux créer un JWT signé en C # en utilisant l'algorithme RS256 pour le chiffrement. Je n'ai aucune expérience de la cryptographie, alors veuillez excuser mon ignorance. Je vois l'exemple suivant dans les documents:

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

qui montre l'utilisation d'un p12 fichier, mais comment utiliser un fichier de clé RSA du formulaire ci-dessous? Je regarde les documents pour X509Certificate2 , mais je ne vois aucune option pour les clés privées RSA. Il semble accepter uniquement PKCS7, que je comprends être des clés publiques.

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

Enfin, quelle est la différence entre les deux options répertoriées dans le docs , et comment choisir entre les deux?

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

Famille RS- * et PS- *

CLR:

Les signatures RS256, RS384, RS512 et PS256, PS384, PS512 nécessitent une clé RSACryptoServiceProvider (généralement privée) de longueur correspondante. CSP doit être obligé d'utiliser Microsoft Enhanced RSA et AES Cryptographic Provider. Ce qui peut généralement être fait en réimportant des paramètres RSAP. Voir http://clrsecurity.codeplex.com/discussions/243156 pour plus de détails.

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

CORECLR: Les signatures RS256, RS384, RS512 nécessitent une clé RSA (généralement privée) de longueur correspondante.

13
FullStack

Je sais que ce post est ancien, mais il m'a fallu une éternité pour le comprendre, alors j'ai pensé que je partagerais.

Pour tester, j'ai créé des clés RSA à l'aide d'OpenSSL:

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

Vous aurez besoin des 2 paquets de pépites suivants:

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

Code de test

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

Créer un jeton

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

Jeton de décodage

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

J'ai trouvé https://jwt.io/ une excellente ressource pour tester vos jetons

20
Roche

Si vous souhaitez utiliser un certificat, vous pouvez le récupérer par son empreinte numérique en utilisant cette méthode

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

puis:

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

La clé de cette question est d'utiliser les bibliothèques JWT et Bouncy Castle pour encoder le jeton et le signer respectivement.

  1. JWT pour l'encodage et le décodage des jetons JWT
  2. Bouncy Castle prend en charge le cryptage et le décryptage, en particulier RS256 obtenez-le ici

Tout d'abord, vous devez transformer la clé privée sous la forme de paramètres RSA. Ensuite, vous devez passer les paramètres RSA à l'algorithme RSA comme clé privée. Enfin, vous utilisez la bibliothèque JWT pour coder et signer le jeton.

    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: la clé privée RSA doit avoir le format suivant:

----- COMMENCER LA CLÉ PRIVÉE RSA -----

{valeur formatée en base64}

----- FIN DE LA CLÉ PRIVÉE RSA -----

0
Ehsan Mirsaeedi
  1. RS256 est un algorithme de signature et non un algorithme de cryptage
  2. Le cryptage se fait avec la clé publique
  3. Voici le code pour créer un JWT chiffré:

    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
0
Broken Link

Si vous utilisez un certificat public et .NET 4.6, pour le décodage, vous pouvez utiliser:

string token = "eyJhbGciOiJSUzI1NiIsInR....";
string certificate = "MIICnzCCAYcCBgFd2yEPx....";
var publicKey = new X509Certificate2(Convert.FromBase64String(certificate )).GetRSAPublicKey();
string decoded = JWT.Decode(token, publicKey, JwsAlgorithm.RS256);
0
rubiktubik