0

I'm trying to implement a generic HMAC function in PHP. I'm following the RFC and the wikipedia page, but I cannot get my function to match the sample outputs. What am I doing wrong?

function myHmac(string $data, string $key, callable $algoFn, int $algoBlockSizeInBytes): string
  {
    if (strlen($key) > $algoBlockSizeInBytes)
    {
      $key = $algoFn($key); // keys longer than blocksize are shortened
    }

    if (strlen($key) < $algoBlockSizeInBytes)
    {
      $key = $key . str_repeat(0x00, $algoBlockSizeInBytes - strlen($key)); // keys shorter than blocksize are zero-padded
    }

    $outerKeyPad = str_repeat(0x5c, $algoBlockSizeInBytes) ^ $key;
    $innerKeyPad = str_repeat(0x36, $algoBlockSizeInBytes) ^ $key;

    return bin2hex($algoFn($outerKeyPad . $algoFn($innerKeyPad . $data)));
  }

$md5Fn = function ($str) { return md5($str, true); };

echo 'my output: ' . myHmac("", "", $md5Fn, 64) . "\n";
echo 'correct output: ' . hash_hmac('md5', "", "") . "\n";
Community
  • 1
  • 1
Alex Grin
  • 8,121
  • 6
  • 33
  • 57
  • 1
    Trying to implement your own HMAC for one – Sherif Aug 27 '16 at 22:14
  • Thanks, that's very helpful. I know I'm not supposed to roll my own crypto. I'm trying to learn. Also, php doesn't support HMAC for SHA3, which I need. – Alex Grin Aug 27 '16 at 22:16
  • PHP supports whatever is in [`hash_algos()`](http://php.net/hash-algos) which is system dependent for some algorithms, others are natively supported by PHP. sha384 should typically be in there. – Sherif Aug 27 '16 at 22:18
  • 1
    FWIW, the XOR operator `^` is bitwise. You're performing bitwise operations on a string, which casts the operands to an integers. You're assuming the result is string. This probably accounts for a huge chunk of your mistakes here. Try debugging your code a bit more. – Sherif Aug 27 '16 at 22:20
  • 1
    @Sherif: [the doc says](http://php.net/manual/en/language.operators.bitwise.php): `If both operands for the &, | and ^ operators are strings, then the operation will be performed on the ASCII values of the characters that make up the strings and the result will be a string.` Sounds like that's exactly what I want, right? – Alex Grin Aug 27 '16 at 22:36
  • I don't know. This was more of a casual observation since I tend to see a lot of people making mistakes with that in PHP. I didn't actually review your code to try and figure out what you wanted. – Sherif Aug 27 '16 at 22:41
  • Here http://stackoverflow.com/q/17368899/3885509 – Charlotte Dunois Aug 27 '16 at 22:51

1 Answers1

3

You invoke string_repeat() with an integer instead of the string to be repeated. So integer to string conversion applies. This means that currently you get something like 0x36 -> '54' -> '54545454...5454' ('54' repeated 64 times) and so on. Use chr(0x36) to get the actual byte.

user268396
  • 11,576
  • 2
  • 31
  • 26