How to generate sha256 hashes of hexadecimal binary data in JavaScript?

I need a function in JavaScript that generate similar result what this command generate in linux.

echo -n '28349b1d4bcdc9905e4ef9719019e55743c84efa0c5e9a0b077f0b54fcd84905' | xxd -r -p | sha256sum -b | awk '{print $1}'

This command outputs:

d533f24d6f28ddcef3f066474f7b8355383e485681ba8e793e037f5cf36e4883

What this command does is: given an hexadecimal string, convert it to binary, and display the sha256 hash of the binary data.

I tried different libraries but they simply out put sha256 string. but that doesn't fulfill my requirement i need exact result of the command above. Can anyone help me please ?

2 answers

  • answered 2018-11-08 08:08 Gabriel Hautclocq

    Note to the new reader: this will NOT display the sha256 of a string like you may expect, but the sha256 of binary data in hexadecimal representation, like asked in the question.

    You can use inspiration from the demo sha256 function from Mozilla Developer Network:

    function sha256(hexstr) {
      // We transform the string into an arraybuffer.
      var buffer = new Uint8Array(hexstr.match(/[\da-f]{2}/gi).map(function (h) {
        return parseInt(h, 16)
      }));
      return crypto.subtle.digest("SHA-256", buffer).then(function (hash) {
        return arbuf2hex(hash);
      });
    }
    
    function arbuf2hex(buffer) {
      var hexCodes = [];
      var view = new DataView(buffer);
      for (var i = 0; i < view.byteLength; i += 4) {
        // Using getUint32 reduces the number of iterations needed (we process 4 bytes each time)
        var value = view.getUint32(i)
        // toString(16) will give the hex representation of the number without padding
        var stringValue = value.toString(16)
        // We use concatenation and slice for padding
        var padding = '00000000'
        var paddedValue = (padding + stringValue).slice(-padding.length)
        hexCodes.push(paddedValue);
      }
    
      // Join all the hex strings into one
      return hexCodes.join("");
    }
    
    sha256("28349b1d4bcdc9905e4ef9719019e55743c84efa0c5e9a0b077f0b54fcd84905").then(function(digest) {
      console.log(digest);
    }); // outputs "d533f24d6f28ddcef3f066474f7b8355383e485681ba8e793e037f5cf36e4883"
    

    The key was to slightly change the MDN's sha256 function so that it converts the hex string to an ArrayBuffer instead of just using the string.

    If you need a synchronous solution, you could try to use https://github.com/LinusU/crypto-digest-sync and adapt it to your needs.

  • answered 2018-11-08 12:09 Abdul Manan

    Credit goes to Gabriel Hautclocq

    sha256(hexstr) {
        // We transform the string into an arraybuffer.
        var buffer = new Uint8Array(hexstr.match(/[\da-f]{2}/gi).map(function (h) {
        return parseInt(h, 16)
       }))
      // https://github.com/EOSIO/eosjs-ecc#examples
      return ecc.sha256(buffer)
    }
     sha256("28349b1d4bcdc9905e4ef9719019e55743c84efa0c5e9a0b077f0b54fcd84905")
     result : d533f24d6f28ddcef3f066474f7b8355383e485681ba8e793e037f5cf36e4883