Verify HMAC signature in WCF web service in .NET Framework

120 Views Asked by At

I'm trying to implement HMAC security in a WCF web service, but am having a hard time verifying the HMAC signature. I am using .NET Framework 4.8.

I'm following DocuSign API documentation here:
https://developers.docusign.com/platform/webhooks/connect/validate/

Their documentation provides code samples, specifically in "Step 2: Verify the HMAC signature":

using System;
using System.Text;
using System.Security.Cryptography;

public static class HMACValidation
{
    public static string ComputeHash(string secret, string payload)
    {
        byte[] bytes = Encoding.UTF8.GetBytes(secret);
        HMAC hmac = new HMACSHA256(bytes);
        bytes = Encoding.UTF8.GetBytes(payload);

        return Convert.ToBase64String(hmac.ComputeHash(bytes));
    }

    public static bool HashIsValid(string secret, string payload, string verify)
    {
       ReadOnlySpan<byte> hashBytes = Convert.FromBase64String(ComputeHash(secret, payload));
       ReadOnlySpan<byte> verifyBytes = Convert.FromBase64String(verify);

       return CryptographicOperations.FixedTimeEquals(hashBytes, verifyBytes);
    }
}

Per Microsoft, CryptographicOperations.FixedTimeEquals is only for: .NET Core 2.1, 2.2, 3.0, 3.1, .NET 5, .NET 6, .NET 7

So I'm unable to use this code sample in .NET Framework 4.8.

Question 1: in .NET Framework 4.8, is there another way to verify the HMAC signature?

I was unable to find an alternative, so I tried a similar approach to the Microsoft article below.

A Guide to Designing and Building RESTful Web Services with WCF 3.5

So, I implemented the following in my WCF service, in hopes to work-around the CryptographicOperations.FixedTimeEquals:

public string DocuSign(DocuSignWebhookRequest jsonRequest)
{
    var payload = JsonConvert.SerializeObject(jsonRequest);
    var secretKey = ConfigurationManager.AppSettings["HMAC_Key"];
    var verifyKey = HttpContext.Current.Request.Headers["x-docusign-signature-1"];

    var computedHashString = ComputeHash(secretKey, payload);
    var valid = computedHashString.Equals(verifyKey); // false
}

private string ComputeHash(string secret, string payload)
{
    byte[] bytes = Encoding.UTF8.GetBytes(secret);
    HMAC Mac = new HMACSHA256(bytes);
    bytes = Encoding.UTF8.GetBytes(payload);
    return Convert.ToBase64String(Mac.ComputeHash(bytes));
}

Question 2: any ideas why my code is not able to verify the HMAC signature? It's always returning false when comparing to the verify key sent by DocuSign.

1

There are 1 best solutions below

1
Jiayao On

Here is an official document which shows how to sign a file by using the HMACSHA256 object and then how to verify the file: HMACSHA256 Class.

About the second question, the code you post have substituted in the actual value. I'm not sure if this will cause a problem.