0.00

Hash methods in Javascript: SHA512, SHA256, SHA1, MD5 - HEX encoded

Sample hex Hash functions in Javascript


programming language: javascript ES6 or later
operating system: any
Updated:


Copyright notice

All the code below is based, adapted and refactored by w3soft.org (an associate of unix-world) from the following open-source project:
  • Js/CryptUtils/Hash [ md5, sha1, sha256, sha512 ] - (c) 2006-2022 unix-world # license: BSD
    • Based on: md5, sha1, sha512 (c) 2015 github.com/hirak/phpjs # license: BSD
    • Based on: sha256 (c) 2014 github.com/geraintluff # license: Public Domain


Method definition: SHA512 / Hex - String

const sha512Hex = (s, utf8) => {
	if(!!utf8) {
		s = utf8_encode(s); // make it unicode
	}
	return bin2hex(crypt_binb2str(sha512_core(s)), !!utf8);
};



Method definition: SHA384 / Hex - String
N/A


Method definition: SHA256 / Hex - String

const sha256Hex = (s, utf8) => {
	if(!!utf8) {
		s = utf8_encode(s); // make it unicode
	}
	return sha256_core(s); // this method have it's own (internal) mechanism to provide the hex encoded string
};



Method definition: SHA1 / Hex - String

const sha1Hex = (s, utf8) => {
	if(!!utf8) {
		s = utf8_encode(s); // make it unicode
	}
	return bin2hex(crypt_binb2str(sha1_core(crypt_str2binb(s), s.length * crypt_chrsz())), !!utf8);
}; //END



Method definition: MD5 / Hex - String

const md5Hex = (s, utf8) => {
	if(!!utf8) {
		s = utf8_encode(s); // make it unicode
	}
	return bin2hex(crypt_binl2str(md5_core(crypt_str2binl(s), s.length * crypt_chrsz())), !!utf8);
};




Helper functions - required by the above methods

//-- JS shared helper methods for UTF8 and HEX encodings

const utf8_encode = function(str) {
	str = String((str == undefined) ? '' : str);
	if(str == '') {
		return '';
	} //end if
	let utftext = '';
	str = str.replace(/\r\n/g, /\n/).replace(/\r/g, /\n/); // replace both: \r\n and \r to \n
	for(let n = 0; n < str.length; n++) {
		let c = str.charCodeAt(n);
		if(c < 128) {
			utftext += String.fromCharCode(c);
		} else if((c > 127) && (c < 2048)) {
			utftext += String.fromCharCode((c >> 6) | 192);
			utftext += String.fromCharCode((c & 63) | 128);
		} else {
			utftext += String.fromCharCode((c >> 12) | 224);
			utftext += String.fromCharCode(((c >> 6) & 63) | 128);
			utftext += String.fromCharCode((c & 63) | 128);
		}
	}
	return String(utftext);
};
const bin2hex = function(s, bin=false) {
	s = String((s == undefined) ? '' : s);
	if(s == '') {
		return '';
	}
	if(bin !== true) { // binary content must not be encoded to UTF-8
		s = String(utf8_encode(s));
	}
	let hex = '';
	let i, l, n;
	for(i=0, l=s.length; i<l; i++) {
		n = s.charCodeAt(i).toString(16);
		hex += n.length < 2 ? '0' + n : n;
	}
	return String(hex).toLowerCase();
};

//-- JS shared helper methods for the Hash algorithm

