3
$\begingroup$

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?

$\endgroup$
1
  • 1
    $\begingroup$ 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. $\endgroup$
    – flinty
    May 15 at 20:00
1
$\begingroup$

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"]
]
$\endgroup$
0
$\begingroup$

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" *)
$\endgroup$
2
  • $\begingroup$ Created 26 April 2021 so not sure if it will work in v11.3 $\endgroup$
    – flinty
    May 19 at 20:51
  • $\begingroup$ 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. $\endgroup$
    – Oleg
    May 21 at 3:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.