Estoy tratando de verificar el token jwt ES512 usando la clave pública que está en formato de cadena:

Estoy tratando de imitar una muestra escrita para ES256 que es algo como esto:

    // The code for ES256
    public static void VerifyES512Jwt(string token,string publicKey)
    {
        byte[] publicKeyBytes = Convert.FromBase64String(publicKey);

        string[] parts = token.Split('.');

        string header = parts[0];
        string payload = parts[1];
        string signature = parts[2];

        var keyType = new byte[] { 0x45, 0x43, 0x53, 0x31 };
        var keyLength = new byte[] { 0x20, 0x00, 0x00, 0x00 };
        var key = keyType.Concat(keyLength).Concat(publicKeyBytes.Skip(publicKeyBytes.Length - 64)).ToArray(); 
        CngKey cngKey = CngKey.Import(key, CngKeyBlobFormat.EccPublicBlob);
        
        // the purpose is to get ECDsaCng and verify the payload data
         ECDsaCng eCDsaCng = new ECDsaCng(cngKey);
        
        bool result = eCDsaCng.VerifyData(payload, signatureBytes); 
    }

Estoy tratando de usar este código para ES512 y me quedé atascado al obtener la clave

        var keyType = new byte[] { 0x45, 0x43, 0x53, 0x31 };
        var keyLength = new byte[] { 0x20, 0x00, 0x00, 0x00 };
        var key = keyType.Concat(keyLength).Concat(publicKeyBytes.Skip(publicKeyBytes.Length - 64)).ToArray(); 

Cuando se usa con lo anterior, da error al obtener la clave:

CngKey cngKey = CngKey.Import(key, CngKeyBlobFormat.EccPublicBlob);

El token de clave pública y estoy usando son los siguientes : clave pública " MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQBgc4HZz + / + fBbC7lmEww0AO3NK9wVZ PDZ0VEnsaUFLEYpTzb90nITtJUcPUbvOsdZIZ1Q8fnbquAYgxXL5UgHMoywAib47 6MkyyYgPk0BXZq3mq4zImTRNuaU9slj9TVJ3ScT3L1bXwVuPJDzpr5GOFpaj WWM Al8G7CqwoJOsW7Kddns = "

Token: " eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzUxMiJ9.eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE1NjUwOTk2ODgsImV4cCI6MTU5ODE4OTg4NSwiYXVkIjoiaHR0cDovL2xvY2FsaG9zdDozNTg4Iiwic3ViIjoiaHR0cDovL2xvY2FsaG9zdDo1MDM3NiIsImZpcnN0bmFtZSI6IkFydmluZCIsImxhc3RuYW1lIjoiS3VtYXIiLCJFbWFpbCI6ImFydmluZC5rdW1hckBzdHJlYW1hbWcuY29tIiwiSWQiOiIxMDEifQ.AVwAJeY44lKrnywnDs7CdUOu3gli2cGafSJ6iP3zT7lkZpd2QnL0k54aVmPVxAGuN5dDnzbYmMTdRl5u2QE92ccOAHrcf5yA2gsvhhAGuDAAeh6Io4VU7v5TOTvwWGRb - ubgdjUvagA_HSJOyeXvFR16_M_MzGfDnXfg02sj4y9VFjDr "

Cualquier ayuda sería muy apreciada. Gracias y saludos.

enter code here
1
Arvind Krmar 24 jun. 2020 a las 13:44

2 respuestas

Generé la clave según lo sugerido por @Topaco y la usé con JwtSecurityTokenHandler del modelo de identidad y funcionó. la función que estaba tratando de usar en cuestión no funcionó por algunas razones: el código de trabajo es el siguiente:

public static bool ValidateEcdsa512JwtToken(string token, string publicKey)
{
    ECDsa pubKey = LoadPublicKey(publicKey);

    var securityTokenHandler = new JwtSecurityTokenHandler();
    var validationParameters = new TokenValidationParameters()
    {
        ValidateAudience = false,
        ValidateIssuer = false,
        IssuerSigningKey = new ECDsaSecurityKey(pubKey)
    };

    SecurityToken stoken;
    var claims = securityTokenHandler.ValidateToken(token, validationParameters, out stoken);
    var verified=claims.Identity.IsAuthenticated;

    return verified;
}


private static ECDsa LoadPublicKey(string publicKey)
{
     byte[] publicKeyBytes = Convert.FromBase64String(publicKey);
     var keyType = new byte[] { 0x45, 0x43, 0x53, 0x35 };
     var keyLength = new byte[] { 0x42, 0x00, 0x00, 0x00 };
     var key = keyType.Concat(keyLength).Concat(publicKeyBytes.Skip(publicKeyBytes.Length - 132)).ToArray();

     CngKey cngKey = CngKey.Import(key, CngKeyBlobFormat.EccPublicBlob);
     ECDsaCng eCDsaCng = new ECDsaCng(cngKey);
     eCDsaCng.HashAlgorithm = CngAlgorithm.ECDsaP521;
     return eCDsaCng;
}
1
Arvind Krmar 25 jun. 2020 a las 14:00

ES512 usa ECDSA con P-521 y SHA-512.

Una clave pública para P-521 (secp521r1, cap. 2.6.1) tiene un tamaño de 2 x 66 = 132 bytes en forma no comprimida (byte frontal 0x04). MS especifica la clave pública para P-521 con el valor 0x35534345.

Por lo tanto, la clave debe generarse de la siguiente manera:

var keyType = new byte[] { 0x45, 0x43, 0x53, 0x35 };
var keyLength = new byte[] { 0x42, 0x00, 0x00, 0x00 };
var key = keyType.Concat(keyLength).Concat(publicKeyBytes.Skip(publicKeyBytes.Length - 132)).ToArray();

Los datos a firmar son encabezado y carga útil (ambos codificados en Base64url) incluyendo el separador (.). La firma también está codificada en Base64url. Por lo tanto, la verificación debe realizarse de la siguiente manera:

byte[] headerPayloadBytes = Encoding.UTF8.GetBytes(header + "." + payload);
byte[] signatureBytes = Base64UrlDecode(signature);
bool verified = eCDsaCng.VerifyData(headerPayloadBytes, signatureBytes, HashAlgorithmName.SHA512);

Base64UrlDecode realiza la decodificación Base64url, ver p. aquí para obtener detalles sobre la implementación.

1
Topaco 24 jun. 2020 a las 15:26