nathanVegetable
nathanVegetable

Reputation: 79

Getting HmacSHA1 Java Hash to match Powershell Hash

I have this Powershell snippet, which I cannot change and provides the Hash I need to match:

$key = 'test'
$bytes = [Text.Encoding]::UTF8.GetBytes($key)
WRITE-HOST "bytes: " $bytes
$hmacsha = new-object system.security.cryptography.HMACSHA1
$hmacsha.key = $bytes
$hash = $hmacsha.ComputeHash($bytes)
WRITE-HOST "hash: " $hash

Which gives this result:

bytes:  116 101 115 116
hash:  12 148 81 92 21 229 9 91 138 135 165 11 160 223 59 243 142 208 95 230

And this in Java:

String key = "test";
byte[] bytes = key.getBytes("UTF-8");
System.out.println("bytes: " + Arrays.toString(bytes));

MessageDigest md = MessageDigest.getInstance("SHA-1");
byte[] keyBytes = md.digest(bytes);
SecretKey sk = new SecretKeySpec(keyBytes, "HmacSHA1");
Mac mac = Mac.getInstance("HmacSHA1");
mac.init(sk);
byte[] hash = mac.doFinal(keyBytes);
System.out.println("hash 1: " + Arrays.toString(hash));

sk = new SecretKeySpec(bytes, "HmacSHA1");
mac = Mac.getInstance("HmacSHA1");
mac.init(sk);
hash = mac.doFinal(bytes);
System.out.println("hash 2: " + Arrays.toString(hash));

Which outputs:

bytes: [116, 101, 115, 116]
hash 1: [-112, -37, 64, 65, -91, -97, 36, 60, -80, -110, 62, -105, -63, -69, -79, -18, 29, -95, 23, -116]
hash 2: [12, -108, 81, 92, 21, -27, 9, 91, -118, -121, -91, 11, -96, -33, 59, -13, -114, -48, 95, -26]

I cannot seem to get the Hash to match what Powershell is outputting. In both examples I am creating a hmacsha1 instance with a key of "test", then getting the hash of "test", but both have some minor difference causing them to give different results.

Upvotes: 0

Views: 270

Answers (1)

ArcSet
ArcSet

Reputation: 6860

You are not getting 2 different hashes. Matter of fact ...

12, -108, 81, 92, 21, -27, 9, 91, -118, -121, -91, 11, -96, -33, 59, -13, -114, -48, 95, -26

is the same as

12 148 81 92 21 229 9 91 138 135 165 11 160 223 59 243 142 208 95 230

What is happening is in java when you turn to string it is making these values signed.

An example of this is with -108 and 148

00000000,10010100 = 148
11111111,10010100 = -108

If you want to make the byte look unsigned you can use 0xFF combined with the byte.

byte b = (byte) Integer.parseInt("148");
System.out.println(b);

outputs : -108

byte b = (byte) Integer.parseInt("148");
System.out.println(b & 0xFF);

outputs : 148

What is happening is you are usinga bitwise AND operator so 0xFF = 255 aka 11111111 and matching common bits and keeping them.

00000000,11111111 = 255 aka 0xFF
11111111,10010100 = -108
--------
00000000,10010100 = 148

Upvotes: 1

Related Questions