const crypt_chrsz = () => {
	return 8;
};
const crypt_safe_add = function(x, y) {
	let lsw = (x & 0xFFFF) + (y & 0xFFFF);
	let msw = (x >> 16) + (y >> 16) + (lsw >> 16);
	return (msw << 16) | (lsw & 0xFFFF);
};
const crypt_bit_rol = (num, cnt) => {
	return (num << cnt) | (num >>> (32 - cnt));
};
const crypt_str2binl = function(str) {
	let bin = Array();
	let mask = (1 << crypt_chrsz()) - 1;
	for(let i = 0; i < str.length * crypt_chrsz(); i += crypt_chrsz()) {
		bin[i>>5] |= (str.charCodeAt(i / crypt_chrsz()) & mask) << (i%32);
	}
	return bin;
};
const crypt_binl2str = function(bin) {
	let str = '';
	let mask = (1 << crypt_chrsz()) - 1;
	for(let i = 0; i < bin.length * 32; i += crypt_chrsz()) {
		str += String.fromCharCode((bin[i>>5] >>> (i % 32)) & mask);
	}
	return str;
};
const crypt_str2binb = function(str) {
	const mask = (1 << crypt_chrsz()) - 1;
	let bin = Array();
	for(let i = 0; i < str.length * crypt_chrsz(); i += crypt_chrsz()) {
		bin[i>>5] |= (str.charCodeAt(i / crypt_chrsz()) & mask) << (32 - crypt_chrsz() - i%32);
	}
	return bin;
};
const crypt_binb2str = function(bin) {
	const mask = (1 << crypt_chrsz()) - 1;
	let str = '';
	for(let i = 0; i < bin.length * 32; i += crypt_chrsz()) {
		str += String.fromCharCode((bin[i>>5] >>> (32 - crypt_chrsz() - i%32)) & mask);
	}
	return str;
};
const crypt_strtoarr = function(str) {
	const l = str.length;
	let bytes = new Array(l);
	for(let i=0; i<l; i++) {
		bytes[i] = str.charCodeAt(i);
	}
	return bytes;
};

//-- JS helper methods for the SHA512 algorithm

