Path: blob/trunk/third_party/closure/goog/crypt/sha2_64bit.js
2868 views
// Copyright 2014 The Closure Library Authors. All Rights Reserved.1//2// Licensed under the Apache License, Version 2.0 (the "License");3// you may not use this file except in compliance with the License.4// You may obtain a copy of the License at5//6// http://www.apache.org/licenses/LICENSE-2.07//8// Unless required by applicable law or agreed to in writing, software9// distributed under the License is distributed on an "AS-IS" BASIS,10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.11// See the License for the specific language governing permissions and12// limitations under the License.1314/**15* @fileoverview Base class for the 64-bit SHA-2 cryptographic hashes.16*17* Variable names follow the notation in FIPS PUB 180-3:18* http://csrc.nist.gov/publications/fips/fips180-3/fips180-3_final.pdf.19*20* This code borrows heavily from the 32-bit SHA2 implementation written by21* Yue Zhang (zysxqn@).22*23* @author [email protected] (Frank Yellin)24*/2526goog.provide('goog.crypt.Sha2_64bit');2728goog.require('goog.array');29goog.require('goog.asserts');30goog.require('goog.crypt.Hash');31goog.require('goog.math.Long');32333435/**36* Constructs a SHA-2 64-bit cryptographic hash.37* This class should not be used. Rather, one should use one of its38* subclasses.39* @constructor40* @param {number} numHashBlocks The size of the output in 16-byte blocks41* @param {!Array<number>} initHashBlocks The hash-specific initialization42* vector, as a sequence of sixteen 32-bit numbers.43* @extends {goog.crypt.Hash}44* @struct45*/46goog.crypt.Sha2_64bit = function(numHashBlocks, initHashBlocks) {47goog.crypt.Sha2_64bit.base(this, 'constructor');4849/**50* The number of bytes that are digested in each pass of this hasher.51* @const {number}52*/53this.blockSize = goog.crypt.Sha2_64bit.BLOCK_SIZE_;5455/**56* A chunk holding the currently processed message bytes. Once the chunk has57* {@code this.blocksize} bytes, we feed it into [@code computeChunk_}.58* @private {!Uint8Array|!Array<number>}59*/60this.chunk_ = goog.global['Uint8Array'] ? new Uint8Array(this.blockSize) :61new Array(this.blockSize);6263/**64* Current number of bytes in {@code this.chunk_}.65* @private {number}66*/67this.chunkBytes_ = 0;6869/**70* Total number of bytes in currently processed message.71* @private {number}72*/73this.total_ = 0;7475/**76* Holds the previous values of accumulated hash a-h in the77* {@code computeChunk_} function.78* @private {!Array<!goog.math.Long>}79*/80this.hash_ = [];8182/**83* The number of blocks of output produced by this hash function, where each84* block is eight bytes long.85* @private {number}86*/87this.numHashBlocks_ = numHashBlocks;8889/**90* Temporary array used in chunk computation. Allocate here as a91* member rather than as a local within computeChunk_() as a92* performance optimization to reduce the number of allocations and93* reduce garbage collection.94* @type {!Array<!goog.math.Long>}95* @private96*/97this.w_ = [];9899/**100* The value to which {@code this.hash_} should be reset when this101* Hasher is reset.102* @private @const {!Array<!goog.math.Long>}103*/104this.initHashBlocks_ = goog.crypt.Sha2_64bit.toLongArray_(initHashBlocks);105106/**107* If true, we have taken the digest from this hasher, but we have not108* yet reset it.109*110* @private {boolean}111*/112this.needsReset_ = false;113114this.reset();115};116goog.inherits(goog.crypt.Sha2_64bit, goog.crypt.Hash);117118119/**120* The number of bytes that are digested in each pass of this hasher.121* @private @const {number}122*/123goog.crypt.Sha2_64bit.BLOCK_SIZE_ = 1024 / 8;124125126/**127* Contains data needed to pad messages less than {@code blocksize} bytes.128* @private {!Array<number>}129*/130goog.crypt.Sha2_64bit.PADDING_ = goog.array.concat(131[0x80], goog.array.repeat(0, goog.crypt.Sha2_64bit.BLOCK_SIZE_ - 1));132133134/**135* Resets this hash function.136* @override137*/138goog.crypt.Sha2_64bit.prototype.reset = function() {139this.chunkBytes_ = 0;140this.total_ = 0;141this.hash_ = goog.array.clone(this.initHashBlocks_);142this.needsReset_ = false;143};144145146/** @override */147goog.crypt.Sha2_64bit.prototype.update = function(message, opt_length) {148var length = goog.isDef(opt_length) ? opt_length : message.length;149150// Make sure this hasher is usable.151if (this.needsReset_) {152throw Error('this hasher needs to be reset');153}154// Process the message from left to right up to |length| bytes.155// When we get a 512-bit chunk, compute the hash of it and reset156// this.chunk_. The message might not be multiple of 512 bits so we157// might end up with a chunk that is less than 512 bits. We store158// such partial chunk in chunk_ and it will be filled up later159// in digest().160var chunkBytes = this.chunkBytes_;161162// The input message could be either byte array or string.163if (goog.isString(message)) {164for (var i = 0; i < length; i++) {165var b = message.charCodeAt(i);166if (b > 255) {167throw Error('Characters must be in range [0,255]');168}169this.chunk_[chunkBytes++] = b;170if (chunkBytes == this.blockSize) {171this.computeChunk_();172chunkBytes = 0;173}174}175} else if (goog.isArrayLike(message)) {176for (var i = 0; i < length; i++) {177var b = message[i];178// Hack: b|0 coerces b to an integer, so the last part confirms that179// b has no fractional part.180if (!goog.isNumber(b) || b < 0 || b > 255 || b != (b | 0)) {181throw Error('message must be a byte array');182}183this.chunk_[chunkBytes++] = b;184if (chunkBytes == this.blockSize) {185this.computeChunk_();186chunkBytes = 0;187}188}189} else {190throw Error('message must be string or array');191}192193// Record the current bytes in chunk to support partial update.194this.chunkBytes_ = chunkBytes;195196// Record total message bytes we have processed so far.197this.total_ += length;198};199200201/** @override */202goog.crypt.Sha2_64bit.prototype.digest = function() {203if (this.needsReset_) {204throw Error('this hasher needs to be reset');205}206var totalBits = this.total_ * 8;207208// Append pad 0x80 0x00* until this.chunkBytes_ == 112209if (this.chunkBytes_ < 112) {210this.update(goog.crypt.Sha2_64bit.PADDING_, 112 - this.chunkBytes_);211} else {212// the rest of this block, plus 112 bytes of next block213this.update(214goog.crypt.Sha2_64bit.PADDING_,215this.blockSize - this.chunkBytes_ + 112);216}217218// Append # bits in the 64-bit big-endian format.219for (var i = 127; i >= 112; i--) {220this.chunk_[i] = totalBits & 255;221totalBits /= 256; // Don't use bit-shifting here!222}223this.computeChunk_();224225// Finally, output the result digest.226var n = 0;227var digest = new Array(8 * this.numHashBlocks_);228for (var i = 0; i < this.numHashBlocks_; i++) {229var block = this.hash_[i];230var high = block.getHighBits();231var low = block.getLowBits();232for (var j = 24; j >= 0; j -= 8) {233digest[n++] = ((high >> j) & 255);234}235for (var j = 24; j >= 0; j -= 8) {236digest[n++] = ((low >> j) & 255);237}238}239240// The next call to this hasher must be a reset241this.needsReset_ = true;242return digest;243};244245246/**247* Updates this hash by processing the 1024-bit message chunk in this.chunk_.248* @private249*/250goog.crypt.Sha2_64bit.prototype.computeChunk_ = function() {251var chunk = this.chunk_;252var K_ = goog.crypt.Sha2_64bit.K_;253254// Divide the chunk into 16 64-bit-words.255var w = this.w_;256for (var i = 0; i < 16; i++) {257var offset = i * 8;258w[i] = new goog.math.Long(259(chunk[offset + 4] << 24) | (chunk[offset + 5] << 16) |260(chunk[offset + 6] << 8) | (chunk[offset + 7]),261(chunk[offset] << 24) | (chunk[offset + 1] << 16) |262(chunk[offset + 2] << 8) | (chunk[offset + 3]));263}264265// Extend the w[] array to be the number of rounds.266for (var i = 16; i < 80; i++) {267var s0 = this.sigma0_(w[i - 15]);268var s1 = this.sigma1_(w[i - 2]);269w[i] = this.sum_(w[i - 16], w[i - 7], s0, s1);270}271272var a = this.hash_[0];273var b = this.hash_[1];274var c = this.hash_[2];275var d = this.hash_[3];276var e = this.hash_[4];277var f = this.hash_[5];278var g = this.hash_[6];279var h = this.hash_[7];280for (var i = 0; i < 80; i++) {281var S0 = this.Sigma0_(a);282var maj = this.majority_(a, b, c);283var t2 = S0.add(maj);284var S1 = this.Sigma1_(e);285var ch = this.choose_(e, f, g);286var t1 = this.sum_(h, S1, ch, K_[i], w[i]);287h = g;288g = f;289f = e;290e = d.add(t1);291d = c;292c = b;293b = a;294a = t1.add(t2);295}296297this.hash_[0] = this.hash_[0].add(a);298this.hash_[1] = this.hash_[1].add(b);299this.hash_[2] = this.hash_[2].add(c);300this.hash_[3] = this.hash_[3].add(d);301this.hash_[4] = this.hash_[4].add(e);302this.hash_[5] = this.hash_[5].add(f);303this.hash_[6] = this.hash_[6].add(g);304this.hash_[7] = this.hash_[7].add(h);305};306307308/**309* Calculates the SHA2 64-bit sigma0 function.310* rotateRight(value, 1) ^ rotateRight(value, 8) ^ (value >>> 7)311*312* @private313* @param {!goog.math.Long} value314* @return {!goog.math.Long}315*/316goog.crypt.Sha2_64bit.prototype.sigma0_ = function(value) {317var valueLow = value.getLowBits();318var valueHigh = value.getHighBits();319// Implementation note: We purposely do not use the shift operations defined320// in goog.math.Long. Inlining the code for specific values of shifting and321// not generating the intermediate results doubles the speed of this code.322var low = (valueLow >>> 1) ^ (valueHigh << 31) ^ (valueLow >>> 8) ^323(valueHigh << 24) ^ (valueLow >>> 7) ^ (valueHigh << 25);324var high = (valueHigh >>> 1) ^ (valueLow << 31) ^ (valueHigh >>> 8) ^325(valueLow << 24) ^ (valueHigh >>> 7);326return new goog.math.Long(low, high);327};328329330/**331* Calculates the SHA2 64-bit sigma1 function.332* rotateRight(value, 19) ^ rotateRight(value, 61) ^ (value >>> 6)333*334* @private335* @param {!goog.math.Long} value336* @return {!goog.math.Long}337*/338goog.crypt.Sha2_64bit.prototype.sigma1_ = function(value) {339var valueLow = value.getLowBits();340var valueHigh = value.getHighBits();341// Implementation note: See _sigma0() above342var low = (valueLow >>> 19) ^ (valueHigh << 13) ^ (valueHigh >>> 29) ^343(valueLow << 3) ^ (valueLow >>> 6) ^ (valueHigh << 26);344var high = (valueHigh >>> 19) ^ (valueLow << 13) ^ (valueLow >>> 29) ^345(valueHigh << 3) ^ (valueHigh >>> 6);346return new goog.math.Long(low, high);347};348349350/**351* Calculates the SHA2 64-bit Sigma0 function.352* rotateRight(value, 28) ^ rotateRight(value, 34) ^ rotateRight(value, 39)353*354* @private355* @param {!goog.math.Long} value356* @return {!goog.math.Long}357*/358goog.crypt.Sha2_64bit.prototype.Sigma0_ = function(value) {359var valueLow = value.getLowBits();360var valueHigh = value.getHighBits();361// Implementation note: See _sigma0() above362var low = (valueLow >>> 28) ^ (valueHigh << 4) ^ (valueHigh >>> 2) ^363(valueLow << 30) ^ (valueHigh >>> 7) ^ (valueLow << 25);364var high = (valueHigh >>> 28) ^ (valueLow << 4) ^ (valueLow >>> 2) ^365(valueHigh << 30) ^ (valueLow >>> 7) ^ (valueHigh << 25);366return new goog.math.Long(low, high);367};368369370/**371* Calculates the SHA2 64-bit Sigma1 function.372* rotateRight(value, 14) ^ rotateRight(value, 18) ^ rotateRight(value, 41)373*374* @private375* @param {!goog.math.Long} value376* @return {!goog.math.Long}377*/378goog.crypt.Sha2_64bit.prototype.Sigma1_ = function(value) {379var valueLow = value.getLowBits();380var valueHigh = value.getHighBits();381// Implementation note: See _sigma0() above382var low = (valueLow >>> 14) ^ (valueHigh << 18) ^ (valueLow >>> 18) ^383(valueHigh << 14) ^ (valueHigh >>> 9) ^ (valueLow << 23);384var high = (valueHigh >>> 14) ^ (valueLow << 18) ^ (valueHigh >>> 18) ^385(valueLow << 14) ^ (valueLow >>> 9) ^ (valueHigh << 23);386return new goog.math.Long(low, high);387};388389390/**391* Calculates the SHA-2 64-bit choose function.392*393* This function uses {@code value} as a mask to choose bits from either394* {@code one} if the bit is set or {@code two} if the bit is not set.395*396* @private397* @param {!goog.math.Long} value398* @param {!goog.math.Long} one399* @param {!goog.math.Long} two400* @return {!goog.math.Long}401*/402goog.crypt.Sha2_64bit.prototype.choose_ = function(value, one, two) {403var valueLow = value.getLowBits();404var valueHigh = value.getHighBits();405return new goog.math.Long(406(valueLow & one.getLowBits()) | (~valueLow & two.getLowBits()),407(valueHigh & one.getHighBits()) | (~valueHigh & two.getHighBits()));408};409410411/**412* Calculates the SHA-2 64-bit majority function.413* This function returns, for each bit position, the bit held by the majority414* of its three arguments.415*416* @private417* @param {!goog.math.Long} one418* @param {!goog.math.Long} two419* @param {!goog.math.Long} three420* @return {!goog.math.Long}421*/422goog.crypt.Sha2_64bit.prototype.majority_ = function(one, two, three) {423return new goog.math.Long(424(one.getLowBits() & two.getLowBits()) |425(two.getLowBits() & three.getLowBits()) |426(one.getLowBits() & three.getLowBits()),427(one.getHighBits() & two.getHighBits()) |428(two.getHighBits() & three.getHighBits()) |429(one.getHighBits() & three.getHighBits()));430};431432433/**434* Adds two or more goog.math.Long values.435*436* @private437* @param {!goog.math.Long} one first summand438* @param {!goog.math.Long} two second summand439* @param {...goog.math.Long} var_args more arguments to sum440* @return {!goog.math.Long} The resulting sum.441*/442goog.crypt.Sha2_64bit.prototype.sum_ = function(one, two, var_args) {443// The low bits may be signed, but they represent a 32-bit unsigned quantity.444// We must be careful to normalize them.445// This doesn't matter for the high bits.446// Implementation note: Performance testing shows that this method runs447// fastest when the first two arguments are pulled out of the loop.448var low = (one.getLowBits() ^ 0x80000000) + (two.getLowBits() ^ 0x80000000);449var high = one.getHighBits() + two.getHighBits();450for (var i = arguments.length - 1; i >= 2; --i) {451low += arguments[i].getLowBits() ^ 0x80000000;452high += arguments[i].getHighBits();453}454// Because of the ^0x80000000, each value we added is 0x80000000 too small.455// Add arguments.length * 0x80000000 to the current sum. We can do this456// quickly by adding 0x80000000 to low when the number of arguments is457// odd, and adding (number of arguments) >> 1 to high.458if (arguments.length & 1) {459low += 0x80000000;460}461high += arguments.length >> 1;462463// If low is outside the range [0, 0xFFFFFFFF], its overflow or underflow464// should be added to high. We don't actually need to modify low or465// normalize high because the goog.math.Long constructor already does that.466high += Math.floor(low / 0x100000000);467return new goog.math.Long(low, high);468};469470471/**472* Converts an array of 32-bit integers into an array of goog.math.Long473* elements.474*475* @private476* @param {!Array<number>} values An array of 32-bit numbers. Its length477* must be even. Each pair of numbers represents a 64-bit integer478* in big-endian order479* @return {!Array<!goog.math.Long>}480*/481goog.crypt.Sha2_64bit.toLongArray_ = function(values) {482goog.asserts.assert(values.length % 2 == 0);483var result = [];484for (var i = 0; i < values.length; i += 2) {485result.push(new goog.math.Long(values[i + 1], values[i]));486}487return result;488};489490491/**492* Fixed constants used in SHA-512 variants.493*494* These values are from Section 4.2.3 of495* http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf496* @const497* @private {!Array<!goog.math.Long>}498*/499goog.crypt.Sha2_64bit.K_ = goog.crypt.Sha2_64bit.toLongArray_([5000x428a2f98, 0xd728ae22, 0x71374491, 0x23ef65cd, 0xb5c0fbcf, 0xec4d3b2f,5010xe9b5dba5, 0x8189dbbc, 0x3956c25b, 0xf348b538, 0x59f111f1, 0xb605d019,5020x923f82a4, 0xaf194f9b, 0xab1c5ed5, 0xda6d8118, 0xd807aa98, 0xa3030242,5030x12835b01, 0x45706fbe, 0x243185be, 0x4ee4b28c, 0x550c7dc3, 0xd5ffb4e2,5040x72be5d74, 0xf27b896f, 0x80deb1fe, 0x3b1696b1, 0x9bdc06a7, 0x25c71235,5050xc19bf174, 0xcf692694, 0xe49b69c1, 0x9ef14ad2, 0xefbe4786, 0x384f25e3,5060x0fc19dc6, 0x8b8cd5b5, 0x240ca1cc, 0x77ac9c65, 0x2de92c6f, 0x592b0275,5070x4a7484aa, 0x6ea6e483, 0x5cb0a9dc, 0xbd41fbd4, 0x76f988da, 0x831153b5,5080x983e5152, 0xee66dfab, 0xa831c66d, 0x2db43210, 0xb00327c8, 0x98fb213f,5090xbf597fc7, 0xbeef0ee4, 0xc6e00bf3, 0x3da88fc2, 0xd5a79147, 0x930aa725,5100x06ca6351, 0xe003826f, 0x14292967, 0x0a0e6e70, 0x27b70a85, 0x46d22ffc,5110x2e1b2138, 0x5c26c926, 0x4d2c6dfc, 0x5ac42aed, 0x53380d13, 0x9d95b3df,5120x650a7354, 0x8baf63de, 0x766a0abb, 0x3c77b2a8, 0x81c2c92e, 0x47edaee6,5130x92722c85, 0x1482353b, 0xa2bfe8a1, 0x4cf10364, 0xa81a664b, 0xbc423001,5140xc24b8b70, 0xd0f89791, 0xc76c51a3, 0x0654be30, 0xd192e819, 0xd6ef5218,5150xd6990624, 0x5565a910, 0xf40e3585, 0x5771202a, 0x106aa070, 0x32bbd1b8,5160x19a4c116, 0xb8d2d0c8, 0x1e376c08, 0x5141ab53, 0x2748774c, 0xdf8eeb99,5170x34b0bcb5, 0xe19b48a8, 0x391c0cb3, 0xc5c95a63, 0x4ed8aa4a, 0xe3418acb,5180x5b9cca4f, 0x7763e373, 0x682e6ff3, 0xd6b2b8a3, 0x748f82ee, 0x5defb2fc,5190x78a5636f, 0x43172f60, 0x84c87814, 0xa1f0ab72, 0x8cc70208, 0x1a6439ec,5200x90befffa, 0x23631e28, 0xa4506ceb, 0xde82bde9, 0xbef9a3f7, 0xb2c67915,5210xc67178f2, 0xe372532b, 0xca273ece, 0xea26619c, 0xd186b8c7, 0x21c0c207,5220xeada7dd6, 0xcde0eb1e, 0xf57d4f7f, 0xee6ed178, 0x06f067aa, 0x72176fba,5230x0a637dc5, 0xa2c898a6, 0x113f9804, 0xbef90dae, 0x1b710b35, 0x131c471b,5240x28db77f5, 0x23047d84, 0x32caab7b, 0x40c72493, 0x3c9ebe0a, 0x15c9bebc,5250x431d67c4, 0x9c100d4c, 0x4cc5d4be, 0xcb3e42b6, 0x597f299c, 0xfc657e2a,5260x5fcb6fab, 0x3ad6faec, 0x6c44198c, 0x4a475817527]);528529530