mirror of
https://github.com/seiichiro0185/sailotp.git
synced 2024-11-24 08:19:41 +00:00
1380 lines
47 KiB
JavaScript
1380 lines
47 KiB
JavaScript
/**
|
|
* @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-2013
|
|
* Distributed under the BSD License
|
|
* See http://caligatio.github.com/jsSHA/ for more information
|
|
*
|
|
* Several functions taken from Paul Johnston
|
|
*/
|
|
|
|
/**
|
|
* 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
|
|
*/
|
|
var SUPPORTED_ALGS = 4 | 2 | 1;
|
|
|
|
"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;
|
|
}
|
|
|
|
/**
|
|
* 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 UTF16, to use to
|
|
* encode the source string
|
|
* @return {{value : Array.<number>, 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;
|
|
|
|
if ("UTF8" === utfType)
|
|
{
|
|
for (i = 0; i < str.length; i += 1)
|
|
{
|
|
codePnt = str.charCodeAt(i);
|
|
binArr = [];
|
|
|
|
if (0x800 < codePnt)
|
|
{
|
|
binArr[0] = 0xE0 | ((codePnt & 0xF000) >>> 12);
|
|
binArr[1] = 0x80 | ((codePnt & 0xFC0) >>> 6);
|
|
binArr[2] = 0x80 | (codePnt & 0x3F);
|
|
}
|
|
else if (0x80 < codePnt)
|
|
{
|
|
binArr[0] = 0xC0 | ((codePnt & 0x7C0) >>> 6);
|
|
binArr[1] = 0x80 | (codePnt & 0x3F);
|
|
}
|
|
else
|
|
{
|
|
binArr[0] = codePnt;
|
|
}
|
|
|
|
for (j = 0; j < binArr.length; j += 1)
|
|
{
|
|
bin[byteCnt >>> 2] |= binArr[j] << (24 - (8 * (byteCnt % 4)));
|
|
byteCnt += 1;
|
|
}
|
|
}
|
|
}
|
|
else if ("UTF16" === utfType)
|
|
{
|
|
for (i = 0; i < str.length; i += 1)
|
|
{
|
|
codePnt = str.charCodeAt(i);
|
|
|
|
bin[byteCnt >>> 2] |= str.charCodeAt(i) << (16 - (8 * (byteCnt % 4)));
|
|
byteCnt += 2;
|
|
}
|
|
}
|
|
return {"value" : bin, "binLen" : byteCnt * 8};
|
|
}
|
|
|
|
/**
|
|
* 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.<number>, 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;
|
|
|
|
if (0 !== (length % 2))
|
|
{
|
|
throw "String of HEX type must be in byte increments";
|
|
}
|
|
|
|
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 "String of HEX type contains invalid characters";
|
|
}
|
|
}
|
|
|
|
return {"value" : bin, "binLen" : length * 4};
|
|
}
|
|
|
|
/**
|
|
* 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.<number>, 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,
|
|
b64Tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
|
|
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";
|
|
}
|
|
|
|
for (i = 0; i < str.length; i += 4)
|
|
{
|
|
strPart = str.substr(i, 4);
|
|
tmpInt = 0;
|
|
|
|
for (j = 0; j < strPart.length; j += 1)
|
|
{
|
|
index = b64Tab.indexOf(strPart[j]);
|
|
tmpInt |= index << (18 - (6 * j));
|
|
}
|
|
|
|
for (j = 0; j < strPart.length - 1; j += 1)
|
|
{
|
|
retVal[byteCnt >> 2] |= ((tmpInt >>> (16 - (j * 8))) & 0xFF) <<
|
|
(24 - (8 * (byteCnt % 4)));
|
|
byteCnt += 1;
|
|
}
|
|
}
|
|
|
|
return {"value" : retVal, "binLen" : byteCnt * 8};
|
|
}
|
|
|
|
/**
|
|
* Convert an array of big-endian words to a hex string.
|
|
*
|
|
* @private
|
|
* @param {Array.<number>} 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;
|
|
|
|
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);
|
|
}
|
|
|
|
return (formatOpts["outputUpper"]) ? str.toUpperCase() : str;
|
|
}
|
|
|
|
/**
|
|
* Convert an array of big-endian words to a base-64 string
|
|
*
|
|
* @private
|
|
* @param {Array.<number>} 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,
|
|
b64Tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
|
|
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 += b64Tab.charAt((triplet >>> 6 * (3 - j)) & 0x3F);
|
|
}
|
|
else
|
|
{
|
|
str += formatOpts["b64Pad"];
|
|
}
|
|
}
|
|
}
|
|
return str;
|
|
}
|
|
|
|
/**
|
|
* 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" : "="};
|
|
|
|
try
|
|
{
|
|
if (outputOpts.hasOwnProperty("outputUpper"))
|
|
{
|
|
retVal["outputUpper"] = outputOpts["outputUpper"];
|
|
}
|
|
|
|
if (outputOpts.hasOwnProperty("b64Pad"))
|
|
{
|
|
retVal["b64Pad"] = outputOpts["b64Pad"];
|
|
}
|
|
}
|
|
catch(ignore)
|
|
{}
|
|
|
|
if ("boolean" !== typeof(retVal["outputUpper"]))
|
|
{
|
|
throw "Invalid outputUpper formatting option";
|
|
}
|
|
|
|
if ("string" !== typeof(retVal["b64Pad"]))
|
|
{
|
|
throw "Invalid b64Pad formatting option";
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
|
|
/**
|
|
* 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));
|
|
}
|
|
|
|
/**
|
|
* 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));
|
|
}
|
|
|
|
/**
|
|
* 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);
|
|
|
|
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 retVal;
|
|
}
|
|
|
|
/**
|
|
* 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;
|
|
}
|
|
|
|
/**
|
|
* 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;
|
|
|
|
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 retVal;
|
|
}
|
|
|
|
/**
|
|
* 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;
|
|
}
|
|
|
|
/**
|
|
* 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.<number>} message The binary array representation of the
|
|
* string to hash
|
|
* @param {number} messageLen The number of bits in the message
|
|
* @return {Array.<number>} 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,
|
|
H = [
|
|
0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0
|
|
];
|
|
|
|
/* 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;
|
|
|
|
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 (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, 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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
/**
|
|
* Calculates the desired SHA-2 hash of the string set at instantiation
|
|
*
|
|
* @private
|
|
* @param {Array.<number>} 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.<number>} 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 = [],
|
|
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") &&
|
|
(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 ("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(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 ("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;
|
|
|
|
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 (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]
|
|
);
|
|
}
|
|
|
|
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]);
|
|
}
|
|
|
|
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";
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
|
|
/**
|
|
* 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, TEXT, or ASCII
|
|
* @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;
|
|
|
|
utfType = encoding || "UTF8";
|
|
|
|
if (!(("UTF8" === utfType) || ("UTF16" === utfType)))
|
|
{
|
|
throw "encoding must be UTF8 or UTF16";
|
|
}
|
|
|
|
/* 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 (("ASCII" === inputFormat) || ("TEXT" === 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
|
|
{
|
|
throw "inputFormat must be HEX, TEXT, ASCII, or B64";
|
|
}
|
|
|
|
/**
|
|
* 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 or HEX)
|
|
* @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;
|
|
|
|
/* 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 numRounds argument */
|
|
if ((numRounds !== parseInt(numRounds, 10)) || (1 > numRounds))
|
|
{
|
|
throw "numRounds must a integer >= 1";
|
|
}
|
|
|
|
/* Validate the output format selection */
|
|
switch (format)
|
|
{
|
|
case "HEX":
|
|
formatFunc = binb2hex;
|
|
break;
|
|
case "B64":
|
|
formatFunc = binb2b64;
|
|
break;
|
|
default:
|
|
throw "format must be HEX or B64";
|
|
}
|
|
|
|
if (("SHA-1" === variant) && (1 & SUPPORTED_ALGS))
|
|
{
|
|
for (i = 0; i < numRounds; i++)
|
|
{
|
|
message = coreSHA1(message, messageBinLen);
|
|
messageBinLen = 160;
|
|
}
|
|
}
|
|
else if (("SHA-224" === variant) && (2 & SUPPORTED_ALGS))
|
|
{
|
|
for (i = 0; i < numRounds; i++)
|
|
{
|
|
message = coreSHA2(message, messageBinLen, variant);
|
|
messageBinLen = 224;
|
|
}
|
|
}
|
|
else if (("SHA-256" === variant) && (2 & SUPPORTED_ALGS))
|
|
{
|
|
for (i = 0; i < numRounds; i++)
|
|
{
|
|
message = coreSHA2(message, messageBinLen, variant);
|
|
messageBinLen = 256;
|
|
}
|
|
}
|
|
else if (("SHA-384" === variant) && (4 & SUPPORTED_ALGS))
|
|
{
|
|
for (i = 0; i < numRounds; i++)
|
|
{
|
|
message = coreSHA2(message, messageBinLen, variant);
|
|
messageBinLen = 384;
|
|
}
|
|
}
|
|
else if (("SHA-512" === variant) && (4 & SUPPORTED_ALGS))
|
|
{
|
|
for (i = 0; i < numRounds; i++)
|
|
{
|
|
message = coreSHA2(message, messageBinLen, variant);
|
|
messageBinLen = 512;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw "Chosen SHA variant is not supported";
|
|
}
|
|
|
|
return formatFunc(message, getOutputOpts(outputFormatOpts));
|
|
};
|
|
|
|
/**
|
|
* 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 or TEXT or ASCII
|
|
* @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)
|
|
* @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;
|
|
|
|
/* Validate the output format selection */
|
|
switch (outputFormat)
|
|
{
|
|
case "HEX":
|
|
formatFunc = binb2hex;
|
|
break;
|
|
case "B64":
|
|
formatFunc = binb2b64;
|
|
break;
|
|
default:
|
|
throw "outputFormat must be HEX or B64";
|
|
}
|
|
|
|
/* 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";
|
|
}
|
|
|
|
/* Validate input format selection */
|
|
if ("HEX" === inputFormat)
|
|
{
|
|
keyConvertRet = hex2binb(key);
|
|
keyBinLen = keyConvertRet["binLen"];
|
|
keyToUse = keyConvertRet["value"];
|
|
}
|
|
else if (("ASCII" === inputFormat) || ("TEXT" === 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
|
|
{
|
|
throw "inputFormat must be HEX, TEXT, ASCII, or B64";
|
|
}
|
|
|
|
/* These are used multiple times, calculate and store them */
|
|
blockBitSize = blockByteSize * 8;
|
|
lastArrayIndex = (blockByteSize / 4) - 1;
|
|
|
|
/* 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 */
|
|
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;
|
|
}
|
|
|
|
/* 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));
|
|
};
|
|
};
|