3

I need a HMAC SHA implementation for Mathematica for an API authentication. I am not experienced at all in cryptography, hash functions, and HMAC. So far what I found is this:

hmac[key_, message_] := 
 Module[{keyLen = StringLength[key], dkey, opad, ipad, blocksize = 64,
    method = "SHA"}, 
  dkey = If[keyLen > blocksize, IntegerString[Hash[key, method], 16], 
    StringPadRight[key, blocksize, FromCharacterCode[0]]]; {opad, 
    ipad} = FromCharacterCode[
      BitXor[ToCharacterCode@
        StringRepeat[FromCharacterCode[FromDigits[#, 16]], blocksize],
        ToCharacterCode@dkey]] & /@ {"5c", "36"};
  IntegerString[
   Hash[StringJoin[opad, 
     ExportString[
      IntegerDigits[Hash[StringJoin[ipad, message], method], 256], 
      "Binary"]], method], 16]]

But using the examples from Wikipedia, it returns wrong results. With

hmac["key", "The quick brown fox jumps over the lazy dog"]

I get the result: c0af2d1bc1449a4d4e239af0012d8d183d639fcc. The correct output should be de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9.

Could anyone on advise what is wrong? Also, what would be the modifications that I will need to turn this into SHA256 from SHA1?

Oleg
  • 131
  • 4
  • 1
    Have a look at the bottom of this answer . If you use hmacFnew["SHA1", "The quick brown fox jumps over the lazy dog", "key"] then you get the de7c9b85... result from Wikipedia. – flinty May 15 '21 at 20:00

2 Answers2

1

Thanks for your reply. Indeed, the function hmacFnew[] from that answers works perfectly on Mathematica v11.3- confirmed and tested.

hmacFnew[method_, message_, key_] := 
 Module[{dkey, dmsg, opad, ipad, blocksize}, 
  blocksize = If[method === "SHA384" || method === "SHA512", 128, 64];
  {dkey, dmsg} = StringToByteArray /@ {key, message};
  If[Length[dkey] > blocksize, dkey = Hash[dkey, method, "ByteArray"]];
  dkey = Normal[dkey];
  If[Length[dkey] < blocksize, dkey = PadRight[dkey, blocksize, 0]];
  {opad, ipad} = ByteArray[BitXor[dkey, ConstantArray[#, blocksize]]]& /@ {92,54};
  Hash[Join[opad,Hash[Join[ipad,dmsg], method, "ByteArray"]], method, "HexString"]
]
Oleg
  • 131
  • 4
0

There's ResourceFunction["HMAC"] on the WFR for this:

BaseEncode[
  ResourceFunction["HMAC"][
   "The quick brown fox jumps over the lazy dog", "key", "SHA1"], 
  "Base16"] // ToLowerCase
(* "de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9" *)
flinty
  • 25,147
  • 2
  • 20
  • 86
  • Created 26 April 2021 so not sure if it will work in v11.3 – flinty May 19 '21 at 20:51
  • Hi, thanks for the suggestion. This doesn't quite work in 11.3. I think BaseEncode can only do Base 64 in my version, and the option for Base16 is from version 12.2. – Oleg May 21 '21 at 03:19