0

I am trying to count manual HMAC SHA-1 truncation for HOTP but it doesn't give back the same result as I count it with source code. For example I have code to generate HMAC SHA-1 as:

$hash = hash_hmac('sha1','375317186160478973','test');

It will give me HMAC = c359e469b8ef0939f83e79a300b20a6ef4b53a05

And divide it into [19] arrays so it will be:

c3 59 e4 69 b8 ef 09 39 f8 3e 79 a3 00 b2 0a 6e f4 b5 3a 05

From the last array I have 05 (101 in binary) and after do the 101 & 0xf = 5

So I count from the 5th arrays ef (11101111) 09 (1001) 39 (111001) f8 (11111000)

After that do the (((11101111) & 0x7f) << 24) | (((1001) & 0xff) << 16) | (((111001) & 0xff) << 8) | ((11111000) & 0xff)) % pow (10,6)

It give me a result as: 56024

But if I use this code:

$offset = ($hash[19]) & 0xf;
$otp    = (((($hash[$offset + 0]) & 0x7f) << 24) |
          ((($hash[$offset + 1]) & 0xff) << 16) |
          ((($hash[$offset + 2]) & 0xff) << 8) |
          (($hash[$offset + 3]) & 0xff)) % pow(10, 6);

It give me a result as: 599808

The same different result will show if I write binary or decimal value as the value from arrays. Can someone help me explain where is my fault, so I can count the manual and via source code and give me result a same value of HOTP. Thank you

1 Answers1

0

Apa kabar :) First, SHA-1 is 160 bits (20 bytes) in size not 19. You are using PHP right? The problem is, that accessing the array like that doesn't work since you are always only reading excatly on character:

$hash[5] // (4)
$hash[6] // (6)
$hash[7] // (9)
$hash[8] // (b)

Following should work:

((intval(substr($hash, ($offset + 0) * 2, 2), 16) & 0x7f) << 24) |
((intval(substr($hash, ($offset + 1) * 2, 2), 16) & 0xff) << 16) |
((intval(substr($hash, ($offset + 2) * 2, 2), 16) & 0xff) << 8) |
(intval(substr($hash, ($offset + 3) * 2, 2), 16) & 0xff);

Important, since $hash seems to be php a string, you may not simply access it as array since this will return wrong values. But you can get components of the string with the help of the substr method. You always have to read 2 bytes and convert it into an integer. Sicne the string contains hexa decimal values, you have to use base 16 in intval.

PS: I'm assuming that the hash string is exactly 20 bytes long.

Summary: $hash[5] for example will not give you the expected array value 0xEF, but it will give you the 5th string character '4' (part of substring E4).

bkausbk
  • 2,740
  • 1
  • 36
  • 52
  • Kabar baik, Danke :). Thank you for your reply Sir. I don't really understand about the arrays, because this is my first try to decode how HOTP (RFC 4226) can be truncated into 6 digits. And also i'm trying to do the same as here: http://goo.gl/LljCZ0 , here: http://goo.gl/ovosgA and here: http://goo.gl/JEEQwW will return different value of HOTP, and I can't change the truncation formula given by RFC 4226, This is my result: http://goo.gl/S0aUqT . It converted hex to decimal value. Please advice Sir :) – Gudang Garam Dec 01 '14 at 15:18
  • @GudangGaram I've updated my explanation. I don't know exactly the HOTP algorithm, but it seems that this isn't your problem here. The problem is how you are accessing the data that is stored in a string not in an array. – bkausbk Dec 01 '14 at 16:22
  • Sorry Sir, I haven't read your updated explanation in your answer now I read it, now i'm working on that. Later I will write if it success or not. Thank you for advice Sir. – Gudang Garam Dec 01 '14 at 17:24