const sha512_int_64 = function(msint_32, lsint_32) { // this is the constructor method !
	const _M$ = this; // self referencing
	_M$.highOrder = msint_32;
	_M$.lowOrder = lsint_32;
};
const sha512_safeadd_2 = function(x, y) {
	let lsw, msw, lowOrder, highOrder;
	lsw = (x.lowOrder & 0xFFFF) + (y.lowOrder & 0xFFFF);
	msw = (x.lowOrder >>> 16) + (y.lowOrder >>> 16) + (lsw >>> 16);
	lowOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF);
	lsw = (x.highOrder & 0xFFFF) + (y.highOrder & 0xFFFF) + (msw >>> 16);
	msw = (x.highOrder >>> 16) + (y.highOrder >>> 16) + (lsw >>> 16);
	highOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF);
	return new sha512_int_64(highOrder, lowOrder);
};
const sha512_safeadd_4 = function(a, b, c, d) {
	let lsw, msw, lowOrder, highOrder;
	lsw = (a.lowOrder & 0xFFFF) + (b.lowOrder & 0xFFFF) + (c.lowOrder & 0xFFFF) + (d.lowOrder & 0xFFFF);
	msw = (a.lowOrder >>> 16) + (b.lowOrder >>> 16) + (c.lowOrder >>> 16) + (d.lowOrder >>> 16) + (lsw >>> 16);
	lowOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF);
	lsw = (a.highOrder & 0xFFFF) + (b.highOrder & 0xFFFF) + (c.highOrder & 0xFFFF) + (d.highOrder & 0xFFFF) + (msw >>> 16);
	msw = (a.highOrder >>> 16) + (b.highOrder >>> 16) + (c.highOrder >>> 16) + (d.highOrder >>> 16) + (lsw >>> 16);
	highOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF);
	return new sha512_int_64(highOrder, lowOrder);
};
const sha512_safeadd_5 = function(a, b, c, d, e) {
	let lsw, msw, lowOrder, highOrder;
	lsw = (a.lowOrder & 0xFFFF) + (b.lowOrder & 0xFFFF) + (c.lowOrder & 0xFFFF) + (d.lowOrder & 0xFFFF) + (e.lowOrder & 0xFFFF);
	msw = (a.lowOrder >>> 16) + (b.lowOrder >>> 16) + (c.lowOrder >>> 16) + (d.lowOrder >>> 16) + (e.lowOrder >>> 16) + (lsw >>> 16);
	lowOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF);
	lsw = (a.highOrder & 0xFFFF) + (b.highOrder & 0xFFFF) + (c.highOrder & 0xFFFF) + (d.highOrder & 0xFFFF) + (e.highOrder & 0xFFFF) + (msw >>> 16);
	msw = (a.highOrder >>> 16) + (b.highOrder >>> 16) + (c.highOrder >>> 16) + (d.highOrder >>> 16) + (e.highOrder >>> 16) + (lsw >>> 16);
	highOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF);
	return new sha512_int_64(highOrder, lowOrder);
};
const sha512_maj = (x, y, z) => {
	return new sha512_int_64(
		(x.highOrder & y.highOrder) ^ (x.highOrder & z.highOrder) ^ (y.highOrder & z.highOrder),
		(x.lowOrder & y.lowOrder) ^ (x.lowOrder & z.lowOrder) ^ (y.lowOrder & z.lowOrder)
	);
};
const sha512_ch = (x, y, z) => {
	return new sha512_int_64(
		(x.highOrder & y.highOrder) ^ (~x.highOrder & z.highOrder),
		(x.lowOrder & y.lowOrder) ^ (~x.lowOrder & z.lowOrder)
	);
};
const sha512_rot_r = (x, n) => {
	if(n <= 32) {
		return new sha512_int_64(
			(x.highOrder >>> n) | (x.lowOrder << (32 - n)),
			(x.lowOrder >>> n) | (x.highOrder << (32 - n))
		);
	} else {
		return new sha512_int_64(
			(x.lowOrder >>> n) | (x.highOrder << (32 - n)),
			(x.highOrder >>> n) | (x.lowOrder << (32 - n))
		);
	}
};
const sha512_sh_r = (x, n) => {
	if(n <= 32) {
		return new sha512_int_64(
			x.highOrder >>> n,
			x.lowOrder >>> n | (x.highOrder << (32 - n))
		);
	} else {
		return new sha512_int_64(
			0,
			x.highOrder << (32 - n)
		);
	}
};
const sha512_sigma_0 = function(x) {
	let rotr28 = sha512_rot_r(x, 28);
	let rotr34 = sha512_rot_r(x, 34);
	let rotr39 = sha512_rot_r(x, 39);
	return new sha512_int_64(
		rotr28.highOrder ^ rotr34.highOrder ^ rotr39.highOrder,
		rotr28.lowOrder ^ rotr34.lowOrder ^ rotr39.lowOrder
	);
};
const sha512_sigma_1 = function(x) {
	let rotr14 = sha512_rot_r(x, 14);
	let rotr18 = sha512_rot_r(x, 18);
	let rotr41 = sha512_rot_r(x, 41);
	return new sha512_int_64(
		rotr14.highOrder ^ rotr18.highOrder ^ rotr41.highOrder,
		rotr14.lowOrder ^ rotr18.lowOrder ^ rotr41.lowOrder
	);
};
const sha512_gamma_0 = function(x) {
	let rotr1 = sha512_rot_r(x, 1), rotr8 = sha512_rot_r(x, 8), shr7 = sha512_sh_r(x, 7);
	return new sha512_int_64(
		rotr1.highOrder ^ rotr8.highOrder ^ shr7.highOrder,
		rotr1.lowOrder ^ rotr8.lowOrder ^ shr7.lowOrder
	);
};
const sha512_gamma_1 = function(x) {
	let rotr19 = sha512_rot_r(x, 19);
	let rotr61 = sha512_rot_r(x, 61);
	let shr6 = sha512_sh_r(x, 6);
	return new sha512_int_64(
		rotr19.highOrder ^ rotr61.highOrder ^ shr6.highOrder,
		rotr19.lowOrder ^ rotr61.lowOrder ^ shr6.lowOrder
	);
};
const sha512_core = function(str) {
	let H = [
			new sha512_int_64(0x6a09e667, 0xf3bcc908), new sha512_int_64(0xbb67ae85, 0x84caa73b),
			new sha512_int_64(0x3c6ef372, 0xfe94f82b), new sha512_int_64(0xa54ff53a, 0x5f1d36f1),
			new sha512_int_64(0x510e527f, 0xade682d1), new sha512_int_64(0x9b05688c, 0x2b3e6c1f),
			new sha512_int_64(0x1f83d9ab, 0xfb41bd6b), new sha512_int_64(0x5be0cd19, 0x137e2179)
		];
	let K = [
			new sha512_int_64(0x428a2f98, 0xd728ae22), new sha512_int_64(0x71374491, 0x23ef65cd),
			new sha512_int_64(0xb5c0fbcf, 0xec4d3b2f), new sha512_int_64(0xe9b5dba5, 0x8189dbbc),
			new sha512_int_64(0x3956c25b, 0xf348b538), new sha512_int_64(0x59f111f1, 0xb605d019),
			new sha512_int_64(0x923f82a4, 0xaf194f9b), new sha512_int_64(0xab1c5ed5, 0xda6d8118),
			new sha512_int_64(0xd807aa98, 0xa3030242), new sha512_int_64(0x12835b01, 0x45706fbe),
			new sha512_int_64(0x243185be, 0x4ee4b28c), new sha512_int_64(0x550c7dc3, 0xd5ffb4e2),
			new sha512_int_64(0x72be5d74, 0xf27b896f), new sha512_int_64(0x80deb1fe, 0x3b1696b1),
			new sha512_int_64(0x9bdc06a7, 0x25c71235), new sha512_int_64(0xc19bf174, 0xcf692694),
			new sha512_int_64(0xe49b69c1, 0x9ef14ad2), new sha512_int_64(0xefbe4786, 0x384f25e3),
			new sha512_int_64(0x0fc19dc6, 0x8b8cd5b5), new sha512_int_64(0x240ca1cc, 0x77ac9c65),
			new sha512_int_64(0x2de92c6f, 0x592b0275), new sha512_int_64(0x4a7484aa, 0x6ea6e483),
			new sha512_int_64(0x5cb0a9dc, 0xbd41fbd4), new sha512_int_64(0x76f988da, 0x831153b5),
			new sha512_int_64(0x983e5152, 0xee66dfab), new sha512_int_64(0xa831c66d, 0x2db43210),
			new sha512_int_64(0xb00327c8, 0x98fb213f), new sha512_int_64(0xbf597fc7, 0xbeef0ee4),
			new sha512_int_64(0xc6e00bf3, 0x3da88fc2), new sha512_int_64(0xd5a79147, 0x930aa725),
			new sha512_int_64(0x06ca6351, 0xe003826f), new sha512_int_64(0x14292967, 0x0a0e6e70),
			new sha512_int_64(0x27b70a85, 0x46d22ffc), new sha512_int_64(0x2e1b2138, 0x5c26c926),
			new sha512_int_64(0x4d2c6dfc, 0x5ac42aed), new sha512_int_64(0x53380d13, 0x9d95b3df),
			new sha512_int_64(0x650a7354, 0x8baf63de), new sha512_int_64(0x766a0abb, 0x3c77b2a8),
			new sha512_int_64(0x81c2c92e, 0x47edaee6), new sha512_int_64(0x92722c85, 0x1482353b),
			new sha512_int_64(0xa2bfe8a1, 0x4cf10364), new sha512_int_64(0xa81a664b, 0xbc423001),
			new sha512_int_64(0xc24b8b70, 0xd0f89791), new sha512_int_64(0xc76c51a3, 0x0654be30),
			new sha512_int_64(0xd192e819, 0xd6ef5218), new sha512_int_64(0xd6990624, 0x5565a910),
			new sha512_int_64(0xf40e3585, 0x5771202a), new sha512_int_64(0x106aa070, 0x32bbd1b8),
			new sha512_int_64(0x19a4c116, 0xb8d2d0c8), new sha512_int_64(0x1e376c08, 0x5141ab53),
			new sha512_int_64(0x2748774c, 0xdf8eeb99), new sha512_int_64(0x34b0bcb5, 0xe19b48a8),
			new sha512_int_64(0x391c0cb3, 0xc5c95a63), new sha512_int_64(0x4ed8aa4a, 0xe3418acb),
			new sha512_int_64(0x5b9cca4f, 0x7763e373), new sha512_int_64(0x682e6ff3, 0xd6b2b8a3),
			new sha512_int_64(0x748f82ee, 0x5defb2fc), new sha512_int_64(0x78a5636f, 0x43172f60),
			new sha512_int_64(0x84c87814, 0xa1f0ab72), new sha512_int_64(0x8cc70208, 0x1a6439ec),
			new sha512_int_64(0x90befffa, 0x23631e28), new sha512_int_64(0xa4506ceb, 0xde82bde9),
			new sha512_int_64(0xbef9a3f7, 0xb2c67915), new sha512_int_64(0xc67178f2, 0xe372532b),
			new sha512_int_64(0xca273ece, 0xea26619c), new sha512_int_64(0xd186b8c7, 0x21c0c207),
			new sha512_int_64(0xeada7dd6, 0xcde0eb1e), new sha512_int_64(0xf57d4f7f, 0xee6ed178),
			new sha512_int_64(0x06f067aa, 0x72176fba), new sha512_int_64(0x0a637dc5, 0xa2c898a6),
			new sha512_int_64(0x113f9804, 0xbef90dae), new sha512_int_64(0x1b710b35, 0x131c471b),
			new sha512_int_64(0x28db77f5, 0x23047d84), new sha512_int_64(0x32caab7b, 0x40c72493),
			new sha512_int_64(0x3c9ebe0a, 0x15c9bebc), new sha512_int_64(0x431d67c4, 0x9c100d4c),
			new sha512_int_64(0x4cc5d4be, 0xcb3e42b6), new sha512_int_64(0x597f299c, 0xfc657e2a),
			new sha512_int_64(0x5fcb6fab, 0x3ad6faec), new sha512_int_64(0x6c44198c, 0x4a475817)
		];
	let W = new Array(64);
	let a, b, c, d, e, f, g, h, i, j;
	let T1, T2;
	const strlen = str.length * crypt_chrsz();
	str = crypt_str2binb(str);
	str[strlen >> 5] |= 0x80 << (24 - strlen % 32);
	str[(((strlen + 128) >> 10) << 5) + 31] = strlen;
	for(let i = 0; i < str.length; i += 32) {
		a = H[0];
		b = H[1];
		c = H[2];
		d = H[3];
		e = H[4];
		f = H[5];
		g = H[6];
		h = H[7];
		for(let j = 0; j < 80; j++) {
			if(j < 16) {
				W[j] = new sha512_int_64(str[j*2 + i], str[j*2 + i + 1]);
			} else {
				W[j] = sha512_safeadd_4(sha512_gamma_1(W[j - 2]), W[j - 7], sha512_gamma_0(W[j - 15]), W[j - 16]);
			}
			T1 = sha512_safeadd_5(h, sha512_sigma_1(e), sha512_ch(e, f, g), K[j], W[j]);
			T2 = sha512_safeadd_2(sha512_sigma_0(a), sha512_maj(a, b, c));
			h = g;
			g = f;
			f = e;
			e = sha512_safeadd_2(d, T1);
			d = c;
			c = b;
			b = a;
			a = sha512_safeadd_2(T1, T2);
		}
		H[0] = sha512_safeadd_2(a, H[0]);
		H[1] = sha512_safeadd_2(b, H[1]);
		H[2] = sha512_safeadd_2(c, H[2]);
		H[3] = sha512_safeadd_2(d, H[3]);
		H[4] = sha512_safeadd_2(e, H[4]);
		H[5] = sha512_safeadd_2(f, H[5]);
		H[6] = sha512_safeadd_2(g, H[6]);
		H[7] = sha512_safeadd_2(h, H[7]);
	}
	let binarray = [];
	for(let i = 0; i < H.length; i++) {
		binarray.push(H[i].highOrder);
		binarray.push(H[i].lowOrder);
	}
	return binarray;
};

