Sheldon Pinkman
Sheldon Pinkman

Reputation: 1106

How to calculate a 256-bit HMAC_SHA3 hash with CryptoJS?

Recent CryptoJS versions support SHA3 hashing.

SHA3 can output different hash sizes, including 512-bit (default) and 256-bit. These two work fine:

var sha3_512_hash = CryptoJS.SHA3( 'test' );
var sha3_256_hash = CryptoJS.SHA3( 'test' , { outputLength:256 } );

Similarly, CryptoJS can also calculate HMAC values. However, I can't figure out how to change the default output size there:

var sha3_512_hmac = CryptoJS.HmacSHA3( 'test' , 'key' );
var sha3_256_hmac = CryptoJS.HmacSHA3( 'test' , 'key' , { outputLength:256 } );

The first works OK (the result is a 512-bit hmac value) but the second is the same (i.e. also 512-bit), as if it ignores the {outputLength:256} parameter!

Here's a live example: http://jsfiddle.net/M8xf3/ (using hmac-sha3.js from CryptoJS 3.1.2)

Does anyone know how to create 256-bit SHA3-based HMAC hashes?

P.S. For the SHA2 family of functions, CryptoJS has separate Hmac functions for each output size (that's HmacSHA256 and HmacSHA512). But this doesn't seem to be the case for SHA3?

Upvotes: 1

Views: 2144

Answers (3)

Zac
Zac

Reputation: 1072

!!!IMPORTANT!!! Please read: https://stackoverflow.com/a/43821196 CryptoJS sha3 is not sha3, it is Keccak

By reading the source code from https://github.com/brix/crypto-js/blob/ac34a5a584337b33a2e567f50d96819a96ac44bf/src/sha3.js, you can use below code:

const HamcWithLen = (len) => {
  const SHA3 = CryptoJS.algo.SHA3.extend({
    cfg: CryptoJS.lib.Hasher.cfg.extend({
      outputLength: len
    }),
    // below code copy from https://github.com/brix/crypto-js/pull/383/files
    _doFinalize: function () {
            // Shortcuts
            var data = this._data;
            var dataWords = data.words;
            var nBitsTotal = this._nDataBytes * 8;
            var nBitsLeft = data.sigBytes * 8;
            var blockSizeBits = this.blockSize * 32;

            // Add padding
            dataWords[nBitsLeft >>> 5] |= 0x06 << (24 - nBitsLeft % 32); // here is the change
            dataWords[((Math.ceil((nBitsLeft + 1) / blockSizeBits) * blockSizeBits) >>> 5) - 1] |= 0x80;
            data.sigBytes = dataWords.length * 4;

            // Hash final blocks
            this._process();

            // Shortcuts
            var state = this._state;
            var outputLengthBytes = this.cfg.outputLength / 8;
            var outputLengthLanes = outputLengthBytes / 8;

            // Squeeze
            var hashWords = [];
            for (var i = 0; i < outputLengthLanes; i++) {
                // Shortcuts
                var lane = state[i];
                var laneMsw = lane.high;
                var laneLsw = lane.low;

                // Swap endian
                laneMsw = (
                    (((laneMsw << 8)  | (laneMsw >>> 24)) & 0x00ff00ff) |
                    (((laneMsw << 24) | (laneMsw >>> 8))  & 0xff00ff00)
                );
                laneLsw = (
                    (((laneLsw << 8)  | (laneLsw >>> 24)) & 0x00ff00ff) |
                    (((laneLsw << 24) | (laneLsw >>> 8))  & 0xff00ff00)
                );

                // Squeeze state to retrieve hash
                hashWords.push(laneLsw);
                hashWords.push(laneMsw);
            }

            // Return final computed hash
            return new CJS.lib.WordArray.init(hashWords, outputLengthBytes);
        }
  });

  return CryptoJS.lib.Hasher._createHmacHelper(SHA3);
}

var secretKey = "My SeCrEt KeY";
console.log('HamcWithLen(256)', HamcWithLen(256)('test', secretKey));
console.log('HamcWithLen(512)', HamcWithLen(512)('test', secretKey));

Please check: https://jsfiddle.net/v4agcpho/

Upvotes: 0

Mozart Heart
Mozart Heart

Reputation: 1

You can just edit hmac-sha3.js and change the outputLength to 256-bit instead of 512-bit.

  1. Open hmac-sha3.js file, using your text editor.
  2. Find "{outputLength:512}" and replace it with "{outputLength:256}"

Then the hash output will be 256-bit in length.

To be sure that you did not messed up things, double check your 256-bit hmac-sha3 output with some test cases available on the internet, for example: http://www.di-mgt.com.au/hmac_sha3_testvectors.html

Upvotes: 1

Rogier
Rogier

Reputation: 163

This doesn't answer the actual question, but note that with SHA3 you don't really need HMAC hashes. Unlike SHA1 and SHA2 and MD5, SHA3 is not vulnerable to length-extension attacks.

Therefore with SHA3 it would suffice to just prepend or append the secret key to your input.

Or, if you're paranoid of a single hash step becoming compromised (not to be expected in the foreseeable future, especially not with SHA3, but still) you could do something like SHA3(key+SHA3(key+data)) or SHA3(key+SHA3(key+data)+data) (obviously with "+" denoting binary concatenation).

Upvotes: 2

Related Questions