1

Motivation: I want to make a browser-based hashing utility so users can compute file hashes without installing software.

The approach I'm considering is a static page with "a file upload button" (except no upload takes place): the user picks a file, and the script computes and displays its hash.

So let's say we have this element on the page:

<input id="file-hasher" type="file" />

This creates a button that allows the users of the web page to select a file via an OS "File open..." dialog in the browser.

Let's say the user clicks said button, selects a file in the dialog, then clicks the "Ok" button to close the dialog.

The selected file name is now stored in:

document.getElementById("file-hasher").value

Here, I'm hoping to use a library like https://github.com/bitwiseshiftleft/sjcl/ to compute the hash of the chosen file. Is there a way to do this or does the browser's security model get in the way?

Babak Farhang
  • 79
  • 1
  • 8
  • 1
    Do it and you will see. BTW: https://geraintluff.github.io/sha256/ – ceving Mar 09 '20 at 09:27
  • Thanks for pointing me to your hash implementation. Looks clean. The issue here tho is how to read/stream the chosen file's contents (without uploading it) – Babak Farhang Mar 09 '20 at 20:56
  • Ahh.. I didn't realize the security model is specifically designed to allow this. Here's a good article https://humanwhocodes.com/blog/2012/05/08/working-with-files-in-javascript-part-1/ – Babak Farhang Mar 11 '20 at 00:54
  • 2
    Does this answer your question? [How can I hash a string with SHA256 in JS?](https://stackoverflow.com/questions/59777670/how-can-i-hash-a-string-with-sha256-in-js) see my [answer](https://stackoverflow.com/a/68545495/9935654) – Carson Jul 28 '21 at 02:28

2 Answers2

3

Yes, you can select a file using the file element, and take a hash of the file locally, 'in-browser', using javascript. The browser's security model does not prevent this; and the hash function from the native Web Crypto API can be used, so there is no need for any external crypto libraries.

Here is a working example:

function hashfile() {
  readbinaryfile(fileselector.files[0])
    .then(function(result) {
      result = new Uint8Array(result);
      return window.crypto.subtle.digest('SHA-256', result);
    }).then(function(result) {
      result = new Uint8Array(result);
      var resulthex = Uint8ArrayToHexString(result);
      divresult.innerText = 'result: ' + resulthex;
    });
}

function readbinaryfile(file) {
  return new Promise((resolve, reject) => {
    var fr = new FileReader();
    fr.onload = () => {
      resolve(fr.result)
    };
    fr.readAsArrayBuffer(file);
  });
}

function Uint8ArrayToHexString(ui8array) {
  var hexstring = '',
    h;
  for (var i = 0; i < ui8array.length; i++) {
    h = ui8array[i].toString(16);
    if (h.length == 1) {
      h = '0' + h;
    }
    hexstring += h;
  }
  var p = Math.pow(2, Math.ceil(Math.log2(hexstring.length)));
  hexstring = hexstring.padStart(p, '0');
  return hexstring;
}
<h2>File Hash</h2>
<div>
  Select file to take hash of:
  <br/>
  <input type="file" id="fileselector" onchange="javascript:hashfile();">
</div>
<br/>
<div id="divresult"></div>
Lucas
  • 1,359
  • 7
  • 16
mti2935
  • 11,465
  • 3
  • 29
  • 33
  • Thanks for sharing this! I like how it uses no external deps. In the event, I ended up with a streaming solution (need to gracefully handle multi GB files).. https://crums.io I'm sure there must be a way with the builtin Web Crypto API you suggest to incrementally update the digest. Works for now, but I'll revisit :D – Babak Farhang Aug 31 '21 at 16:57
  • @BabakFarhang Actually, it's funny you should ask about streaming / chunking large files. I worked on something similar to this for tails.org (see https://tails.boum.org/news/verification_extension_deprecation/index.en.html). I don't think it's possible to stream / chunk the file with the web crypto api window.crypto.subtle.digest() function. We ended up using the Forge library instead, for that reason. See https://tails.boum.org/contribute/design/download_verification/ for more info (near the bottom of the page). – mti2935 Aug 31 '21 at 17:13
  • cool. Tangential: that Tails project is interesting. Worked on a portable OS called FaunOS ..(bootable from USB but could still save state). PS sorry for my clumsy edits – Babak Farhang Sep 01 '21 at 20:56
0

The standard browser security model allows you to have the user pick a file and do what you will with it. I'm an older guy and thought surely this kinda mingling with a user's parts would require additional hoops/consent. So @ceving 's answer was best: "Do it and you will see."

Here's a link to a good article: https://humanwhocodes.com/blog/2012/05/08/working-with-files-in-javascript-part-1/

Apologies for not trying first before posting.

Babak Farhang
  • 79
  • 1
  • 8