//-- JS helper methods and variables for the SHA256 algorithm

let sha256_cache_h = [];
let sha256_cache_k = [];
const sha256_core = function(str) {
	const rightRotate = (value, amount) => (value>>>amount) | (value<<(32 - amount));
	const mathPow = Math.pow;
	const maxWord = mathPow(2, 32);
	const lengthProperty = 'length';
	const lenStr = str[lengthProperty] * 8;
	let i, j;
	let result = '';
	let words = [];
	let hash = sha256_cache_h = sha256_cache_h || [];
	let k = sha256_cache_k = sha256_cache_k || [];
	let primeCounter = k[lengthProperty];
	if(primeCounter <= 0) { // only run once - is cached
		let isComposite = {};
		for(let candidate = 2; primeCounter < 64; candidate++) {
			if(!isComposite[candidate]) {
				for(i=0; i<313; i+=candidate) {
					isComposite[i] = candidate;
				}
				hash[primeCounter] = (mathPow(candidate, 0.5) * maxWord) | 0;
				k[primeCounter++] = (mathPow(candidate, 1/3) * maxWord) | 0;
			}
		}
	}
	str += '\x80'; // add Ƈ' bit (plus zero padding)
	while(str[lengthProperty] % 64 - 56) {
		str += '\x00'; // zero padding
	}
	for(i=0; i<str[lengthProperty]; i++) {
		j = str.charCodeAt(i);
		if(j>>8) {
			return ''; // ASCII check: only accept characters in range 0-255
		}
		words[i>>2] |= j << ((3 - i) % 4) * 8;
	}
	words[words[lengthProperty]] = ((lenStr / maxWord) | 0);
	words[words[lengthProperty]] = (lenStr);
	for(j=0; j<words[lengthProperty];) {
		let w = words.slice(j, j += 16); // expand into 64 words as part of the iteration
		let oldHash = hash;
		hash = hash.slice(0, 8);
		for(i=0; i<64; i++) {
			let i2 = i + j;
			let w15 = w[i - 15], w2 = w[i - 2];
			let a = hash[0], e = hash[4];
			let temp1 = hash[7] + (rightRotate(e, 6) ^ rightRotate(e, 11) ^ rightRotate(e, 25)) // S1
				+ ((e&hash[5])^((~e)&hash[6]))
				+ k[i]
				+ (w[i] = (i < 16) ? w[i] : (
						w[i - 16]
						+ (rightRotate(w15, 7) ^ rightRotate(w15, 18) ^ (w15>>>3)) // s0
						+ w[i - 7]
						+ (rightRotate(w2, 17) ^ rightRotate(w2, 19) ^ (w2>>>10)) // s1
					) | 0
				);
			let temp2 = (rightRotate(a, 2) ^ rightRotate(a, 13) ^ rightRotate(a, 22)) // S0
				+ ((a&hash[1])^(a&hash[2])^(hash[1]&hash[2])); // maj
			hash = [(temp1 + temp2) | 0].concat(hash);
			hash[4] = (hash[4] + temp1) | 0;
		}
		for(i=0; i<8; i++) {
			hash[i] = (hash[i] + oldHash[i]) | 0;
		}
	}
	for(i=0; i<8; i++) {
		for(j=3; j+1; j--) {
			let b = (hash[i]>>(j*8))&255;
			result += ((b < 16) ? 0 : '') + b.toString(16);
		}
	}
	return String(result || '');
};

