c# How to verify signature JWT?

anhtv13 picture anhtv13 · Mar 23, 2016 · Viewed 31.8k times · Source

I have a token, a file containing public key and I want to verify the signature. I tried to verify signature based on this.

However, decodedCrypto and decodedSignature don't match.

Here is my code:

public static string Decode(string token, string key, bool verify)
    {
        var parts = token.Split('.');
        var header = parts[0];
        var payload = parts[1];
        byte[] crypto = Base64UrlDecode(parts[2]);

        var headerJson = Encoding.UTF8.GetString(Base64UrlDecode(header));
        var headerData = JObject.Parse(headerJson);
        var payloadJson = Encoding.UTF8.GetString(Base64UrlDecode(payload));
        var payloadData = JObject.Parse(payloadJson);

        if (verify)
        {
            var bytesToSign = Encoding.UTF8.GetBytes(string.Concat(header, ".", payload));
            var keyBytes = Encoding.UTF8.GetBytes(key);
            var algorithm = (string)headerData["alg"];
            var signature = HashAlgorithms[GetHashAlgorithm(algorithm)](keyBytes, bytesToSign);
            var decodedCrypto = Convert.ToBase64String(crypto);
            var decodedSignature = Convert.ToBase64String(signature);

            if (decodedCrypto != decodedSignature)
            {
                throw new ApplicationException(string.Format("Invalid signature. Expected {0} got {1}", decodedCrypto, decodedSignature));
            }
        }

        return payloadData.ToString();
    }

I'm sure that the signature of token is valid. I try to verify on https://jwt.io/ and it showed that Signature verified. So the problem is the algorithm to encode, decode.

Is there anyone can solve this problem? The algorithm is RS256

enter image description here

Answer

anhtv13 picture anhtv13 · Mar 23, 2016

I finally got a solution from my colleague.

For those who have the same problem, try my code:

public static string Decode(string token, string key, bool verify = true)
{
    string[] parts = token.Split('.');
    string header = parts[0];
    string payload = parts[1];
    byte[] crypto = Base64UrlDecode(parts[2]);

    string headerJson = Encoding.UTF8.GetString(Base64UrlDecode(header));
    JObject headerData = JObject.Parse(headerJson);

    string payloadJson = Encoding.UTF8.GetString(Base64UrlDecode(payload));
    JObject payloadData = JObject.Parse(payloadJson);

    if (verify)
    {
        var keyBytes = Convert.FromBase64String(key); // your key here

        AsymmetricKeyParameter asymmetricKeyParameter = PublicKeyFactory.CreateKey(keyBytes);
        RsaKeyParameters rsaKeyParameters = (RsaKeyParameters)asymmetricKeyParameter;
        RSAParameters rsaParameters = new RSAParameters();
        rsaParameters.Modulus = rsaKeyParameters.Modulus.ToByteArrayUnsigned();
        rsaParameters.Exponent = rsaKeyParameters.Exponent.ToByteArrayUnsigned();
        RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
        rsa.ImportParameters(rsaParameters);

        SHA256 sha256 = SHA256.Create();
        byte[] hash = sha256.ComputeHash(Encoding.UTF8.GetBytes(parts[0] + '.' + parts[1]));

        RSAPKCS1SignatureDeformatter rsaDeformatter = new RSAPKCS1SignatureDeformatter(rsa);
        rsaDeformatter.SetHashAlgorithm("SHA256");
        if (!rsaDeformatter.VerifySignature(hash, FromBase64Url(parts[2])))
            throw new ApplicationException(string.Format("Invalid signature"));
    }

    return payloadData.ToString();
}

It works for me. The algorithm is RS256.