1 /*
  2  * ***** BEGIN LICENSE BLOCK *****
  3  * Zimbra Collaboration Suite Web Client
  4  * Copyright (C) 2006, 2007, 2009, 2010, 2013, 2014, 2016 Synacor, Inc.
  5  *
  6  * The contents of this file are subject to the Common Public Attribution License Version 1.0 (the "License");
  7  * you may not use this file except in compliance with the License.
  8  * You may obtain a copy of the License at: https://www.zimbra.com/license
  9  * The License is based on the Mozilla Public License Version 1.1 but Sections 14 and 15
 10  * have been added to cover use of software over a computer network and provide for limited attribution
 11  * for the Original Developer. In addition, Exhibit A has been modified to be consistent with Exhibit B.
 12  *
 13  * Software distributed under the License is distributed on an "AS IS" basis,
 14  * WITHOUT WARRANTY OF ANY KIND, either express or implied.
 15  * See the License for the specific language governing rights and limitations under the License.
 16  * The Original Code is Zimbra Open Source Web Client.
 17  * The Initial Developer of the Original Code is Zimbra, Inc.  All rights to the Original Code were
 18  * transferred by Zimbra, Inc. to Synacor, Inc. on September 14, 2015.
 19  *
 20  * All portions of the code are Copyright (C) 2006, 2007, 2009, 2010, 2013, 2014, 2016 Synacor, Inc. All Rights Reserved.
 21  * ***** END LICENSE BLOCK *****
 22  */
 23 /*
 24  * Based on code by Paul Johnston:
 25  *
 26  * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined
 27  * in FIPS PUB 180-1
 28  * Version 2.1a Copyright Paul Johnston 2000 - 2002.
 29  * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
 30  * Distributed under the BSD License
 31  * See http://pajhome.org.uk/crypt/md5 for details.
 32  */
 33 
 34 var AjxSHA1 = function() {
 35 
 36 	/*
 37 	 * Configurable variables. You may need to tweak these to be compatible with
 38 	 * the server-side, but the defaults work in most cases.
 39 	 */
 40 	var hexcase = 0;  /* hex output format. 0 - lowercase; 1 - uppercase        */
 41 	var b64pad  = ""; /* base-64 pad character. "=" for strict RFC compliance   */
 42 	var chrsz   = 8;  /* bits per input character. 8 - ASCII; 16 - Unicode      */
 43 
 44 	/*
 45 	 * These are the functions you'll usually want to call
 46 	 * They take string arguments and return either hex or base-64 encoded strings
 47 	 */
 48 	function hex_sha1(s){return binb2hex(core_sha1(str2binb(s),s.length * chrsz));};
 49 	function b64_sha1(s){return binb2b64(core_sha1(str2binb(s),s.length * chrsz));};
 50 	function str_sha1(s){return binb2str(core_sha1(str2binb(s),s.length * chrsz));};
 51 	function hex_hmac_sha1(key, data){ return binb2hex(core_hmac_sha1(key, data));};
 52 	function b64_hmac_sha1(key, data){ return binb2b64(core_hmac_sha1(key, data));};
 53 	function str_hmac_sha1(key, data){ return binb2str(core_hmac_sha1(key, data));};
 54 
 55 	/*
 56 	 * Perform a simple self-test to see if the VM is working
 57 	 */
 58 	function sha1_vm_test()
 59 	{
 60 		return hex_sha1("abc") == "a9993e364706816aba3e25717850c26c9cd0d89d";
 61 	};
 62 
 63 	/*
 64 	 * Calculate the SHA-1 of an array of big-endian words, and a bit length
 65 	 */
 66 	function core_sha1(x, len)
 67 	{
 68 		/* append padding */
 69 		x[len >> 5] |= 0x80 << (24 - len % 32);
 70 		x[((len + 64 >> 9) << 4) + 15] = len;
 71 
 72 		var w = Array(80);
 73 		var a =  1732584193;
 74 		var b = -271733879;
 75 		var c = -1732584194;
 76 		var d =  271733878;
 77 		var e = -1009589776;
 78 
 79 		for(var i = 0; i < x.length; i += 16) {
 80 			var olda = a;
 81 			var oldb = b;
 82 			var oldc = c;
 83 			var oldd = d;
 84 			var olde = e;
 85 
 86 			for(var j = 0; j < 80; j++) {
 87 				if(j < 16) w[j] = x[i + j];
 88 				else w[j] = rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1);
 89 				var t = safe_add(safe_add(rol(a, 5), sha1_ft(j, b, c, d)),
 90 						 safe_add(safe_add(e, w[j]), sha1_kt(j)));
 91 				e = d;
 92 				d = c;
 93 				c = rol(b, 30);
 94 				b = a;
 95 				a = t;
 96 			}
 97 
 98 			a = safe_add(a, olda);
 99 			b = safe_add(b, oldb);
100 			c = safe_add(c, oldc);
101 			d = safe_add(d, oldd);
102 			e = safe_add(e, olde);
103 		}
104 		return Array(a, b, c, d, e);
105 
106 	};
107 
108 	/*
109 	 * Perform the appropriate triplet combination function for the current
110 	 * iteration
111 	 */
112 	function sha1_ft(t, b, c, d)
113 	{
114 		if(t < 20) return (b & c) | ((~b) & d);
115 		if(t < 40) return b ^ c ^ d;
116 		if(t < 60) return (b & c) | (b & d) | (c & d);
117 		return b ^ c ^ d;
118 	};
119 
120 	/*
121 	 * Determine the appropriate additive constant for the current iteration
122 	 */
123 	function sha1_kt(t)
124 	{
125 		return (t < 20) ?  1518500249 : (t < 40) ?  1859775393 :
126 			(t < 60) ? -1894007588 : -899497514;
127 	};
128 
129 	/*
130 	 * Calculate the HMAC-SHA1 of a key and some data
131 	 */
132 	function core_hmac_sha1(key, data)
133 	{
134 		var bkey = str2binb(key);
135 		if(bkey.length > 16) bkey = core_sha1(bkey, key.length * chrsz);
136 
137 		var ipad = Array(16), opad = Array(16);
138 		for(var i = 0; i < 16; i++) {
139 			ipad[i] = bkey[i] ^ 0x36363636;
140 			opad[i] = bkey[i] ^ 0x5C5C5C5C;
141 		}
142 
143 		var hash = core_sha1(ipad.concat(str2binb(data)), 512 + data.length * chrsz);
144 		return core_sha1(opad.concat(hash), 512 + 160);
145 	};
146 
147 	/*
148 	 * Add integers, wrapping at 2^32. This uses 16-bit operations internally
149 	 * to work around bugs in some JS interpreters.
150 	 */
151 	function safe_add(x, y)
152 	{
153 		var lsw = (x & 0xFFFF) + (y & 0xFFFF);
154 		var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
155 		return (msw << 16) | (lsw & 0xFFFF);
156 	};
157 
158 	/*
159 	 * Bitwise rotate a 32-bit number to the left.
160 	 */
161 	function rol(num, cnt)
162 	{
163 		return (num << cnt) | (num >>> (32 - cnt));
164 	};
165 
166 	/*
167 	 * Convert an 8-bit or 16-bit string to an array of big-endian words
168 	 * In 8-bit function, characters >255 have their hi-byte silently ignored.
169 	 */
170 	function str2binb(str)
171 	{
172 		var bin = Array();
173 		var mask = (1 << chrsz) - 1;
174 		for(var i = 0; i < str.length * chrsz; i += chrsz)
175 			bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (32 - chrsz - i%32);
176 		return bin;
177 	};
178 
179 	/*
180 	 * Convert an array of big-endian words to a string
181 	 */
182 	function binb2str(bin)
183 	{
184 		var str = "";
185 		var mask = (1 << chrsz) - 1;
186 		for(var i = 0; i < bin.length * 32; i += chrsz)
187 			str += String.fromCharCode((bin[i>>5] >>> (32 - chrsz - i%32)) & mask);
188 		return str;
189 	};
190 
191 	/*
192 	 * Convert an array of big-endian words to a hex string.
193 	 */
194 	function binb2hex(binarray)
195 	{
196 		var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
197 		var str = "";
198 		for(var i = 0; i < binarray.length * 4; i++) {
199 			str += hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8+4)) & 0xF) +
200 				hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8  )) & 0xF);
201 		}
202 		return str;
203 	};
204 
205 	/*
206 	 * Convert an array of big-endian words to a base-64 string
207 	 */
208 	function binb2b64(binarray)
209 	{
210 		var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
211 		var str = "";
212 		for(var i = 0; i < binarray.length * 4; i += 3) {
213 			var triplet = (((binarray[i   >> 2] >> 8 * (3 -  i   %4)) & 0xFF) << 16)
214 				| (((binarray[i+1 >> 2] >> 8 * (3 - (i+1)%4)) & 0xFF) << 8 )
215 				|  ((binarray[i+2 >> 2] >> 8 * (3 - (i+2)%4)) & 0xFF);
216 			for(var j = 0; j < 4; j++) {
217 				if(i * 8 + j * 6 > binarray.length * 32) str += b64pad;
218 				else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F);
219 			}
220 		}
221 		return str;
222 	};
223 
224 	// export functions
225 	this.hex_sha1 = hex_sha1;
226 	this.b64_sha1 = b64_sha1;
227 	this.str_sha1 = str_sha1;
228 	this.hex_hmac_sha1 = hex_hmac_sha1;
229 	this.b64_hmac_sha1 = b64_hmac_sha1;
230 	this.str_hmac_sha1 = str_hmac_sha1;
231 
232 	this.sha1_vm_test = sha1_vm_test;
233 
234 };
235 
236 AjxSHA1 = new AjxSHA1();
237