//-- JS helper methods for the SHA1 algorithm

const sha1_ft = (t, b, c, d) => {
	if(t < 20) {
		return (b & c) | ((~b) & d);
	}
	if(t < 40) {
		return b ^ c ^ d;
	}
	if(t < 60) {
		return (b & c) | (b & d) | (c & d);
	}
	return b ^ c ^ d;
};
const sha1_kt = (t) => {
  return (t < 20) ?  1518500249 : (t < 40) ?  1859775393 : (t < 60) ? -1894007588 : -899497514 ;
};
const sha1_core = function(x, len) {
	x[len >> 5] |= 0x80 << (24 - len % 32);
	x[((len + 64 >> 9) << 4) + 15] = len;
	let a =  1732584193;
	let b = -271733879;
	let c = -1732584194;
	let d =  271733878;
	let e = -1009589776;
	let w = Array(80);
	for(let i = 0; i < x.length; i += 16) {
		let olda = a;
		let oldb = b;
		let oldc = c;
		let oldd = d;
		let olde = e;
		for(let j = 0; j < 80; j++) {
			if(j < 16) {
				w[j] = x[i + j];
			} else {
				w[j] = crypt_bit_rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1);
			}
			let t = crypt_safe_add(crypt_safe_add(crypt_bit_rol(a, 5), sha1_ft(j, b, c, d)), crypt_safe_add(crypt_safe_add(e, w[j]), sha1_kt(j)));
			e = d;
			d = c;
			c = crypt_bit_rol(b, 30);
			b = a;
			a = t;
		}
		a = crypt_safe_add(a, olda);
		b = crypt_safe_add(b, oldb);
		c = crypt_safe_add(c, oldc);
		d = crypt_safe_add(d, oldd);
		e = crypt_safe_add(e, olde);
	}
	return Array(a, b, c, d, e);
};

