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