0

I am trying to connect to an API where I need to authenticate by passing in the header a hashed string in my C# application. In the documentation from the provider though they only have an example of how to hash the string using JS functions in a react application, bellow is the screenshot of the code snippet found in said documentation.

Code snippet from documentation

I have already found an article here on stackoverflow on an alternative for the btoa function but I am completely stuck on the CryptoJS.HmacSHA384 function alternative. I have tried using the System.Security.Cryptography.HMACSHA384 class but can't figure out how to encode the strings I am passing to the method in order to obtain the same result, causing an Authorization denied when I try to connect to the API endpoint. Bellow is the code from the method I have written so far (that is not working):

    public void myMethodToConnet(string user, string pass, string custId, string partId, string partKey, string ver, string commId)
{
    int resetPasswordErrorCode;

    _user = user;
    _password = pass;
    _rooftopId = custId;
    _partnerId = partId;
    _partnerKey = Encoding.UTF8.GetBytes(partKey);
    _version = ver;
    _communityId = commId;

    _url = "url";

    _token = GetToken().Result;

    using (HMACSHA384 hmac = new HMACSHA384(_partnerKey))
    {
        _hmac = hmac.ComputeHash(Encoding.UTF8.GetBytes(_token));

        _hash = BTOA($"{_user}:{Encoding.UTF8.GetString(_hmac)}:{_password}");
    }
    ActivateToken().Result;
}
private static string BTOA(string toEncode)
{
    byte[] bytes = Encoding.GetEncoding(28591).GetBytes(toEncode);
    string result = System.Convert.ToBase64String(bytes);
    return result;
}
private async Task<int> ActivateToken()
{
    CheckPasswordRequest request = new CheckPasswordRequest();
    CheckPasswordResponse response = new CheckPasswordResponse();
    StringContent content;
    string jsonString;
    string apiResponse;
    int errorCode = 0;

    using (HttpClient httpClient = new HttpClient())
    {
        request = new CheckPasswordRequest() { RooftopId = _rooftopId };
        jsonString = JsonConvert.SerializeObject(request);
        content = new StringContent(jsonString, Encoding.UTF8, "application/json");
        httpClient.DefaultRequestHeaders.Add("Authorization", $"DataHub-Hash {_hash}");
        using (var resp = await httpClient.PostAsync($"{_url}/CheckPassword", content))
        {
            apiResponse = await resp.Content.ReadAsStringAsync();
            response = JsonConvert.DeserializeObject<CheckPasswordResponse>(apiResponse);
            errorCode = response.ErrorCode;
        }
    }
    return errorCode;
}

Thanks!

guster47
  • 71
  • 1
  • 7
  • 1
    Are you sure you're getting the correct bytes for `_partnerKey` and passing the correct string to `BTOA`? I'm saying this with no knowledge of your system, but `Encoding.UTF8.GetBytes` seems like an odd way to get the key. I would expect `partKey` to be a Base64 string or maybe a hexadecimal string. Same thing with the way you're encoding `_hmac`. I would expect you'd need to take that to Base64 or perhaps hex. – Joshua Robinson Jul 21 '20 at 15:43
  • 1
    I finally figured it out, the key was actually correct, the problem was in the _hmac that needs to be in hex for this specific situation. I'll write a complete explanation of what I did once I clean everything up from the various tests snippets I added! – guster47 Jul 21 '20 at 16:09

1 Answers1

0

I finally figured it out by creating a simple HTML page where I ran the JS commands and printed out the output to than compare it to what the output in my C# application was. At the end the solution was that of converting the byte array output of the encryption algorithm to hex, to do so I created this helper method:

public static string ByteToString(byte[] input)
{
    string output= "";

    for (int i = 0; i < input.Length; i++)
    {
        output+= input[i].ToString("X2");
    }
    return (output);
}  

by inserting the output string of this method between the user and password and running my BTOA helper method returned the string the API was expecting and managed to authenticate.

guster47
  • 71
  • 1
  • 7