├── LICENSE ├── README.md ├── USAGE.gif └── jumper.js /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 poslua 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Xshell-OTP 2 | 3 | Xshell 自动登录 One-time Password 跳板机 4 | 5 | ![USAGE](USAGE.gif) 6 | 7 | ## 使用 8 | 9 | 下载 jumper.js 后拖到最后,修改 `Main` 函数中的配置: 10 | 11 | ```js 12 | function Main() 13 | { 14 | // Calculate OTP token 15 | var totpObj = new TOTP(); 16 | var epoch = Math.floor(new Date().getTime() / 1000 % 30); 17 | var elapsed = 30 - epoch 18 | 19 | // Adjust the sliding window 20 | if (elapsed <= 3 ) { 21 | xsh.Dialog.MsgBox("Hold on, and wait " + elapsed + " seconds!"); 22 | xsh.Session.Sleep(elapsed * 1000 + 100); 23 | } 24 | 25 | // Calculate OTP token 26 | // REVISED 修改为你自己的 Google Authenticator Secret 27 | var otp = totpObj.getOTP("REVISED"); 28 | 29 | // Copy the token to clipboard 30 | xsh.Screen.Synchronous = true; 31 | xsh.Screen.Send("cmd /c echo " + otp + "| clip"); 32 | xsh.Screen.Send(String.fromCharCode(13)); 33 | xsh.Screen.Clear(); 34 | 35 | // Open Session 36 | // xsh.Session.Open("ssh://username:password@host:port") 37 | // 修改为你自己的 xsh 文件路径 38 | xsh.Session.Open("C:\Users\REVISED\Documents\NetSarang\Xshell\Sessions\jump.xsh"); 39 | 40 | // Close the local shell 41 | // xsh.Session.Sleep(1000); 42 | xsh.Screen.Send("exit"); 43 | xsh.Screen.Send(String.fromCharCode(13)); 44 | } 45 | ``` 46 | 47 | ## 原理 48 | 49 | 使用 [Google Authenticator][1] MFA 验证机制登录跳板机,可以通过其导出的 secret 在本地计算出当前的 token。Xshell 支持运行 javascript 脚本,所以这个 token 可以直接在 Xshell 端计算完成。但是 Xshell 在处理 MFA 验证机制时,是直接弹出对话框,并不支持传统的 terminal 输入,Xshell 也并没有提供自动完成的 API,所以只能手动拷贝输入。 50 | 51 | [1]: https://chrome.google.com/webstore/detail/authenticator/bhghoamapcdpbohphigoooaddinpkbai 52 | -------------------------------------------------------------------------------- /USAGE.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ms2008/Xshell-OTP/f099631d1a0881c77f34b031d5be5bbed88e4e41/USAGE.gif -------------------------------------------------------------------------------- /jumper.js: -------------------------------------------------------------------------------- 1 | //Article about TOTP on my blog https://stapp.space/generate-totp-in-postman/ 2 | 3 | /** 4 | * @preserve A JavaScript implementation of the SHA family of hashes, as 5 | * defined in FIPS PUB 180-4 and FIPS PUB 202, as well as the corresponding 6 | * HMAC implementation as defined in FIPS PUB 198a 7 | * 8 | * Copyright Brian Turek 2008-2017 9 | * Distributed under the BSD License 10 | * See http://caligatio.github.com/jsSHA/ for more information 11 | * 12 | * Several functions taken from Paul Johnston 13 | */ 14 | 15 | /*jslint 16 | bitwise: true, multivar: true, for: true, this: true, sub: true, esversion: 3 17 | */ 18 | 19 | /** 20 | * SUPPORTED_ALGS is the stub for a compile flag that will cause pruning of 21 | * functions that are not needed when a limited number of SHA families are 22 | * selected 23 | * 24 | * @define {number} ORed value of SHA variants to be supported 25 | * 1 = SHA-1, 2 = SHA-224/SHA-256, 4 = SHA-384/SHA-512, 8 = SHA3 26 | */ 27 | var SUPPORTED_ALGS = 8 | 4 | 2 | 1; 28 | var X={}; 29 | 30 | (function (global) 31 | { 32 | "use strict"; 33 | 34 | /* Globals */ 35 | var TWO_PWR_32 = 4294967296; 36 | 37 | /** 38 | * Int_64 is a object for 2 32-bit numbers emulating a 64-bit number 39 | * 40 | * @private 41 | * @constructor 42 | * @this {Int_64} 43 | * @param {number} msint_32 The most significant 32-bits of a 64-bit number 44 | * @param {number} lsint_32 The least significant 32-bits of a 64-bit number 45 | */ 46 | function Int_64(msint_32, lsint_32) 47 | { 48 | this.highOrder = msint_32; 49 | this.lowOrder = lsint_32; 50 | } 51 | 52 | /** 53 | * Convert a string to an array of big-endian words 54 | * 55 | * There is a known bug with an odd number of existing bytes and using a 56 | * UTF-16 encoding. However, this function is used such that the existing 57 | * bytes are always a result of a previous UTF-16 str2packed call and 58 | * therefore there should never be an odd number of existing bytes 59 | * 60 | * @private 61 | * @param {string} str String to be converted to binary representation 62 | * @param {string} utfType The Unicode type, UTF8 or UTF16BE, UTF16LE, to 63 | * use to encode the source string 64 | * @param {Array} existingPacked A packed int array of bytes to 65 | * append the results to 66 | * @param {number} existingPackedLen The number of bits in the existingPacked 67 | * array 68 | * @param {number} bigEndianMod Modifier for whether hash function is 69 | * big or small endian 70 | * @return {{value : Array, binLen : number}} Hash list where 71 | * "value" contains the output number array and "binLen" is the binary 72 | * length of "value" 73 | */ 74 | function str2packed(str, utfType, existingPacked, existingPackedLen, bigEndianMod) 75 | { 76 | var packed, codePnt, codePntArr, byteCnt = 0, i, j, existingByteLen, 77 | intOffset, byteOffset, shiftModifier, transposeBytes; 78 | 79 | packed = existingPacked || [0]; 80 | existingPackedLen = existingPackedLen || 0; 81 | existingByteLen = existingPackedLen >>> 3; 82 | 83 | if ("UTF8" === utfType) 84 | { 85 | shiftModifier = (bigEndianMod === -1) ? 3 : 0; 86 | for (i = 0; i < str.length; i += 1) 87 | { 88 | codePnt = str.charCodeAt(i); 89 | codePntArr = []; 90 | 91 | if (0x80 > codePnt) 92 | { 93 | codePntArr.push(codePnt); 94 | } 95 | else if (0x800 > codePnt) 96 | { 97 | codePntArr.push(0xC0 | (codePnt >>> 6)); 98 | codePntArr.push(0x80 | (codePnt & 0x3F)); 99 | } 100 | else if ((0xd800 > codePnt) || (0xe000 <= codePnt)) { 101 | codePntArr.push( 102 | 0xe0 | (codePnt >>> 12), 103 | 0x80 | ((codePnt >>> 6) & 0x3f), 104 | 0x80 | (codePnt & 0x3f) 105 | ); 106 | } 107 | else 108 | { 109 | i += 1; 110 | codePnt = 0x10000 + (((codePnt & 0x3ff) << 10) | (str.charCodeAt(i) & 0x3ff)); 111 | codePntArr.push( 112 | 0xf0 | (codePnt >>> 18), 113 | 0x80 | ((codePnt >>> 12) & 0x3f), 114 | 0x80 | ((codePnt >>> 6) & 0x3f), 115 | 0x80 | (codePnt & 0x3f) 116 | ); 117 | } 118 | 119 | for (j = 0; j < codePntArr.length; j += 1) 120 | { 121 | byteOffset = byteCnt + existingByteLen; 122 | intOffset = byteOffset >>> 2; 123 | while (packed.length <= intOffset) 124 | { 125 | packed.push(0); 126 | } 127 | /* Known bug kicks in here */ 128 | packed[intOffset] |= codePntArr[j] << (8 * (shiftModifier + bigEndianMod * (byteOffset % 4))); 129 | byteCnt += 1; 130 | } 131 | } 132 | } 133 | else if (("UTF16BE" === utfType) || "UTF16LE" === utfType) 134 | { 135 | shiftModifier = (bigEndianMod === -1) ? 2 : 0; 136 | /* Internally strings are UTF-16BE so transpose bytes under two conditions: 137 | * need LE and not switching endianness due to SHA-3 138 | * need BE and switching endianness due to SHA-3 */ 139 | transposeBytes = (("UTF16LE" === utfType) && (bigEndianMod !== 1)) || (("UTF16LE" !== utfType) && (bigEndianMod === 1)); 140 | for (i = 0; i < str.length; i += 1) 141 | { 142 | codePnt = str.charCodeAt(i); 143 | if (transposeBytes === true) 144 | { 145 | j = codePnt & 0xFF; 146 | codePnt = (j << 8) | (codePnt >>> 8); 147 | } 148 | 149 | byteOffset = byteCnt + existingByteLen; 150 | intOffset = byteOffset >>> 2; 151 | while (packed.length <= intOffset) 152 | { 153 | packed.push(0); 154 | } 155 | packed[intOffset] |= codePnt << (8 * (shiftModifier + bigEndianMod * (byteOffset % 4))); 156 | byteCnt += 2; 157 | } 158 | } 159 | return {"value" : packed, "binLen" : byteCnt * 8 + existingPackedLen}; 160 | } 161 | 162 | /** 163 | * Convert a hex string to an array of big-endian words 164 | * 165 | * @private 166 | * @param {string} str String to be converted to binary representation 167 | * @param {Array} existingPacked A packed int array of bytes to 168 | * append the results to 169 | * @param {number} existingPackedLen The number of bits in the existingPacked 170 | * array 171 | * @param {number} bigEndianMod Modifier for whether hash function is 172 | * big or small endian 173 | * @return {{value : Array, binLen : number}} Hash list where 174 | * "value" contains the output number array and "binLen" is the binary 175 | * length of "value" 176 | */ 177 | function hex2packed(str, existingPacked, existingPackedLen, bigEndianMod) 178 | { 179 | var packed, length = str.length, i, num, intOffset, byteOffset, 180 | existingByteLen, shiftModifier; 181 | 182 | if (0 !== (length % 2)) 183 | { 184 | throw new Error("String of HEX type must be in byte increments"); 185 | } 186 | 187 | packed = existingPacked || [0]; 188 | existingPackedLen = existingPackedLen || 0; 189 | existingByteLen = existingPackedLen >>> 3; 190 | shiftModifier = (bigEndianMod === -1) ? 3 : 0; 191 | 192 | for (i = 0; i < length; i += 2) 193 | { 194 | num = parseInt(str.substr(i, 2), 16); 195 | if (!isNaN(num)) 196 | { 197 | byteOffset = (i >>> 1) + existingByteLen; 198 | intOffset = byteOffset >>> 2; 199 | while (packed.length <= intOffset) 200 | { 201 | packed.push(0); 202 | } 203 | packed[intOffset] |= num << (8 * (shiftModifier + bigEndianMod * (byteOffset % 4))); 204 | } 205 | else 206 | { 207 | throw new Error("String of HEX type contains invalid characters"); 208 | } 209 | } 210 | 211 | return {"value" : packed, "binLen" : length * 4 + existingPackedLen}; 212 | } 213 | 214 | /** 215 | * Convert a string of raw bytes to an array of big-endian words 216 | * 217 | * @private 218 | * @param {string} str String of raw bytes to be converted to binary representation 219 | * @param {Array} existingPacked A packed int array of bytes to 220 | * append the results to 221 | * @param {number} existingPackedLen The number of bits in the existingPacked 222 | * array 223 | * @param {number} bigEndianMod Modifier for whether hash function is 224 | * big or small endian 225 | * @return {{value : Array, binLen : number}} Hash list where 226 | * "value" contains the output number array and "binLen" is the binary 227 | * length of "value" 228 | */ 229 | function bytes2packed(str, existingPacked, existingPackedLen, bigEndianMod) 230 | { 231 | var packed, codePnt, i, existingByteLen, intOffset, 232 | byteOffset, shiftModifier; 233 | 234 | packed = existingPacked || [0]; 235 | existingPackedLen = existingPackedLen || 0; 236 | existingByteLen = existingPackedLen >>> 3; 237 | shiftModifier = (bigEndianMod === -1) ? 3 : 0; 238 | 239 | for (i = 0; i < str.length; i += 1) 240 | { 241 | codePnt = str.charCodeAt(i); 242 | 243 | byteOffset = i + existingByteLen; 244 | intOffset = byteOffset >>> 2; 245 | if (packed.length <= intOffset) 246 | { 247 | packed.push(0); 248 | } 249 | packed[intOffset] |= codePnt << (8 * (shiftModifier + bigEndianMod * (byteOffset % 4))); 250 | } 251 | 252 | return {"value" : packed, "binLen" : str.length * 8 + existingPackedLen}; 253 | } 254 | 255 | /** 256 | * Convert a base-64 string to an array of big-endian words 257 | * 258 | * @private 259 | * @param {string} str String to be converted to binary representation 260 | * @param {Array} existingPacked A packed int array of bytes to 261 | * append the results to 262 | * @param {number} existingPackedLen The number of bits in the existingPacked 263 | * array 264 | * @param {number} bigEndianMod Modifier for whether hash function is 265 | * big or small endian 266 | * @return {{value : Array, binLen : number}} Hash list where 267 | * "value" contains the output number array and "binLen" is the binary 268 | * length of "value" 269 | */ 270 | function b642packed(str, existingPacked, existingPackedLen, bigEndianMod) 271 | { 272 | var packed, byteCnt = 0, index, i, j, tmpInt, strPart, firstEqual, 273 | b64Tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", 274 | existingByteLen, intOffset, byteOffset, shiftModifier; 275 | 276 | if (-1 === str.search(/^[a-zA-Z0-9=+\/]+$/)) 277 | { 278 | throw new Error("Invalid character in base-64 string"); 279 | } 280 | 281 | firstEqual = str.indexOf("="); 282 | str = str.replace(/\=/g, ""); 283 | if ((-1 !== firstEqual) && (firstEqual < str.length)) 284 | { 285 | throw new Error("Invalid '=' found in base-64 string"); 286 | } 287 | 288 | packed = existingPacked || [0]; 289 | existingPackedLen = existingPackedLen || 0; 290 | existingByteLen = existingPackedLen >>> 3; 291 | shiftModifier = (bigEndianMod === -1) ? 3 : 0; 292 | 293 | for (i = 0; i < str.length; i += 4) 294 | { 295 | strPart = str.substr(i, 4); 296 | tmpInt = 0; 297 | 298 | for (j = 0; j < strPart.length; j += 1) 299 | { 300 | index = b64Tab.indexOf(strPart[j]); 301 | tmpInt |= index << (18 - (6 * j)); 302 | } 303 | 304 | for (j = 0; j < strPart.length - 1; j += 1) 305 | { 306 | byteOffset = byteCnt + existingByteLen; 307 | intOffset = byteOffset >>> 2; 308 | while (packed.length <= intOffset) 309 | { 310 | packed.push(0); 311 | } 312 | packed[intOffset] |= ((tmpInt >>> (16 - (j * 8))) & 0xFF) << 313 | (8 * (shiftModifier + bigEndianMod * (byteOffset % 4))); 314 | byteCnt += 1; 315 | } 316 | } 317 | 318 | return {"value" : packed, "binLen" : byteCnt * 8 + existingPackedLen}; 319 | } 320 | 321 | /** 322 | * Convert an ArrayBuffer to an array of big-endian words 323 | * 324 | * @private 325 | * @param {ArrayBuffer} arr ArrayBuffer to be converted to binary 326 | * representation 327 | * @param {Array} existingPacked A packed int array of bytes to 328 | * append the results to 329 | * @param {number} existingPackedLen The number of bits in the existingPacked 330 | * array 331 | * @param {number} bigEndianMod Modifier for whether hash function is 332 | * big or small endian 333 | * @return {{value : Array, binLen : number}} Hash list where 334 | * "value" contains the output number array and "binLen" is the binary 335 | * length of "value" 336 | */ 337 | function arraybuffer2packed(arr, existingPacked, existingPackedLen, bigEndianMod) 338 | { 339 | var packed, i, existingByteLen, intOffset, byteOffset, shiftModifier, arrView; 340 | 341 | packed = existingPacked || [0]; 342 | existingPackedLen = existingPackedLen || 0; 343 | existingByteLen = existingPackedLen >>> 3; 344 | shiftModifier = (bigEndianMod === -1) ? 3 : 0; 345 | arrView = new Uint8Array(arr); 346 | 347 | for (i = 0; i < arr.byteLength; i += 1) 348 | { 349 | byteOffset = i + existingByteLen; 350 | intOffset = byteOffset >>> 2; 351 | if (packed.length <= intOffset) 352 | { 353 | packed.push(0); 354 | } 355 | packed[intOffset] |= arrView[i] << (8 * (shiftModifier + bigEndianMod * (byteOffset % 4))); 356 | } 357 | 358 | return {"value" : packed, "binLen" : arr.byteLength * 8 + existingPackedLen}; 359 | } 360 | 361 | /** 362 | * Convert an array of big-endian words to a hex string. 363 | * 364 | * @private 365 | * @param {Array} packed Array of integers to be converted to 366 | * hexidecimal representation 367 | * @param {number} outputLength Length of output in bits 368 | * @param {number} bigEndianMod Modifier for whether hash function is 369 | * big or small endian 370 | * @param {{outputUpper : boolean, b64Pad : string}} formatOpts Hash list 371 | * containing validated output formatting options 372 | * @return {string} Hexidecimal representation of the parameter in string 373 | * form 374 | */ 375 | function packed2hex(packed, outputLength, bigEndianMod, formatOpts) 376 | { 377 | var hex_tab = "0123456789abcdef", str = "", 378 | length = outputLength / 8, i, srcByte, shiftModifier; 379 | 380 | shiftModifier = (bigEndianMod === -1) ? 3 : 0; 381 | 382 | for (i = 0; i < length; i += 1) 383 | { 384 | /* The below is more than a byte but it gets taken care of later */ 385 | srcByte = packed[i >>> 2] >>> (8 * (shiftModifier + bigEndianMod * (i % 4))); 386 | str += hex_tab.charAt((srcByte >>> 4) & 0xF) + 387 | hex_tab.charAt(srcByte & 0xF); 388 | } 389 | 390 | return (formatOpts["outputUpper"]) ? str.toUpperCase() : str; 391 | } 392 | 393 | /** 394 | * Convert an array of big-endian words to a base-64 string 395 | * 396 | * @private 397 | * @param {Array} packed Array of integers to be converted to 398 | * base-64 representation 399 | * @param {number} outputLength Length of output in bits 400 | * @param {number} bigEndianMod Modifier for whether hash function is 401 | * big or small endian 402 | * @param {{outputUpper : boolean, b64Pad : string}} formatOpts Hash list 403 | * containing validated output formatting options 404 | * @return {string} Base-64 encoded representation of the parameter in 405 | * string form 406 | */ 407 | function packed2b64(packed, outputLength, bigEndianMod, formatOpts) 408 | { 409 | var str = "", length = outputLength / 8, i, j, triplet, int1, int2, shiftModifier, 410 | b64Tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 411 | 412 | shiftModifier = (bigEndianMod === -1) ? 3 : 0; 413 | 414 | for (i = 0; i < length; i += 3) 415 | { 416 | int1 = ((i + 1) < length) ? packed[(i + 1) >>> 2] : 0; 417 | int2 = ((i + 2) < length) ? packed[(i + 2) >>> 2] : 0; 418 | triplet = (((packed[i >>> 2] >>> (8 * (shiftModifier + bigEndianMod * (i % 4)))) & 0xFF) << 16) | 419 | (((int1 >>> (8 * (shiftModifier + bigEndianMod * ((i + 1) % 4)))) & 0xFF) << 8) | 420 | ((int2 >>> (8 * (shiftModifier + bigEndianMod * ((i + 2) % 4)))) & 0xFF); 421 | for (j = 0; j < 4; j += 1) 422 | { 423 | if (i * 8 + j * 6 <= outputLength) 424 | { 425 | str += b64Tab.charAt((triplet >>> 6 * (3 - j)) & 0x3F); 426 | } 427 | else 428 | { 429 | str += formatOpts["b64Pad"]; 430 | } 431 | } 432 | } 433 | return str; 434 | } 435 | 436 | /** 437 | * Convert an array of big-endian words to raw bytes string 438 | * 439 | * @private 440 | * @param {Array} packed Array of integers to be converted to 441 | * a raw bytes string representation 442 | * @param {number} outputLength Length of output in bits 443 | * @param {number} bigEndianMod Modifier for whether hash function is 444 | * big or small endian 445 | * @return {string} Raw bytes representation of the parameter in string 446 | * form 447 | */ 448 | function packed2bytes(packed, outputLength, bigEndianMod) 449 | { 450 | var str = "", length = outputLength / 8, i, srcByte, shiftModifier; 451 | 452 | shiftModifier = (bigEndianMod === -1) ? 3 : 0; 453 | 454 | for (i = 0; i < length; i += 1) 455 | { 456 | srcByte = (packed[i >>> 2] >>> (8 * (shiftModifier + bigEndianMod * (i % 4)))) & 0xFF; 457 | str += String.fromCharCode(srcByte); 458 | } 459 | 460 | return str; 461 | } 462 | 463 | /** 464 | * Convert an array of big-endian words to an ArrayBuffer 465 | * 466 | * @private 467 | * @param {Array} packed Array of integers to be converted to 468 | * an ArrayBuffer 469 | * @param {number} outputLength Length of output in bits 470 | * @param {number} bigEndianMod Modifier for whether hash function is 471 | * big or small endian 472 | * @return {ArrayBuffer} Raw bytes representation of the parameter in an 473 | * ArrayBuffer 474 | */ 475 | function packed2arraybuffer(packed, outputLength, bigEndianMod) 476 | { 477 | var length = outputLength / 8, i, retVal = new ArrayBuffer(length), shiftModifier, arrView; 478 | arrView = new Uint8Array(retVal); 479 | 480 | shiftModifier = (bigEndianMod === -1) ? 3 : 0; 481 | 482 | for (i = 0; i < length; i += 1) 483 | { 484 | arrView[i] = (packed[i >>> 2] >>> (8 * (shiftModifier + bigEndianMod * (i % 4)))) & 0xFF; 485 | } 486 | 487 | return retVal; 488 | } 489 | 490 | /** 491 | * Validate hash list containing output formatting options, ensuring 492 | * presence of every option or adding the default value 493 | * 494 | * @private 495 | * @param {{outputUpper : (boolean|undefined), b64Pad : (string|undefined), 496 | * shakeLen : (number|undefined)}=} options Hash list of output formatting options 497 | * @return {{outputUpper : boolean, b64Pad : string, shakeLen : number}} Validated 498 | * hash list containing output formatting options 499 | */ 500 | function getOutputOpts(options) 501 | { 502 | var retVal = {"outputUpper" : false, "b64Pad" : "=", "shakeLen" : -1}, 503 | outputOptions; 504 | outputOptions = options || {}; 505 | 506 | retVal["outputUpper"] = outputOptions["outputUpper"] || false; 507 | 508 | if (true === outputOptions.hasOwnProperty("b64Pad")) 509 | { 510 | retVal["b64Pad"] = outputOptions["b64Pad"]; 511 | } 512 | 513 | if ((true === outputOptions.hasOwnProperty("shakeLen")) && ((8 & SUPPORTED_ALGS) !== 0)) 514 | { 515 | if (outputOptions["shakeLen"] % 8 !== 0) 516 | { 517 | throw new Error("shakeLen must be a multiple of 8"); 518 | } 519 | retVal["shakeLen"] = outputOptions["shakeLen"]; 520 | } 521 | 522 | if ("boolean" !== typeof(retVal["outputUpper"])) 523 | { 524 | throw new Error("Invalid outputUpper formatting option"); 525 | } 526 | 527 | if ("string" !== typeof(retVal["b64Pad"])) 528 | { 529 | throw new Error("Invalid b64Pad formatting option"); 530 | } 531 | 532 | return retVal; 533 | } 534 | 535 | /** 536 | * Function that takes an input format and UTF encoding and returns the 537 | * appropriate function used to convert the input. 538 | * 539 | * @private 540 | * @param {string} format The format of the string to be converted 541 | * @param {string} utfType The string encoding to use (UTF8, UTF16BE, 542 | * UTF16LE) 543 | * @param {number} bigEndianMod Modifier for whether hash function is 544 | * big or small endian 545 | * @return {function((string|ArrayBuffer), Array=, number=): {value : 546 | * Array, binLen : number}} Function that will convert an input 547 | * string to a packed int array 548 | */ 549 | function getStrConverter(format, utfType, bigEndianMod) 550 | { 551 | var retVal; 552 | 553 | /* Validate encoding */ 554 | switch (utfType) 555 | { 556 | case "UTF8": 557 | /* Fallthrough */ 558 | case "UTF16BE": 559 | /* Fallthrough */ 560 | case "UTF16LE": 561 | /* Fallthrough */ 562 | break; 563 | default: 564 | throw new Error("encoding must be UTF8, UTF16BE, or UTF16LE"); 565 | } 566 | 567 | /* Map inputFormat to the appropriate converter */ 568 | switch (format) 569 | { 570 | case "HEX": 571 | /** 572 | * @param {string} str String of raw bytes to be converted to binary representation 573 | * @param {Array} existingBin A packed int array of bytes to 574 | * append the results to 575 | * @param {number} existingBinLen The number of bits in the existingBin 576 | * array 577 | * @return {{value : Array, binLen : number}} Hash list where 578 | * "value" contains the output number array and "binLen" is the binary 579 | * length of "value" 580 | */ 581 | retVal = function(str, existingBin, existingBinLen) 582 | { 583 | return hex2packed(str, existingBin, existingBinLen, bigEndianMod); 584 | }; 585 | break; 586 | case "TEXT": 587 | /** 588 | * @param {string} str String of raw bytes to be converted to binary representation 589 | * @param {Array} existingBin A packed int array of bytes to 590 | * append the results to 591 | * @param {number} existingBinLen The number of bits in the existingBin 592 | * array 593 | * @return {{value : Array, binLen : number}} Hash list where 594 | * "value" contains the output number array and "binLen" is the binary 595 | * length of "value" 596 | */ 597 | retVal = function(str, existingBin, existingBinLen) 598 | { 599 | return str2packed(str, utfType, existingBin, existingBinLen, bigEndianMod); 600 | }; 601 | break; 602 | case "B64": 603 | /** 604 | * @param {string} str String of raw bytes to be converted to binary representation 605 | * @param {Array} existingBin A packed int array of bytes to 606 | * append the results to 607 | * @param {number} existingBinLen The number of bits in the existingBin 608 | * array 609 | * @return {{value : Array, binLen : number}} Hash list where 610 | * "value" contains the output number array and "binLen" is the binary 611 | * length of "value" 612 | */ 613 | retVal = function(str, existingBin, existingBinLen) 614 | { 615 | return b642packed(str, existingBin, existingBinLen, bigEndianMod); 616 | }; 617 | break; 618 | case "BYTES": 619 | /** 620 | * @param {string} str String of raw bytes to be converted to binary representation 621 | * @param {Array} existingBin A packed int array of bytes to 622 | * append the results to 623 | * @param {number} existingBinLen The number of bits in the existingBin 624 | * array 625 | * @return {{value : Array, binLen : number}} Hash list where 626 | * "value" contains the output number array and "binLen" is the binary 627 | * length of "value" 628 | */ 629 | retVal = function(str, existingBin, existingBinLen) 630 | { 631 | return bytes2packed(str, existingBin, existingBinLen, bigEndianMod); 632 | }; 633 | break; 634 | case "ARRAYBUFFER": 635 | try { 636 | retVal = new ArrayBuffer(0); 637 | } catch(ignore) { 638 | throw new Error("ARRAYBUFFER not supported by this environment"); 639 | } 640 | /** 641 | * @param {ArrayBuffer} arr ArrayBuffer to be converted to binary 642 | * representation 643 | * @param {Array} existingBin A packed int array of bytes to 644 | * append the results to 645 | * @param {number} existingBinLen The number of bits in the existingBin 646 | * array 647 | * @return {{value : Array, binLen : number}} Hash list where 648 | * "value" contains the output number array and "binLen" is the binary 649 | * length of "value" 650 | */ 651 | retVal = function(arr, existingBin, existingBinLen) 652 | { 653 | return arraybuffer2packed(arr, existingBin, existingBinLen, bigEndianMod); 654 | }; 655 | break; 656 | default: 657 | throw new Error("format must be HEX, TEXT, B64, BYTES, or ARRAYBUFFER"); 658 | } 659 | 660 | return retVal; 661 | } 662 | 663 | /** 664 | * The 32-bit implementation of circular rotate left 665 | * 666 | * @private 667 | * @param {number} x The 32-bit integer argument 668 | * @param {number} n The number of bits to shift 669 | * @return {number} The x shifted circularly by n bits 670 | */ 671 | function rotl_32(x, n) 672 | { 673 | return (x << n) | (x >>> (32 - n)); 674 | } 675 | 676 | /** 677 | * The 64-bit implementation of circular rotate left 678 | * 679 | * @private 680 | * @param {Int_64} x The 64-bit integer argument 681 | * @param {number} n The number of bits to shift 682 | * @return {Int_64} The x shifted circularly by n bits 683 | */ 684 | function rotl_64(x, n) 685 | { 686 | if (n > 32) 687 | { 688 | n = n - 32; 689 | return new Int_64( 690 | x.lowOrder << n | x.highOrder >>> (32 - n), 691 | x.highOrder << n | x.lowOrder >>> (32 - n) 692 | ); 693 | } 694 | else if (0 !== n) 695 | { 696 | return new Int_64( 697 | x.highOrder << n | x.lowOrder >>> (32 - n), 698 | x.lowOrder << n | x.highOrder >>> (32 - n) 699 | ); 700 | } 701 | else 702 | { 703 | return x; 704 | } 705 | } 706 | 707 | /** 708 | * The 32-bit implementation of circular rotate right 709 | * 710 | * @private 711 | * @param {number} x The 32-bit integer argument 712 | * @param {number} n The number of bits to shift 713 | * @return {number} The x shifted circularly by n bits 714 | */ 715 | function rotr_32(x, n) 716 | { 717 | return (x >>> n) | (x << (32 - n)); 718 | } 719 | 720 | /** 721 | * The 64-bit implementation of circular rotate right 722 | * 723 | * @private 724 | * @param {Int_64} x The 64-bit integer argument 725 | * @param {number} n The number of bits to shift 726 | * @return {Int_64} The x shifted circularly by n bits 727 | */ 728 | function rotr_64(x, n) 729 | { 730 | var retVal = null, tmp = new Int_64(x.highOrder, x.lowOrder); 731 | 732 | if (32 >= n) 733 | { 734 | retVal = new Int_64( 735 | (tmp.highOrder >>> n) | ((tmp.lowOrder << (32 - n)) & 0xFFFFFFFF), 736 | (tmp.lowOrder >>> n) | ((tmp.highOrder << (32 - n)) & 0xFFFFFFFF) 737 | ); 738 | } 739 | else 740 | { 741 | retVal = new Int_64( 742 | (tmp.lowOrder >>> (n - 32)) | ((tmp.highOrder << (64 - n)) & 0xFFFFFFFF), 743 | (tmp.highOrder >>> (n - 32)) | ((tmp.lowOrder << (64 - n)) & 0xFFFFFFFF) 744 | ); 745 | } 746 | 747 | return retVal; 748 | } 749 | 750 | /** 751 | * The 32-bit implementation of shift right 752 | * 753 | * @private 754 | * @param {number} x The 32-bit integer argument 755 | * @param {number} n The number of bits to shift 756 | * @return {number} The x shifted by n bits 757 | */ 758 | function shr_32(x, n) 759 | { 760 | return x >>> n; 761 | } 762 | 763 | /** 764 | * The 64-bit implementation of shift right 765 | * 766 | * @private 767 | * @param {Int_64} x The 64-bit integer argument 768 | * @param {number} n The number of bits to shift 769 | * @return {Int_64} The x shifted by n bits 770 | */ 771 | function shr_64(x, n) 772 | { 773 | var retVal = null; 774 | 775 | if (32 >= n) 776 | { 777 | retVal = new Int_64( 778 | x.highOrder >>> n, 779 | x.lowOrder >>> n | ((x.highOrder << (32 - n)) & 0xFFFFFFFF) 780 | ); 781 | } 782 | else 783 | { 784 | retVal = new Int_64( 785 | 0, 786 | x.highOrder >>> (n - 32) 787 | ); 788 | } 789 | 790 | return retVal; 791 | } 792 | 793 | /** 794 | * The 32-bit implementation of the NIST specified Parity function 795 | * 796 | * @private 797 | * @param {number} x The first 32-bit integer argument 798 | * @param {number} y The second 32-bit integer argument 799 | * @param {number} z The third 32-bit integer argument 800 | * @return {number} The NIST specified output of the function 801 | */ 802 | function parity_32(x, y, z) 803 | { 804 | return x ^ y ^ z; 805 | } 806 | 807 | /** 808 | * The 32-bit implementation of the NIST specified Ch function 809 | * 810 | * @private 811 | * @param {number} x The first 32-bit integer argument 812 | * @param {number} y The second 32-bit integer argument 813 | * @param {number} z The third 32-bit integer argument 814 | * @return {number} The NIST specified output of the function 815 | */ 816 | function ch_32(x, y, z) 817 | { 818 | return (x & y) ^ (~x & z); 819 | } 820 | 821 | /** 822 | * The 64-bit implementation of the NIST specified Ch function 823 | * 824 | * @private 825 | * @param {Int_64} x The first 64-bit integer argument 826 | * @param {Int_64} y The second 64-bit integer argument 827 | * @param {Int_64} z The third 64-bit integer argument 828 | * @return {Int_64} The NIST specified output of the function 829 | */ 830 | function ch_64(x, y, z) 831 | { 832 | return new Int_64( 833 | (x.highOrder & y.highOrder) ^ (~x.highOrder & z.highOrder), 834 | (x.lowOrder & y.lowOrder) ^ (~x.lowOrder & z.lowOrder) 835 | ); 836 | } 837 | 838 | /** 839 | * The 32-bit implementation of the NIST specified Maj function 840 | * 841 | * @private 842 | * @param {number} x The first 32-bit integer argument 843 | * @param {number} y The second 32-bit integer argument 844 | * @param {number} z The third 32-bit integer argument 845 | * @return {number} The NIST specified output of the function 846 | */ 847 | function maj_32(x, y, z) 848 | { 849 | return (x & y) ^ (x & z) ^ (y & z); 850 | } 851 | 852 | /** 853 | * The 64-bit implementation of the NIST specified Maj function 854 | * 855 | * @private 856 | * @param {Int_64} x The first 64-bit integer argument 857 | * @param {Int_64} y The second 64-bit integer argument 858 | * @param {Int_64} z The third 64-bit integer argument 859 | * @return {Int_64} The NIST specified output of the function 860 | */ 861 | function maj_64(x, y, z) 862 | { 863 | return new Int_64( 864 | (x.highOrder & y.highOrder) ^ 865 | (x.highOrder & z.highOrder) ^ 866 | (y.highOrder & z.highOrder), 867 | (x.lowOrder & y.lowOrder) ^ 868 | (x.lowOrder & z.lowOrder) ^ 869 | (y.lowOrder & z.lowOrder) 870 | ); 871 | } 872 | 873 | /** 874 | * The 32-bit implementation of the NIST specified Sigma0 function 875 | * 876 | * @private 877 | * @param {number} x The 32-bit integer argument 878 | * @return {number} The NIST specified output of the function 879 | */ 880 | function sigma0_32(x) 881 | { 882 | return rotr_32(x, 2) ^ rotr_32(x, 13) ^ rotr_32(x, 22); 883 | } 884 | 885 | /** 886 | * The 64-bit implementation of the NIST specified Sigma0 function 887 | * 888 | * @private 889 | * @param {Int_64} x The 64-bit integer argument 890 | * @return {Int_64} The NIST specified output of the function 891 | */ 892 | function sigma0_64(x) 893 | { 894 | var rotr28 = rotr_64(x, 28), rotr34 = rotr_64(x, 34), 895 | rotr39 = rotr_64(x, 39); 896 | 897 | return new Int_64( 898 | rotr28.highOrder ^ rotr34.highOrder ^ rotr39.highOrder, 899 | rotr28.lowOrder ^ rotr34.lowOrder ^ rotr39.lowOrder); 900 | } 901 | 902 | /** 903 | * The 32-bit implementation of the NIST specified Sigma1 function 904 | * 905 | * @private 906 | * @param {number} x The 32-bit integer argument 907 | * @return {number} The NIST specified output of the function 908 | */ 909 | function sigma1_32(x) 910 | { 911 | return rotr_32(x, 6) ^ rotr_32(x, 11) ^ rotr_32(x, 25); 912 | } 913 | 914 | /** 915 | * The 64-bit implementation of the NIST specified Sigma1 function 916 | * 917 | * @private 918 | * @param {Int_64} x The 64-bit integer argument 919 | * @return {Int_64} The NIST specified output of the function 920 | */ 921 | function sigma1_64(x) 922 | { 923 | var rotr14 = rotr_64(x, 14), rotr18 = rotr_64(x, 18), 924 | rotr41 = rotr_64(x, 41); 925 | 926 | return new Int_64( 927 | rotr14.highOrder ^ rotr18.highOrder ^ rotr41.highOrder, 928 | rotr14.lowOrder ^ rotr18.lowOrder ^ rotr41.lowOrder); 929 | } 930 | 931 | /** 932 | * The 32-bit implementation of the NIST specified Gamma0 function 933 | * 934 | * @private 935 | * @param {number} x The 32-bit integer argument 936 | * @return {number} The NIST specified output of the function 937 | */ 938 | function gamma0_32(x) 939 | { 940 | return rotr_32(x, 7) ^ rotr_32(x, 18) ^ shr_32(x, 3); 941 | } 942 | 943 | /** 944 | * The 64-bit implementation of the NIST specified Gamma0 function 945 | * 946 | * @private 947 | * @param {Int_64} x The 64-bit integer argument 948 | * @return {Int_64} The NIST specified output of the function 949 | */ 950 | function gamma0_64(x) 951 | { 952 | var rotr1 = rotr_64(x, 1), rotr8 = rotr_64(x, 8), shr7 = shr_64(x, 7); 953 | 954 | return new Int_64( 955 | rotr1.highOrder ^ rotr8.highOrder ^ shr7.highOrder, 956 | rotr1.lowOrder ^ rotr8.lowOrder ^ shr7.lowOrder 957 | ); 958 | } 959 | 960 | /** 961 | * The 32-bit implementation of the NIST specified Gamma1 function 962 | * 963 | * @private 964 | * @param {number} x The 32-bit integer argument 965 | * @return {number} The NIST specified output of the function 966 | */ 967 | function gamma1_32(x) 968 | { 969 | return rotr_32(x, 17) ^ rotr_32(x, 19) ^ shr_32(x, 10); 970 | } 971 | 972 | /** 973 | * The 64-bit implementation of the NIST specified Gamma1 function 974 | * 975 | * @private 976 | * @param {Int_64} x The 64-bit integer argument 977 | * @return {Int_64} The NIST specified output of the function 978 | */ 979 | function gamma1_64(x) 980 | { 981 | var rotr19 = rotr_64(x, 19), rotr61 = rotr_64(x, 61), 982 | shr6 = shr_64(x, 6); 983 | 984 | return new Int_64( 985 | rotr19.highOrder ^ rotr61.highOrder ^ shr6.highOrder, 986 | rotr19.lowOrder ^ rotr61.lowOrder ^ shr6.lowOrder 987 | ); 988 | } 989 | 990 | /** 991 | * Add two 32-bit integers, wrapping at 2^32. This uses 16-bit operations 992 | * internally to work around bugs in some JS interpreters. 993 | * 994 | * @private 995 | * @param {number} a The first 32-bit integer argument to be added 996 | * @param {number} b The second 32-bit integer argument to be added 997 | * @return {number} The sum of a + b 998 | */ 999 | function safeAdd_32_2(a, b) 1000 | { 1001 | var lsw = (a & 0xFFFF) + (b & 0xFFFF), 1002 | msw = (a >>> 16) + (b >>> 16) + (lsw >>> 16); 1003 | 1004 | return ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF); 1005 | } 1006 | 1007 | /** 1008 | * Add four 32-bit integers, wrapping at 2^32. This uses 16-bit operations 1009 | * internally to work around bugs in some JS interpreters. 1010 | * 1011 | * @private 1012 | * @param {number} a The first 32-bit integer argument to be added 1013 | * @param {number} b The second 32-bit integer argument to be added 1014 | * @param {number} c The third 32-bit integer argument to be added 1015 | * @param {number} d The fourth 32-bit integer argument to be added 1016 | * @return {number} The sum of a + b + c + d 1017 | */ 1018 | function safeAdd_32_4(a, b, c, d) 1019 | { 1020 | var lsw = (a & 0xFFFF) + (b & 0xFFFF) + (c & 0xFFFF) + (d & 0xFFFF), 1021 | msw = (a >>> 16) + (b >>> 16) + (c >>> 16) + (d >>> 16) + 1022 | (lsw >>> 16); 1023 | 1024 | return ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF); 1025 | } 1026 | 1027 | /** 1028 | * Add five 32-bit integers, wrapping at 2^32. This uses 16-bit operations 1029 | * internally to work around bugs in some JS interpreters. 1030 | * 1031 | * @private 1032 | * @param {number} a The first 32-bit integer argument to be added 1033 | * @param {number} b The second 32-bit integer argument to be added 1034 | * @param {number} c The third 32-bit integer argument to be added 1035 | * @param {number} d The fourth 32-bit integer argument to be added 1036 | * @param {number} e The fifth 32-bit integer argument to be added 1037 | * @return {number} The sum of a + b + c + d + e 1038 | */ 1039 | function safeAdd_32_5(a, b, c, d, e) 1040 | { 1041 | var lsw = (a & 0xFFFF) + (b & 0xFFFF) + (c & 0xFFFF) + (d & 0xFFFF) + 1042 | (e & 0xFFFF), 1043 | msw = (a >>> 16) + (b >>> 16) + (c >>> 16) + (d >>> 16) + 1044 | (e >>> 16) + (lsw >>> 16); 1045 | 1046 | return ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF); 1047 | } 1048 | 1049 | /** 1050 | * Add two 64-bit integers, wrapping at 2^64. This uses 16-bit operations 1051 | * internally to work around bugs in some JS interpreters. 1052 | * 1053 | * @private 1054 | * @param {Int_64} x The first 64-bit integer argument to be added 1055 | * @param {Int_64} y The second 64-bit integer argument to be added 1056 | * @return {Int_64} The sum of x + y 1057 | */ 1058 | function safeAdd_64_2(x, y) 1059 | { 1060 | var lsw, msw, lowOrder, highOrder; 1061 | 1062 | lsw = (x.lowOrder & 0xFFFF) + (y.lowOrder & 0xFFFF); 1063 | msw = (x.lowOrder >>> 16) + (y.lowOrder >>> 16) + (lsw >>> 16); 1064 | lowOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF); 1065 | 1066 | lsw = (x.highOrder & 0xFFFF) + (y.highOrder & 0xFFFF) + (msw >>> 16); 1067 | msw = (x.highOrder >>> 16) + (y.highOrder >>> 16) + (lsw >>> 16); 1068 | highOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF); 1069 | 1070 | return new Int_64(highOrder, lowOrder); 1071 | } 1072 | 1073 | /** 1074 | * Add four 64-bit integers, wrapping at 2^64. This uses 16-bit operations 1075 | * internally to work around bugs in some JS interpreters. 1076 | * 1077 | * @private 1078 | * @param {Int_64} a The first 64-bit integer argument to be added 1079 | * @param {Int_64} b The second 64-bit integer argument to be added 1080 | * @param {Int_64} c The third 64-bit integer argument to be added 1081 | * @param {Int_64} d The fouth 64-bit integer argument to be added 1082 | * @return {Int_64} The sum of a + b + c + d 1083 | */ 1084 | function safeAdd_64_4(a, b, c, d) 1085 | { 1086 | var lsw, msw, lowOrder, highOrder; 1087 | 1088 | lsw = (a.lowOrder & 0xFFFF) + (b.lowOrder & 0xFFFF) + 1089 | (c.lowOrder & 0xFFFF) + (d.lowOrder & 0xFFFF); 1090 | msw = (a.lowOrder >>> 16) + (b.lowOrder >>> 16) + 1091 | (c.lowOrder >>> 16) + (d.lowOrder >>> 16) + (lsw >>> 16); 1092 | lowOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF); 1093 | 1094 | lsw = (a.highOrder & 0xFFFF) + (b.highOrder & 0xFFFF) + 1095 | (c.highOrder & 0xFFFF) + (d.highOrder & 0xFFFF) + (msw >>> 16); 1096 | msw = (a.highOrder >>> 16) + (b.highOrder >>> 16) + 1097 | (c.highOrder >>> 16) + (d.highOrder >>> 16) + (lsw >>> 16); 1098 | highOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF); 1099 | 1100 | return new Int_64(highOrder, lowOrder); 1101 | } 1102 | 1103 | /** 1104 | * Add five 64-bit integers, wrapping at 2^64. This uses 16-bit operations 1105 | * internally to work around bugs in some JS interpreters. 1106 | * 1107 | * @private 1108 | * @param {Int_64} a The first 64-bit integer argument to be added 1109 | * @param {Int_64} b The second 64-bit integer argument to be added 1110 | * @param {Int_64} c The third 64-bit integer argument to be added 1111 | * @param {Int_64} d The fouth 64-bit integer argument to be added 1112 | * @param {Int_64} e The fouth 64-bit integer argument to be added 1113 | * @return {Int_64} The sum of a + b + c + d + e 1114 | */ 1115 | function safeAdd_64_5(a, b, c, d, e) 1116 | { 1117 | var lsw, msw, lowOrder, highOrder; 1118 | 1119 | lsw = (a.lowOrder & 0xFFFF) + (b.lowOrder & 0xFFFF) + 1120 | (c.lowOrder & 0xFFFF) + (d.lowOrder & 0xFFFF) + 1121 | (e.lowOrder & 0xFFFF); 1122 | msw = (a.lowOrder >>> 16) + (b.lowOrder >>> 16) + 1123 | (c.lowOrder >>> 16) + (d.lowOrder >>> 16) + (e.lowOrder >>> 16) + 1124 | (lsw >>> 16); 1125 | lowOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF); 1126 | 1127 | lsw = (a.highOrder & 0xFFFF) + (b.highOrder & 0xFFFF) + 1128 | (c.highOrder & 0xFFFF) + (d.highOrder & 0xFFFF) + 1129 | (e.highOrder & 0xFFFF) + (msw >>> 16); 1130 | msw = (a.highOrder >>> 16) + (b.highOrder >>> 16) + 1131 | (c.highOrder >>> 16) + (d.highOrder >>> 16) + 1132 | (e.highOrder >>> 16) + (lsw >>> 16); 1133 | highOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF); 1134 | 1135 | return new Int_64(highOrder, lowOrder); 1136 | } 1137 | 1138 | /** 1139 | * XORs two given arguments. 1140 | * 1141 | * @private 1142 | * @param {Int_64} a First argument to be XORed 1143 | * @param {Int_64} b Second argument to be XORed 1144 | * @return {Int_64} The XOR of the arguments 1145 | */ 1146 | function xor_64_2(a, b) 1147 | { 1148 | return new Int_64( 1149 | a.highOrder ^ b.highOrder, 1150 | a.lowOrder ^ b.lowOrder 1151 | ); 1152 | } 1153 | 1154 | /** 1155 | * XORs five given arguments. 1156 | * 1157 | * @private 1158 | * @param {Int_64} a First argument to be XORed 1159 | * @param {Int_64} b Second argument to be XORed 1160 | * @param {Int_64} c Third argument to be XORed 1161 | * @param {Int_64} d Fourth argument to be XORed 1162 | * @param {Int_64} e Fifth argument to be XORed 1163 | * @return {Int_64} The XOR of the arguments 1164 | */ 1165 | function xor_64_5(a, b, c, d, e) 1166 | { 1167 | return new Int_64( 1168 | a.highOrder ^ b.highOrder ^ c.highOrder ^ d.highOrder ^ e.highOrder, 1169 | a.lowOrder ^ b.lowOrder ^ c.lowOrder ^ d.lowOrder ^ e.lowOrder 1170 | ); 1171 | } 1172 | 1173 | /** 1174 | * Returns a clone of the given SHA3 state 1175 | * 1176 | * @private 1177 | * @param {Array>} state The state to be cloned 1178 | * @return {Array>} The cloned state 1179 | */ 1180 | function cloneSHA3State(state) { 1181 | var clone = [], i; 1182 | for (i = 0; i < 5; i += 1) 1183 | { 1184 | clone[i] = state[i].slice(); 1185 | } 1186 | 1187 | return clone; 1188 | } 1189 | 1190 | /** 1191 | * Gets the state values for the specified SHA variant 1192 | * 1193 | * @param {string} variant The SHA variant 1194 | * @return {Array>} The initial state values 1195 | */ 1196 | function getNewState(variant) 1197 | { 1198 | var retVal = [], H_trunc, H_full, i; 1199 | 1200 | if (("SHA-1" === variant) && ((1 & SUPPORTED_ALGS) !== 0)) 1201 | { 1202 | retVal = [ 1203 | 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0 1204 | ]; 1205 | } 1206 | else if ((variant.lastIndexOf("SHA-", 0) === 0) && ((6 & SUPPORTED_ALGS) !== 0)) 1207 | { 1208 | H_trunc = [ 1209 | 0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, 1210 | 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4 1211 | ]; 1212 | H_full = [ 1213 | 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 1214 | 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19 1215 | ]; 1216 | 1217 | switch (variant) 1218 | { 1219 | case "SHA-224": 1220 | retVal = H_trunc; 1221 | break; 1222 | case "SHA-256": 1223 | retVal = H_full; 1224 | break; 1225 | case "SHA-384": 1226 | retVal = [ 1227 | new Int_64(0xcbbb9d5d, H_trunc[0]), 1228 | new Int_64(0x0629a292a, H_trunc[1]), 1229 | new Int_64(0x9159015a, H_trunc[2]), 1230 | new Int_64(0x0152fecd8, H_trunc[3]), 1231 | new Int_64(0x67332667, H_trunc[4]), 1232 | new Int_64(0x98eb44a87, H_trunc[5]), 1233 | new Int_64(0xdb0c2e0d, H_trunc[6]), 1234 | new Int_64(0x047b5481d, H_trunc[7]) 1235 | ]; 1236 | break; 1237 | case "SHA-512": 1238 | retVal = [ 1239 | new Int_64(H_full[0], 0xf3bcc908), 1240 | new Int_64(H_full[1], 0x84caa73b), 1241 | new Int_64(H_full[2], 0xfe94f82b), 1242 | new Int_64(H_full[3], 0x5f1d36f1), 1243 | new Int_64(H_full[4], 0xade682d1), 1244 | new Int_64(H_full[5], 0x2b3e6c1f), 1245 | new Int_64(H_full[6], 0xfb41bd6b), 1246 | new Int_64(H_full[7], 0x137e2179) 1247 | ]; 1248 | break; 1249 | default: 1250 | throw new Error("Unknown SHA variant"); 1251 | } 1252 | } 1253 | else if (((variant.lastIndexOf("SHA3-", 0) === 0) || (variant.lastIndexOf("SHAKE", 0) === 0)) && 1254 | ((8 & SUPPORTED_ALGS) !== 0)) 1255 | { 1256 | for (i = 0; i < 5; i += 1) 1257 | { 1258 | retVal[i] = [new Int_64(0, 0), new Int_64(0, 0), new Int_64(0, 0), new Int_64(0, 0), new Int_64(0, 0)]; 1259 | } 1260 | } 1261 | else 1262 | { 1263 | throw new Error("No SHA variants supported"); 1264 | } 1265 | 1266 | return retVal; 1267 | } 1268 | 1269 | /** 1270 | * Performs a round of SHA-1 hashing over a 512-byte block 1271 | * 1272 | * @private 1273 | * @param {Array} block The binary array representation of the 1274 | * block to hash 1275 | * @param {Array} H The intermediate H values from a previous 1276 | * round 1277 | * @return {Array} The resulting H values 1278 | */ 1279 | function roundSHA1(block, H) 1280 | { 1281 | var W = [], a, b, c, d, e, T, ch = ch_32, parity = parity_32, 1282 | maj = maj_32, rotl = rotl_32, safeAdd_2 = safeAdd_32_2, t, 1283 | safeAdd_5 = safeAdd_32_5; 1284 | 1285 | a = H[0]; 1286 | b = H[1]; 1287 | c = H[2]; 1288 | d = H[3]; 1289 | e = H[4]; 1290 | 1291 | for (t = 0; t < 80; t += 1) 1292 | { 1293 | if (t < 16) 1294 | { 1295 | W[t] = block[t]; 1296 | } 1297 | else 1298 | { 1299 | W[t] = rotl(W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16], 1); 1300 | } 1301 | 1302 | if (t < 20) 1303 | { 1304 | T = safeAdd_5(rotl(a, 5), ch(b, c, d), e, 0x5a827999, W[t]); 1305 | } 1306 | else if (t < 40) 1307 | { 1308 | T = safeAdd_5(rotl(a, 5), parity(b, c, d), e, 0x6ed9eba1, W[t]); 1309 | } 1310 | else if (t < 60) 1311 | { 1312 | T = safeAdd_5(rotl(a, 5), maj(b, c, d), e, 0x8f1bbcdc, W[t]); 1313 | } else { 1314 | T = safeAdd_5(rotl(a, 5), parity(b, c, d), e, 0xca62c1d6, W[t]); 1315 | } 1316 | 1317 | e = d; 1318 | d = c; 1319 | c = rotl(b, 30); 1320 | b = a; 1321 | a = T; 1322 | } 1323 | 1324 | H[0] = safeAdd_2(a, H[0]); 1325 | H[1] = safeAdd_2(b, H[1]); 1326 | H[2] = safeAdd_2(c, H[2]); 1327 | H[3] = safeAdd_2(d, H[3]); 1328 | H[4] = safeAdd_2(e, H[4]); 1329 | 1330 | return H; 1331 | } 1332 | 1333 | /** 1334 | * Finalizes the SHA-1 hash 1335 | * 1336 | * @private 1337 | * @param {Array} remainder Any leftover unprocessed packed ints 1338 | * that still need to be processed 1339 | * @param {number} remainderBinLen The number of bits in remainder 1340 | * @param {number} processedBinLen The number of bits already 1341 | * processed 1342 | * @param {Array} H The intermediate H values from a previous 1343 | * round 1344 | * @param {number} outputLen Unused for this variant 1345 | * @return {Array} The array of integers representing the SHA-1 1346 | * hash of message 1347 | */ 1348 | function finalizeSHA1(remainder, remainderBinLen, processedBinLen, H, outputLen) 1349 | { 1350 | var i, appendedMessageLength, offset, totalLen; 1351 | 1352 | /* The 65 addition is a hack but it works. The correct number is 1353 | actually 72 (64 + 8) but the below math fails if 1354 | remainderBinLen + 72 % 512 = 0. Since remainderBinLen % 8 = 0, 1355 | "shorting" the addition is OK. */ 1356 | offset = (((remainderBinLen + 65) >>> 9) << 4) + 15; 1357 | while (remainder.length <= offset) 1358 | { 1359 | remainder.push(0); 1360 | } 1361 | /* Append '1' at the end of the binary string */ 1362 | remainder[remainderBinLen >>> 5] |= 0x80 << (24 - (remainderBinLen % 32)); 1363 | /* Append length of binary string in the position such that the new 1364 | * length is a multiple of 512. Logic does not work for even multiples 1365 | * of 512 but there can never be even multiples of 512. JavaScript 1366 | * numbers are limited to 2^53 so it's "safe" to treat the totalLen as 1367 | * a 64-bit integer. */ 1368 | totalLen = remainderBinLen + processedBinLen; 1369 | remainder[offset] = totalLen & 0xFFFFFFFF; 1370 | /* Bitwise operators treat the operand as a 32-bit number so need to 1371 | * use hacky division and round to get access to upper 32-ish bits */ 1372 | remainder[offset - 1] = (totalLen / TWO_PWR_32) | 0; 1373 | 1374 | appendedMessageLength = remainder.length; 1375 | 1376 | /* This will always be at least 1 full chunk */ 1377 | for (i = 0; i < appendedMessageLength; i += 16) 1378 | { 1379 | H = roundSHA1(remainder.slice(i, i + 16), H); 1380 | } 1381 | 1382 | return H; 1383 | } 1384 | 1385 | /* Put this here so the K arrays aren't put on the stack for every block */ 1386 | var K_sha2, K_sha512, r_sha3, rc_sha3; 1387 | if ((6 & SUPPORTED_ALGS) !== 0) 1388 | { 1389 | K_sha2 = [ 1390 | 0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5, 1391 | 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5, 1392 | 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3, 1393 | 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174, 1394 | 0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC, 1395 | 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA, 1396 | 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7, 1397 | 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967, 1398 | 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13, 1399 | 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85, 1400 | 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3, 1401 | 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070, 1402 | 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5, 1403 | 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3, 1404 | 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208, 1405 | 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2 1406 | ]; 1407 | 1408 | if ((4 & SUPPORTED_ALGS) !== 0) 1409 | { 1410 | K_sha512 = [ 1411 | new Int_64(K_sha2[ 0], 0xd728ae22), new Int_64(K_sha2[ 1], 0x23ef65cd), 1412 | new Int_64(K_sha2[ 2], 0xec4d3b2f), new Int_64(K_sha2[ 3], 0x8189dbbc), 1413 | new Int_64(K_sha2[ 4], 0xf348b538), new Int_64(K_sha2[ 5], 0xb605d019), 1414 | new Int_64(K_sha2[ 6], 0xaf194f9b), new Int_64(K_sha2[ 7], 0xda6d8118), 1415 | new Int_64(K_sha2[ 8], 0xa3030242), new Int_64(K_sha2[ 9], 0x45706fbe), 1416 | new Int_64(K_sha2[10], 0x4ee4b28c), new Int_64(K_sha2[11], 0xd5ffb4e2), 1417 | new Int_64(K_sha2[12], 0xf27b896f), new Int_64(K_sha2[13], 0x3b1696b1), 1418 | new Int_64(K_sha2[14], 0x25c71235), new Int_64(K_sha2[15], 0xcf692694), 1419 | new Int_64(K_sha2[16], 0x9ef14ad2), new Int_64(K_sha2[17], 0x384f25e3), 1420 | new Int_64(K_sha2[18], 0x8b8cd5b5), new Int_64(K_sha2[19], 0x77ac9c65), 1421 | new Int_64(K_sha2[20], 0x592b0275), new Int_64(K_sha2[21], 0x6ea6e483), 1422 | new Int_64(K_sha2[22], 0xbd41fbd4), new Int_64(K_sha2[23], 0x831153b5), 1423 | new Int_64(K_sha2[24], 0xee66dfab), new Int_64(K_sha2[25], 0x2db43210), 1424 | new Int_64(K_sha2[26], 0x98fb213f), new Int_64(K_sha2[27], 0xbeef0ee4), 1425 | new Int_64(K_sha2[28], 0x3da88fc2), new Int_64(K_sha2[29], 0x930aa725), 1426 | new Int_64(K_sha2[30], 0xe003826f), new Int_64(K_sha2[31], 0x0a0e6e70), 1427 | new Int_64(K_sha2[32], 0x46d22ffc), new Int_64(K_sha2[33], 0x5c26c926), 1428 | new Int_64(K_sha2[34], 0x5ac42aed), new Int_64(K_sha2[35], 0x9d95b3df), 1429 | new Int_64(K_sha2[36], 0x8baf63de), new Int_64(K_sha2[37], 0x3c77b2a8), 1430 | new Int_64(K_sha2[38], 0x47edaee6), new Int_64(K_sha2[39], 0x1482353b), 1431 | new Int_64(K_sha2[40], 0x4cf10364), new Int_64(K_sha2[41], 0xbc423001), 1432 | new Int_64(K_sha2[42], 0xd0f89791), new Int_64(K_sha2[43], 0x0654be30), 1433 | new Int_64(K_sha2[44], 0xd6ef5218), new Int_64(K_sha2[45], 0x5565a910), 1434 | new Int_64(K_sha2[46], 0x5771202a), new Int_64(K_sha2[47], 0x32bbd1b8), 1435 | new Int_64(K_sha2[48], 0xb8d2d0c8), new Int_64(K_sha2[49], 0x5141ab53), 1436 | new Int_64(K_sha2[50], 0xdf8eeb99), new Int_64(K_sha2[51], 0xe19b48a8), 1437 | new Int_64(K_sha2[52], 0xc5c95a63), new Int_64(K_sha2[53], 0xe3418acb), 1438 | new Int_64(K_sha2[54], 0x7763e373), new Int_64(K_sha2[55], 0xd6b2b8a3), 1439 | new Int_64(K_sha2[56], 0x5defb2fc), new Int_64(K_sha2[57], 0x43172f60), 1440 | new Int_64(K_sha2[58], 0xa1f0ab72), new Int_64(K_sha2[59], 0x1a6439ec), 1441 | new Int_64(K_sha2[60], 0x23631e28), new Int_64(K_sha2[61], 0xde82bde9), 1442 | new Int_64(K_sha2[62], 0xb2c67915), new Int_64(K_sha2[63], 0xe372532b), 1443 | new Int_64(0xca273ece, 0xea26619c), new Int_64(0xd186b8c7, 0x21c0c207), 1444 | new Int_64(0xeada7dd6, 0xcde0eb1e), new Int_64(0xf57d4f7f, 0xee6ed178), 1445 | new Int_64(0x06f067aa, 0x72176fba), new Int_64(0x0a637dc5, 0xa2c898a6), 1446 | new Int_64(0x113f9804, 0xbef90dae), new Int_64(0x1b710b35, 0x131c471b), 1447 | new Int_64(0x28db77f5, 0x23047d84), new Int_64(0x32caab7b, 0x40c72493), 1448 | new Int_64(0x3c9ebe0a, 0x15c9bebc), new Int_64(0x431d67c4, 0x9c100d4c), 1449 | new Int_64(0x4cc5d4be, 0xcb3e42b6), new Int_64(0x597f299c, 0xfc657e2a), 1450 | new Int_64(0x5fcb6fab, 0x3ad6faec), new Int_64(0x6c44198c, 0x4a475817) 1451 | ]; 1452 | } 1453 | } 1454 | if ((8 & SUPPORTED_ALGS) !== 0) 1455 | { 1456 | rc_sha3 = [ 1457 | new Int_64(0x00000000, 0x00000001), new Int_64(0x00000000, 0x00008082), 1458 | new Int_64(0x80000000, 0x0000808A), new Int_64(0x80000000, 0x80008000), 1459 | new Int_64(0x00000000, 0x0000808B), new Int_64(0x00000000, 0x80000001), 1460 | new Int_64(0x80000000, 0x80008081), new Int_64(0x80000000, 0x00008009), 1461 | new Int_64(0x00000000, 0x0000008A), new Int_64(0x00000000, 0x00000088), 1462 | new Int_64(0x00000000, 0x80008009), new Int_64(0x00000000, 0x8000000A), 1463 | new Int_64(0x00000000, 0x8000808B), new Int_64(0x80000000, 0x0000008B), 1464 | new Int_64(0x80000000, 0x00008089), new Int_64(0x80000000, 0x00008003), 1465 | new Int_64(0x80000000, 0x00008002), new Int_64(0x80000000, 0x00000080), 1466 | new Int_64(0x00000000, 0x0000800A), new Int_64(0x80000000, 0x8000000A), 1467 | new Int_64(0x80000000, 0x80008081), new Int_64(0x80000000, 0x00008080), 1468 | new Int_64(0x00000000, 0x80000001), new Int_64(0x80000000, 0x80008008) 1469 | ]; 1470 | 1471 | r_sha3 = [ 1472 | [ 0, 36, 3, 41, 18], 1473 | [ 1, 44, 10, 45, 2], 1474 | [62, 6, 43, 15, 61], 1475 | [28, 55, 25, 21, 56], 1476 | [27, 20, 39, 8, 14] 1477 | ]; 1478 | } 1479 | 1480 | /** 1481 | * Performs a round of SHA-2 hashing over a block 1482 | * 1483 | * @private 1484 | * @param {Array} block The binary array representation of the 1485 | * block to hash 1486 | * @param {Array} H The intermediate H values from a previous 1487 | * round 1488 | * @param {string} variant The desired SHA-2 variant 1489 | * @return {Array} The resulting H values 1490 | */ 1491 | function roundSHA2(block, H, variant) 1492 | { 1493 | var a, b, c, d, e, f, g, h, T1, T2, numRounds, t, binaryStringMult, 1494 | safeAdd_2, safeAdd_4, safeAdd_5, gamma0, gamma1, sigma0, sigma1, 1495 | ch, maj, Int, W = [], int1, int2, offset, K; 1496 | 1497 | /* Set up the various function handles and variable for the specific 1498 | * variant */ 1499 | if ((variant === "SHA-224" || variant === "SHA-256") && 1500 | ((2 & SUPPORTED_ALGS) !== 0)) 1501 | { 1502 | /* 32-bit variant */ 1503 | numRounds = 64; 1504 | binaryStringMult = 1; 1505 | Int = Number; 1506 | safeAdd_2 = safeAdd_32_2; 1507 | safeAdd_4 = safeAdd_32_4; 1508 | safeAdd_5 = safeAdd_32_5; 1509 | gamma0 = gamma0_32; 1510 | gamma1 = gamma1_32; 1511 | sigma0 = sigma0_32; 1512 | sigma1 = sigma1_32; 1513 | maj = maj_32; 1514 | ch = ch_32; 1515 | K = K_sha2; 1516 | } 1517 | else if ((variant === "SHA-384" || variant === "SHA-512") && 1518 | ((4 & SUPPORTED_ALGS) !== 0)) 1519 | { 1520 | /* 64-bit variant */ 1521 | numRounds = 80; 1522 | binaryStringMult = 2; 1523 | Int = Int_64; 1524 | safeAdd_2 = safeAdd_64_2; 1525 | safeAdd_4 = safeAdd_64_4; 1526 | safeAdd_5 = safeAdd_64_5; 1527 | gamma0 = gamma0_64; 1528 | gamma1 = gamma1_64; 1529 | sigma0 = sigma0_64; 1530 | sigma1 = sigma1_64; 1531 | maj = maj_64; 1532 | ch = ch_64; 1533 | K = K_sha512; 1534 | } 1535 | else 1536 | { 1537 | throw new Error("Unexpected error in SHA-2 implementation"); 1538 | } 1539 | 1540 | a = H[0]; 1541 | b = H[1]; 1542 | c = H[2]; 1543 | d = H[3]; 1544 | e = H[4]; 1545 | f = H[5]; 1546 | g = H[6]; 1547 | h = H[7]; 1548 | 1549 | for (t = 0; t < numRounds; t += 1) 1550 | { 1551 | if (t < 16) 1552 | { 1553 | offset = t * binaryStringMult; 1554 | int1 = (block.length <= offset) ? 0 : block[offset]; 1555 | int2 = (block.length <= offset + 1) ? 0 : block[offset + 1]; 1556 | /* Bit of a hack - for 32-bit, the second term is ignored */ 1557 | W[t] = new Int(int1, int2); 1558 | } 1559 | else 1560 | { 1561 | W[t] = safeAdd_4( 1562 | gamma1(W[t - 2]), W[t - 7], 1563 | gamma0(W[t - 15]), W[t - 16] 1564 | ); 1565 | } 1566 | 1567 | T1 = safeAdd_5(h, sigma1(e), ch(e, f, g), K[t], W[t]); 1568 | T2 = safeAdd_2(sigma0(a), maj(a, b, c)); 1569 | h = g; 1570 | g = f; 1571 | f = e; 1572 | e = safeAdd_2(d, T1); 1573 | d = c; 1574 | c = b; 1575 | b = a; 1576 | a = safeAdd_2(T1, T2); 1577 | } 1578 | 1579 | H[0] = safeAdd_2(a, H[0]); 1580 | H[1] = safeAdd_2(b, H[1]); 1581 | H[2] = safeAdd_2(c, H[2]); 1582 | H[3] = safeAdd_2(d, H[3]); 1583 | H[4] = safeAdd_2(e, H[4]); 1584 | H[5] = safeAdd_2(f, H[5]); 1585 | H[6] = safeAdd_2(g, H[6]); 1586 | H[7] = safeAdd_2(h, H[7]); 1587 | 1588 | return H; 1589 | } 1590 | 1591 | /** 1592 | * Finalizes the SHA-2 hash 1593 | * 1594 | * @private 1595 | * @param {Array} remainder Any leftover unprocessed packed ints 1596 | * that still need to be processed 1597 | * @param {number} remainderBinLen The number of bits in remainder 1598 | * @param {number} processedBinLen The number of bits already 1599 | * processed 1600 | * @param {Array} H The intermediate H values from a previous 1601 | * round 1602 | * @param {string} variant The desired SHA-2 variant 1603 | * @param {number} outputLen Unused for this variant 1604 | * @return {Array} The array of integers representing the SHA-2 1605 | * hash of message 1606 | */ 1607 | function finalizeSHA2(remainder, remainderBinLen, processedBinLen, H, variant, outputLen) 1608 | { 1609 | var i, appendedMessageLength, offset, retVal, binaryStringInc, totalLen; 1610 | 1611 | if ((variant === "SHA-224" || variant === "SHA-256") && 1612 | ((2 & SUPPORTED_ALGS) !== 0)) 1613 | { 1614 | /* 32-bit variant */ 1615 | /* The 65 addition is a hack but it works. The correct number is 1616 | actually 72 (64 + 8) but the below math fails if 1617 | remainderBinLen + 72 % 512 = 0. Since remainderBinLen % 8 = 0, 1618 | "shorting" the addition is OK. */ 1619 | offset = (((remainderBinLen + 65) >>> 9) << 4) + 15; 1620 | binaryStringInc = 16; 1621 | } 1622 | else if ((variant === "SHA-384" || variant === "SHA-512") && 1623 | ((4 & SUPPORTED_ALGS) !== 0)) 1624 | { 1625 | /* 64-bit variant */ 1626 | /* The 129 addition is a hack but it works. The correct number is 1627 | actually 136 (128 + 8) but the below math fails if 1628 | remainderBinLen + 136 % 1024 = 0. Since remainderBinLen % 8 = 0, 1629 | "shorting" the addition is OK. */ 1630 | offset = (((remainderBinLen + 129) >>> 10) << 5) + 31; 1631 | binaryStringInc = 32; 1632 | } 1633 | else 1634 | { 1635 | throw new Error("Unexpected error in SHA-2 implementation"); 1636 | } 1637 | 1638 | while (remainder.length <= offset) 1639 | { 1640 | remainder.push(0); 1641 | } 1642 | /* Append '1' at the end of the binary string */ 1643 | remainder[remainderBinLen >>> 5] |= 0x80 << (24 - remainderBinLen % 32); 1644 | /* Append length of binary string in the position such that the new 1645 | * length is correct. JavaScript numbers are limited to 2^53 so it's 1646 | * "safe" to treat the totalLen as a 64-bit integer. */ 1647 | totalLen = remainderBinLen + processedBinLen; 1648 | remainder[offset] = totalLen & 0xFFFFFFFF; 1649 | /* Bitwise operators treat the operand as a 32-bit number so need to 1650 | * use hacky division and round to get access to upper 32-ish bits */ 1651 | remainder[offset - 1] = (totalLen / TWO_PWR_32) | 0; 1652 | 1653 | appendedMessageLength = remainder.length; 1654 | 1655 | /* This will always be at least 1 full chunk */ 1656 | for (i = 0; i < appendedMessageLength; i += binaryStringInc) 1657 | { 1658 | H = roundSHA2(remainder.slice(i, i + binaryStringInc), H, variant); 1659 | } 1660 | 1661 | if (("SHA-224" === variant) && ((2 & SUPPORTED_ALGS) !== 0)) 1662 | { 1663 | retVal = [ 1664 | H[0], H[1], H[2], H[3], 1665 | H[4], H[5], H[6] 1666 | ]; 1667 | } 1668 | else if (("SHA-256" === variant) && ((2 & SUPPORTED_ALGS) !== 0)) 1669 | { 1670 | retVal = H; 1671 | } 1672 | else if (("SHA-384" === variant) && ((4 & SUPPORTED_ALGS) !== 0)) 1673 | { 1674 | retVal = [ 1675 | H[0].highOrder, H[0].lowOrder, 1676 | H[1].highOrder, H[1].lowOrder, 1677 | H[2].highOrder, H[2].lowOrder, 1678 | H[3].highOrder, H[3].lowOrder, 1679 | H[4].highOrder, H[4].lowOrder, 1680 | H[5].highOrder, H[5].lowOrder 1681 | ]; 1682 | } 1683 | else if (("SHA-512" === variant) && ((4 & SUPPORTED_ALGS) !== 0)) 1684 | { 1685 | retVal = [ 1686 | H[0].highOrder, H[0].lowOrder, 1687 | H[1].highOrder, H[1].lowOrder, 1688 | H[2].highOrder, H[2].lowOrder, 1689 | H[3].highOrder, H[3].lowOrder, 1690 | H[4].highOrder, H[4].lowOrder, 1691 | H[5].highOrder, H[5].lowOrder, 1692 | H[6].highOrder, H[6].lowOrder, 1693 | H[7].highOrder, H[7].lowOrder 1694 | ]; 1695 | } 1696 | else /* This should never be reached */ 1697 | { 1698 | throw new Error("Unexpected error in SHA-2 implementation"); 1699 | } 1700 | 1701 | return retVal; 1702 | } 1703 | 1704 | /** 1705 | * Performs a round of SHA-3 hashing over a block 1706 | * 1707 | * @private 1708 | * @param {Array|null} block The binary array representation of the 1709 | * block to hash 1710 | * @param {Array>} state The binary array representation of the 1711 | * block to hash 1712 | * @return {Array>} The resulting state value 1713 | */ 1714 | function roundSHA3(block, state) 1715 | { 1716 | var round, x, y, B, C = [], D = []; 1717 | 1718 | if (null !== block) 1719 | { 1720 | for (x = 0; x < block.length; x+=2) 1721 | { 1722 | state[(x >>> 1) % 5][((x >>> 1) / 5) | 0] = xor_64_2( 1723 | state[(x >>> 1) % 5][((x >>> 1) / 5) | 0], 1724 | new Int_64(block[x + 1], block[x]) 1725 | ); 1726 | } 1727 | } 1728 | 1729 | for (round = 0; round < 24; round += 1) 1730 | { 1731 | /* getNewState doesn't care about variant beyond SHA3 so feed it a 1732 | value that triggers the getNewState "if" statement 1733 | */ 1734 | B = getNewState("SHA3-"); 1735 | 1736 | /* Perform theta step */ 1737 | for (x = 0; x < 5; x += 1) 1738 | { 1739 | C[x] = xor_64_5(state[x][0], state[x][1], state[x][2], 1740 | state[x][3], state[x][4]); 1741 | } 1742 | for (x = 0; x < 5; x += 1) 1743 | { 1744 | D[x] = xor_64_2(C[(x + 4) % 5], rotl_64(C[(x + 1) % 5], 1)); 1745 | } 1746 | for (x = 0; x < 5; x += 1) 1747 | { 1748 | for (y = 0; y < 5; y += 1) 1749 | { 1750 | state[x][y] = xor_64_2(state[x][y], D[x]); 1751 | } 1752 | } 1753 | 1754 | /* Perform combined ro and pi steps */ 1755 | for (x = 0; x < 5; x += 1) 1756 | { 1757 | for (y = 0; y < 5; y += 1) 1758 | { 1759 | B[y][(2 * x + 3 * y) % 5] = rotl_64( 1760 | state[x][y], 1761 | r_sha3[x][y] 1762 | ); 1763 | } 1764 | } 1765 | 1766 | /* Perform chi step */ 1767 | for (x = 0; x < 5; x += 1) 1768 | { 1769 | for (y = 0; y < 5; y += 1) 1770 | { 1771 | state[x][y] = xor_64_2( 1772 | B[x][y], 1773 | new Int_64( 1774 | ~(B[(x + 1) % 5][y].highOrder) & B[(x + 2) % 5][y].highOrder, 1775 | ~(B[(x + 1) % 5][y].lowOrder) & B[(x + 2) % 5][y].lowOrder 1776 | ) 1777 | ); 1778 | } 1779 | } 1780 | 1781 | /* Perform iota step */ 1782 | state[0][0] = xor_64_2(state[0][0], rc_sha3[round]); 1783 | } 1784 | 1785 | return state; 1786 | } 1787 | 1788 | /** 1789 | * Finalizes the SHA-3 hash 1790 | * 1791 | * @private 1792 | * @param {Array} remainder Any leftover unprocessed packed ints 1793 | * that still need to be processed 1794 | * @param {number} remainderBinLen The number of bits in remainder 1795 | * @param {number} processedBinLen The number of bits already 1796 | * processed 1797 | * @param {Array>} state The state from a previous round 1798 | * @param {number} blockSize The block size/rate of the variant in bits 1799 | * @param {number} delimiter The delimiter value for the variant 1800 | * @param {number} outputLen The output length for the variant in bits 1801 | * @return {Array} The array of integers representing the SHA-3 1802 | * hash of message 1803 | */ 1804 | function finalizeSHA3(remainder, remainderBinLen, processedBinLen, state, blockSize, delimiter, outputLen) 1805 | { 1806 | var i, retVal = [], binaryStringInc = blockSize >>> 5, state_offset = 0, 1807 | remainderIntLen = remainderBinLen >>> 5, temp; 1808 | 1809 | 1810 | /* Process as many blocks as possible, some may be here for multiple rounds 1811 | with SHAKE 1812 | */ 1813 | for (i = 0; i < remainderIntLen && remainderBinLen >= blockSize; i += binaryStringInc) 1814 | { 1815 | state = roundSHA3(remainder.slice(i, i + binaryStringInc), state); 1816 | remainderBinLen -= blockSize; 1817 | } 1818 | 1819 | remainder = remainder.slice(i); 1820 | remainderBinLen = remainderBinLen % blockSize; 1821 | 1822 | /* Pad out the remainder to a full block */ 1823 | while (remainder.length < binaryStringInc) 1824 | { 1825 | remainder.push(0); 1826 | } 1827 | 1828 | /* Find the next "empty" byte for the 0x80 and append it via an xor */ 1829 | i = remainderBinLen >>> 3; 1830 | remainder[i >> 2] ^= delimiter << (8 * (i % 4)); 1831 | 1832 | remainder[binaryStringInc - 1] ^= 0x80000000; 1833 | state = roundSHA3(remainder, state); 1834 | 1835 | while (retVal.length * 32 < outputLen) 1836 | { 1837 | temp = state[state_offset % 5][(state_offset / 5) | 0]; 1838 | retVal.push(temp.lowOrder); 1839 | if (retVal.length * 32 >= outputLen) 1840 | { 1841 | break; 1842 | } 1843 | retVal.push(temp.highOrder); 1844 | state_offset += 1; 1845 | 1846 | if (0 === ((state_offset * 64) % blockSize)) 1847 | { 1848 | roundSHA3(null, state); 1849 | } 1850 | } 1851 | 1852 | return retVal; 1853 | } 1854 | 1855 | /** 1856 | * jsSHA is the workhorse of the library. Instantiate it with the string to 1857 | * be hashed as the parameter 1858 | * 1859 | * @constructor 1860 | * @this {jsSHA} 1861 | * @param {string} variant The desired SHA variant (SHA-1, SHA-224, SHA-256, 1862 | * SHA-384, SHA-512, SHA3-224, SHA3-256, SHA3-384, or SHA3-512) 1863 | * @param {string} inputFormat The format of srcString: HEX, TEXT, B64, 1864 | * BYTES, or ARRAYBUFFER 1865 | * @param {{encoding: (string|undefined), numRounds: (number|undefined)}=} 1866 | * options Optional values 1867 | */ 1868 | var jsSHA = function(variant, inputFormat, options) 1869 | { 1870 | var processedLen = 0, remainder = [], remainderLen = 0, utfType, 1871 | intermediateState, converterFunc, shaVariant = variant, outputBinLen, 1872 | variantBlockSize, roundFunc, finalizeFunc, stateCloneFunc, 1873 | hmacKeySet = false, keyWithIPad = [], keyWithOPad = [], numRounds, 1874 | updatedCalled = false, inputOptions, isSHAKE = false, bigEndianMod = -1; 1875 | 1876 | inputOptions = options || {}; 1877 | utfType = inputOptions["encoding"] || "UTF8"; 1878 | numRounds = inputOptions["numRounds"] || 1; 1879 | 1880 | if ((numRounds !== parseInt(numRounds, 10)) || (1 > numRounds)) 1881 | { 1882 | throw new Error("numRounds must a integer >= 1"); 1883 | } 1884 | 1885 | if (("SHA-1" === shaVariant) && ((1 & SUPPORTED_ALGS) !== 0)) 1886 | { 1887 | variantBlockSize = 512; 1888 | roundFunc = roundSHA1; 1889 | finalizeFunc = finalizeSHA1; 1890 | outputBinLen = 160; 1891 | stateCloneFunc = function(state) { return state.slice();}; 1892 | } 1893 | else if ((shaVariant.lastIndexOf("SHA-", 0) === 0) && ((6 & SUPPORTED_ALGS) !== 0)) 1894 | { 1895 | roundFunc = function (block, H) { 1896 | return roundSHA2(block, H, shaVariant); 1897 | }; 1898 | finalizeFunc = function (remainder, remainderBinLen, processedBinLen, H, outputLen) 1899 | { 1900 | return finalizeSHA2(remainder, remainderBinLen, processedBinLen, H, shaVariant, outputLen); 1901 | }; 1902 | stateCloneFunc = function(state) { return state.slice(); }; 1903 | 1904 | if (("SHA-224" === shaVariant) && ((2 & SUPPORTED_ALGS) !== 0)) 1905 | { 1906 | variantBlockSize = 512; 1907 | outputBinLen = 224; 1908 | } 1909 | else if (("SHA-256" === shaVariant) && ((2 & SUPPORTED_ALGS) !== 0)) 1910 | { 1911 | variantBlockSize = 512; 1912 | outputBinLen = 256; 1913 | } 1914 | else if (("SHA-384" === shaVariant) && ((4 & SUPPORTED_ALGS) !== 0)) 1915 | { 1916 | variantBlockSize = 1024; 1917 | outputBinLen = 384; 1918 | } 1919 | else if (("SHA-512" === shaVariant) && ((4 & SUPPORTED_ALGS) !== 0)) 1920 | { 1921 | variantBlockSize = 1024; 1922 | outputBinLen = 512; 1923 | } 1924 | else 1925 | { 1926 | throw new Error("Chosen SHA variant is not supported "+shaVariant); 1927 | } 1928 | } 1929 | else if (((shaVariant.lastIndexOf("SHA3-", 0) === 0) || (shaVariant.lastIndexOf("SHAKE", 0) === 0)) && 1930 | ((8 & SUPPORTED_ALGS) !== 0)) 1931 | { 1932 | var delimiter = 0x06; 1933 | 1934 | roundFunc = roundSHA3; 1935 | stateCloneFunc = function(state) { return cloneSHA3State(state);}; 1936 | bigEndianMod = 1; 1937 | 1938 | if ("SHA3-224" === shaVariant) 1939 | { 1940 | variantBlockSize = 1152; 1941 | outputBinLen = 224; 1942 | 1943 | } 1944 | else if ("SHA3-256" === shaVariant) 1945 | { 1946 | variantBlockSize = 1088; 1947 | outputBinLen = 256; 1948 | } 1949 | else if ("SHA3-384" === shaVariant) 1950 | { 1951 | variantBlockSize = 832; 1952 | outputBinLen = 384; 1953 | } 1954 | else if ("SHA3-512" === shaVariant) 1955 | { 1956 | variantBlockSize = 576; 1957 | outputBinLen = 512; 1958 | } 1959 | else if ("SHAKE128" === shaVariant) 1960 | { 1961 | variantBlockSize = 1344; 1962 | outputBinLen = -1; 1963 | delimiter = 0x1F; 1964 | isSHAKE = true; 1965 | } 1966 | else if ("SHAKE256" === shaVariant) 1967 | { 1968 | variantBlockSize = 1088; 1969 | outputBinLen = -1; 1970 | delimiter = 0x1F; 1971 | isSHAKE = true; 1972 | } 1973 | else 1974 | { 1975 | throw new Error("Chosen SHA variant is not supported "+shaVariant); 1976 | } 1977 | finalizeFunc = function (remainder, remainderBinLen, processedBinLen, state, outputLen) 1978 | { 1979 | return finalizeSHA3(remainder, remainderBinLen, processedBinLen, state, variantBlockSize, delimiter, outputLen); 1980 | }; 1981 | } 1982 | else 1983 | { 1984 | throw new Error("Chosen SHA varwwwiant is not supported "+shaVariant); 1985 | } 1986 | converterFunc = getStrConverter(inputFormat, utfType, bigEndianMod); 1987 | intermediateState = getNewState(shaVariant); 1988 | 1989 | /** 1990 | * Sets the HMAC key for an eventual getHMAC call. Must be called 1991 | * immediately after jsSHA object instantiation 1992 | * 1993 | * @expose 1994 | * @param {string|ArrayBuffer} key The key used to calculate the HMAC 1995 | * @param {string} inputFormat The format of key, HEX, TEXT, B64, BYTES, 1996 | * or ARRAYBUFFER 1997 | * @param {{encoding : (string|undefined)}=} options Associative array 1998 | * of input format options 1999 | */ 2000 | this.setHMACKey = function(key, inputFormat, options) 2001 | { 2002 | var keyConverterFunc, convertRet, keyBinLen, keyToUse, blockByteSize, 2003 | i, lastArrayIndex, keyOptions; 2004 | 2005 | if (true === hmacKeySet) 2006 | { 2007 | throw new Error("HMAC key already set"); 2008 | } 2009 | 2010 | if (true === updatedCalled) 2011 | { 2012 | throw new Error("Cannot set HMAC key after calling update"); 2013 | } 2014 | 2015 | if ((isSHAKE === true) && ((8 & SUPPORTED_ALGS) !== 0)) 2016 | { 2017 | throw new Error("SHAKE is not supported for HMAC"); 2018 | } 2019 | 2020 | keyOptions = options || {}; 2021 | utfType = keyOptions["encoding"] || "UTF8"; 2022 | 2023 | keyConverterFunc = getStrConverter(inputFormat, utfType, bigEndianMod); 2024 | 2025 | convertRet = keyConverterFunc(key); 2026 | keyBinLen = convertRet["binLen"]; 2027 | keyToUse = convertRet["value"]; 2028 | 2029 | blockByteSize = variantBlockSize >>> 3; 2030 | 2031 | /* These are used multiple times, calculate and store them */ 2032 | lastArrayIndex = (blockByteSize / 4) - 1; 2033 | 2034 | /* Figure out what to do with the key based on its size relative to 2035 | * the hash's block size */ 2036 | if (blockByteSize < (keyBinLen / 8)) 2037 | { 2038 | 2039 | keyToUse = finalizeFunc(keyToUse, keyBinLen, 0,getNewState(shaVariant), outputBinLen); 2040 | /* For all variants, the block size is bigger than the output 2041 | * size so there will never be a useful byte at the end of the 2042 | * string */ 2043 | while (keyToUse.length <= lastArrayIndex) 2044 | { 2045 | keyToUse.push(0); 2046 | } 2047 | keyToUse[lastArrayIndex] &= 0xFFFFFF00; 2048 | } 2049 | else if (blockByteSize > (keyBinLen / 8)) 2050 | { 2051 | /* If the blockByteSize is greater than the key length, there 2052 | * will always be at LEAST one "useless" byte at the end of the 2053 | * string */ 2054 | while (keyToUse.length <= lastArrayIndex) 2055 | { 2056 | keyToUse.push(0); 2057 | } 2058 | keyToUse[lastArrayIndex] &= 0xFFFFFF00; 2059 | } 2060 | 2061 | /* Create ipad and opad */ 2062 | for (i = 0; i <= lastArrayIndex; i += 1) 2063 | { 2064 | keyWithIPad[i] = keyToUse[i] ^ 0x36363636; 2065 | keyWithOPad[i] = keyToUse[i] ^ 0x5C5C5C5C; 2066 | } 2067 | 2068 | intermediateState = roundFunc(keyWithIPad, intermediateState); 2069 | processedLen = variantBlockSize; 2070 | 2071 | hmacKeySet = true; 2072 | }; 2073 | 2074 | /** 2075 | * Takes strString and hashes as many blocks as possible. Stores the 2076 | * rest for either a future update or getHash call. 2077 | * 2078 | * @expose 2079 | * @param {string|ArrayBuffer} srcString The string to be hashed 2080 | */ 2081 | this.update = function(srcString) 2082 | { 2083 | var convertRet, chunkBinLen, chunkIntLen, chunk, i, updateProcessedLen = 0, 2084 | variantBlockIntInc = variantBlockSize >>> 5; 2085 | 2086 | convertRet = converterFunc(srcString, remainder, remainderLen); 2087 | chunkBinLen = convertRet["binLen"]; 2088 | chunk = convertRet["value"]; 2089 | 2090 | chunkIntLen = chunkBinLen >>> 5; 2091 | for (i = 0; i < chunkIntLen; i += variantBlockIntInc) 2092 | { 2093 | if (updateProcessedLen + variantBlockSize <= chunkBinLen) 2094 | { 2095 | intermediateState = roundFunc( 2096 | chunk.slice(i, i + variantBlockIntInc), 2097 | intermediateState 2098 | ); 2099 | updateProcessedLen += variantBlockSize; 2100 | } 2101 | } 2102 | processedLen += updateProcessedLen; 2103 | remainder = chunk.slice(updateProcessedLen >>> 5); 2104 | remainderLen = chunkBinLen % variantBlockSize; 2105 | updatedCalled = true; 2106 | 2107 | }; 2108 | 2109 | /** 2110 | * Returns the desired SHA hash of the string specified at instantiation 2111 | * using the specified parameters 2112 | * 2113 | * @expose 2114 | * @param {string} format The desired output formatting (B64, HEX, 2115 | * BYTES, or ARRAYBUFFER) 2116 | * @param {{outputUpper : (boolean|undefined), b64Pad : (string|undefined), 2117 | * shakeLen : (number|undefined)}=} options Hash list of output formatting options 2118 | * @return {string|ArrayBuffer} The string representation of the hash 2119 | * in the format specified. 2120 | */ 2121 | this.getHash = function(format, options) 2122 | { 2123 | var formatFunc, i, outputOptions, finalizedState; 2124 | 2125 | if (true === hmacKeySet) 2126 | { 2127 | throw new Error("Cannot call getHash after setting HMAC key"); 2128 | } 2129 | 2130 | outputOptions = getOutputOpts(options); 2131 | 2132 | if ((isSHAKE === true) && ((8 & SUPPORTED_ALGS) !== 0)) 2133 | { 2134 | if (outputOptions["shakeLen"] === -1) 2135 | { 2136 | throw new Error("shakeLen must be specified in options"); 2137 | } 2138 | outputBinLen = outputOptions["shakeLen"]; 2139 | } 2140 | 2141 | /* Validate the output format selection */ 2142 | switch (format) 2143 | { 2144 | case "HEX": 2145 | formatFunc = function(binarray) {return packed2hex(binarray, outputBinLen, bigEndianMod, outputOptions);}; 2146 | break; 2147 | case "B64": 2148 | formatFunc = function(binarray) {return packed2b64(binarray, outputBinLen, bigEndianMod, outputOptions);}; 2149 | break; 2150 | case "BYTES": 2151 | formatFunc = function(binarray) {return packed2bytes(binarray, outputBinLen, bigEndianMod);}; 2152 | break; 2153 | case "ARRAYBUFFER": 2154 | try { 2155 | i = new ArrayBuffer(0); 2156 | } catch (ignore) { 2157 | throw new Error("ARRAYBUFFER not supported by this environment"); 2158 | } 2159 | formatFunc = function(binarray) {return packed2arraybuffer(binarray, outputBinLen, bigEndianMod);}; 2160 | break; 2161 | default: 2162 | throw new Error("format must be HEX, B64, BYTES, or ARRAYBUFFER"); 2163 | } 2164 | 2165 | finalizedState = finalizeFunc(remainder.slice(), remainderLen, processedLen, stateCloneFunc(intermediateState), outputBinLen); 2166 | for (i = 1; i < numRounds; i += 1) 2167 | { 2168 | /* This weird fix-up is only for the case of SHAKE algorithms 2169 | * and outputBinLen is not a multiple of 32. In this case, the 2170 | * very last block of finalizedState has data that needs to be 2171 | * ignored because all the finalizeFunc calls need to have 2172 | * unneeded bits set to 0. 2173 | */ 2174 | if (((8 & SUPPORTED_ALGS) !== 0) && (isSHAKE === true) && (outputBinLen % 32 !== 0)) 2175 | { 2176 | finalizedState[finalizedState.length - 1] &= 0x00FFFFFF >>> 24 - (outputBinLen % 32); 2177 | } 2178 | finalizedState = finalizeFunc(finalizedState, outputBinLen, 0, getNewState(shaVariant), outputBinLen); 2179 | } 2180 | 2181 | return formatFunc(finalizedState); 2182 | }; 2183 | 2184 | /** 2185 | * Returns the the HMAC in the specified format using the key given by 2186 | * a previous setHMACKey call. 2187 | * 2188 | * @expose 2189 | * @param {string} format The desired output formatting 2190 | * (B64, HEX, BYTES, or ARRAYBUFFER) 2191 | * @param {{outputUpper : (boolean|undefined), b64Pad : (string|undefined), 2192 | * shakeLen : (number|undefined)}=} options associative array of output 2193 | * formatting options 2194 | * @return {string|ArrayBuffer} The string representation of the hash in the 2195 | * format specified. 2196 | */ 2197 | this.getHMAC = function(format, options) 2198 | { 2199 | var formatFunc, firstHash, outputOptions, finalizedState; 2200 | 2201 | if (false === hmacKeySet) 2202 | { 2203 | throw new Error("Cannot call getHMAC without first setting HMAC key"); 2204 | } 2205 | 2206 | outputOptions = getOutputOpts(options); 2207 | 2208 | /* Validate the output format selection */ 2209 | switch (format) 2210 | { 2211 | case "HEX": 2212 | formatFunc = function(binarray) {return packed2hex(binarray, outputBinLen, bigEndianMod, outputOptions);}; 2213 | break; 2214 | case "B64": 2215 | formatFunc = function(binarray) {return packed2b64(binarray, outputBinLen, bigEndianMod, outputOptions);}; 2216 | break; 2217 | case "BYTES": 2218 | formatFunc = function(binarray) {return packed2bytes(binarray, outputBinLen, bigEndianMod);}; 2219 | break; 2220 | case "ARRAYBUFFER": 2221 | try { 2222 | formatFunc = new ArrayBuffer(0); 2223 | } catch(ignore) { 2224 | throw new Error("ARRAYBUFFER not supported by this environment"); 2225 | } 2226 | formatFunc = function(binarray) {return packed2arraybuffer(binarray, outputBinLen, bigEndianMod);}; 2227 | break; 2228 | default: 2229 | throw new Error("outputFormat must be HEX, B64, BYTES, or ARRAYBUFFER"); 2230 | } 2231 | 2232 | firstHash = finalizeFunc(remainder.slice(), remainderLen, processedLen, stateCloneFunc(intermediateState), outputBinLen); 2233 | finalizedState = roundFunc(keyWithOPad, getNewState(shaVariant)); 2234 | finalizedState = finalizeFunc(firstHash, outputBinLen, variantBlockSize, finalizedState, outputBinLen); 2235 | 2236 | return formatFunc(finalizedState); 2237 | }; 2238 | }; 2239 | 2240 | if (("function" === typeof define) && (define["amd"])) /* AMD Support */ 2241 | { 2242 | define(function() 2243 | { 2244 | return jsSHA; 2245 | }); 2246 | } else if ("undefined" !== typeof exports) /* Node Support */ 2247 | { 2248 | if (("undefined" !== typeof module) && module["exports"]) 2249 | { 2250 | module["exports"] = jsSHA; 2251 | exports = jsSHA; 2252 | } 2253 | else { 2254 | exports = jsSHA; 2255 | } 2256 | } else { /* Browsers and Web Workers*/ 2257 | global["jsSHA"] = jsSHA; 2258 | } 2259 | }(X)); 2260 | 2261 | TOTP = function() { 2262 | 2263 | var dec2hex = function(s) { 2264 | return (s < 15.5 ? "0" : "") + Math.round(s).toString(16); 2265 | }; 2266 | 2267 | var hex2dec = function(s) { 2268 | return parseInt(s, 16); 2269 | }; 2270 | 2271 | var leftpad = function(s, l, p) { 2272 | if(l + 1 >= s.length) { 2273 | s = Array(l + 1 - s.length).join(p) + s; 2274 | } 2275 | return s; 2276 | }; 2277 | 2278 | var base32tohex = function(base32) { 2279 | var base32chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; 2280 | var bits = ""; 2281 | var hex = ""; 2282 | for(var i = 0; i < base32.length; i++) { 2283 | var val = base32chars.indexOf(base32.charAt(i).toUpperCase()); 2284 | bits += leftpad(val.toString(2), 5, '0'); 2285 | } 2286 | for(var i = 0; i + 4 <= bits.length; i+=4) { 2287 | var chunk = bits.substr(i, 4); 2288 | hex = hex + parseInt(chunk, 2).toString(16) ; 2289 | } 2290 | return hex; 2291 | }; 2292 | 2293 | this.getOTP = function(secret) { 2294 | try { 2295 | var key = base32tohex(secret); 2296 | var epoch = Math.round(new Date().getTime() / 1000.0); 2297 | var time = leftpad(dec2hex(Math.floor(epoch / 30)), 16, "0"); 2298 | var shaObj = new X.jsSHA("SHA-1", "HEX"); 2299 | shaObj.setHMACKey(key, "HEX"); 2300 | shaObj.update(time); 2301 | var hmac = shaObj.getHMAC("HEX"); 2302 | var offset = hex2dec(hmac.substring(hmac.length - 1)); 2303 | var otp = (hex2dec(hmac.substr(offset * 2, 8)) & hex2dec("7fffffff")) + ""; 2304 | otp = (otp).substr(otp.length - 6, 6); 2305 | } catch (error) { 2306 | throw error; 2307 | } 2308 | return otp; 2309 | }; 2310 | 2311 | } 2312 | 2313 | function Main() 2314 | { 2315 | // Calculate OTP token 2316 | var totpObj = new TOTP(); 2317 | var epoch = Math.floor(new Date().getTime() / 1000 % 30); 2318 | var elapsed = 30 - epoch 2319 | 2320 | // Adjust the sliding window 2321 | if (elapsed <= 3 ) { 2322 | xsh.Dialog.MsgBox("Hold on, and wait " + elapsed + " seconds!"); 2323 | xsh.Session.Sleep(elapsed * 1000 + 100); 2324 | } 2325 | 2326 | var otp = totpObj.getOTP("REVISED"); 2327 | // xsh.Dialog.MsgBox(otp); 2328 | // xsh.Dialog.Prompt("Copy This Token", "Prompt Dialog", otp, 0); 2329 | 2330 | // Copy the token to clipboard 2331 | xsh.Screen.Synchronous = true; 2332 | xsh.Screen.Send("cmd /c echo " + otp + "| clip"); 2333 | xsh.Screen.Send(String.fromCharCode(13)); 2334 | xsh.Screen.Clear(); 2335 | 2336 | // Open Session 2337 | // xsh.Session.Open("ssh://username:password@host:port") 2338 | xsh.Session.Open("C:\Users\REVISED\Documents\NetSarang\Xshell\Sessions\jump.xsh"); 2339 | 2340 | // Close the local shell 2341 | // xsh.Session.Sleep(1000); 2342 | xsh.Screen.Send("exit"); 2343 | xsh.Screen.Send(String.fromCharCode(13)); 2344 | } 2345 | --------------------------------------------------------------------------------