C# vs Java HmacSHA1 and then base64 [closed]
Asked Answered
R

2

5

I have a java code example to make a digest computed using the HMAC-SHA1 algorithm (RFC 2104.), then encoded using Base64 encoding (RFC 2045).

here is the java code

public static String buildDigest(String key, String idString) throws SignatureException {


 try {
    String algorithm = "HmacSHA1";
    Charset charset = Charset.forName("utf-8");
    SecretKeySpec signingKey = new SecretKeySpec(key.getBytes(), algorithm);
    Mac mac = Mac.getInstance(algorithm);
    mac.init(signingKey);
    return new String(Base64.encodeBase64(mac.doFinal(idString.getBytes(charset))), charset);
  } catch (Exception e) {
    throw new SignatureException("Failed to generate HMAC : " + e.getMessage());
  }
}

I found answers here in Stack Overflow so here is the C# code

   private string EncodeHMAC(string input, byte[] key)
    {
        HMACSHA1 myhmacsha1 = new HMACSHA1(key);
        byte[] byteArray = Encoding.UTF8.GetBytes(input);
       // MemoryStream stream = new MemoryStream(byteArray);
        var hashValue = myhmacsha1.ComputeHash(byteArray);
        return hashValue.Aggregate("", (s, e) => s + String.Format("{0:x2}", e), s => s);
    }

    private string EncodeTo64(string toEncode)
    {
        byte[] toEncodeAsBytes = System.Text.UTF8Encoding.UTF8.GetBytes(toEncode);

        string returnValue = System.Convert.ToBase64String(toEncodeAsBytes);

        return returnValue;
    }

I am not getting the right results shown in the tutorial that I am following

Russell answered 8/1, 2013 at 13:11 Comment(1)
Why are you passing the key as a string in the Java version? Are you sure that the result of the Java method key.getBytes() is equivalent to the byte array you are using in the C# version? If I understand your C# code correctly, it also returns the HMAC hex encoded, while the Java version uses Base64.Wean
D
7

Try this:

// This method will return the base 64 encoded string using the given input and key.
private string EncodeHMAC(string input, byte[] key)
{
    HMACSHA1 hmac = new HMACSHA1(key);
    byte[] stringBytes = Encoding.UTF8.GetBytes(input);
    byte[] hashedValue = hmac.ComputeHash(stringBytes);
    return Convert.ToBase64String(hashedValue);
}

I don't think you're converting the hashed value to a base 64 string correctly.

Demythologize answered 8/1, 2013 at 13:48 Comment(0)
S
2

I use this function to implement authentication of REST web service calls. It's important that sender and receiver use the same encoding.

Unfortunately it took me a while to find a matching PHP HAMACimplementation to this C# version.

private bool ValidateHash(String uid, String hash, DataToSign data) {
        StringBuilder strToSign = new StringBuilder();

        strToSign.Append(data.HttpMethod + '\n');
        strToSign.Append(data.Date.ToString("r") + '\n');
        strToSign.Append(data.Uri);

        Byte[] secretBytes = UTF8Encoding.UTF8.GetBytes(this._secretKey);
        HMACSHA1 hmac = new HMACSHA1(secretBytes);

        Byte[] dataBytes = UTF8Encoding.UTF8.GetBytes(strToSign.ToString());
        Byte[] calcHash = hmac.ComputeHash(dataBytes);
        String calcHashString = Convert.ToBase64String(calcHash);

        if (calcHashString.Equals(hash)) {
            if (log.IsDebugEnabled) log.Debug(uid + " - [ValidateHash] HMAC is valid.");
            return true;
        }
        return false;
    }

Hope that helps!

Sarre answered 8/1, 2013 at 14:21 Comment(2)
If you're going to use a string builder don't concatenate strings within the append method! If you want to add a new line at the end of your string, do this instead: strToSign.AppendLine(data.HttpMethod)Demythologize
@Demythologize you're right - it's been a while I wrote this.Sarre

© 2022 - 2024 — McMap. All rights reserved.