//-- JS helper methods for the MD5 algorithm

const md5_cmn = (q, a, b, x, s, t) => {
	return crypt_safe_add(crypt_bit_rol(crypt_safe_add(crypt_safe_add(a, q), crypt_safe_add(x, t)), s),b);
};
const md5_ff = (a, b, c, d, x, s, t) => {
	return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
};
const md5_gg = (a, b, c, d, x, s, t) => {
	return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
};
const md5_hh = (a, b, c, d, x, s, t) => {
	return md5_cmn(b ^ c ^ d, a, b, x, s, t);
};
const md5_ii = (a, b, c, d, x, s, t) => {
	return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
};
const md5_core = function(x, len) {
	x[len >> 5] |= 0x80 << ((len) % 32);
	x[(((len + 64) >>> 9) << 4) + 14] = len;
	let a =  1732584193;
	let b = -271733879;
	let c = -1732584194;
	let d =  271733878;
	for(let i = 0; i < x.length; i += 16) {
		let olda = a;
		let oldb = b;
		let oldc = c;
		let oldd = d;
		a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);
		d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);
		c = md5_ff(c, d, a, b, x[i+ 2], 17,  606105819);
		b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);
		a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);
		d = md5_ff(d, a, b, c, x[i+ 5], 12,  1200080426);
		c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);
		b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);
		a = md5_ff(a, b, c, d, x[i+ 8], 7 ,  1770035416);
		d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);
		c = md5_ff(c, d, a, b, x[i+10], 17, -42063);
		b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162);
		a = md5_ff(a, b, c, d, x[i+12], 7 ,  1804603682);
		d = md5_ff(d, a, b, c, x[i+13], 12, -40341101);
		c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);
		b = md5_ff(b, c, d, a, x[i+15], 22,  1236535329);
		a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);
		d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
		c = md5_gg(c, d, a, b, x[i+11], 14,  643717713);
		b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);
		a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);
		d = md5_gg(d, a, b, c, x[i+10], 9 ,  38016083);
		c = md5_gg(c, d, a, b, x[i+15], 14, -660478335);
		b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);
		a = md5_gg(a, b, c, d, x[i+ 9], 5 ,  568446438);
		d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);
		c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);
		b = md5_gg(b, c, d, a, x[i+ 8], 20,  1163531501);
		a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);
		d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);
		c = md5_gg(c, d, a, b, x[i+ 7], 14,  1735328473);
		b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);
		a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);
		d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);
		c = md5_hh(c, d, a, b, x[i+11], 16,  1839030562);
		b = md5_hh(b, c, d, a, x[i+14], 23, -35309556);
		a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);
		d = md5_hh(d, a, b, c, x[i+ 4], 11,  1272893353);
		c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);
		b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640);
		a = md5_hh(a, b, c, d, x[i+13], 4 ,  681279174);
		d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);
		c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);
		b = md5_hh(b, c, d, a, x[i+ 6], 23,  76029189);
		a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);
		d = md5_hh(d, a, b, c, x[i+12], 11, -421815835);
		c = md5_hh(c, d, a, b, x[i+15], 16,  530742520);
		b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);
		a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);
		d = md5_ii(d, a, b, c, x[i+ 7], 10,  1126891415);
		c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905);
		b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);
		a = md5_ii(a, b, c, d, x[i+12], 6 ,  1700485571);
		d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);
		c = md5_ii(c, d, a, b, x[i+10], 15, -1051523);
		b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);
		a = md5_ii(a, b, c, d, x[i+ 8], 6 ,  1873313359);
		d = md5_ii(d, a, b, c, x[i+15], 10, -30611744);
		c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);
		b = md5_ii(b, c, d, a, x[i+13], 21,  1309151649);
		a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);
		d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379);
		c = md5_ii(c, d, a, b, x[i+ 2], 15,  718787259);
		b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);
		a = crypt_safe_add(a, olda);
		b = crypt_safe_add(b, oldb);
		c = crypt_safe_add(c, oldc);
		d = crypt_safe_add(d, oldd);
	}
	return Array(a, b, c, d);
};