JwtSecurityTokenHandler.ValidateToken 相当于 Jose.JWT.Decode 用于解密 JWT 密文 - 总是得到 dx10609: 解密失败

问题描述 投票:0回答:1

我有一个 .PEM 格式的私钥,我试图用它来使用 Microsoft 的库从 JWT 中解密密文,但无法解密。我有一个使用 Jose.JWT.Decode 的工作解决方案。但是,当我尝试使用 JwtSecurityTokenHandler.ValidateToken 时,我总是收到 idx10609: 解密失败。如果有人能向我解释如何使用 Microsoft 库而不是 Jose,我会很高兴。

这是工作的 Jose.JWT 代码:

    public static string jweRsaDecryptFromBase64UrlToken(string rsaPrivateKey, string jweTokenBase64Url)
    {
        RSA rsaAlg = RSA.Create();
        byte[] privateKeyByte = getRsaPrivateKeyEncodedFromPem(rsaPrivateKey);
        int _out;
        rsaAlg.ImportPkcs8PrivateKey(privateKeyByte, out _out);
        string json = "";
        try
        {
            json = Jose.JWT.Decode(jweTokenBase64Url, rsaAlg);
        }
        catch (Jose.EncryptionException)
        {
            Console.WriteLine("*** Error: payload corrupted or wrong private key ***");
            // throws: Jose.EncryptionException: Unable to decrypt content or authentication tag do not match.
        }
        return json;
    }


    static byte[] Base64Decoding(string input)
    {
        return Convert.FromBase64String(input);
    }

    private static byte[] getRsaPrivateKeyEncodedFromPem(string rsaPrivateKeyPem)
    {
        string rsaPrivateKeyHeaderPem = "-----BEGIN PRIVATE KEY-----\r\n";
        string rsaPrivateKeyFooterPem = "-----END PRIVATE KEY-----";
        string rsaPrivateKeyDataPem = rsaPrivateKeyPem.Replace(rsaPrivateKeyHeaderPem, "").Replace(rsaPrivateKeyFooterPem, "").Replace("\n", "");
        return Base64Decoding(rsaPrivateKeyDataPem);
    }

    private static string loadRsaPrivateKeyPem()
    {

        string keyPath = "..\\..\\..\\keys\\";

        string encryptionKey = File.ReadAllText($"{keyPath}private.pem");

        return encryptionKey;


    }

这是我认为应该有效但总是失败的代码:

   public static void DecryptJwe(string jweString, string decryptionKeyInput)
    {
        string jweToken = jweString;
        
        Microsoft.IdentityModel.Logging.IdentityModelEventSource.ShowPII = true;

        
        var handler = new JwtSecurityTokenHandler();
        var jsonToken = handler.ReadToken(jweToken);
        var tokens = jsonToken as JwtSecurityToken;

        var rsaKey = RSA.Create();

        byte[] privateKeyByte = getRsaPrivateKeyEncodedFromPem(decryptionKeyInput);


        static byte[] Base64Decoding(string input)
        {
            return Convert.FromBase64String(input);
        }

        static byte[] getRsaPrivateKeyEncodedFromPem(string rsaPrivateKeyPem)
        {
            string rsaPrivateKeyHeaderPem = "-----BEGIN PRIVATE KEY-----\r\n";
            string rsaPrivateKeyFooterPem = "-----END PRIVATE KEY-----";
            string rsaPrivateKeyDataPem = rsaPrivateKeyPem.Replace(rsaPrivateKeyHeaderPem, "").Replace(rsaPrivateKeyFooterPem, "").Replace("\n", "");
            return Base64Decoding(rsaPrivateKeyDataPem);

        }

        rsaKey.ImportPkcs8PrivateKey(privateKeyByte, out _);

        byte[] hashed = rsaKey.ExportRSAPrivateKey();

        var privateEncryptionKey = new RsaSecurityKey(rsaKey);

        var securityKey = new Microsoft.IdentityModel.Tokens.SymmetricSecurityKey(hashed);
        //var encryptingCredentials = new EncryptingCredentials(new SymmetricSecurityKey(privateKeyByte), SecurityAlgorithms.Aes256Gcm, SecurityAlgorithms.RsaOAEP);

        bool alg = securityKey.IsSupportedAlgorithm("A256GCM");


        var readableToken = handler.CanReadToken(jweString);

        if (readableToken != true)
        {
            Console.WriteLine("The token doesn't seem to be in a proper JWT format.");
        }

        
        /*
        //Extract the headers of the JWT
        var headers = tokens.Header;
        var jwtHeaders = "{";
        foreach (var h in headers)
        {
            jwtHeaders += '"' + h.Key + "\":\"" + h.Value + "\",";
            Console.WriteLine($"Header: {h.Key} Value: {h.Value} ");
        }
        jwtHeaders += "}";
        */


        handler.ValidateToken(jweString, new TokenValidationParameters
        {
            ValidateIssuerSigningKey = true,
            TokenDecryptionKey = new SymmetricSecurityKey(privateKeyByte),
            ValidateIssuer = false,
            ValidateAudience = false,
        }, out SecurityToken validatedToken);
c# encryption jwt pem
1个回答
0
投票

如果 JWT 使用 RSA 密钥加密,则应使用 RsaSecurityKey 而不是 SymmetricSecurityKey。在 TokenValidationParameters 中,您提供了 TokenDecryptionKey 作为从 RSA 私钥字节派生的 SymmetricSecurityKey。您应该直接使用 RsaSecurityKey。

资源:

public static void DecryptJwe(string jweString, string decryptionKeyInput)
{
    Microsoft.IdentityModel.Logging.IdentityModelEventSource.ShowPII = true;

    var handler = new JwtSecurityTokenHandler();

    if (!handler.CanReadToken(jweString))
    {
        Console.WriteLine("The token doesn't seem to be in a proper JWT format.");
        return;
    }

    byte[] privateKeyByte = getRsaPrivateKeyEncodedFromPem(decryptionKeyInput);

    RSA rsaKey = RSA.Create();
    rsaKey.ImportPkcs8PrivateKey(privateKeyByte, out _);
    var privateEncryptionKey = new RsaSecurityKey(rsaKey);

    SecurityToken validatedToken;

    try
    {
        handler.ValidateToken(jweString, new TokenValidationParameters
        {
            ValidateIssuerSigningKey = true,
            TokenDecryptionKey = privateEncryptionKey, // Use the RSA key directly
            ValidateIssuer = false,
            ValidateAudience = false,
        }, out validatedToken);
        
        // If successful, the token is decrypted and validated. Use validatedToken as needed.
    }
    catch (Exception ex)
    {
        Console.WriteLine($"Token validation failed: {ex.Message}");
    }
}

备注:

  • IdentityModelEventSource.ShowPII = true;可能会记录敏感数据。开发调试中OK。
  • 您已将 ValidateIssuer 和 ValidateAudience 设置为 false,因此 JWT 的颁发者和受众将不会得到验证。如果智威汤逊的来源和目标受众很清楚,那就好。
© www.soinside.com 2019 - 2024. All rights reserved.