Path: blob/trunk/third_party/closure/goog/crypt/md5.js
2868 views
// Copyright 2011 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 MD5 cryptographic hash.16* Implementation of http://tools.ietf.org/html/rfc1321 with common17* optimizations and tweaks (see http://en.wikipedia.org/wiki/MD5).18*19* Usage:20* var md5 = new goog.crypt.Md5();21* md5.update(bytes);22* var hash = md5.digest();23*24* Performance:25* Chrome 23 ~680 Mbit/s26* Chrome 13 (in a VM) ~250 Mbit/s27* Firefox 6.0 (in a VM) ~100 Mbit/s28* IE9 (in a VM) ~27 Mbit/s29* Firefox 3.6 ~15 Mbit/s30* IE8 (in a VM) ~13 Mbit/s31*32*/3334goog.provide('goog.crypt.Md5');3536goog.require('goog.crypt.Hash');37383940/**41* MD5 cryptographic hash constructor.42* @constructor43* @extends {goog.crypt.Hash}44* @final45* @struct46*/47goog.crypt.Md5 = function() {48goog.crypt.Md5.base(this, 'constructor');4950this.blockSize = 512 / 8;5152/**53* Holds the current values of accumulated A-D variables (MD buffer).54* @type {!Array<number>}55* @private56*/57this.chain_ = new Array(4);5859/**60* A buffer holding the data until the whole block can be processed.61* @type {!Array<number>}62* @private63*/64this.block_ = new Array(this.blockSize);6566/**67* The length of yet-unprocessed data as collected in the block.68* @type {number}69* @private70*/71this.blockLength_ = 0;7273/**74* The total length of the message so far.75* @type {number}76* @private77*/78this.totalLength_ = 0;7980this.reset();81};82goog.inherits(goog.crypt.Md5, goog.crypt.Hash);838485/**86* Integer rotation constants used by the abbreviated implementation.87* They are hardcoded in the unrolled implementation, so it is left88* here commented out.89* @type {Array<number>}90* @private91*92goog.crypt.Md5.S_ = [937, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,945, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,954, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,966, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 2197];98*/99100/**101* Sine function constants used by the abbreviated implementation.102* They are hardcoded in the unrolled implementation, so it is left103* here commented out.104* @type {Array<number>}105* @private106*107goog.crypt.Md5.T_ = [1080xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,1090xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,1100x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,1110x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,1120xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,1130xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,1140x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,1150xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,1160xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,1170xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,1180x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,1190xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,1200xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,1210x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,1220x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,1230xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391124];125*/126127128/** @override */129goog.crypt.Md5.prototype.reset = function() {130this.chain_[0] = 0x67452301;131this.chain_[1] = 0xefcdab89;132this.chain_[2] = 0x98badcfe;133this.chain_[3] = 0x10325476;134135this.blockLength_ = 0;136this.totalLength_ = 0;137};138139140/**141* Internal compress helper function. It takes a block of data (64 bytes)142* and updates the accumulator.143* @param {Array<number>|Uint8Array|string} buf The block to compress.144* @param {number=} opt_offset Offset of the block in the buffer.145* @private146*/147goog.crypt.Md5.prototype.compress_ = function(buf, opt_offset) {148if (!opt_offset) {149opt_offset = 0;150}151152// We allocate the array every time, but it's cheap in practice.153var X = new Array(16);154155// Get 16 little endian words. It is not worth unrolling this for Chrome 11.156if (goog.isString(buf)) {157for (var i = 0; i < 16; ++i) {158X[i] = (buf.charCodeAt(opt_offset++)) |159(buf.charCodeAt(opt_offset++) << 8) |160(buf.charCodeAt(opt_offset++) << 16) |161(buf.charCodeAt(opt_offset++) << 24);162}163} else {164for (var i = 0; i < 16; ++i) {165X[i] = (buf[opt_offset++]) | (buf[opt_offset++] << 8) |166(buf[opt_offset++] << 16) | (buf[opt_offset++] << 24);167}168}169170var A = this.chain_[0];171var B = this.chain_[1];172var C = this.chain_[2];173var D = this.chain_[3];174var sum = 0;175176/*177* This is an abbreviated implementation, it is left here commented out for178* reference purposes. See below for an unrolled version in use.179*180var f, n, tmp;181for (var i = 0; i < 64; ++i) {182183if (i < 16) {184f = (D ^ (B & (C ^ D)));185n = i;186} else if (i < 32) {187f = (C ^ (D & (B ^ C)));188n = (5 * i + 1) % 16;189} else if (i < 48) {190f = (B ^ C ^ D);191n = (3 * i + 5) % 16;192} else {193f = (C ^ (B | (~D)));194n = (7 * i) % 16;195}196197tmp = D;198D = C;199C = B;200sum = (A + f + goog.crypt.Md5.T_[i] + X[n]) & 0xffffffff;201B += ((sum << goog.crypt.Md5.S_[i]) & 0xffffffff) |202(sum >>> (32 - goog.crypt.Md5.S_[i]));203A = tmp;204}205*/206207/*208* This is an unrolled MD5 implementation, which gives ~30% speedup compared209* to the abbreviated implementation above, as measured on Chrome 11. It is210* important to keep 32-bit croppings to minimum and inline the integer211* rotation.212*/213sum = (A + (D ^ (B & (C ^ D))) + X[0] + 0xd76aa478) & 0xffffffff;214A = B + (((sum << 7) & 0xffffffff) | (sum >>> 25));215sum = (D + (C ^ (A & (B ^ C))) + X[1] + 0xe8c7b756) & 0xffffffff;216D = A + (((sum << 12) & 0xffffffff) | (sum >>> 20));217sum = (C + (B ^ (D & (A ^ B))) + X[2] + 0x242070db) & 0xffffffff;218C = D + (((sum << 17) & 0xffffffff) | (sum >>> 15));219sum = (B + (A ^ (C & (D ^ A))) + X[3] + 0xc1bdceee) & 0xffffffff;220B = C + (((sum << 22) & 0xffffffff) | (sum >>> 10));221sum = (A + (D ^ (B & (C ^ D))) + X[4] + 0xf57c0faf) & 0xffffffff;222A = B + (((sum << 7) & 0xffffffff) | (sum >>> 25));223sum = (D + (C ^ (A & (B ^ C))) + X[5] + 0x4787c62a) & 0xffffffff;224D = A + (((sum << 12) & 0xffffffff) | (sum >>> 20));225sum = (C + (B ^ (D & (A ^ B))) + X[6] + 0xa8304613) & 0xffffffff;226C = D + (((sum << 17) & 0xffffffff) | (sum >>> 15));227sum = (B + (A ^ (C & (D ^ A))) + X[7] + 0xfd469501) & 0xffffffff;228B = C + (((sum << 22) & 0xffffffff) | (sum >>> 10));229sum = (A + (D ^ (B & (C ^ D))) + X[8] + 0x698098d8) & 0xffffffff;230A = B + (((sum << 7) & 0xffffffff) | (sum >>> 25));231sum = (D + (C ^ (A & (B ^ C))) + X[9] + 0x8b44f7af) & 0xffffffff;232D = A + (((sum << 12) & 0xffffffff) | (sum >>> 20));233sum = (C + (B ^ (D & (A ^ B))) + X[10] + 0xffff5bb1) & 0xffffffff;234C = D + (((sum << 17) & 0xffffffff) | (sum >>> 15));235sum = (B + (A ^ (C & (D ^ A))) + X[11] + 0x895cd7be) & 0xffffffff;236B = C + (((sum << 22) & 0xffffffff) | (sum >>> 10));237sum = (A + (D ^ (B & (C ^ D))) + X[12] + 0x6b901122) & 0xffffffff;238A = B + (((sum << 7) & 0xffffffff) | (sum >>> 25));239sum = (D + (C ^ (A & (B ^ C))) + X[13] + 0xfd987193) & 0xffffffff;240D = A + (((sum << 12) & 0xffffffff) | (sum >>> 20));241sum = (C + (B ^ (D & (A ^ B))) + X[14] + 0xa679438e) & 0xffffffff;242C = D + (((sum << 17) & 0xffffffff) | (sum >>> 15));243sum = (B + (A ^ (C & (D ^ A))) + X[15] + 0x49b40821) & 0xffffffff;244B = C + (((sum << 22) & 0xffffffff) | (sum >>> 10));245sum = (A + (C ^ (D & (B ^ C))) + X[1] + 0xf61e2562) & 0xffffffff;246A = B + (((sum << 5) & 0xffffffff) | (sum >>> 27));247sum = (D + (B ^ (C & (A ^ B))) + X[6] + 0xc040b340) & 0xffffffff;248D = A + (((sum << 9) & 0xffffffff) | (sum >>> 23));249sum = (C + (A ^ (B & (D ^ A))) + X[11] + 0x265e5a51) & 0xffffffff;250C = D + (((sum << 14) & 0xffffffff) | (sum >>> 18));251sum = (B + (D ^ (A & (C ^ D))) + X[0] + 0xe9b6c7aa) & 0xffffffff;252B = C + (((sum << 20) & 0xffffffff) | (sum >>> 12));253sum = (A + (C ^ (D & (B ^ C))) + X[5] + 0xd62f105d) & 0xffffffff;254A = B + (((sum << 5) & 0xffffffff) | (sum >>> 27));255sum = (D + (B ^ (C & (A ^ B))) + X[10] + 0x02441453) & 0xffffffff;256D = A + (((sum << 9) & 0xffffffff) | (sum >>> 23));257sum = (C + (A ^ (B & (D ^ A))) + X[15] + 0xd8a1e681) & 0xffffffff;258C = D + (((sum << 14) & 0xffffffff) | (sum >>> 18));259sum = (B + (D ^ (A & (C ^ D))) + X[4] + 0xe7d3fbc8) & 0xffffffff;260B = C + (((sum << 20) & 0xffffffff) | (sum >>> 12));261sum = (A + (C ^ (D & (B ^ C))) + X[9] + 0x21e1cde6) & 0xffffffff;262A = B + (((sum << 5) & 0xffffffff) | (sum >>> 27));263sum = (D + (B ^ (C & (A ^ B))) + X[14] + 0xc33707d6) & 0xffffffff;264D = A + (((sum << 9) & 0xffffffff) | (sum >>> 23));265sum = (C + (A ^ (B & (D ^ A))) + X[3] + 0xf4d50d87) & 0xffffffff;266C = D + (((sum << 14) & 0xffffffff) | (sum >>> 18));267sum = (B + (D ^ (A & (C ^ D))) + X[8] + 0x455a14ed) & 0xffffffff;268B = C + (((sum << 20) & 0xffffffff) | (sum >>> 12));269sum = (A + (C ^ (D & (B ^ C))) + X[13] + 0xa9e3e905) & 0xffffffff;270A = B + (((sum << 5) & 0xffffffff) | (sum >>> 27));271sum = (D + (B ^ (C & (A ^ B))) + X[2] + 0xfcefa3f8) & 0xffffffff;272D = A + (((sum << 9) & 0xffffffff) | (sum >>> 23));273sum = (C + (A ^ (B & (D ^ A))) + X[7] + 0x676f02d9) & 0xffffffff;274C = D + (((sum << 14) & 0xffffffff) | (sum >>> 18));275sum = (B + (D ^ (A & (C ^ D))) + X[12] + 0x8d2a4c8a) & 0xffffffff;276B = C + (((sum << 20) & 0xffffffff) | (sum >>> 12));277sum = (A + (B ^ C ^ D) + X[5] + 0xfffa3942) & 0xffffffff;278A = B + (((sum << 4) & 0xffffffff) | (sum >>> 28));279sum = (D + (A ^ B ^ C) + X[8] + 0x8771f681) & 0xffffffff;280D = A + (((sum << 11) & 0xffffffff) | (sum >>> 21));281sum = (C + (D ^ A ^ B) + X[11] + 0x6d9d6122) & 0xffffffff;282C = D + (((sum << 16) & 0xffffffff) | (sum >>> 16));283sum = (B + (C ^ D ^ A) + X[14] + 0xfde5380c) & 0xffffffff;284B = C + (((sum << 23) & 0xffffffff) | (sum >>> 9));285sum = (A + (B ^ C ^ D) + X[1] + 0xa4beea44) & 0xffffffff;286A = B + (((sum << 4) & 0xffffffff) | (sum >>> 28));287sum = (D + (A ^ B ^ C) + X[4] + 0x4bdecfa9) & 0xffffffff;288D = A + (((sum << 11) & 0xffffffff) | (sum >>> 21));289sum = (C + (D ^ A ^ B) + X[7] + 0xf6bb4b60) & 0xffffffff;290C = D + (((sum << 16) & 0xffffffff) | (sum >>> 16));291sum = (B + (C ^ D ^ A) + X[10] + 0xbebfbc70) & 0xffffffff;292B = C + (((sum << 23) & 0xffffffff) | (sum >>> 9));293sum = (A + (B ^ C ^ D) + X[13] + 0x289b7ec6) & 0xffffffff;294A = B + (((sum << 4) & 0xffffffff) | (sum >>> 28));295sum = (D + (A ^ B ^ C) + X[0] + 0xeaa127fa) & 0xffffffff;296D = A + (((sum << 11) & 0xffffffff) | (sum >>> 21));297sum = (C + (D ^ A ^ B) + X[3] + 0xd4ef3085) & 0xffffffff;298C = D + (((sum << 16) & 0xffffffff) | (sum >>> 16));299sum = (B + (C ^ D ^ A) + X[6] + 0x04881d05) & 0xffffffff;300B = C + (((sum << 23) & 0xffffffff) | (sum >>> 9));301sum = (A + (B ^ C ^ D) + X[9] + 0xd9d4d039) & 0xffffffff;302A = B + (((sum << 4) & 0xffffffff) | (sum >>> 28));303sum = (D + (A ^ B ^ C) + X[12] + 0xe6db99e5) & 0xffffffff;304D = A + (((sum << 11) & 0xffffffff) | (sum >>> 21));305sum = (C + (D ^ A ^ B) + X[15] + 0x1fa27cf8) & 0xffffffff;306C = D + (((sum << 16) & 0xffffffff) | (sum >>> 16));307sum = (B + (C ^ D ^ A) + X[2] + 0xc4ac5665) & 0xffffffff;308B = C + (((sum << 23) & 0xffffffff) | (sum >>> 9));309sum = (A + (C ^ (B | (~D))) + X[0] + 0xf4292244) & 0xffffffff;310A = B + (((sum << 6) & 0xffffffff) | (sum >>> 26));311sum = (D + (B ^ (A | (~C))) + X[7] + 0x432aff97) & 0xffffffff;312D = A + (((sum << 10) & 0xffffffff) | (sum >>> 22));313sum = (C + (A ^ (D | (~B))) + X[14] + 0xab9423a7) & 0xffffffff;314C = D + (((sum << 15) & 0xffffffff) | (sum >>> 17));315sum = (B + (D ^ (C | (~A))) + X[5] + 0xfc93a039) & 0xffffffff;316B = C + (((sum << 21) & 0xffffffff) | (sum >>> 11));317sum = (A + (C ^ (B | (~D))) + X[12] + 0x655b59c3) & 0xffffffff;318A = B + (((sum << 6) & 0xffffffff) | (sum >>> 26));319sum = (D + (B ^ (A | (~C))) + X[3] + 0x8f0ccc92) & 0xffffffff;320D = A + (((sum << 10) & 0xffffffff) | (sum >>> 22));321sum = (C + (A ^ (D | (~B))) + X[10] + 0xffeff47d) & 0xffffffff;322C = D + (((sum << 15) & 0xffffffff) | (sum >>> 17));323sum = (B + (D ^ (C | (~A))) + X[1] + 0x85845dd1) & 0xffffffff;324B = C + (((sum << 21) & 0xffffffff) | (sum >>> 11));325sum = (A + (C ^ (B | (~D))) + X[8] + 0x6fa87e4f) & 0xffffffff;326A = B + (((sum << 6) & 0xffffffff) | (sum >>> 26));327sum = (D + (B ^ (A | (~C))) + X[15] + 0xfe2ce6e0) & 0xffffffff;328D = A + (((sum << 10) & 0xffffffff) | (sum >>> 22));329sum = (C + (A ^ (D | (~B))) + X[6] + 0xa3014314) & 0xffffffff;330C = D + (((sum << 15) & 0xffffffff) | (sum >>> 17));331sum = (B + (D ^ (C | (~A))) + X[13] + 0x4e0811a1) & 0xffffffff;332B = C + (((sum << 21) & 0xffffffff) | (sum >>> 11));333sum = (A + (C ^ (B | (~D))) + X[4] + 0xf7537e82) & 0xffffffff;334A = B + (((sum << 6) & 0xffffffff) | (sum >>> 26));335sum = (D + (B ^ (A | (~C))) + X[11] + 0xbd3af235) & 0xffffffff;336D = A + (((sum << 10) & 0xffffffff) | (sum >>> 22));337sum = (C + (A ^ (D | (~B))) + X[2] + 0x2ad7d2bb) & 0xffffffff;338C = D + (((sum << 15) & 0xffffffff) | (sum >>> 17));339sum = (B + (D ^ (C | (~A))) + X[9] + 0xeb86d391) & 0xffffffff;340B = C + (((sum << 21) & 0xffffffff) | (sum >>> 11));341342this.chain_[0] = (this.chain_[0] + A) & 0xffffffff;343this.chain_[1] = (this.chain_[1] + B) & 0xffffffff;344this.chain_[2] = (this.chain_[2] + C) & 0xffffffff;345this.chain_[3] = (this.chain_[3] + D) & 0xffffffff;346};347348349/** @override */350goog.crypt.Md5.prototype.update = function(bytes, opt_length) {351if (!goog.isDef(opt_length)) {352opt_length = bytes.length;353}354var lengthMinusBlock = opt_length - this.blockSize;355356// Copy some object properties to local variables in order to save on access357// time from inside the loop (~10% speedup was observed on Chrome 11).358var block = this.block_;359var blockLength = this.blockLength_;360var i = 0;361362// The outer while loop should execute at most twice.363while (i < opt_length) {364// When we have no data in the block to top up, we can directly process the365// input buffer (assuming it contains sufficient data). This gives ~30%366// speedup on Chrome 14 and ~70% speedup on Firefox 6.0, but requires that367// the data is provided in large chunks (or in multiples of 64 bytes).368if (blockLength == 0) {369while (i <= lengthMinusBlock) {370this.compress_(bytes, i);371i += this.blockSize;372}373}374375if (goog.isString(bytes)) {376while (i < opt_length) {377block[blockLength++] = bytes.charCodeAt(i++);378if (blockLength == this.blockSize) {379this.compress_(block);380blockLength = 0;381// Jump to the outer loop so we use the full-block optimization.382break;383}384}385} else {386while (i < opt_length) {387block[blockLength++] = bytes[i++];388if (blockLength == this.blockSize) {389this.compress_(block);390blockLength = 0;391// Jump to the outer loop so we use the full-block optimization.392break;393}394}395}396}397398this.blockLength_ = blockLength;399this.totalLength_ += opt_length;400};401402403/** @override */404goog.crypt.Md5.prototype.digest = function() {405// This must accommodate at least 1 padding byte (0x80), 8 bytes of406// total bitlength, and must end at a 64-byte boundary.407var pad = new Array(408(this.blockLength_ < 56 ? this.blockSize : this.blockSize * 2) -409this.blockLength_);410411// Add padding: 0x80 0x00*412pad[0] = 0x80;413for (var i = 1; i < pad.length - 8; ++i) {414pad[i] = 0;415}416// Add the total number of bits, little endian 64-bit integer.417var totalBits = this.totalLength_ * 8;418for (var i = pad.length - 8; i < pad.length; ++i) {419pad[i] = totalBits & 0xff;420totalBits /= 0x100; // Don't use bit-shifting here!421}422this.update(pad);423424var digest = new Array(16);425var n = 0;426for (var i = 0; i < 4; ++i) {427for (var j = 0; j < 32; j += 8) {428digest[n++] = (this.chain_[i] >>> j) & 0xff;429}430}431return digest;432};433434435