From 57110284496bd5eda98e8354b6cf7bae67786bfa Mon Sep 17 00:00:00 2001 From: Bart Butler Date: Mon, 20 Apr 2015 14:51:56 -0700 Subject: [PATCH] does not pass tests yet --- src/crypto/hash/index.js | 12 +- src/crypto/hash/md5.js | 4 +- src/crypto/hash/ripe-md.js | 10 +- src/crypto/hash/sha.js | 2537 ++++++++++------- src/crypto/pkcs1.js | 2 +- src/crypto/signature.js | 4 +- src/packet/public_key.js | 4 +- src/packet/secret_key.js | 24 +- src/packet/signature.js | 10 +- .../sym_encrypted_integrity_protected.js | 4 +- src/type/s2k.js | 27 +- src/util.js | 8 +- 12 files changed, 1569 insertions(+), 1077 deletions(-) diff --git a/src/crypto/hash/index.js b/src/crypto/hash/index.js index 8d35a38d..e8a54954 100644 --- a/src/crypto/hash/index.js +++ b/src/crypto/hash/index.js @@ -3,7 +3,8 @@ * @module crypto/hash */ var sha = require('./sha.js'), - forge_sha256 = require('./forge_sha256.js'); + forge_sha256 = require('./forge_sha256.js'), + util = require('../../util.js'); module.exports = { /** @see module:crypto/hash/md5 */ @@ -24,8 +25,8 @@ module.exports = { /** * Create a hash on the specified data using the specified algorithm * @param {module:enums.hash} algo Hash algorithm type (see {@link http://tools.ietf.org/html/rfc4880#section-9.4|RFC 4880 9.4}) - * @param {String} data Data to be hashed - * @return {String} hash value + * @param {Uint8Array} data Data to be hashed + * @return {Uint8Array} hash value */ digest: function(algo, data) { switch (algo) { @@ -40,9 +41,10 @@ module.exports = { return this.ripemd(data); case 8: // - SHA256 [FIPS180] + //return this.sha256(data); var sha256 = forge_sha256.create(); - sha256.update(data); - return sha256.digest().getBytes(); + sha256.update(util.Uint8Array2str(data)); + return util.str2Uint8Array(sha256.digest().getBytes()); case 9: // - SHA384 [FIPS180] return this.sha384(data); diff --git a/src/crypto/hash/md5.js b/src/crypto/hash/md5.js index a6cd008e..30466d77 100644 --- a/src/crypto/hash/md5.js +++ b/src/crypto/hash/md5.js @@ -24,8 +24,8 @@ var util = require('../../util.js'); * @param {String} entree string to hash */ module.exports = function (entree) { - var hex = md5(entree); - var bin = util.hex2bin(hex); + var hex = md5(util.Uint8Array2str(entree)); + var bin = util.str2Uint8Array(util.hex2bin(hex)); return bin; }; diff --git a/src/crypto/hash/ripe-md.js b/src/crypto/hash/ripe-md.js index 7322e9f1..5b998c6d 100644 --- a/src/crypto/hash/ripe-md.js +++ b/src/crypto/hash/ripe-md.js @@ -20,10 +20,16 @@ /* Modified by Recurity Labs GmbH */ +/* Modified by ProtonTech AG + */ + /** + * @requires util * @module crypto/hash/ripe-md */ +var util = require('../../util.js'); + var RMDsize = 160; var X = []; @@ -284,14 +290,14 @@ function RMD(message) { function RMDstring(message) { - var hashcode = RMD(message); + var hashcode = RMD(util.Uint8Array2str(message)); var retString = ""; for (var i = 0; i < RMDsize / 8; i++) { retString += String.fromCharCode(hashcode[i]); } - return retString; + return util.str2Uint8Array(retString); } module.exports = RMDstring; diff --git a/src/crypto/hash/sha.js b/src/crypto/hash/sha.js index 14447f2c..a936c5a4 100644 --- a/src/crypto/hash/sha.js +++ b/src/crypto/hash/sha.js @@ -1,1125 +1,1608 @@ -/* A JavaScript implementation of the SHA family of hashes, as defined in FIPS - * PUB 180-2 as well as the corresponding HMAC implementation as defined in - * FIPS PUB 198a - * - * Version 1.3 Copyright Brian Turek 2008-2010 - * Distributed under the BSD License - * See http://jssha.sourceforge.net/ for more information - * - * Several functions taken from Paul Johnson - */ - -/* Modified by Recurity Labs GmbH - * - * This code has been slightly modified direct string output: - * - bin2bstr has been added - * - following wrappers of this library have been added: - * - str_sha1 - * - str_sha256 - * - str_sha224 - * - str_sha384 - * - str_sha512 - */ - /** - * @module crypto/hash/sha + * @preserve A JavaScript implementation of the SHA family of hashes, as + * defined in FIPS PUB 180-2 as well as the corresponding HMAC implementation + * as defined in FIPS PUB 198a + * + * Copyright Brian Turek 2008-2015 + * Distributed under the BSD License + * See http://caligatio.github.com/jsSHA/ for more information + * + * Several functions taken from Paul Johnston */ -var jsSHA = (function() { + /** + * SUPPORTED_ALGS is the stub for a compile flag that will cause pruning of + * functions that are not needed when a limited number of SHA families are + * selected + * + * @define {number} ORed value of SHA variants to be supported + * 1 = SHA-1, 2 = SHA-224/SHA-256, 4 = SHA-384/SHA-512 + */ - /* - * Configurable variables. Defaults typically work - */ - /* Number of Bits Per character (8 for ASCII, 16 for Unicode) */ - var charSize = 8, - /* base-64 pad character. "=" for strict RFC compliance */ - b64pad = "", - /* hex output format. 0 - lowercase; 1 - uppercase */ - hexCase = 0, +var util = require('../../util.js'); - /* - * Int_64 is a object for 2 32-bit numbers emulating a 64-bit number - * - * @constructor - * @param {Number} msint_32 The most significant 32-bits of a 64-bit number - * @param {Number} lsint_32 The least significant 32-bits of a 64-bit number - */ - Int_64 = function(msint_32, lsint_32) { - this.highOrder = msint_32; - this.lowOrder = lsint_32; - }, +var SUPPORTED_ALGS = 4 | 2 | 1; - /* - * Convert a string to an array of big-endian words - * If charSize is ASCII, characters >255 have their hi-byte silently - * ignored. - * - * @param {String} str String to be converted to binary representation - * @return Integer array representation of the parameter - */ - str2binb = function(str) { - var bin = [], - mask = (1 << charSize) - 1, - length = str.length * charSize, - i; +(function (global) +{ + "use strict"; + /** + * Int_64 is a object for 2 32-bit numbers emulating a 64-bit number + * + * @private + * @constructor + * @this {Int_64} + * @param {number} msint_32 The most significant 32-bits of a 64-bit number + * @param {number} lsint_32 The least significant 32-bits of a 64-bit number + */ + function Int_64(msint_32, lsint_32) + { + this.highOrder = msint_32; + this.lowOrder = lsint_32; + } - for (i = 0; i < length; i += charSize) { - bin[i >> 5] |= (str.charCodeAt(i / charSize) & mask) << - (32 - charSize - (i % 32)); - } + /** + * Convert a string to an array of big-endian words + * + * @private + * @param {string} str String to be converted to binary representation + * @param {string} utfType The Unicode type, UTF8 or UTF16BE, UTF16LE, to + * use to encode the source string + * @return {{value : Array., binLen : number}} Hash list where + * "value" contains the output number array and "binLen" is the binary + * length of "value" + */ + function str2binb(str, utfType) + { + var bin = [], codePnt, binArr = [], byteCnt = 0, i, j, offset; - return bin; - }, + if ("UTF8" === utfType) + { + for (i = 0; i < str.length; i += 1) + { + codePnt = str.charCodeAt(i); + binArr = []; - /* - * Convert a hex string to an array of big-endian words - * - * @param {String} str String to be converted to binary representation - * @return Integer array representation of the parameter - */ - hex2binb = function(str) { - var bin = [], - length = str.length, - i, num; + if (0x80 > codePnt) + { + binArr.push(codePnt); + } + else if (0x800 > codePnt) + { + binArr.push(0xC0 | (codePnt >>> 6)); + binArr.push(0x80 | (codePnt & 0x3F)); + } + else if ((0xd800 > codePnt) || (0xe000 <= codePnt)) { + binArr.push( + 0xe0 | (codePnt >>> 12), + 0x80 | ((codePnt >>> 6) & 0x3f), + 0x80 | (codePnt & 0x3f) + ); + } + else + { + i += 1; + codePnt = 0x10000 + (((codePnt & 0x3ff) << 10) | (str.charCodeAt(i) & 0x3ff)); + binArr.push( + 0xf0 | (codePnt >>> 18), + 0x80 | ((codePnt >>> 12) & 0x3f), + 0x80 | ((codePnt >>> 6) & 0x3f), + 0x80 | (codePnt & 0x3f) + ); + } - for (i = 0; i < length; i += 2) { - num = parseInt(str.substr(i, 2), 16); - if (!isNaN(num)) { - bin[i >> 3] |= num << (24 - (4 * (i % 8))); - } else { - throw new Error("INVALID HEX STRING"); - } - } + for (j = 0; j < binArr.length; j += 1) + { + offset = byteCnt >>> 2; + while (bin.length <= offset) + { + bin.push(0); + } + bin[offset] |= binArr[j] << (24 - (8 * (byteCnt % 4))); + byteCnt += 1; + } + } + } + else if (("UTF16BE" === utfType) || "UTF16LE" === utfType) + { + for (i = 0; i < str.length; i += 1) + { + codePnt = str.charCodeAt(i); + /* Internally strings are UTF-16BE so only change if UTF-16LE */ + if ("UTF16LE" === utfType) + { + j = codePnt & 0xFF; + codePnt = (j << 8) | (codePnt >> 8); + } - return bin; - }, + offset = byteCnt >>> 2; + while (bin.length <= offset) + { + bin.push(0); + } + bin[offset] |= codePnt << (16 - (8 * (byteCnt % 4))); + byteCnt += 2; + } + } + return {"value" : bin, "binLen" : byteCnt * 8}; + } - /* - * Convert an array of big-endian words to a hex string. - * - * @private - * @param {Array} binarray Array of integers to be converted to hexidecimal - * representation - * @return Hexidecimal representation of the parameter in String form - */ - binb2hex = function(binarray) { - var hex_tab = (hexCase) ? "0123456789ABCDEF" : "0123456789abcdef", - str = "", - length = binarray.length * 4, - i, srcByte; + /** + * Convert a hex string to an array of big-endian words + * + * @private + * @param {string} str String to be converted to binary representation + * @return {{value : Array., binLen : number}} Hash list where + * "value" contains the output number array and "binLen" is the binary + * length of "value" + */ + function hex2binb(str) + { + var bin = [], length = str.length, i, num, offset; - for (i = 0; i < length; i += 1) { - srcByte = binarray[i >> 2] >> ((3 - (i % 4)) * 8); - str += hex_tab.charAt((srcByte >> 4) & 0xF) + - hex_tab.charAt(srcByte & 0xF); - } + if (0 !== (length % 2)) + { + throw "String of HEX type must be in byte increments"; + } - return str; - }, + for (i = 0; i < length; i += 2) + { + num = parseInt(str.substr(i, 2), 16); + if (!isNaN(num)) + { + offset = i >>> 3; + while (bin.length <= offset) + { + bin.push(0); + } + bin[i >>> 3] |= num << (24 - (4 * (i % 8))); + } + else + { + throw "String of HEX type contains invalid characters"; + } + } - /* - * Convert an array of big-endian words to a base-64 string - * - * @private - * @param {Array} binarray Array of integers to be converted to base-64 - * representation - * @return Base-64 encoded representation of the parameter in String form - */ - binb2b64 = function(binarray) { - var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + - "0123456789+/", - str = "", - length = binarray.length * 4, - i, j, - triplet; + return {"value" : bin, "binLen" : length * 4}; + } - for (i = 0; i < length; i += 3) { - triplet = (((binarray[i >> 2] >> 8 * (3 - i % 4)) & 0xFF) << 16) | - (((binarray[i + 1 >> 2] >> 8 * (3 - (i + 1) % 4)) & 0xFF) << 8) | - ((binarray[i + 2 >> 2] >> 8 * (3 - (i + 2) % 4)) & 0xFF); - for (j = 0; j < 4; j += 1) { - if (i * 8 + j * 6 <= binarray.length * 32) { - str += tab.charAt((triplet >> 6 * (3 - j)) & 0x3F); - } else { - str += b64pad; - } - } - } - return str; - }, + /** + * Convert a string of raw bytes to an array of big-endian words + * + * @private + * @param {string} str String of raw bytes to be converted to binary representation + * @return {{value : Array., binLen : number}} Hash list where + * "value" contains the output number array and "binLen" is the binary + * length of "value" + */ + function bytes2binb(str) + { + var bin = [], codePnt, i, offset; - /* - * Convert an array of big-endian words to a string - */ - binb2str = function(bin) { - var str = ""; - var mask = (1 << 8) - 1; - for (var i = 0; i < bin.length * 32; i += 8) - str += String.fromCharCode((bin[i >> 5] >>> (24 - i % 32)) & mask); - return str; - }, - /* - * The 32-bit implementation of circular rotate left - * - * @private - * @param {Number} x The 32-bit integer argument - * @param {Number} n The number of bits to shift - * @return The x shifted circularly by n bits - */ - rotl_32 = function(x, n) { - return (x << n) | (x >>> (32 - n)); - }, + for (i = 0; i < str.length; i += 1) + { + codePnt = str.charCodeAt(i); - /* - * The 32-bit implementation of circular rotate right - * - * @private - * @param {Number} x The 32-bit integer argument - * @param {Number} n The number of bits to shift - * @return The x shifted circularly by n bits - */ - rotr_32 = function(x, n) { - return (x >>> n) | (x << (32 - n)); - }, + offset = i >>> 2; + if (bin.length <= offset) + { + bin.push(0); + } + bin[offset] |= codePnt << (24 - (8 * (i % 4))); + } - /* - * The 64-bit implementation of circular rotate right - * - * @private - * @param {Int_64} x The 64-bit integer argument - * @param {Number} n The number of bits to shift - * @return The x shifted circularly by n bits - */ - rotr_64 = function(x, n) { - if (n <= 32) { - return new Int_64( - (x.highOrder >>> n) | (x.lowOrder << (32 - n)), (x.lowOrder >>> n) | (x.highOrder << (32 - n))); - } else { - return new Int_64( - (x.lowOrder >>> n) | (x.highOrder << (32 - n)), (x.highOrder >>> n) | (x.lowOrder << (32 - n))); - } - }, + return {"value" : bin, "binLen" : str.length * 8}; + } - /* - * The 32-bit implementation of shift right - * - * @private - * @param {Number} x The 32-bit integer argument - * @param {Number} n The number of bits to shift - * @return The x shifted by n bits - */ - shr_32 = function(x, n) { - return x >>> n; - }, + /** + * Convert a Uint8Array of raw bytes to an array of big-endian 32-bit words + * + * @private + * @param {Uint8Array} str String of raw bytes to be converted to binary representation + * @return {{value : Array., binLen : number}} Hash list where + * "value" contains the output array and "binLen" is the binary + * length of "value" + */ + function typed2binb(array) + { - /* - * The 64-bit implementation of shift right - * - * @private - * @param {Int_64} x The 64-bit integer argument - * @param {Number} n The number of bits to shift - * @return The x shifted by n bits - */ - shr_64 = function(x, n) { - if (n <= 32) { - return new Int_64( - x.highOrder >>> n, - x.lowOrder >>> n | (x.highOrder << (32 - n))); - } else { - return new Int_64( - 0, - x.highOrder << (32 - n)); - } - }, + var bin = [], octet, i, offset; - /* - * The 32-bit implementation of the NIST specified Parity function - * - * @private - * @param {Number} x The first 32-bit integer argument - * @param {Number} y The second 32-bit integer argument - * @param {Number} z The third 32-bit integer argument - * @return The NIST specified output of the function - */ - parity_32 = function(x, y, z) { - return x ^ y ^ z; - }, + for (i = 0; i < array.length; i += 1) + { + octet = array[i]; - /* - * The 32-bit implementation of the NIST specified Ch function - * - * @private - * @param {Number} x The first 32-bit integer argument - * @param {Number} y The second 32-bit integer argument - * @param {Number} z The third 32-bit integer argument - * @return The NIST specified output of the function - */ - ch_32 = function(x, y, z) { - return (x & y) ^ (~x & z); - }, + offset = i >>> 2; + if (bin.length <= offset) + { + bin.push(0); + } + bin[offset] |= octet << (24 - (8 * (i % 4))); + } - /* - * The 64-bit implementation of the NIST specified Ch function - * - * @private - * @param {Int_64} x The first 64-bit integer argument - * @param {Int_64} y The second 64-bit integer argument - * @param {Int_64} z The third 64-bit integer argument - * @return The NIST specified output of the function - */ - ch_64 = function(x, y, z) { - return new Int_64( - (x.highOrder & y.highOrder) ^ (~x.highOrder & z.highOrder), (x.lowOrder & y.lowOrder) ^ (~x.lowOrder & z.lowOrder)); - }, + return {"value" : bin, "binLen" : array.length * 8}; + } - /* - * The 32-bit implementation of the NIST specified Maj function - * - * @private - * @param {Number} x The first 32-bit integer argument - * @param {Number} y The second 32-bit integer argument - * @param {Number} z The third 32-bit integer argument - * @return The NIST specified output of the function - */ - maj_32 = function(x, y, z) { - return (x & y) ^ (x & z) ^ (y & z); - }, + /** + * Convert a base-64 string to an array of big-endian words + * + * @private + * @param {string} str String to be converted to binary representation + * @return {{value : Array., binLen : number}} Hash list where + * "value" contains the output number array and "binLen" is the binary + * length of "value" + */ + function b642binb(str) + { + var retVal = [], byteCnt = 0, index, i, j, tmpInt, strPart, firstEqual, offset, + b64Tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - /* - * The 64-bit implementation of the NIST specified Maj function - * - * @private - * @param {Int_64} x The first 64-bit integer argument - * @param {Int_64} y The second 64-bit integer argument - * @param {Int_64} z The third 64-bit integer argument - * @return The NIST specified output of the function - */ - maj_64 = function(x, y, z) { - return new Int_64( - (x.highOrder & y.highOrder) ^ - (x.highOrder & z.highOrder) ^ - (y.highOrder & z.highOrder), (x.lowOrder & y.lowOrder) ^ - (x.lowOrder & z.lowOrder) ^ - (y.lowOrder & z.lowOrder)); - }, + if (-1 === str.search(/^[a-zA-Z0-9=+\/]+$/)) + { + throw "Invalid character in base-64 string"; + } + firstEqual = str.indexOf('='); + str = str.replace(/\=/g, ''); + if ((-1 !== firstEqual) && (firstEqual < str.length)) + { + throw "Invalid '=' found in base-64 string"; + } - /* - * The 32-bit implementation of the NIST specified Sigma0 function - * - * @private - * @param {Number} x The 32-bit integer argument - * @return The NIST specified output of the function - */ - sigma0_32 = function(x) { - return rotr_32(x, 2) ^ rotr_32(x, 13) ^ rotr_32(x, 22); - }, + for (i = 0; i < str.length; i += 4) + { + strPart = str.substr(i, 4); + tmpInt = 0; - /* - * The 64-bit implementation of the NIST specified Sigma0 function - * - * @private - * @param {Int_64} x The 64-bit integer argument - * @return The NIST specified output of the function - */ - sigma0_64 = function(x) { - var rotr28 = rotr_64(x, 28), - rotr34 = rotr_64(x, 34), - rotr39 = rotr_64(x, 39); + for (j = 0; j < strPart.length; j += 1) + { + index = b64Tab.indexOf(strPart[j]); + tmpInt |= index << (18 - (6 * j)); + } - return new Int_64( - rotr28.highOrder ^ rotr34.highOrder ^ rotr39.highOrder, - rotr28.lowOrder ^ rotr34.lowOrder ^ rotr39.lowOrder); - }, + for (j = 0; j < strPart.length - 1; j += 1) + { + offset = byteCnt >>> 2; + while (retVal.length <= offset) + { + retVal.push(0); + } + retVal[offset] |= ((tmpInt >>> (16 - (j * 8))) & 0xFF) << + (24 - (8 * (byteCnt % 4))); + byteCnt += 1; + } + } - /* - * The 32-bit implementation of the NIST specified Sigma1 function - * - * @private - * @param {Number} x The 32-bit integer argument - * @return The NIST specified output of the function - */ - sigma1_32 = function(x) { - return rotr_32(x, 6) ^ rotr_32(x, 11) ^ rotr_32(x, 25); - }, + return {"value" : retVal, "binLen" : byteCnt * 8}; + } - /* - * The 64-bit implementation of the NIST specified Sigma1 function - * - * @private - * @param {Int_64} x The 64-bit integer argument - * @return The NIST specified output of the function - */ - sigma1_64 = function(x) { - var rotr14 = rotr_64(x, 14), - rotr18 = rotr_64(x, 18), - rotr41 = rotr_64(x, 41); + /** + * Convert an array of big-endian words to a hex string. + * + * @private + * @param {Array.} binarray Array of integers to be converted to + * hexidecimal representation + * @param {{outputUpper : boolean, b64Pad : string}} formatOpts Hash list + * containing validated output formatting options + * @return {string} Hexidecimal representation of the parameter in string + * form + */ + function binb2hex(binarray, formatOpts) + { + var hex_tab = "0123456789abcdef", str = "", + length = binarray.length * 4, i, srcByte; - return new Int_64( - rotr14.highOrder ^ rotr18.highOrder ^ rotr41.highOrder, - rotr14.lowOrder ^ rotr18.lowOrder ^ rotr41.lowOrder); - }, + for (i = 0; i < length; i += 1) + { + /* The below is more than a byte but it gets taken care of later */ + srcByte = binarray[i >>> 2] >>> ((3 - (i % 4)) * 8); + str += hex_tab.charAt((srcByte >>> 4) & 0xF) + + hex_tab.charAt(srcByte & 0xF); + } - /* - * The 32-bit implementation of the NIST specified Gamma0 function - * - * @private - * @param {Number} x The 32-bit integer argument - * @return The NIST specified output of the function - */ - gamma0_32 = function(x) { - return rotr_32(x, 7) ^ rotr_32(x, 18) ^ shr_32(x, 3); - }, + return (formatOpts["outputUpper"]) ? str.toUpperCase() : str; + } - /* - * The 64-bit implementation of the NIST specified Gamma0 function - * - * @private - * @param {Int_64} x The 64-bit integer argument - * @return The NIST specified output of the function - */ - gamma0_64 = function(x) { - var rotr1 = rotr_64(x, 1), - rotr8 = rotr_64(x, 8), - shr7 = shr_64(x, 7); + /** + * Convert an array of big-endian words to a base-64 string + * + * @private + * @param {Array.} binarray Array of integers to be converted to + * base-64 representation + * @param {{outputUpper : boolean, b64Pad : string}} formatOpts Hash list + * containing validated output formatting options + * @return {string} Base-64 encoded representation of the parameter in + * string form + */ + function binb2b64(binarray, formatOpts) + { + var str = "", length = binarray.length * 4, i, j, triplet, offset, int1, int2, + b64Tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - return new Int_64( - rotr1.highOrder ^ rotr8.highOrder ^ shr7.highOrder, - rotr1.lowOrder ^ rotr8.lowOrder ^ shr7.lowOrder); - }, + for (i = 0; i < length; i += 3) + { + offset = (i + 1) >>> 2; + int1 = (binarray.length <= offset) ? 0 : binarray[offset]; + offset = (i + 2) >>> 2; + int2 = (binarray.length <= offset) ? 0 : binarray[offset]; + triplet = (((binarray[i >>> 2] >>> 8 * (3 - i % 4)) & 0xFF) << 16) | + (((int1 >>> 8 * (3 - (i + 1) % 4)) & 0xFF) << 8) | + ((int2 >>> 8 * (3 - (i + 2) % 4)) & 0xFF); + for (j = 0; j < 4; j += 1) + { + if (i * 8 + j * 6 <= binarray.length * 32) + { + str += b64Tab.charAt((triplet >>> 6 * (3 - j)) & 0x3F); + } + else + { + str += formatOpts["b64Pad"]; + } + } + } + return str; + } - /* - * The 32-bit implementation of the NIST specified Gamma1 function - * - * @private - * @param {Number} x The 32-bit integer argument - * @return The NIST specified output of the function - */ - gamma1_32 = function(x) { - return rotr_32(x, 17) ^ rotr_32(x, 19) ^ shr_32(x, 10); - }, + /** + * Convert an array of big-endian words to raw bytes string + * + * @private + * @param {Array.} binarray Array of integers to be converted to + * a raw bytes string representation + * @param {!Object} formatOpts Unused Hash list + * @return {string} Raw bytes representation of the parameter in string + * form + */ + function binb2bytes(binarray, formatOpts) + { + var str = "", length = binarray.length * 4, i, srcByte; - /* - * The 64-bit implementation of the NIST specified Gamma1 function - * - * @private - * @param {Int_64} x The 64-bit integer argument - * @return The NIST specified output of the function - */ - gamma1_64 = function(x) { - var rotr19 = rotr_64(x, 19), - rotr61 = rotr_64(x, 61), - shr6 = shr_64(x, 6); + for (i = 0; i < length; i += 1) + { + srcByte = (binarray[i >>> 2] >>> ((3 - (i % 4)) * 8)) & 0xFF; + str += String.fromCharCode(srcByte); + } - return new Int_64( - rotr19.highOrder ^ rotr61.highOrder ^ shr6.highOrder, - rotr19.lowOrder ^ rotr61.lowOrder ^ shr6.lowOrder); - }, + return str; + } - /* - * Add two 32-bit integers, wrapping at 2^32. This uses 16-bit operations - * internally to work around bugs in some JS interpreters. - * - * @private - * @param {Number} x The first 32-bit integer argument to be added - * @param {Number} y The second 32-bit integer argument to be added - * @return The sum of x + y - */ - safeAdd_32_2 = function(x, y) { - var lsw = (x & 0xFFFF) + (y & 0xFFFF), - msw = (x >>> 16) + (y >>> 16) + (lsw >>> 16); + /** + * Convert an array of big-endian words to raw bytes Uint8Array + * + * @private + * @param {Array.} binarray Array of integers to be converted to + * a raw bytes string representation + * @param {!Object} formatOpts Unused Hash list + * @return {Uint8Array} Raw bytes representation of the parameter + */ + function binb2typed(binarray, formatOpts) + { + var length = binarray.length * 4; + var arr = new Uint8Array(length), i; - return ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF); - }, + for (i = 0; i < length; i += 1) + { + arr[i] = (binarray[i >>> 2] >>> ((3 - (i % 4)) * 8)) & 0xFF; + } - /* - * Add four 32-bit integers, wrapping at 2^32. This uses 16-bit operations - * internally to work around bugs in some JS interpreters. - * - * @private - * @param {Number} a The first 32-bit integer argument to be added - * @param {Number} b The second 32-bit integer argument to be added - * @param {Number} c The third 32-bit integer argument to be added - * @param {Number} d The fourth 32-bit integer argument to be added - * @return The sum of a + b + c + d - */ - safeAdd_32_4 = function(a, b, c, d) { - var lsw = (a & 0xFFFF) + (b & 0xFFFF) + (c & 0xFFFF) + (d & 0xFFFF), - msw = (a >>> 16) + (b >>> 16) + (c >>> 16) + (d >>> 16) + - (lsw >>> 16); + return arr; + } - return ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF); - }, + /** + * Validate hash list containing output formatting options, ensuring + * presence of every option or adding the default value + * + * @private + * @param {{outputUpper : boolean, b64Pad : string}|undefined} outputOpts + * Hash list of output formatting options + * @return {{outputUpper : boolean, b64Pad : string}} Validated hash list + * containing output formatting options + */ + function getOutputOpts(outputOpts) + { + var retVal = {"outputUpper" : false, "b64Pad" : "="}; - /* - * Add five 32-bit integers, wrapping at 2^32. This uses 16-bit operations - * internally to work around bugs in some JS interpreters. - * - * @private - * @param {Number} a The first 32-bit integer argument to be added - * @param {Number} b The second 32-bit integer argument to be added - * @param {Number} c The third 32-bit integer argument to be added - * @param {Number} d The fourth 32-bit integer argument to be added - * @param {Number} e The fifth 32-bit integer argument to be added - * @return The sum of a + b + c + d + e - */ - safeAdd_32_5 = function(a, b, c, d, e) { - var lsw = (a & 0xFFFF) + (b & 0xFFFF) + (c & 0xFFFF) + (d & 0xFFFF) + - (e & 0xFFFF), - msw = (a >>> 16) + (b >>> 16) + (c >>> 16) + (d >>> 16) + - (e >>> 16) + (lsw >>> 16); + try + { + if (outputOpts.hasOwnProperty("outputUpper")) + { + retVal["outputUpper"] = outputOpts["outputUpper"]; + } - return ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF); - }, + if (outputOpts.hasOwnProperty("b64Pad")) + { + retVal["b64Pad"] = outputOpts["b64Pad"]; + } + } + catch(ignore) + {} - /* - * Add two 64-bit integers, wrapping at 2^64. This uses 16-bit operations - * internally to work around bugs in some JS interpreters. - * - * @private - * @param {Int_64} x The first 64-bit integer argument to be added - * @param {Int_64} y The second 64-bit integer argument to be added - * @return The sum of x + y - */ - safeAdd_64_2 = function(x, y) { - var lsw, msw, lowOrder, highOrder; + if ("boolean" !== typeof(retVal["outputUpper"])) + { + throw "Invalid outputUpper formatting option"; + } - lsw = (x.lowOrder & 0xFFFF) + (y.lowOrder & 0xFFFF); - msw = (x.lowOrder >>> 16) + (y.lowOrder >>> 16) + (lsw >>> 16); - lowOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF); + if ("string" !== typeof(retVal["b64Pad"])) + { + throw "Invalid b64Pad formatting option"; + } - lsw = (x.highOrder & 0xFFFF) + (y.highOrder & 0xFFFF) + (msw >>> 16); - msw = (x.highOrder >>> 16) + (y.highOrder >>> 16) + (lsw >>> 16); - highOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF); + return retVal; + } - return new Int_64(highOrder, lowOrder); - }, + /** + * The 32-bit implementation of circular rotate left + * + * @private + * @param {number} x The 32-bit integer argument + * @param {number} n The number of bits to shift + * @return {number} The x shifted circularly by n bits + */ + function rotl_32(x, n) + { + return (x << n) | (x >>> (32 - n)); + } - /* - * Add four 64-bit integers, wrapping at 2^64. This uses 16-bit operations - * internally to work around bugs in some JS interpreters. - * - * @private - * @param {Int_64} a The first 64-bit integer argument to be added - * @param {Int_64} b The second 64-bit integer argument to be added - * @param {Int_64} c The third 64-bit integer argument to be added - * @param {Int_64} d The fouth 64-bit integer argument to be added - * @return The sum of a + b + c + d - */ - safeAdd_64_4 = function(a, b, c, d) { - var lsw, msw, lowOrder, highOrder; + /** + * The 32-bit implementation of circular rotate right + * + * @private + * @param {number} x The 32-bit integer argument + * @param {number} n The number of bits to shift + * @return {number} The x shifted circularly by n bits + */ + function rotr_32(x, n) + { + return (x >>> n) | (x << (32 - n)); + } - lsw = (a.lowOrder & 0xFFFF) + (b.lowOrder & 0xFFFF) + - (c.lowOrder & 0xFFFF) + (d.lowOrder & 0xFFFF); - msw = (a.lowOrder >>> 16) + (b.lowOrder >>> 16) + - (c.lowOrder >>> 16) + (d.lowOrder >>> 16) + (lsw >>> 16); - lowOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF); + /** + * The 64-bit implementation of circular rotate right + * + * @private + * @param {Int_64} x The 64-bit integer argument + * @param {number} n The number of bits to shift + * @return {Int_64} The x shifted circularly by n bits + */ + function rotr_64(x, n) + { + var retVal = null, tmp = new Int_64(x.highOrder, x.lowOrder); - lsw = (a.highOrder & 0xFFFF) + (b.highOrder & 0xFFFF) + - (c.highOrder & 0xFFFF) + (d.highOrder & 0xFFFF) + (msw >>> 16); - msw = (a.highOrder >>> 16) + (b.highOrder >>> 16) + - (c.highOrder >>> 16) + (d.highOrder >>> 16) + (lsw >>> 16); - highOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF); + if (32 >= n) + { + retVal = new Int_64( + (tmp.highOrder >>> n) | ((tmp.lowOrder << (32 - n)) & 0xFFFFFFFF), + (tmp.lowOrder >>> n) | ((tmp.highOrder << (32 - n)) & 0xFFFFFFFF) + ); + } + else + { + retVal = new Int_64( + (tmp.lowOrder >>> (n - 32)) | ((tmp.highOrder << (64 - n)) & 0xFFFFFFFF), + (tmp.highOrder >>> (n - 32)) | ((tmp.lowOrder << (64 - n)) & 0xFFFFFFFF) + ); + } - return new Int_64(highOrder, lowOrder); - }, + return retVal; + } - /* - * Add five 64-bit integers, wrapping at 2^64. This uses 16-bit operations - * internally to work around bugs in some JS interpreters. - * - * @private - * @param {Int_64} a The first 64-bit integer argument to be added - * @param {Int_64} b The second 64-bit integer argument to be added - * @param {Int_64} c The third 64-bit integer argument to be added - * @param {Int_64} d The fouth 64-bit integer argument to be added - * @param {Int_64} e The fouth 64-bit integer argument to be added - * @return The sum of a + b + c + d + e - */ - safeAdd_64_5 = function(a, b, c, d, e) { - var lsw, msw, lowOrder, highOrder; + /** + * The 32-bit implementation of shift right + * + * @private + * @param {number} x The 32-bit integer argument + * @param {number} n The number of bits to shift + * @return {number} The x shifted by n bits + */ + function shr_32(x, n) + { + return x >>> n; + } - lsw = (a.lowOrder & 0xFFFF) + (b.lowOrder & 0xFFFF) + - (c.lowOrder & 0xFFFF) + (d.lowOrder & 0xFFFF) + - (e.lowOrder & 0xFFFF); - msw = (a.lowOrder >>> 16) + (b.lowOrder >>> 16) + - (c.lowOrder >>> 16) + (d.lowOrder >>> 16) + (e.lowOrder >>> 16) + - (lsw >>> 16); - lowOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF); + /** + * The 64-bit implementation of shift right + * + * @private + * @param {Int_64} x The 64-bit integer argument + * @param {number} n The number of bits to shift + * @return {Int_64} The x shifted by n bits + */ + function shr_64(x, n) + { + var retVal = null; - lsw = (a.highOrder & 0xFFFF) + (b.highOrder & 0xFFFF) + - (c.highOrder & 0xFFFF) + (d.highOrder & 0xFFFF) + - (e.highOrder & 0xFFFF) + (msw >>> 16); - msw = (a.highOrder >>> 16) + (b.highOrder >>> 16) + - (c.highOrder >>> 16) + (d.highOrder >>> 16) + - (e.highOrder >>> 16) + (lsw >>> 16); - highOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF); + if (32 >= n) + { + retVal = new Int_64( + x.highOrder >>> n, + x.lowOrder >>> n | ((x.highOrder << (32 - n)) & 0xFFFFFFFF) + ); + } + else + { + retVal = new Int_64( + 0, + x.highOrder >>> (n - 32) + ); + } - return new Int_64(highOrder, lowOrder); - }, + return retVal; + } - /* - * Calculates the SHA-1 hash of the string set at instantiation - * - * @private - * @param {Array} message The binary array representation of the string to - * hash - * @param {Number} messageLen The number of bits in the message - * @return The array of integers representing the SHA-1 hash of message - */ - coreSHA1 = function(message, messageLen) { - var W = [], - a, b, c, d, e, T, ch = ch_32, - parity = parity_32, - maj = maj_32, - rotl = rotl_32, - safeAdd_2 = safeAdd_32_2, - i, t, - safeAdd_5 = safeAdd_32_5, - appendedMessageLength, - H = [ - 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0 - ], - K = [ - 0x5a827999, 0x5a827999, 0x5a827999, 0x5a827999, - 0x5a827999, 0x5a827999, 0x5a827999, 0x5a827999, - 0x5a827999, 0x5a827999, 0x5a827999, 0x5a827999, - 0x5a827999, 0x5a827999, 0x5a827999, 0x5a827999, - 0x5a827999, 0x5a827999, 0x5a827999, 0x5a827999, - 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, - 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, - 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, - 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, - 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, - 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, - 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, - 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, - 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, - 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, - 0xca62c1d6, 0xca62c1d6, 0xca62c1d6, 0xca62c1d6, - 0xca62c1d6, 0xca62c1d6, 0xca62c1d6, 0xca62c1d6, - 0xca62c1d6, 0xca62c1d6, 0xca62c1d6, 0xca62c1d6, - 0xca62c1d6, 0xca62c1d6, 0xca62c1d6, 0xca62c1d6, - 0xca62c1d6, 0xca62c1d6, 0xca62c1d6, 0xca62c1d6 - ]; + /** + * The 32-bit implementation of the NIST specified Parity function + * + * @private + * @param {number} x The first 32-bit integer argument + * @param {number} y The second 32-bit integer argument + * @param {number} z The third 32-bit integer argument + * @return {number} The NIST specified output of the function + */ + function parity_32(x, y, z) + { + return x ^ y ^ z; + } - /* Append '1' at the end of the binary string */ - message[messageLen >> 5] |= 0x80 << (24 - (messageLen % 32)); - /* Append length of binary string in the position such that the new + /** + * The 32-bit implementation of the NIST specified Ch function + * + * @private + * @param {number} x The first 32-bit integer argument + * @param {number} y The second 32-bit integer argument + * @param {number} z The third 32-bit integer argument + * @return {number} The NIST specified output of the function + */ + function ch_32(x, y, z) + { + return (x & y) ^ (~x & z); + } + + /** + * The 64-bit implementation of the NIST specified Ch function + * + * @private + * @param {Int_64} x The first 64-bit integer argument + * @param {Int_64} y The second 64-bit integer argument + * @param {Int_64} z The third 64-bit integer argument + * @return {Int_64} The NIST specified output of the function + */ + function ch_64(x, y, z) + { + return new Int_64( + (x.highOrder & y.highOrder) ^ (~x.highOrder & z.highOrder), + (x.lowOrder & y.lowOrder) ^ (~x.lowOrder & z.lowOrder) + ); + } + + /** + * The 32-bit implementation of the NIST specified Maj function + * + * @private + * @param {number} x The first 32-bit integer argument + * @param {number} y The second 32-bit integer argument + * @param {number} z The third 32-bit integer argument + * @return {number} The NIST specified output of the function + */ + function maj_32(x, y, z) + { + return (x & y) ^ (x & z) ^ (y & z); + } + + /** + * The 64-bit implementation of the NIST specified Maj function + * + * @private + * @param {Int_64} x The first 64-bit integer argument + * @param {Int_64} y The second 64-bit integer argument + * @param {Int_64} z The third 64-bit integer argument + * @return {Int_64} The NIST specified output of the function + */ + function maj_64(x, y, z) + { + return new Int_64( + (x.highOrder & y.highOrder) ^ + (x.highOrder & z.highOrder) ^ + (y.highOrder & z.highOrder), + (x.lowOrder & y.lowOrder) ^ + (x.lowOrder & z.lowOrder) ^ + (y.lowOrder & z.lowOrder) + ); + } + + /** + * The 32-bit implementation of the NIST specified Sigma0 function + * + * @private + * @param {number} x The 32-bit integer argument + * @return {number} The NIST specified output of the function + */ + function sigma0_32(x) + { + return rotr_32(x, 2) ^ rotr_32(x, 13) ^ rotr_32(x, 22); + } + + /** + * The 64-bit implementation of the NIST specified Sigma0 function + * + * @private + * @param {Int_64} x The 64-bit integer argument + * @return {Int_64} The NIST specified output of the function + */ + function sigma0_64(x) + { + var rotr28 = rotr_64(x, 28), rotr34 = rotr_64(x, 34), + rotr39 = rotr_64(x, 39); + + return new Int_64( + rotr28.highOrder ^ rotr34.highOrder ^ rotr39.highOrder, + rotr28.lowOrder ^ rotr34.lowOrder ^ rotr39.lowOrder); + } + + /** + * The 32-bit implementation of the NIST specified Sigma1 function + * + * @private + * @param {number} x The 32-bit integer argument + * @return {number} The NIST specified output of the function + */ + function sigma1_32(x) + { + return rotr_32(x, 6) ^ rotr_32(x, 11) ^ rotr_32(x, 25); + } + + /** + * The 64-bit implementation of the NIST specified Sigma1 function + * + * @private + * @param {Int_64} x The 64-bit integer argument + * @return {Int_64} The NIST specified output of the function + */ + function sigma1_64(x) + { + var rotr14 = rotr_64(x, 14), rotr18 = rotr_64(x, 18), + rotr41 = rotr_64(x, 41); + + return new Int_64( + rotr14.highOrder ^ rotr18.highOrder ^ rotr41.highOrder, + rotr14.lowOrder ^ rotr18.lowOrder ^ rotr41.lowOrder); + } + + /** + * The 32-bit implementation of the NIST specified Gamma0 function + * + * @private + * @param {number} x The 32-bit integer argument + * @return {number} The NIST specified output of the function + */ + function gamma0_32(x) + { + return rotr_32(x, 7) ^ rotr_32(x, 18) ^ shr_32(x, 3); + } + + /** + * The 64-bit implementation of the NIST specified Gamma0 function + * + * @private + * @param {Int_64} x The 64-bit integer argument + * @return {Int_64} The NIST specified output of the function + */ + function gamma0_64(x) + { + var rotr1 = rotr_64(x, 1), rotr8 = rotr_64(x, 8), shr7 = shr_64(x, 7); + + return new Int_64( + rotr1.highOrder ^ rotr8.highOrder ^ shr7.highOrder, + rotr1.lowOrder ^ rotr8.lowOrder ^ shr7.lowOrder + ); + } + + /** + * The 32-bit implementation of the NIST specified Gamma1 function + * + * @private + * @param {number} x The 32-bit integer argument + * @return {number} The NIST specified output of the function + */ + function gamma1_32(x) + { + return rotr_32(x, 17) ^ rotr_32(x, 19) ^ shr_32(x, 10); + } + + /** + * The 64-bit implementation of the NIST specified Gamma1 function + * + * @private + * @param {Int_64} x The 64-bit integer argument + * @return {Int_64} The NIST specified output of the function + */ + function gamma1_64(x) + { + var rotr19 = rotr_64(x, 19), rotr61 = rotr_64(x, 61), + shr6 = shr_64(x, 6); + + return new Int_64( + rotr19.highOrder ^ rotr61.highOrder ^ shr6.highOrder, + rotr19.lowOrder ^ rotr61.lowOrder ^ shr6.lowOrder + ); + } + + /** + * Add two 32-bit integers, wrapping at 2^32. This uses 16-bit operations + * internally to work around bugs in some JS interpreters. + * + * @private + * @param {number} a The first 32-bit integer argument to be added + * @param {number} b The second 32-bit integer argument to be added + * @return {number} The sum of a + b + */ + function safeAdd_32_2(a, b) + { + var lsw = (a & 0xFFFF) + (b & 0xFFFF), + msw = (a >>> 16) + (b >>> 16) + (lsw >>> 16); + + return ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF); + } + + /** + * Add four 32-bit integers, wrapping at 2^32. This uses 16-bit operations + * internally to work around bugs in some JS interpreters. + * + * @private + * @param {number} a The first 32-bit integer argument to be added + * @param {number} b The second 32-bit integer argument to be added + * @param {number} c The third 32-bit integer argument to be added + * @param {number} d The fourth 32-bit integer argument to be added + * @return {number} The sum of a + b + c + d + */ + function safeAdd_32_4(a, b, c, d) + { + var lsw = (a & 0xFFFF) + (b & 0xFFFF) + (c & 0xFFFF) + (d & 0xFFFF), + msw = (a >>> 16) + (b >>> 16) + (c >>> 16) + (d >>> 16) + + (lsw >>> 16); + + return ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF); + } + + /** + * Add five 32-bit integers, wrapping at 2^32. This uses 16-bit operations + * internally to work around bugs in some JS interpreters. + * + * @private + * @param {number} a The first 32-bit integer argument to be added + * @param {number} b The second 32-bit integer argument to be added + * @param {number} c The third 32-bit integer argument to be added + * @param {number} d The fourth 32-bit integer argument to be added + * @param {number} e The fifth 32-bit integer argument to be added + * @return {number} The sum of a + b + c + d + e + */ + function safeAdd_32_5(a, b, c, d, e) + { + var lsw = (a & 0xFFFF) + (b & 0xFFFF) + (c & 0xFFFF) + (d & 0xFFFF) + + (e & 0xFFFF), + msw = (a >>> 16) + (b >>> 16) + (c >>> 16) + (d >>> 16) + + (e >>> 16) + (lsw >>> 16); + + return ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF); + } + + /** + * Add two 64-bit integers, wrapping at 2^64. This uses 16-bit operations + * internally to work around bugs in some JS interpreters. + * + * @private + * @param {Int_64} x The first 64-bit integer argument to be added + * @param {Int_64} y The second 64-bit integer argument to be added + * @return {Int_64} The sum of x + y + */ + function safeAdd_64_2(x, y) + { + var lsw, msw, lowOrder, highOrder; + + lsw = (x.lowOrder & 0xFFFF) + (y.lowOrder & 0xFFFF); + msw = (x.lowOrder >>> 16) + (y.lowOrder >>> 16) + (lsw >>> 16); + lowOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF); + + lsw = (x.highOrder & 0xFFFF) + (y.highOrder & 0xFFFF) + (msw >>> 16); + msw = (x.highOrder >>> 16) + (y.highOrder >>> 16) + (lsw >>> 16); + highOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF); + + return new Int_64(highOrder, lowOrder); + } + + /** + * Add four 64-bit integers, wrapping at 2^64. This uses 16-bit operations + * internally to work around bugs in some JS interpreters. + * + * @private + * @param {Int_64} a The first 64-bit integer argument to be added + * @param {Int_64} b The second 64-bit integer argument to be added + * @param {Int_64} c The third 64-bit integer argument to be added + * @param {Int_64} d The fouth 64-bit integer argument to be added + * @return {Int_64} The sum of a + b + c + d + */ + function safeAdd_64_4(a, b, c, d) + { + var lsw, msw, lowOrder, highOrder; + + lsw = (a.lowOrder & 0xFFFF) + (b.lowOrder & 0xFFFF) + + (c.lowOrder & 0xFFFF) + (d.lowOrder & 0xFFFF); + msw = (a.lowOrder >>> 16) + (b.lowOrder >>> 16) + + (c.lowOrder >>> 16) + (d.lowOrder >>> 16) + (lsw >>> 16); + lowOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF); + + lsw = (a.highOrder & 0xFFFF) + (b.highOrder & 0xFFFF) + + (c.highOrder & 0xFFFF) + (d.highOrder & 0xFFFF) + (msw >>> 16); + msw = (a.highOrder >>> 16) + (b.highOrder >>> 16) + + (c.highOrder >>> 16) + (d.highOrder >>> 16) + (lsw >>> 16); + highOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF); + + return new Int_64(highOrder, lowOrder); + } + + /** + * Add five 64-bit integers, wrapping at 2^64. This uses 16-bit operations + * internally to work around bugs in some JS interpreters. + * + * @private + * @param {Int_64} a The first 64-bit integer argument to be added + * @param {Int_64} b The second 64-bit integer argument to be added + * @param {Int_64} c The third 64-bit integer argument to be added + * @param {Int_64} d The fouth 64-bit integer argument to be added + * @param {Int_64} e The fouth 64-bit integer argument to be added + * @return {Int_64} The sum of a + b + c + d + e + */ + function safeAdd_64_5(a, b, c, d, e) + { + var lsw, msw, lowOrder, highOrder; + + lsw = (a.lowOrder & 0xFFFF) + (b.lowOrder & 0xFFFF) + + (c.lowOrder & 0xFFFF) + (d.lowOrder & 0xFFFF) + + (e.lowOrder & 0xFFFF); + msw = (a.lowOrder >>> 16) + (b.lowOrder >>> 16) + + (c.lowOrder >>> 16) + (d.lowOrder >>> 16) + (e.lowOrder >>> 16) + + (lsw >>> 16); + lowOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF); + + lsw = (a.highOrder & 0xFFFF) + (b.highOrder & 0xFFFF) + + (c.highOrder & 0xFFFF) + (d.highOrder & 0xFFFF) + + (e.highOrder & 0xFFFF) + (msw >>> 16); + msw = (a.highOrder >>> 16) + (b.highOrder >>> 16) + + (c.highOrder >>> 16) + (d.highOrder >>> 16) + + (e.highOrder >>> 16) + (lsw >>> 16); + highOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF); + + return new Int_64(highOrder, lowOrder); + } + + /** + * Calculates the SHA-1 hash of the string set at instantiation + * + * @private + * @param {Array.} message The binary array representation of the + * string to hash + * @param {number} messageLen The number of bits in the message + * @return {Array.} The array of integers representing the SHA-1 + * hash of message + */ + function coreSHA1(message, messageLen) + { + var W = [], a, b, c, d, e, T, ch = ch_32, parity = parity_32, + maj = maj_32, rotl = rotl_32, safeAdd_2 = safeAdd_32_2, i, t, + safeAdd_5 = safeAdd_32_5, appendedMessageLength, offset, + H = [ + 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0 + ]; + + offset = (((messageLen + 65) >>> 9) << 4) + 15; + while (message.length <= offset) + { + message.push(0); + } + /* Append '1' at the end of the binary string */ + message[messageLen >>> 5] |= 0x80 << (24 - (messageLen % 32)); + /* Append length of binary string in the position such that the new length is a multiple of 512. Logic does not work for even multiples of 512 but there can never be even multiples of 512 */ - message[(((messageLen + 65) >> 9) << 4) + 15] = messageLen; + message[offset] = messageLen; - appendedMessageLength = message.length; + appendedMessageLength = message.length; - for (i = 0; i < appendedMessageLength; i += 16) { - a = H[0]; - b = H[1]; - c = H[2]; - d = H[3]; - e = H[4]; + for (i = 0; i < appendedMessageLength; i += 16) + { + a = H[0]; + b = H[1]; + c = H[2]; + d = H[3]; + e = H[4]; - for (t = 0; t < 80; t += 1) { - if (t < 16) { - W[t] = message[t + i]; - } else { - W[t] = rotl(W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16], 1); - } + for (t = 0; t < 80; t += 1) + { + if (t < 16) + { + W[t] = message[t + i]; + } + else + { + W[t] = rotl(W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16], 1); + } - if (t < 20) { - T = safeAdd_5(rotl(a, 5), ch(b, c, d), e, K[t], W[t]); - } else if (t < 40) { - T = safeAdd_5(rotl(a, 5), parity(b, c, d), e, K[t], W[t]); - } else if (t < 60) { - T = safeAdd_5(rotl(a, 5), maj(b, c, d), e, K[t], W[t]); - } else { - T = safeAdd_5(rotl(a, 5), parity(b, c, d), e, K[t], W[t]); - } + if (t < 20) + { + T = safeAdd_5(rotl(a, 5), ch(b, c, d), e, 0x5a827999, W[t]); + } + else if (t < 40) + { + T = safeAdd_5(rotl(a, 5), parity(b, c, d), e, 0x6ed9eba1, W[t]); + } + else if (t < 60) + { + T = safeAdd_5(rotl(a, 5), maj(b, c, d), e, 0x8f1bbcdc, W[t]); + } else { + T = safeAdd_5(rotl(a, 5), parity(b, c, d), e, 0xca62c1d6, W[t]); + } - e = d; - d = c; - c = rotl(b, 30); - b = a; - a = T; - } + e = d; + d = c; + c = rotl(b, 30); + b = a; + a = T; + } - H[0] = safeAdd_2(a, H[0]); - H[1] = safeAdd_2(b, H[1]); - H[2] = safeAdd_2(c, H[2]); - H[3] = safeAdd_2(d, H[3]); - H[4] = safeAdd_2(e, H[4]); - } + H[0] = safeAdd_2(a, H[0]); + H[1] = safeAdd_2(b, H[1]); + H[2] = safeAdd_2(c, H[2]); + H[3] = safeAdd_2(d, H[3]); + H[4] = safeAdd_2(e, H[4]); + } - return H; - }, + return H; + } - /* - * Calculates the desired SHA-2 hash of the string set at instantiation - * - * @private - * @param {Array} The binary array representation of the string to hash - * @param {Number} The number of bits in message - * @param {String} variant The desired SHA-2 variant - * @return The array of integers representing the SHA-2 hash of message - */ - coreSHA2 = function(message, messageLen, variant) { - var a, b, c, d, e, f, g, h, T1, T2, H, numRounds, lengthPosition, i, t, - binaryStringInc, binaryStringMult, safeAdd_2, safeAdd_4, safeAdd_5, - gamma0, gamma1, sigma0, sigma1, ch, maj, Int, K, W = [], - appendedMessageLength; + /** + * Calculates the desired SHA-2 hash of the string set at instantiation + * + * @private + * @param {Array.} message The binary array representation of the + * string to hash + * @param {number} messageLen The number of bits in message + * @param {string} variant The desired SHA-2 variant + * @return {Array.} The array of integers representing the SHA-2 + * hash of message + */ + function coreSHA2(message, messageLen, variant) + { + var a, b, c, d, e, f, g, h, T1, T2, H, numRounds, lengthPosition, i, t, + binaryStringInc, binaryStringMult, safeAdd_2, safeAdd_4, safeAdd_5, + gamma0, gamma1, sigma0, sigma1, ch, maj, Int, W = [], int1, int2, offset, + appendedMessageLength, retVal, + K = [ + 0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5, + 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5, + 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3, + 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174, + 0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC, + 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA, + 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7, + 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967, + 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13, + 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85, + 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3, + 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070, + 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5, + 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3, + 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208, + 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2 + ], + H_trunc = [ + 0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, + 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4 + ], + H_full = [ + 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, + 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19 + ]; - /* Set up the various function handles and variable for the specific - * variant */ - if (variant === "SHA-224" || variant === "SHA-256") { - /* 32-bit variant */ - numRounds = 64; - lengthPosition = (((messageLen + 65) >> 9) << 4) + 15; - binaryStringInc = 16; - binaryStringMult = 1; - Int = Number; - safeAdd_2 = safeAdd_32_2; - safeAdd_4 = safeAdd_32_4; - safeAdd_5 = safeAdd_32_5; - gamma0 = gamma0_32; - gamma1 = gamma1_32; - sigma0 = sigma0_32; - sigma1 = sigma1_32; - maj = maj_32; - ch = ch_32; - K = [ - 0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5, - 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5, - 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3, - 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174, - 0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC, - 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA, - 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7, - 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967, - 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13, - 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85, - 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3, - 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070, - 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5, - 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3, - 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208, - 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2 - ]; + /* Set up the various function handles and variable for the specific + * variant */ + if ((variant === "SHA-224" || variant === "SHA-256") && + (2 & SUPPORTED_ALGS)) + { + /* 32-bit variant */ + numRounds = 64; + lengthPosition = (((messageLen + 65) >>> 9) << 4) + 15; + binaryStringInc = 16; + binaryStringMult = 1; + Int = Number; + safeAdd_2 = safeAdd_32_2; + safeAdd_4 = safeAdd_32_4; + safeAdd_5 = safeAdd_32_5; + gamma0 = gamma0_32; + gamma1 = gamma1_32; + sigma0 = sigma0_32; + sigma1 = sigma1_32; + maj = maj_32; + ch = ch_32; - if (variant === "SHA-224") { - H = [ - 0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, - 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4 - ]; - } else { - H = [ - 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, - 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19 - ]; - } - } else if (variant === "SHA-384" || variant === "SHA-512") { - /* 64-bit variant */ - numRounds = 80; - lengthPosition = (((messageLen + 128) >> 10) << 5) + 31; - binaryStringInc = 32; - binaryStringMult = 2; - Int = Int_64; - safeAdd_2 = safeAdd_64_2; - safeAdd_4 = safeAdd_64_4; - safeAdd_5 = safeAdd_64_5; - gamma0 = gamma0_64; - gamma1 = gamma1_64; - sigma0 = sigma0_64; - sigma1 = sigma1_64; - maj = maj_64; - ch = ch_64; + if ("SHA-224" === variant) + { + H = H_trunc; + } + else /* "SHA-256" === variant */ + { + H = H_full; + } + } + else if ((variant === "SHA-384" || variant === "SHA-512") && + (4 & SUPPORTED_ALGS)) + { + /* 64-bit variant */ + numRounds = 80; + lengthPosition = (((messageLen + 128) >>> 10) << 5) + 31; + binaryStringInc = 32; + binaryStringMult = 2; + Int = Int_64; + safeAdd_2 = safeAdd_64_2; + safeAdd_4 = safeAdd_64_4; + safeAdd_5 = safeAdd_64_5; + gamma0 = gamma0_64; + gamma1 = gamma1_64; + sigma0 = sigma0_64; + sigma1 = sigma1_64; + maj = maj_64; + ch = ch_64; - K = [ - new Int(0x428a2f98, 0xd728ae22), new Int(0x71374491, 0x23ef65cd), - new Int(0xb5c0fbcf, 0xec4d3b2f), new Int(0xe9b5dba5, 0x8189dbbc), - new Int(0x3956c25b, 0xf348b538), new Int(0x59f111f1, 0xb605d019), - new Int(0x923f82a4, 0xaf194f9b), new Int(0xab1c5ed5, 0xda6d8118), - new Int(0xd807aa98, 0xa3030242), new Int(0x12835b01, 0x45706fbe), - new Int(0x243185be, 0x4ee4b28c), new Int(0x550c7dc3, 0xd5ffb4e2), - new Int(0x72be5d74, 0xf27b896f), new Int(0x80deb1fe, 0x3b1696b1), - new Int(0x9bdc06a7, 0x25c71235), new Int(0xc19bf174, 0xcf692694), - new Int(0xe49b69c1, 0x9ef14ad2), new Int(0xefbe4786, 0x384f25e3), - new Int(0x0fc19dc6, 0x8b8cd5b5), new Int(0x240ca1cc, 0x77ac9c65), - new Int(0x2de92c6f, 0x592b0275), new Int(0x4a7484aa, 0x6ea6e483), - new Int(0x5cb0a9dc, 0xbd41fbd4), new Int(0x76f988da, 0x831153b5), - new Int(0x983e5152, 0xee66dfab), new Int(0xa831c66d, 0x2db43210), - new Int(0xb00327c8, 0x98fb213f), new Int(0xbf597fc7, 0xbeef0ee4), - new Int(0xc6e00bf3, 0x3da88fc2), new Int(0xd5a79147, 0x930aa725), - new Int(0x06ca6351, 0xe003826f), new Int(0x14292967, 0x0a0e6e70), - new Int(0x27b70a85, 0x46d22ffc), new Int(0x2e1b2138, 0x5c26c926), - new Int(0x4d2c6dfc, 0x5ac42aed), new Int(0x53380d13, 0x9d95b3df), - new Int(0x650a7354, 0x8baf63de), new Int(0x766a0abb, 0x3c77b2a8), - new Int(0x81c2c92e, 0x47edaee6), new Int(0x92722c85, 0x1482353b), - new Int(0xa2bfe8a1, 0x4cf10364), new Int(0xa81a664b, 0xbc423001), - new Int(0xc24b8b70, 0xd0f89791), new Int(0xc76c51a3, 0x0654be30), - new Int(0xd192e819, 0xd6ef5218), new Int(0xd6990624, 0x5565a910), - new Int(0xf40e3585, 0x5771202a), new Int(0x106aa070, 0x32bbd1b8), - new Int(0x19a4c116, 0xb8d2d0c8), new Int(0x1e376c08, 0x5141ab53), - new Int(0x2748774c, 0xdf8eeb99), new Int(0x34b0bcb5, 0xe19b48a8), - new Int(0x391c0cb3, 0xc5c95a63), new Int(0x4ed8aa4a, 0xe3418acb), - new Int(0x5b9cca4f, 0x7763e373), new Int(0x682e6ff3, 0xd6b2b8a3), - new Int(0x748f82ee, 0x5defb2fc), new Int(0x78a5636f, 0x43172f60), - new Int(0x84c87814, 0xa1f0ab72), new Int(0x8cc70208, 0x1a6439ec), - new Int(0x90befffa, 0x23631e28), new Int(0xa4506ceb, 0xde82bde9), - new Int(0xbef9a3f7, 0xb2c67915), new Int(0xc67178f2, 0xe372532b), - new Int(0xca273ece, 0xea26619c), new Int(0xd186b8c7, 0x21c0c207), - new Int(0xeada7dd6, 0xcde0eb1e), new Int(0xf57d4f7f, 0xee6ed178), - new Int(0x06f067aa, 0x72176fba), new Int(0x0a637dc5, 0xa2c898a6), - new Int(0x113f9804, 0xbef90dae), new Int(0x1b710b35, 0x131c471b), - new Int(0x28db77f5, 0x23047d84), new Int(0x32caab7b, 0x40c72493), - new Int(0x3c9ebe0a, 0x15c9bebc), new Int(0x431d67c4, 0x9c100d4c), - new Int(0x4cc5d4be, 0xcb3e42b6), new Int(0x597f299c, 0xfc657e2a), - new Int(0x5fcb6fab, 0x3ad6faec), new Int(0x6c44198c, 0x4a475817) - ]; + K = [ + new Int(K[ 0], 0xd728ae22), new Int(K[ 1], 0x23ef65cd), + new Int(K[ 2], 0xec4d3b2f), new Int(K[ 3], 0x8189dbbc), + new Int(K[ 4], 0xf348b538), new Int(K[ 5], 0xb605d019), + new Int(K[ 6], 0xaf194f9b), new Int(K[ 7], 0xda6d8118), + new Int(K[ 8], 0xa3030242), new Int(K[ 9], 0x45706fbe), + new Int(K[10], 0x4ee4b28c), new Int(K[11], 0xd5ffb4e2), + new Int(K[12], 0xf27b896f), new Int(K[13], 0x3b1696b1), + new Int(K[14], 0x25c71235), new Int(K[15], 0xcf692694), + new Int(K[16], 0x9ef14ad2), new Int(K[17], 0x384f25e3), + new Int(K[18], 0x8b8cd5b5), new Int(K[19], 0x77ac9c65), + new Int(K[20], 0x592b0275), new Int(K[21], 0x6ea6e483), + new Int(K[22], 0xbd41fbd4), new Int(K[23], 0x831153b5), + new Int(K[24], 0xee66dfab), new Int(K[25], 0x2db43210), + new Int(K[26], 0x98fb213f), new Int(K[27], 0xbeef0ee4), + new Int(K[28], 0x3da88fc2), new Int(K[29], 0x930aa725), + new Int(K[30], 0xe003826f), new Int(K[31], 0x0a0e6e70), + new Int(K[32], 0x46d22ffc), new Int(K[33], 0x5c26c926), + new Int(K[34], 0x5ac42aed), new Int(K[35], 0x9d95b3df), + new Int(K[36], 0x8baf63de), new Int(K[37], 0x3c77b2a8), + new Int(K[38], 0x47edaee6), new Int(K[39], 0x1482353b), + new Int(K[40], 0x4cf10364), new Int(K[41], 0xbc423001), + new Int(K[42], 0xd0f89791), new Int(K[43], 0x0654be30), + new Int(K[44], 0xd6ef5218), new Int(K[45], 0x5565a910), + new Int(K[46], 0x5771202a), new Int(K[47], 0x32bbd1b8), + new Int(K[48], 0xb8d2d0c8), new Int(K[49], 0x5141ab53), + new Int(K[50], 0xdf8eeb99), new Int(K[51], 0xe19b48a8), + new Int(K[52], 0xc5c95a63), new Int(K[53], 0xe3418acb), + new Int(K[54], 0x7763e373), new Int(K[55], 0xd6b2b8a3), + new Int(K[56], 0x5defb2fc), new Int(K[57], 0x43172f60), + new Int(K[58], 0xa1f0ab72), new Int(K[59], 0x1a6439ec), + new Int(K[60], 0x23631e28), new Int(K[61], 0xde82bde9), + new Int(K[62], 0xb2c67915), new Int(K[63], 0xe372532b), + new Int(0xca273ece, 0xea26619c), new Int(0xd186b8c7, 0x21c0c207), + new Int(0xeada7dd6, 0xcde0eb1e), new Int(0xf57d4f7f, 0xee6ed178), + new Int(0x06f067aa, 0x72176fba), new Int(0x0a637dc5, 0xa2c898a6), + new Int(0x113f9804, 0xbef90dae), new Int(0x1b710b35, 0x131c471b), + new Int(0x28db77f5, 0x23047d84), new Int(0x32caab7b, 0x40c72493), + new Int(0x3c9ebe0a, 0x15c9bebc), new Int(0x431d67c4, 0x9c100d4c), + new Int(0x4cc5d4be, 0xcb3e42b6), new Int(0x597f299c, 0xfc657e2a), + new Int(0x5fcb6fab, 0x3ad6faec), new Int(0x6c44198c, 0x4a475817) + ]; - if (variant === "SHA-384") { - H = [ - new Int(0xcbbb9d5d, 0xc1059ed8), new Int(0x0629a292a, 0x367cd507), - new Int(0x9159015a, 0x3070dd17), new Int(0x0152fecd8, 0xf70e5939), - new Int(0x67332667, 0xffc00b31), new Int(0x98eb44a87, 0x68581511), - new Int(0xdb0c2e0d, 0x64f98fa7), new Int(0x047b5481d, 0xbefa4fa4) - ]; - } else { - H = [ - new Int(0x6a09e667, 0xf3bcc908), new Int(0xbb67ae85, 0x84caa73b), - new Int(0x3c6ef372, 0xfe94f82b), new Int(0xa54ff53a, 0x5f1d36f1), - new Int(0x510e527f, 0xade682d1), new Int(0x9b05688c, 0x2b3e6c1f), - new Int(0x1f83d9ab, 0xfb41bd6b), new Int(0x5be0cd19, 0x137e2179) - ]; - } - } + if ("SHA-384" === variant) + { + H = [ + new Int(0xcbbb9d5d, H_trunc[0]), new Int(0x0629a292a, H_trunc[1]), + new Int(0x9159015a, H_trunc[2]), new Int(0x0152fecd8, H_trunc[3]), + new Int(0x67332667, H_trunc[4]), new Int(0x98eb44a87, H_trunc[5]), + new Int(0xdb0c2e0d, H_trunc[6]), new Int(0x047b5481d, H_trunc[7]) + ]; + } + else /* "SHA-512" === variant */ + { + H = [ + new Int(H_full[0], 0xf3bcc908), new Int(H_full[1], 0x84caa73b), + new Int(H_full[2], 0xfe94f82b), new Int(H_full[3], 0x5f1d36f1), + new Int(H_full[4], 0xade682d1), new Int(H_full[5], 0x2b3e6c1f), + new Int(H_full[6], 0xfb41bd6b), new Int(H_full[7], 0x137e2179) + ]; + } + } + else + { + throw "Unexpected error in SHA-2 implementation"; + } - /* Append '1' at the end of the binary string */ - message[messageLen >> 5] |= 0x80 << (24 - messageLen % 32); - /* Append length of binary string in the position such that the new - * length is correct */ - message[lengthPosition] = messageLen; + while (message.length <= lengthPosition) + { + message.push(0); + } + /* Append '1' at the end of the binary string */ + message[messageLen >>> 5] |= 0x80 << (24 - messageLen % 32); + /* Append length of binary string in the position such that the new + * length is correct */ + message[lengthPosition] = messageLen; - appendedMessageLength = message.length; + appendedMessageLength = message.length; - for (i = 0; i < appendedMessageLength; i += binaryStringInc) { - a = H[0]; - b = H[1]; - c = H[2]; - d = H[3]; - e = H[4]; - f = H[5]; - g = H[6]; - h = H[7]; + for (i = 0; i < appendedMessageLength; i += binaryStringInc) + { + a = H[0]; + b = H[1]; + c = H[2]; + d = H[3]; + e = H[4]; + f = H[5]; + g = H[6]; + h = H[7]; - for (t = 0; t < numRounds; t += 1) { - if (t < 16) { - /* Bit of a hack - for 32-bit, the second term is ignored */ - W[t] = new Int(message[t * binaryStringMult + i], - message[t * binaryStringMult + i + 1]); - } else { - W[t] = safeAdd_4( - gamma1(W[t - 2]), W[t - 7], - gamma0(W[t - 15]), W[t - 16]); - } + for (t = 0; t < numRounds; t += 1) + { + if (t < 16) + { + offset = t * binaryStringMult + i; + int1 = (message.length <= offset) ? 0 : message[offset]; + int2 = (message.length <= offset + 1) ? 0 : message[offset + 1]; + /* Bit of a hack - for 32-bit, the second term is ignored */ + W[t] = new Int(int1, int2); + } + else + { + W[t] = safeAdd_4( + gamma1(W[t - 2]), W[t - 7], + gamma0(W[t - 15]), W[t - 16] + ); + } - T1 = safeAdd_5(h, sigma1(e), ch(e, f, g), K[t], W[t]); - T2 = safeAdd_2(sigma0(a), maj(a, b, c)); - h = g; - g = f; - f = e; - e = safeAdd_2(d, T1); - d = c; - c = b; - b = a; - a = safeAdd_2(T1, T2); - } + T1 = safeAdd_5(h, sigma1(e), ch(e, f, g), K[t], W[t]); + T2 = safeAdd_2(sigma0(a), maj(a, b, c)); + h = g; + g = f; + f = e; + e = safeAdd_2(d, T1); + d = c; + c = b; + b = a; + a = safeAdd_2(T1, T2); - H[0] = safeAdd_2(a, H[0]); - H[1] = safeAdd_2(b, H[1]); - H[2] = safeAdd_2(c, H[2]); - H[3] = safeAdd_2(d, H[3]); - H[4] = safeAdd_2(e, H[4]); - H[5] = safeAdd_2(f, H[5]); - H[6] = safeAdd_2(g, H[6]); - H[7] = safeAdd_2(h, H[7]); - } + } - switch (variant) { - case "SHA-224": - return [ - H[0], H[1], H[2], H[3], - H[4], H[5], H[6]]; - case "SHA-256": - return H; - case "SHA-384": - return [ - H[0].highOrder, H[0].lowOrder, - H[1].highOrder, H[1].lowOrder, - H[2].highOrder, H[2].lowOrder, - H[3].highOrder, H[3].lowOrder, - H[4].highOrder, H[4].lowOrder, - H[5].highOrder, H[5].lowOrder]; - case "SHA-512": - return [ - H[0].highOrder, H[0].lowOrder, - H[1].highOrder, H[1].lowOrder, - H[2].highOrder, H[2].lowOrder, - H[3].highOrder, H[3].lowOrder, - H[4].highOrder, H[4].lowOrder, - H[5].highOrder, H[5].lowOrder, - H[6].highOrder, H[6].lowOrder, - H[7].highOrder, H[7].lowOrder]; - default: - /* This should never be reached */ - throw new Error('Unknown SHA variant'); - } - }, + H[0] = safeAdd_2(a, H[0]); + H[1] = safeAdd_2(b, H[1]); + H[2] = safeAdd_2(c, H[2]); + H[3] = safeAdd_2(d, H[3]); + H[4] = safeAdd_2(e, H[4]); + H[5] = safeAdd_2(f, H[5]); + H[6] = safeAdd_2(g, H[6]); + H[7] = safeAdd_2(h, H[7]); + } - /* - * jsSHA is the workhorse of the library. Instantiate it with the string to - * be hashed as the parameter - * - * @constructor - * @param {String} srcString The string to be hashed - * @param {String} inputFormat The format of srcString, ASCII or HEX - */ - jsSHA = function(srcString, inputFormat) { + if (("SHA-224" === variant) && (2 & SUPPORTED_ALGS)) + { + retVal = [ + H[0], H[1], H[2], H[3], + H[4], H[5], H[6] + ]; + } + else if (("SHA-256" === variant) && (2 & SUPPORTED_ALGS)) + { + retVal = H; + } + else if (("SHA-384" === variant) && (4 & SUPPORTED_ALGS)) + { + retVal = [ + H[0].highOrder, H[0].lowOrder, + H[1].highOrder, H[1].lowOrder, + H[2].highOrder, H[2].lowOrder, + H[3].highOrder, H[3].lowOrder, + H[4].highOrder, H[4].lowOrder, + H[5].highOrder, H[5].lowOrder + ]; + } + else if (("SHA-512" === variant) && (4 & SUPPORTED_ALGS)) + { + retVal = [ + H[0].highOrder, H[0].lowOrder, + H[1].highOrder, H[1].lowOrder, + H[2].highOrder, H[2].lowOrder, + H[3].highOrder, H[3].lowOrder, + H[4].highOrder, H[4].lowOrder, + H[5].highOrder, H[5].lowOrder, + H[6].highOrder, H[6].lowOrder, + H[7].highOrder, H[7].lowOrder + ]; + } + else /* This should never be reached */ + { + throw "Unexpected error in SHA-2 implementation"; + } - this.sha1 = null; - this.sha224 = null; - this.sha256 = null; - this.sha384 = null; - this.sha512 = null; + return retVal; + } - this.strBinLen = null; - this.strToHash = null; + /** + * jsSHA is the workhorse of the library. Instantiate it with the string to + * be hashed as the parameter + * + * @constructor + * @this {jsSHA} + * @param {string} srcString The string to be hashed + * @param {string} inputFormat The format of srcString, HEX, ASCII, TEXT, + * B64, or BYTES + * @param {string=} encoding The text encoding to use to encode the source + * string + */ + var jsSHA = function(srcString, inputFormat, encoding) + { + var strBinLen = 0, strToHash = [0], utfType = '', srcConvertRet = null; - /* Convert the input string into the correct type */ - if ("HEX" === inputFormat) { - if (0 !== (srcString.length % 2)) { - throw new Error("TEXT MUST BE IN BYTE INCREMENTS"); - } - this.strBinLen = srcString.length * 4; - this.strToHash = hex2binb(srcString); - } else if (("ASCII" === inputFormat) || - ('undefined' === typeof(inputFormat))) { - this.strBinLen = srcString.length * charSize; - this.strToHash = str2binb(srcString); - } else { - throw new Error("UNKNOWN TEXT INPUT TYPE"); - } - }; + utfType = encoding || "UTF8"; - jsSHA.prototype = { - /* - * Returns the desired SHA hash of the string specified at instantiation - * using the specified parameters - * - * @param {String} variant The desired SHA variant (SHA-1, SHA-224, - * SHA-256, SHA-384, or SHA-512) - * @param {String} format The desired output formatting (B64 or HEX) - * @return The string representation of the hash in the format specified - */ - getHash: function(variant, format) { - var formatFunc = null, - message = this.strToHash.slice(); + if (!(("UTF8" === utfType) || ("UTF16BE" === utfType) || ("UTF16LE" === utfType))) + { + throw "encoding must be UTF8, UTF16BE, or UTF16LE"; + } - switch (format) { - case "HEX": - formatFunc = binb2hex; - break; - case "B64": - formatFunc = binb2b64; - break; - case "ASCII": - formatFunc = binb2str; - break; - default: - throw new Error("FORMAT NOT RECOGNIZED"); - } + /* Convert the input string into the correct type */ + if ("HEX" === inputFormat) + { + if (0 !== (srcString.length % 2)) + { + throw "srcString of HEX type must be in byte increments"; + } + srcConvertRet = hex2binb(srcString); + strBinLen = srcConvertRet["binLen"]; + strToHash = srcConvertRet["value"]; + } + else if (("TEXT" === inputFormat) || ("ASCII" === inputFormat)) + { + srcConvertRet = str2binb(srcString, utfType); + strBinLen = srcConvertRet["binLen"]; + strToHash = srcConvertRet["value"]; + } + else if ("B64" === inputFormat) + { + srcConvertRet = b642binb(srcString); + strBinLen = srcConvertRet["binLen"]; + strToHash = srcConvertRet["value"]; + } + else if ("BYTES" === inputFormat) + { + srcConvertRet = bytes2binb(srcString); + strBinLen = srcConvertRet["binLen"]; + strToHash = srcConvertRet["value"]; + } + else if ("TYPED" === inputFormat) + { + srcConvertRet = typed2binb(srcString); + strBinLen = srcConvertRet["binLen"]; + strToHash = srcConvertRet["value"]; + } + else + { + throw "inputFormat must be HEX, TEXT, ASCII, B64, BYTES, or TYPED"; + } - switch (variant) { - case "SHA-1": - if (null === this.sha1) { - this.sha1 = coreSHA1(message, this.strBinLen); - } - return formatFunc(this.sha1); - case "SHA-224": - if (null === this.sha224) { - this.sha224 = coreSHA2(message, this.strBinLen, variant); - } - return formatFunc(this.sha224); - case "SHA-256": - if (null === this.sha256) { - this.sha256 = coreSHA2(message, this.strBinLen, variant); - } - return formatFunc(this.sha256); - case "SHA-384": - if (null === this.sha384) { - this.sha384 = coreSHA2(message, this.strBinLen, variant); - } - return formatFunc(this.sha384); - case "SHA-512": - if (null === this.sha512) { - this.sha512 = coreSHA2(message, this.strBinLen, variant); - } - return formatFunc(this.sha512); - default: - throw new Error("HASH NOT RECOGNIZED"); - } - }, + /** + * Returns the desired SHA hash of the string specified at instantiation + * using the specified parameters + * + * @expose + * @param {string} variant The desired SHA variant (SHA-1, SHA-224, + * SHA-256, SHA-384, or SHA-512) + * @param {string} format The desired output formatting (B64, HEX, or BYTES) + * @param {number=} numRounds The number of rounds of hashing to be + * executed + * @param {{outputUpper : boolean, b64Pad : string}=} outputFormatOpts + * Hash list of output formatting options + * @return {string} The string representation of the hash in the format + * specified + */ + this.getHash = function(variant, format, numRounds, outputFormatOpts) + { + var formatFunc = null, message = strToHash.slice(), + messageBinLen = strBinLen, i; - /* - * Returns the desired HMAC of the string specified at instantiation - * using the key and variant param. - * - * @param {String} key The key used to calculate the HMAC - * @param {String} inputFormat The format of key, ASCII or HEX - * @param {String} variant The desired SHA variant (SHA-1, SHA-224, - * SHA-256, SHA-384, or SHA-512) - * @param {String} outputFormat The desired output formatting - * (B64 or HEX) - * @return The string representation of the hash in the format specified - */ - getHMAC: function(key, inputFormat, variant, outputFormat) { - var formatFunc, keyToUse, blockByteSize, blockBitSize, i, - retVal, lastArrayIndex, keyBinLen, hashBitSize, - keyWithIPad = [], - keyWithOPad = []; + /* Need to do argument patching since both numRounds and + outputFormatOpts are optional */ + if (3 === arguments.length) + { + if ("number" !== typeof numRounds) + { + outputFormatOpts = numRounds; + numRounds = 1; + } + } + else if (2 === arguments.length) + { + numRounds = 1; + } - /* Validate the output format selection */ - switch (outputFormat) { - case "HEX": - formatFunc = binb2hex; - break; - case "B64": - formatFunc = binb2b64; - break; - case "ASCII": - formatFunc = binb2str; - break; - default: - throw new Error("FORMAT NOT RECOGNIZED"); - } + /* Validate the numRounds argument */ + if ((numRounds !== parseInt(numRounds, 10)) || (1 > numRounds)) + { + throw "numRounds must a integer >= 1"; + } - /* Validate the hash variant selection and set needed variables */ - switch (variant) { - case "SHA-1": - blockByteSize = 64; - hashBitSize = 160; - break; - case "SHA-224": - blockByteSize = 64; - hashBitSize = 224; - break; - case "SHA-256": - blockByteSize = 64; - hashBitSize = 256; - break; - case "SHA-384": - blockByteSize = 128; - hashBitSize = 384; - break; - case "SHA-512": - blockByteSize = 128; - hashBitSize = 512; - break; - default: - throw new Error("HASH NOT RECOGNIZED"); - } + /* Validate the output format selection */ + switch (format) + { + case "HEX": + formatFunc = binb2hex; + break; + case "B64": + formatFunc = binb2b64; + break; + case "BYTES": + formatFunc = binb2bytes; + break; + case "TYPED": + formatFunc = binb2typed; + break; + default: + throw "format must be HEX, B64, or BYTES"; + } - /* Validate input format selection */ - if ("HEX" === inputFormat) { - /* Nibbles must come in pairs */ - if (0 !== (key.length % 2)) { - throw new Error("KEY MUST BE IN BYTE INCREMENTS"); - } - keyToUse = hex2binb(key); - keyBinLen = key.length * 4; - } else if ("ASCII" === inputFormat) { - keyToUse = str2binb(key); - keyBinLen = key.length * charSize; - } else { - throw new Error("UNKNOWN KEY INPUT TYPE"); - } + if (("SHA-1" === variant) && (1 & SUPPORTED_ALGS)) + { + for (i = 0; i < numRounds; i += 1) + { + message = coreSHA1(message, messageBinLen); + messageBinLen = 160; + } + } + else if (("SHA-224" === variant) && (2 & SUPPORTED_ALGS)) + { + for (i = 0; i < numRounds; i += 1) + { + message = coreSHA2(message, messageBinLen, variant); + messageBinLen = 224; + } + } + else if (("SHA-256" === variant) && (2 & SUPPORTED_ALGS)) + { + for (i = 0; i < numRounds; i += 1) + { + message = coreSHA2(message, messageBinLen, variant); + messageBinLen = 256; + } + } + else if (("SHA-384" === variant) && (4 & SUPPORTED_ALGS)) + { + for (i = 0; i < numRounds; i += 1) + { + message = coreSHA2(message, messageBinLen, variant); + messageBinLen = 384; + } + } + else if (("SHA-512" === variant) && (4 & SUPPORTED_ALGS)) + { + for (i = 0; i < numRounds; i += 1) + { + message = coreSHA2(message, messageBinLen, variant); + messageBinLen = 512; + } + } + else + { + throw "Chosen SHA variant is not supported"; + } - /* These are used multiple times, calculate and store them */ - blockBitSize = blockByteSize * 8; - lastArrayIndex = (blockByteSize / 4) - 1; + return formatFunc(message, getOutputOpts(outputFormatOpts)); + }; - /* Figure out what to do with the key based on its size relative to - * the hash's block size */ - if (blockByteSize < (keyBinLen / 8)) { - if ("SHA-1" === variant) { - keyToUse = coreSHA1(keyToUse, keyBinLen); - } else { - keyToUse = coreSHA2(keyToUse, keyBinLen, variant); - } - /* For all variants, the block size is bigger than the output - * size so there will never be a useful byte at the end of the - * string */ - keyToUse[lastArrayIndex] &= 0xFFFFFF00; - } else if (blockByteSize > (keyBinLen / 8)) { - /* If the blockByteSize is greater than the key length, there - * will always be at LEAST one "useless" byte at the end of the - * string */ - keyToUse[lastArrayIndex] &= 0xFFFFFF00; - } + /** + * Returns the desired HMAC of the string specified at instantiation + * using the key and variant parameter + * + * @expose + * @param {string} key The key used to calculate the HMAC + * @param {string} inputFormat The format of key, HEX, TEXT, ASCII, + * B64, or BYTES + * @param {string} variant The desired SHA variant (SHA-1, SHA-224, + * SHA-256, SHA-384, or SHA-512) + * @param {string} outputFormat The desired output formatting + * (B64, HEX, or BYTES) + * @param {{outputUpper : boolean, b64Pad : string}=} outputFormatOpts + * associative array of output formatting options + * @return {string} The string representation of the hash in the format + * specified + */ + this.getHMAC = function(key, inputFormat, variant, outputFormat, + outputFormatOpts) + { + var formatFunc, keyToUse, blockByteSize, blockBitSize, i, + retVal, lastArrayIndex, keyBinLen, hashBitSize, + keyWithIPad = [], keyWithOPad = [], keyConvertRet = null; - /* Create ipad and opad */ - for (i = 0; i <= lastArrayIndex; i += 1) { - keyWithIPad[i] = keyToUse[i] ^ 0x36363636; - keyWithOPad[i] = keyToUse[i] ^ 0x5C5C5C5C; - } + /* Validate the output format selection */ + switch (outputFormat) + { + case "HEX": + formatFunc = binb2hex; + break; + case "B64": + formatFunc = binb2b64; + break; + case "BYTES": + formatFunc = binb2bytes; + break; + default: + throw "outputFormat must be HEX, B64, or BYTES"; + } - /* Calculate the HMAC */ - if ("SHA-1" === variant) { - retVal = coreSHA1( - keyWithIPad.concat(this.strToHash), - blockBitSize + this.strBinLen); - retVal = coreSHA1( - keyWithOPad.concat(retVal), - blockBitSize + hashBitSize); - } else { - retVal = coreSHA2( - keyWithIPad.concat(this.strToHash), - blockBitSize + this.strBinLen, variant); - retVal = coreSHA2( - keyWithOPad.concat(retVal), - blockBitSize + hashBitSize, variant); - } + /* Validate the hash variant selection and set needed variables */ + if (("SHA-1" === variant) && (1 & SUPPORTED_ALGS)) + { + blockByteSize = 64; + hashBitSize = 160; + } + else if (("SHA-224" === variant) && (2 & SUPPORTED_ALGS)) + { + blockByteSize = 64; + hashBitSize = 224; + } + else if (("SHA-256" === variant) && (2 & SUPPORTED_ALGS)) + { + blockByteSize = 64; + hashBitSize = 256; + } + else if (("SHA-384" === variant) && (4 & SUPPORTED_ALGS)) + { + blockByteSize = 128; + hashBitSize = 384; + } + else if (("SHA-512" === variant) && (4 & SUPPORTED_ALGS)) + { + blockByteSize = 128; + hashBitSize = 512; + } + else + { + throw "Chosen SHA variant is not supported"; + } - return (formatFunc(retVal)); - } - }; + /* Validate input format selection */ + if ("HEX" === inputFormat) + { + keyConvertRet = hex2binb(key); + keyBinLen = keyConvertRet["binLen"]; + keyToUse = keyConvertRet["value"]; + } + else if (("TEXT" === inputFormat) || ("ASCII" === inputFormat)) + { + keyConvertRet = str2binb(key, utfType); + keyBinLen = keyConvertRet["binLen"]; + keyToUse = keyConvertRet["value"]; + } + else if ("B64" === inputFormat) + { + keyConvertRet = b642binb(key); + keyBinLen = keyConvertRet["binLen"]; + keyToUse = keyConvertRet["value"]; + } + else if ("BYTES" === inputFormat) + { + keyConvertRet = bytes2binb(key); + keyBinLen = keyConvertRet["binLen"]; + keyToUse = keyConvertRet["value"]; + } + else + { + throw "inputFormat must be HEX, TEXT, ASCII, B64, or BYTES"; + } - return jsSHA; -}()); + /* These are used multiple times, calculate and store them */ + blockBitSize = blockByteSize * 8; + lastArrayIndex = (blockByteSize / 4) - 1; -module.exports = { - /** SHA1 hash */ - sha1: function(str) { - var shaObj = new jsSHA(str, "ASCII"); - return shaObj.getHash("SHA-1", "ASCII"); - }, - /** SHA224 hash */ - sha224: function(str) { - var shaObj = new jsSHA(str, "ASCII"); - return shaObj.getHash("SHA-224", "ASCII"); - }, - /** SHA256 hash */ - sha256: function(str) { - var shaObj = new jsSHA(str, "ASCII"); - return shaObj.getHash("SHA-256", "ASCII"); - }, - /** SHA384 hash */ - sha384: function(str) { - var shaObj = new jsSHA(str, "ASCII"); - return shaObj.getHash("SHA-384", "ASCII"); + /* Figure out what to do with the key based on its size relative to + * the hash's block size */ + if (blockByteSize < (keyBinLen / 8)) + { + if (("SHA-1" === variant) && (1 & SUPPORTED_ALGS)) + { + keyToUse = coreSHA1(keyToUse, keyBinLen); + } + else if (6 & SUPPORTED_ALGS) + { + keyToUse = coreSHA2(keyToUse, keyBinLen, variant); + } + else + { + throw "Unexpected error in HMAC implementation"; + } + /* For all variants, the block size is bigger than the output + * size so there will never be a useful byte at the end of the + * string */ + while (keyToUse.length <= lastArrayIndex) + { + keyToUse.push(0); + } + keyToUse[lastArrayIndex] &= 0xFFFFFF00; + } + else if (blockByteSize > (keyBinLen / 8)) + { + /* If the blockByteSize is greater than the key length, there + * will always be at LEAST one "useless" byte at the end of the + * string */ + while (keyToUse.length <= lastArrayIndex) + { + keyToUse.push(0); + } + keyToUse[lastArrayIndex] &= 0xFFFFFF00; + } - }, - /** SHA512 hash */ - sha512: function(str) { - var shaObj = new jsSHA(str, "ASCII"); - return shaObj.getHash("SHA-512", "ASCII"); - } -}; + /* Create ipad and opad */ + for (i = 0; i <= lastArrayIndex; i += 1) + { + keyWithIPad[i] = keyToUse[i] ^ 0x36363636; + keyWithOPad[i] = keyToUse[i] ^ 0x5C5C5C5C; + } + + /* Calculate the HMAC */ + if (("SHA-1" === variant) && (1 & SUPPORTED_ALGS)) + { + retVal = coreSHA1( + keyWithOPad.concat( + coreSHA1( + keyWithIPad.concat(strToHash), + blockBitSize + strBinLen + ) + ), + blockBitSize + hashBitSize); + } + else if (6 & SUPPORTED_ALGS) + { + retVal = coreSHA2( + keyWithOPad.concat( + coreSHA2( + keyWithIPad.concat(strToHash), + blockBitSize + strBinLen, + variant + ) + ), + blockBitSize + hashBitSize, variant); + } + else + { + throw "Unexpected error in HMAC implementation"; + } + + return formatFunc(retVal, getOutputOpts(outputFormatOpts)); + }; + }; + + module.exports = { + /** SHA1 hash */ + sha1: function(str) { + var shaObj = new jsSHA(str, "TYPED", "UTF8"); + return shaObj.getHash("SHA-1", "TYPED"); + }, + /** SHA224 hash */ + sha224: function(str) { + var shaObj = new jsSHA(str, "TYPED", "UTF8"); + return shaObj.getHash("SHA-224", "TYPED"); + }, + /** SHA256 hash */ + sha256: function(str) { + var shaObj = new jsSHA(str, "TYPED", "UTF8"); + return shaObj.getHash("SHA-256", "TYPED"); + }, + /** SHA384 hash */ + sha384: function(str) { + var shaObj = new jsSHA(str, "TYPED", "UTF8"); + return shaObj.getHash("SHA-384", "TYPED"); + + }, + /** SHA512 hash */ + sha512: function(str) { + var shaObj = new jsSHA(str, "TYPED", "UTF8"); + return shaObj.getHash("SHA-512", "TYPED"); + } + }; +}(this)); diff --git a/src/crypto/pkcs1.js b/src/crypto/pkcs1.js index 19bc6b80..e7adf1f5 100644 --- a/src/crypto/pkcs1.js +++ b/src/crypto/pkcs1.js @@ -135,7 +135,7 @@ module.exports = { encode: function(algo, M, emLen) { var i; // Apply the hash function to the message M to produce a hash value H - var H = hash.digest(algo, M); + var H = util.Uint8Array2str(hash.digest(algo, util.str2Uint8Array(M))); if (H.length !== hash.getHashByteLength(algo)) { throw new Error('Invalid hash length'); } diff --git a/src/crypto/signature.js b/src/crypto/signature.js index 5f0268df..0620330e 100644 --- a/src/crypto/signature.js +++ b/src/crypto/signature.js @@ -88,7 +88,7 @@ module.exports = { var n = keyIntegers[0].toBigInteger(); m = pkcs1.emsa.encode(hash_algo, data, keyIntegers[0].byteLength()); - return rsa.sign(m, d, n).toMPI(); + return util.str2Uint8Array(rsa.sign(m, d, n).toMPI()); case 17: // DSA (Digital Signature Algorithm) [FIPS186] [HAC] @@ -102,7 +102,7 @@ module.exports = { m = data; var result = dsa.sign(hash_algo, m, g, p, q, x); - return result[0].toString() + result[1].toString(); + return util.str2Uint8Array(result[0].toString() + result[1].toString()); case 16: // Elgamal (Encrypt-Only) [ELGAMAL] [HAC] throw new Error('Signing with Elgamal is not defined in the OpenPGP standard.'); diff --git a/src/packet/public_key.js b/src/packet/public_key.js index 184de578..c31b49a1 100644 --- a/src/packet/public_key.js +++ b/src/packet/public_key.js @@ -191,13 +191,13 @@ PublicKey.prototype.getFingerprint = function () { var toHash = ''; if (this.version == 4) { toHash = this.writeOld(); - this.fingerprint = crypto.hash.sha1(util.Uint8Array2str(toHash)); + this.fingerprint = util.Uint8Array2str(crypto.hash.sha1(toHash)); } else if (this.version == 3) { var mpicount = crypto.getPublicMpiCount(this.algorithm); for (var i = 0; i < mpicount; i++) { toHash += this.mpi[i].toBytes(); } - this.fingerprint = crypto.hash.md5(toHash); + this.fingerprint = util.Uint8Array2str(crypto.hash.md5(util.str2Uint8Array(toHash))); } this.fingerprint = util.hexstrdump(this.fingerprint); return this.fingerprint; diff --git a/src/packet/secret_key.js b/src/packet/secret_key.js index 028f40c5..909227d1 100644 --- a/src/packet/secret_key.js +++ b/src/packet/secret_key.js @@ -68,7 +68,7 @@ function get_hash_fn(hash) { return crypto.hash.sha1; else return function(c) { - return util.Uint8Array2str(util.writeNumber(util.calc_checksum(util.str2Uint8Array(c)), 2)); + return util.writeNumber(util.calc_checksum(c), 2); }; } @@ -81,7 +81,11 @@ function parse_cleartext_mpi(hash_algorithm, cleartext, algorithm) { var hashtext = util.Uint8Array2str(cleartext.subarray(cleartext.length - hashlen, cleartext.length)); cleartext = cleartext.subarray(0, cleartext.length - hashlen); - var hash = hashfn(util.Uint8Array2str(cleartext)); + var hash = util.Uint8Array2str(hashfn(cleartext)); + + console.log(hash); + console.log(hashtext); + console.log(hash_algorithm); if (hash != hashtext) return new Error("Hash mismatch."); @@ -109,9 +113,9 @@ function write_cleartext_mpi(hash_algorithm, algorithm, mpi) { var bytes = util.concatUint8Array(arr); - var hash = get_hash_fn(hash_algorithm)(util.Uint8Array2str(bytes)); + var hash = get_hash_fn(hash_algorithm)(bytes); - return util.concatUint8Array([bytes, util.str2Uint8Array(hash)]); + return util.concatUint8Array([bytes, hash]); } @@ -220,16 +224,6 @@ SecretKey.prototype.decrypt = function (passphrase) { symmetric, key; - if(!Uint8Array.prototype.isPrototypeOf(this.encrypted)) { - if(Uint8Array.prototype.isPrototypeOf(this.encrypted.message)) { - throw new Error('this.encrypted.message is a typed array!'); - } - if(this.encrypted === null) { - throw new Error('this.encrypted is null!'); - } - throw new Error(Object.prototype.toString.call(this.encrypted)); - } - var s2k_usage = this.encrypted[i++]; // - [Optional] If string-to-key usage octet was 255 or 254, a one- @@ -248,7 +242,7 @@ SecretKey.prototype.decrypt = function (passphrase) { } else { symmetric = s2k_usage; symmetric = enums.read(enums.symmetric, symmetric); - key = util.str2Uint8Array(crypto.hash.md5(passphrase)); + key = crypto.hash.md5(passphrase); } diff --git a/src/packet/signature.js b/src/packet/signature.js index 03bcb9a2..76c98dd8 100644 --- a/src/packet/signature.js +++ b/src/packet/signature.js @@ -224,14 +224,14 @@ Signature.prototype.sign = function (key, data) { var trailer = this.calculateTrailer(); - var toHash = util.Uint8Array2str(util.concatUint8Array([this.toSign(signatureType, data), this.signatureData, trailer])); + var toHash = util.concatUint8Array([this.toSign(signatureType, data), this.signatureData, trailer]); var hash = crypto.hash.digest(hashAlgorithm, toHash); - this.signedHashValue = util.str2Uint8Array(hash.substr(0, 2)); + this.signedHashValue = hash.subarray(0, 2); - this.signature = util.str2Uint8Array(crypto.signature.sign(hashAlgorithm, - publicKeyAlgorithm, key.mpi, util.str2Uint8Array(toHash))); + this.signature = crypto.signature.sign(hashAlgorithm, + publicKeyAlgorithm, key.mpi, toHash); }; /** @@ -287,7 +287,7 @@ Signature.prototype.write_all_sub_packets = function () { // 2 octets of value length bytes.push(util.writeNumber(value.length, 2)); bytes.push(util.str2Uint8Array(name + value)); - bytes = concatUint8Array(bytes); + bytes = util.concatUint8Array(bytes); arr.push(write_sub_packet(sub.notation_data, bytes)); } } diff --git a/src/packet/sym_encrypted_integrity_protected.js b/src/packet/sym_encrypted_integrity_protected.js index e01d4490..0e5ec725 100644 --- a/src/packet/sym_encrypted_integrity_protected.js +++ b/src/packet/sym_encrypted_integrity_protected.js @@ -87,7 +87,7 @@ SymEncryptedIntegrityProtected.prototype.encrypt = function (sessionKeyAlgorithm // This could probably be cleaned up to use less memory var tohash = util.concatUint8Array([bytes, mdc]); - var hash = util.str2Uint8Array(crypto.hash.sha1(util.Uint8Array2str(util.concatUint8Array([prefix, tohash])))); + var hash = crypto.hash.sha1(util.concatUint8Array([prefix, tohash])); tohash = util.concatUint8Array([tohash, hash]); @@ -111,7 +111,7 @@ SymEncryptedIntegrityProtected.prototype.decrypt = function (sessionKeyAlgorithm // there must be a modification detection code packet as the // last packet and everything gets hashed except the hash itself - this.hash = crypto.hash.sha1(util.Uint8Array2str(util.concatUint8Array([crypto.cfb.mdc(sessionKeyAlgorithm, key, this.encrypted), + this.hash = util.Uint8Array2str(crypto.hash.sha1(util.concatUint8Array([crypto.cfb.mdc(sessionKeyAlgorithm, key, this.encrypted), decrypted.subarray(0, decrypted.length - 20)]))); var mdc = util.Uint8Array2str(decrypted.subarray(decrypted.length - 20, decrypted.length)); diff --git a/src/type/s2k.js b/src/type/s2k.js index b3a1d4b9..10e9e7ec 100644 --- a/src/type/s2k.js +++ b/src/type/s2k.js @@ -142,33 +142,33 @@ S2K.prototype.write = function () { * hashAlgorithm hash length */ S2K.prototype.produce_key = function (passphrase, numBytes) { - passphrase = util.encode_utf8(passphrase); + passphrase = util.str2Uint8Array(util.encode_utf8(passphrase)); function round(prefix, s2k) { var algorithm = enums.write(enums.hash, s2k.algorithm); switch (s2k.type) { case 'simple': - return util.str2Uint8Array(crypto.hash.digest(algorithm, prefix + passphrase)); + return crypto.hash.digest(algorithm, util.concatUint8Array([prefix,passphrase])); case 'salted': - return util.str2Uint8Array(crypto.hash.digest(algorithm, - prefix + util.Uint8Array2str(s2k.salt) + passphrase)); + return crypto.hash.digest(algorithm, + util.concatUint8Array([prefix, s2k.salt, passphrase])); case 'iterated': var isp = [], count = s2k.get_count(), - data = util.Uint8Array2str(s2k.salt) + passphrase; + data = util.concatUint8Array([s2k.salt,passphrase]); while (isp.length * data.length < count) isp.push(data); - isp = isp.join(''); + isp = util.concatUint8Array(isp); if (isp.length > count) - isp = isp.substr(0, count); + isp = isp.subarray(0, count); - return util.str2Uint8Array(crypto.hash.digest(algorithm, prefix + isp)); + return crypto.hash.digest(algorithm, util.concatUint8Array([prefix,isp])); case 'gnu': throw new Error("GNU s2k type not supported."); @@ -179,14 +179,19 @@ S2K.prototype.produce_key = function (passphrase, numBytes) { } var arr = [], + i = 0, rlength = 0, - prefix = ''; + prefix = new Uint8Array(numBytes); + + for(var i = 0; i