/** @fileOverview Javascript SHA-1 implementation. * * Based on the implementation in RFC 3174, method 1, and on the SJCL * SHA-256 implementation. * * @author Quinn Slack */ /** * Context for a SHA-1 operation in progress. * @constructor * @class Secure Hash Algorithm, 160 bits. */ sjcl.hash.sha1 = function (hash) { if (hash) { this._h = hash._h.slice(0); this._buffer = hash._buffer.slice(0); this._length = hash._length; } else { this.reset(); } }; /** * Hash a string or an array of words. * @static * @param {bitArray|String} data the data to hash. * @return {bitArray} The hash value, an array of 5 big-endian words. */ sjcl.hash.sha1.hash = function (data) { return (new sjcl.hash.sha1()).update(data).finalize(); }; sjcl.hash.sha1.prototype = { /** * The hash's block size, in bits. * @constant */ blockSize: 512, /** * Reset the hash state. * @return this */ reset: function () { this._h = this._init.slice(0); this._buffer = []; this._length = 0; return this; }, /** * Input several words to the hash. * @param {bitArray|String} data the data to hash. * @return this */ update: function (data) { if (typeof data === "string") { data = sjcl.codec.utf8String.toBits(data); } var i, b = this._buffer = sjcl.bitArray.concat(this._buffer, data), ol = this._length, nl = this._length = ol + sjcl.bitArray.bitLength(data); for (i = this.blockSize + ol & -this.blockSize; i <= nl; i += this.blockSize) { this._block(b.splice(0, 16)); } return this; }, /** * Complete hashing and output the hash value. * @return {bitArray} The hash value, an array of 5 big-endian words. TODO */ finalize: function () { var i, b = this._buffer, h = this._h; // Round out and push the buffer b = sjcl.bitArray.concat(b, [sjcl.bitArray.partial(1, 1)]); // Round out the buffer to a multiple of 16 words, less the 2 length words. for (i = b.length + 2; i & 15; i++) { b.push(0); } // append the length b.push(Math.floor(this._length / 0x100000000)); b.push(this._length | 0); while (b.length) { this._block(b.splice(0, 16)); } this.reset(); return h; }, /** * The SHA-1 initialization vector. * @private */ _init: [0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0], /** * The SHA-1 hash key. * @private */ _key: [0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6], /** * The SHA-1 logical functions f(0), f(1), ..., f(79). * @private */ _f: function (t, b, c, d) { if (t <= 19) { return (b & c) | (~b & d); } else if (t <= 39) { return b ^ c ^ d; } else if (t <= 59) { return (b & c) | (b & d) | (c & d); } else if (t <= 79) { return b ^ c ^ d; } }, /** * Circular left-shift operator. * @private */ _S: function (n, x) { return (x << n) | (x >>> 32 - n); }, /** * Perform one cycle of SHA-1. * @param {bitArray} words one block of words. * @private */ _block: function (words) { var t, tmp, a, b, c, d, e, w = words.slice(0), h = this._h, k = this._key; a = h[0]; b = h[1]; c = h[2]; d = h[3]; e = h[4]; for (t = 0; t <= 79; t++) { if (t >= 16) { w[t] = this._S(1, w[t - 3] ^ w[t - 8] ^ w[t - 14] ^ w[t - 16]); } tmp = (this._S(5, a) + this._f(t, b, c, d) + e + w[t] + this._key[Math.floor(t / 20)]) | 0; e = d; d = c; c = this._S(30, b); b = a; a = tmp; } h[0] = (h[0] + a) | 0; h[1] = (h[1] + b) | 0; h[2] = (h[2] + c) | 0; h[3] = (h[3] + d) | 0; h[4] = (h[4] + e) | 0; } };