HuseyinUslu
HuseyinUslu

Reputation: 4134

can't get the same hmac_sha1 results for java and c# (winrt)

I'm trying to convert a java based code to c# as followed;

The original java code;

String str2 = "5f1fa09364a6ae7e35a090b434f182652ab8dd76:{\"expiration\": 1353759442.0991001, \"channel\": \"dreamhacksc2\", \"user_agent\": \".*"

Mac localMac = Mac.getInstance("HmacSHA1");
localMac.init(new SecretKeySpec("Wd75Yj9sS26Lmhve".getBytes(), localMac.getAlgorithm()));
String str3 = new BigInteger(1, localMac.doFinal(str2.getBytes())).toString(16);
Object[] arrayOfObject2 = new Object[2];
arrayOfObject2[0] = str3;
arrayOfObject2[1] = URLEncoder.encode(str2);
String str4 = String.format("%s:%s", arrayOfObject2);

And here is my WinRT based c# code

var token="5f1fa09364a6ae7e35a090b434f182652ab8dd76:{\"expiration\": 1353759442.0991001, \"channel\": \"dreamhacksc2\", \"user_agent\": \".*";

var encoding = new System.Text.UTF8Encoding();
var key = encoding.GetBytes("Wd75Yj9sS26Lmhve");
//var key = Convert.FromBase64String("Wd75Yj9sS26Lmhve");

var tokenData = encoding.GetBytes(token);

var result = HmacSha1(key, tokenData);

var hexString = new BigInteger(result).ToString("x");
var urlEncoded = System.Net.WebUtility.UrlEncode(token);

var combined = String.Format("{0}:{1}", hexString, urlEncoded);

and the hmacsha1 function as I'm running on WinRT;

    public static byte[] HmacSha1(byte[] key, byte[] data)
    {
        var crypt = Windows.Security.Cryptography.Core.MacAlgorithmProvider.OpenAlgorithm("HMAC_SHA1");
        var keyBuffer = Windows.Security.Cryptography.CryptographicBuffer.CreateFromByteArray(key);
        var cryptKey = crypt.CreateKey(keyBuffer);

        var dataBuffer = Windows.Security.Cryptography.CryptographicBuffer.CreateFromByteArray(data);
        var signBuffer = Windows.Security.Cryptography.Core.CryptographicEngine.Sign(cryptKey, dataBuffer);

        byte[] result;
        Windows.Security.Cryptography.CryptographicBuffer.CopyToByteArray(signBuffer, out result);

        return result;
    }

So here's the corresponding outpus;

(JAVA) 92e893efe72a2f7df6ed409ce35819faba191a63:5f1fa09364a6ae7e35a090b434f182652ab8dd76%3A%7B%22expiration%22%3A+1353759442.0991001%2C+%22channel%22%3A+%22dreamhacksc2%22%2C+%22user_agent%22%3A+%22.*
  (C#) 63b10e1d8e9f99cd7fba2ed46fe8e4a4a40222f5:5f1fa09364a6ae7e35a090b434f182652ab8dd76%3A%7B%22expiration%22%3A+1353759442.0991001%2C+%22channel%22%3A+%22dreamhacksc2%22%2C+%22user_agent%22%3A+%22.*

as shown above, the ouputs of HMAC_SHA1 from java and c# are not equal. Any ideas? Am I running encoding problems?

Upvotes: 3

Views: 2193

Answers (3)

Esailija
Esailija

Reputation: 140210

Just keep it simple and the code equal.

Java:

public static String toHexString(byte[] bytes) {
    StringBuilder sb = new StringBuilder(bytes.length * 2);
    for (int i = 0; i < bytes.length; ++i) {
        sb.append(String.format("%02x", bytes[i]));
    }
    return sb.toString();
}

public static void main(String[] args) {
    String str2 = "5f1fa09364a6ae7e35a090b434f182652ab8dd76:{\"expiration\": 1353759442.0991001, \"channel\": \"dreamhacksc2\", \"user_agent\": \".*";
    Mac localMac;
    try {
        localMac = Mac.getInstance("HmacSHA1");

        localMac.init(new SecretKeySpec("Wd75Yj9sS26Lmhve"
                .getBytes("UTF-8"), localMac.getAlgorithm()));
        byte[] result = localMac.doFinal(str2.getBytes("UTF-8"));
        String hexString = toHexString(result);
        System.out.println(hexString);
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    } catch (InvalidKeyException e) {
        e.printStackTrace();
    } catch (IllegalStateException e) {
        e.printStackTrace();
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    }

}

Result:

f52202a4a4e4e86fd42eba7fcd999f8e1d0eb163

C#:

var token = "5f1fa09364a6ae7e35a090b434f182652ab8dd76:{\"expiration\": 1353759442.0991001, \"channel\": \"dreamhacksc2\", \"user_agent\": \".*";

var encoding = new System.Text.UTF8Encoding();
var privateKey = "Wd75Yj9sS26Lmhve";
HMACSHA1 hmac_sha1 = new HMACSHA1(encoding.GetBytes(privateKey));
hmac_sha1.Initialize();
byte[] result = hmac_sha1.ComputeHash(encoding.GetBytes(token));

string hexString = String.Join( "", result.Select( a => a.ToString("x2") ));

Console.WriteLine(hexString);

Result:

f52202a4a4e4e86fd42eba7fcd999f8e1d0eb163

Upvotes: 4

Maarten Bodewes
Maarten Bodewes

Reputation: 93948

You are confusing bytes with strings. The result of getBytes() depends on the default , which may be different from system to system.

Upvotes: 1

Three tips:

  1. When I tested your Java code, I received this value for str3: f52202a4a4e4e86fd42eba7fcd999f8e1d0eb163 That differs from both Java and C# result posted by you. (This online tool also calculates my result.)

  2. Wikipedia contains an example, and it seems to be correct based on Java code and online calculator. In the first step, test your Java and C# code with the "The quick brown fox jumps over the lazy dog", "key", "de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9" triplet.

  3. It is not a good idea using BigInterger.toString(16) converting byte array to hex string, because when the byte array begins with one ore more zero digit (or hexit?), then the converted hex string will not contains the leading 0 characters.

Upvotes: 4

Related Questions