Edit: I just ended up using the SHA256 routine from http://www.movable-type.co.uk/scripts/sha256.html because I didn't need high performance, and the code is short and sweet and the same code path is used everywhere. The crypto.subtle API turned out to have too many corner cases where it failed for me (I had problems on some mobile devices, apart from the Chrome issue linked below that caused me grief, and I needed to support older browsers too).
I wrote this function for IE11 which worked for me (although hardly tested):
function textEncode(str) {
if (window.TextEncoder) {
return new TextEncoder('utf-8').encode(str);
}
var utf8 = unescape(encodeURIComponent(str));
var result = new Uint8Array(utf8.length);
for (var i = 0; i < utf8.length; i++) {
result[i] = utf8.charCodeAt(i);
}
return result;
}
Be aware there are other problems because IE11 doesn't have promises, and msCrypto.subtle.digest()
is synchronous. The following might work for you, although you should fix the hacks (it needs work to make it robust and to use a Promise polyfill):
function sha256(str) {
function hex(buffer) {
var hexCodes = [];
var view = new DataView(buffer);
for (var i = 0; i < view.byteLength; i += 4) {
var value = view.getUint32(i);
var stringValue = value.toString(16);
var padding = '00000000';
var paddedValue = (padding + stringValue).slice(-padding.length);
hexCodes.push(paddedValue);
}
return hexCodes.join('');
}
var buffer = textEncode(str);
var res = crypto.subtle.digest('SHA-256', buffer);
if (res.then) {
return res.then(function (hash) {
return hex(hash);
});
} else if (res.result) { // IE11
return {
then: function(resolver) {
resolver(hex(res.result));
}
}
}
}
Also be aware of this Chrome issue which you can use the regexp /^https:|^file:|^http:\/\/localhost|^http:\/\/127.0.0.1/.test(location.protocol)
to test for.