11

I have to generate string representation of CryptoJS.HmacSHA256 in digest (bytes representation).

I need it because i have to duplicate python code which generate such digest in javascript:

print hmac.new("secret", "test", hashlib.sha256).digest() ')�kb��>�y+������:�o��H� ' 

The goal is to duplicate behaviour of code above in javascript.

Could you please suggest me how to do this?

2
  • 2
    I'm not sure what you are trying to achieve here. What is the exact output format that you require? Just 32 bytes? Commented Apr 3, 2015 at 12:58
  • Beware that comparing HMAC values may result in a time based side channel attack, depending on the protocol used. Commented Jun 30, 2017 at 15:58

2 Answers 2

47

You can't simply send bytes to JavaScript. You need to convert this to a textual representation for it to be comparable. Hex encoding is supported by both python's hmac module and CryptoJS.

CryptoJS:

CryptoJS.HmacSHA256("test", "secret").toString(CryptoJS.enc.Hex) 

Python2:

hmac.new("secret", "test", hashlib.sha256).hexdigest() 

Python3:

hmac.new("secret".encode("utf-8"), "test".encode("utf-8"), hashlib.sha256).hexdigest() 

Note the difference in the argument ordering.

All produce

0329a06b62cd16b33eb6792be8c60b158d89a2ee3a876fce9a881ebb488c0914 
Sign up to request clarification or add additional context in comments.

3 Comments

Fun fact, if you're using Shopify's liquid hmac_sha256 string filter, it also outputs the Hex value.
In the case of Python - you cannot pass String to hmac.new() method. If I pass string I am receiving this error: TypeError: key: expected bytes or bytearray, but got 'str'
@SlickSlime Yes, this answer was written for Python 2. You would have to encode the (Unicode) string first
5

If you need raw bytes then CryptoJS does not seem to supply code for it. It is mentioned that this is because of lack of cross browser compatibility for Uint8Array and friends.

However, after searching, I did find some conversion code created by Vincenzo Ciancia:

CryptoJS.enc.u8array = { /** * Converts a word array to a Uint8Array. * * @param {WordArray} wordArray The word array. * * @return {Uint8Array} The Uint8Array. * * @static * * @example * * var u8arr = CryptoJS.enc.u8array.stringify(wordArray); */ stringify: function (wordArray) { // Shortcuts var words = wordArray.words; var sigBytes = wordArray.sigBytes; // Convert var u8 = new Uint8Array(sigBytes); for (var i = 0; i < sigBytes; i++) { var byte = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; u8[i]=byte; } return u8; }, /** * Converts a Uint8Array to a word array. * * @param {string} u8Str The Uint8Array. * * @return {WordArray} The word array. * * @static * * @example * * var wordArray = CryptoJS.enc.u8array.parse(u8arr); */ parse: function (u8arr) { // Shortcut var len = u8arr.length; // Convert var words = []; for (var i = 0; i < len; i++) { words[i >>> 2] |= (u8arr[i] & 0xff) << (24 - (i % 4) * 8); } return CryptoJS.lib.WordArray.create(words, len); } }; 

Note of course that bytes don't translate directly to characters; you cannot use a text compare to compare against ')�kb��>�y+������:�o��H� ' generated by python. For that you do need an encoder such as hexadecimals or base 64. In that case please look at the answer from Artjom instead.

2 Comments

Note: I haven't tested the code above. There were a few people out there that seemed happy with it. I would recommend writing some tests around it though.
I haven't found the original source of the code, so I used a link to your post from this answer. Can you provide one?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.