// https://github.com/microsoft/MSR-JavaScript-Crypto // version "1.6.5" //******************************************************************************* // // Copyright 2020 Microsoft // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // //******************************************************************************* 'use strict' var msrCryptoVersion = '1.6.5' ;(function (root, factory) { if (typeof define === 'function' && define.amd) { define([], function () { return (root.msrCrypto = factory(root)) }) } else if (typeof exports === 'object') { module.exports = factory(root) } else { root.msrCrypto = factory(root) } })(this, function (global) { global = global || {} var msrCrypto = function () { var operations = {} operations.register = function ( operationType, algorithmName, functionToCall, ) { if (!operations[operationType]) { operations[operationType] = {} } var op = operations[operationType] if (!op[algorithmName]) { op[algorithmName] = functionToCall } } operations.exists = function (operationType, algorithmName) { if (!operations[operationType]) { return false } return operations[operationType][algorithmName] ? true : false } var scriptUrl = (function () { if (typeof document !== 'undefined') { try { throw new Error() } catch (e) { if (e.stack) { var match = /\w+:\/\/(.+?\/)*.+\.js/.exec(e.stack) return match && match.length > 0 ? match[0] : null } } } else if ( typeof self !== 'undefined' && typeof self.location !== 'undefined' ) { return self.location.href } return null })() var fprngEntropyProvided = false var webWorkerSupport = typeof Worker !== 'undefined' var runningInWorkerInstance = typeof importScripts === 'function' && self instanceof WorkerGlobalScope var workerInitialized = false var typedArraySupport = typeof ArrayBuffer !== 'undefined' var setterSupport = (function () { try { Object.defineProperty({}, 'oncomplete', {}) return true } catch (ex) { return false } })() var asyncMode = false var createProperty = function ( parentObject, propertyName, initialValue, getterFunction, setterFunction, ) { if (!setterSupport) { parentObject[propertyName] = initialValue return } var setGet = {} getterFunction && (setGet.get = getterFunction) setterFunction && (setGet.set = setterFunction) Object.defineProperty(parentObject, propertyName, setGet) } var msrcryptoHashFunctions = {} var msrcryptoUtilities = (function () { var encodingChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=' function consoleLog(text) { if ('console' in self && 'log' in console) { console.log(text) } } function toBase64(data, base64Url) { var dataType = getObjectType(data) if ( dataType !== 'Array' && dataType !== 'Uint8Array' && dataType !== 'ArrayBuffer' ) { throw new Error('invalid input') } var output = '' var input = toArray(data) if (!base64Url) { base64Url = false } var char1, char2, char3, enc1, enc2, enc3, enc4 var i for (i = 0; i < input.length; i += 3) { char1 = input[i] char2 = input[i + 1] char3 = input[i + 2] enc1 = char1 >> 2 enc2 = ((char1 & 0x3) << 4) | (char2 >> 4) enc3 = ((char2 & 0xf) << 2) | (char3 >> 6) enc4 = char3 & 0x3f if (isNaN(char2)) { enc3 = enc4 = 64 } else if (isNaN(char3)) { enc4 = 64 } output = output + encodingChars.charAt(enc1) + encodingChars.charAt(enc2) + encodingChars.charAt(enc3) + encodingChars.charAt(enc4) } if (base64Url) { return output .replace(/\+/g, '-') .replace(/\//g, '_') .replace(/\=/g, '') } return output } function base64ToBytes(encodedString) { encodedString = encodedString.replace(/-/g, '+').replace(/_/g, '/') while (encodedString.length % 4 !== 0) { encodedString += '=' } var output = [] var char1, char2, char3 var enc1, enc2, enc3, enc4 var i encodedString = encodedString.replace(/[^A-Za-z0-9\+\/\=]/g, '') for (i = 0; i < encodedString.length; i += 4) { enc1 = encodingChars.indexOf(encodedString.charAt(i)) enc2 = encodingChars.indexOf(encodedString.charAt(i + 1)) enc3 = encodingChars.indexOf(encodedString.charAt(i + 2)) enc4 = encodingChars.indexOf(encodedString.charAt(i + 3)) char1 = (enc1 << 2) | (enc2 >> 4) char2 = ((enc2 & 15) << 4) | (enc3 >> 2) char3 = ((enc3 & 3) << 6) | enc4 output.push(char1) if (enc3 !== 64) { output.push(char2) } if (enc4 !== 64) { output.push(char3) } } return output } function getObjectType(object) { return Object.prototype.toString.call(object).slice(8, -1) } function bytesToHexString(bytes, separate) { var result = '' if (typeof separate === 'undefined') { separate = false } for (var i = 0; i < bytes.length; i++) { if (separate && i % 4 === 0 && i !== 0) { result += '-' } var hexval = bytes[i].toString(16).toUpperCase() if (hexval.length === 1) { result += '0' } result += hexval } return result } function bytesToInt32(bytes, index) { index = index || 0 return ( (bytes[index] << 24) | (bytes[index + 1] << 16) | (bytes[index + 2] << 8) | bytes[index + 3] ) } function hexToBytesArray(hexString) { hexString = hexString.replace(/\-/g, '') var result = [] while (hexString.length >= 2) { result.push(parseInt(hexString.substring(0, 2), 16)) hexString = hexString.substring(2, hexString.length) } return result } function clone(object) { var newObject = {} for (var propertyName in object) { if (object.hasOwnProperty(propertyName)) { newObject[propertyName] = object[propertyName] } } return newObject } function unpackData(base64String, arraySize, toUint32s) { var bytes = base64ToBytes(base64String), data = [], i if (isNaN(arraySize)) { return bytes } else { for (i = 0; i < bytes.length; i += arraySize) { data.push(bytes.slice(i, i + arraySize)) } } if (toUint32s) { for (i = 0; i < data.length; i++) { data[i] = (data[i][0] << 24) + (data[i][1] << 16) + (data[i][2] << 8) + data[i][3] } } return data } function int32ToBytes(int32) { return [ (int32 >>> 24) & 255, (int32 >>> 16) & 255, (int32 >>> 8) & 255, int32 & 255, ] } function int32ArrayToBytes(int32Array) { var result = [] for (var i = 0; i < int32Array.length; i++) { result = result.concat(int32ToBytes(int32Array[i])) } return result } function xorVectors(a, b, res) { var length = Math.min(a.length, b.length), res = res || new Array(length) for (var i = 0; i < length; i += 1) { res[i] = a[i] ^ b[i] } return res } function getVector(length, fillValue) { if (isNaN(fillValue)) { fillValue = 0 } var res = new Array(length) for (var i = 0; i < length; i += 1) { res[i] = fillValue } return res } function toArray(typedArray) { if (!typedArray) { return [] } if (typedArray.pop) { return typedArray } if (getObjectType(typedArray) === 'ArrayBuffer') { typedArray = new Uint8Array(typedArray) } else if (typedArray.BYTES_PER_ELEMENT > 1) { typedArray = new Uint8Array(typedArray.buffer) } if (typedArray.length === 1) { return [typedArray[0]] } if (typedArray.length < 65536) { return Array.apply(null, typedArray) } var returnArray = new Array(typedArray.length) for (var i = 0; i < typedArray.length; i++) { returnArray[i] = typedArray[i] } return returnArray } function padEnd(array, value, finalLength) { while (array.length < finalLength) { array.push(value) } return array } function padFront(array, value, finalLength) { while (array.length < finalLength) { array.unshift(value) } return array } function arraysEqual(array1, array2) { var result = true if (array1.length !== array2.length) { result = false } for (var i = 0; i < array1.length; i++) { if (array1[i] !== array2[i]) { result = false } } return result } function verifyByteArray(array) { if (getObjectType(array) !== 'Array') { return false } var element for (var i = 0; i < array.length; i++) { element = array[i] if (isNaN(element) || element < 0 || element > 255) { return false } } return true } function checkParam(param, type, errorMessage) { if (!param) { throw new Error(errorMessage) } if (type && getObjectType(param) !== type) { throw new Error(errorMessage) } return true } function stringToBytes(text) { var encodedBytes = [] for (var i = 0, j = 0; i < text.length; i++) { var charCode = text.charCodeAt(i) if (charCode < 128) { encodedBytes[j++] = charCode } else if (charCode < 2048) { encodedBytes[j++] = (charCode >>> 6) | 192 encodedBytes[j++] = (charCode & 63) | 128 } else if (charCode < 0xd800 || charCode > 0xdfff) { encodedBytes[j++] = (charCode >>> 12) | 224 encodedBytes[j++] = ((charCode >>> 6) & 63) | 128 encodedBytes[j++] = (charCode & 63) | 128 } else { charCode = (charCode - 0xd800) * 0x400 + (text.charCodeAt(++i) - 0xdc00) + 0x10000 encodedBytes[j++] = (charCode >>> 18) | 240 encodedBytes[j++] = ((charCode >>> 12) & 63) | 128 encodedBytes[j++] = ((charCode >>> 6) & 63) | 128 encodedBytes[j++] = (charCode & 63) | 128 } } return encodedBytes } function bytesToString(textBytes) { var result = '', charCode textBytes = toArray(textBytes) for (var i = 0; i < textBytes.length; ) { var encodedChar = textBytes[i++] if (encodedChar < 128) { charCode = encodedChar } else if (encodedChar < 224) { charCode = (encodedChar << 6) + textBytes[i++] - 0x3080 } else if (encodedChar < 240) { charCode = (encodedChar << 12) + (textBytes[i++] << 6) + textBytes[i++] - 0xe2080 } else { charCode = (encodedChar << 18) + (textBytes[i++] << 12) + (textBytes[i++] << 6) + textBytes[i++] - 0x3c82080 } if (charCode > 0xffff) { var surrogateHigh = Math.floor((charCode - 0x10000) / 0x400) + 0xd800 var surrogateLow = ((charCode - 0x10000) % 0x400) + 0xdc00 result += String.fromCharCode(surrogateHigh, surrogateLow) continue } result += String.fromCharCode(charCode) } return result } return { consoleLog: consoleLog, toBase64: toBase64, fromBase64: base64ToBytes, checkParam: checkParam, getObjectType: getObjectType, bytesToHexString: bytesToHexString, bytesToInt32: bytesToInt32, stringToBytes: stringToBytes, bytesToString: bytesToString, unpackData: unpackData, hexToBytesArray: hexToBytesArray, int32ToBytes: int32ToBytes, int32ArrayToBytes: int32ArrayToBytes, toArray: toArray, arraysEqual: arraysEqual, clone: clone, xorVectors: xorVectors, padEnd: padEnd, padFront: padFront, getVector: getVector, verifyByteArray: verifyByteArray, } })() var asn1 = (function () { var asn1Types = { 0x00: 'CUSTOM', 0x01: 'BOOLEAN', 0x02: 'INTEGER', 0x03: 'BIT STRING', 0x04: 'OCTET STRING', 0x05: 'NULL', 0x06: 'OBJECT IDENTIFIER', 0x10: 'SEQUENCE', 0x11: 'SET', 0x13: 'PRINTABLE STRING', 0x17: 'UTCTime', } var asn1Classes = { 0x00: 'UNIVERSAL', 0x01: 'APPLICATION', 0x02: 'Context-Defined', 0x03: 'PRIVATE', } function parse(bytes, force) { force = !!force var type = asn1Types[bytes[0] & 0x1f], dataLen = bytes[1], i = 0, constructed = !!(bytes[0] & 0x20), remainder, child, header if (dataLen & 0x80) { for (i = 0, dataLen = 0; i < (bytes[1] & 127); i++) { dataLen = (dataLen << 8) + bytes[2 + i] } } header = 2 + i if (type === undefined || dataLen > bytes.length) { return null } var obj = constructed ? [] : {} obj.type = type obj.header = header obj.data = bytes.slice(0, dataLen + header) if (constructed || force) { if (obj.type === 'BIT STRING' && bytes[header] === 0) { i++ } remainder = bytes.slice(header, obj.data.length) while (remainder.length > 0) { child = parse(remainder) if (child === null) { break } obj.push(child) remainder = remainder.slice(child.data.length) } } return obj } function encode(asn1tree) { throw new Error('not implemented') } function toString(objTree, indent) { var output = new Array(indent + 1).join(' ') + objTree.type + ' (' + objTree.length + ') ' + bytesToHexString(objTree.data).substring(0, 16) + '\n' if (!objTree.children) { return output } for (var i = 0; i < objTree.children.length; i++) { output += toString(objTree.children[i], indent + 4) + '' } return output } return { parse: parse, encode: encode, toString: function (objTree) { return toString(objTree, 0) }, } })() var msrcryptoWorker = (function () { function returnResult(result) { if (workerInitialized && runningInWorkerInstance) { self.postMessage(result) } return result } var workerId, operationType, operationSubType return { jsCryptoRunner: function (e) { workerId = e.data.workerid operationType = e.data.operationType operationSubType = e.data.operationSubType var operation = e.data.operationType, result, func = operations[operation][e.data.algorithm.name], p = e.data if (!operations.exists(operation, e.data.algorithm.name)) { throw new Error('unregistered algorithm.') } if (p.operationSubType) { result = returnResult({ type: p.operationSubType, result: func(p), }) } else { result = returnResult(func(p)) } return result }, returnResult: returnResult, } })() if (runningInWorkerInstance) { self.onmessage = function (e) { if (!workerInitialized && e.data.prngSeed) { var entropy = e.data.prngSeed msrcryptoPseudoRandom.init(entropy) workerInitialized = true return msrcryptoWorker.returnResult({ initialized: true, }) } if (workerInitialized === true) { msrcryptoWorker.jsCryptoRunner(e) } } } var msrcryptoJwk = (function () { var utils = msrcryptoUtilities function stringToArray(stringData) { var result = [] for (var i = 0; i < stringData.length; i++) { result[i] = stringData.charCodeAt(i) } if (result[result.length - 1] === 0) { result.pop() } return result } function getKeyType(keyHandle) { var algType = keyHandle.algorithm.name.slice(0, 3).toUpperCase() if (algType === 'RSA') { return 'RSA' } if (algType === 'ECD') { return 'EC' } return 'oct' } function hashSize(algorithm) { return algorithm.hash.name.substring( algorithm.hash.name.indexOf('-') + 1, ) } var algorithmMap = { HMAC: function (algorithm) { return 'HS' + hashSize(algorithm) }, 'AES-CBC': function (algorithm) { return 'A' + algorithm.length.toString() + 'CBC' }, 'AES-GCM': function (algorithm) { return 'A' + algorithm.length.toString() + 'GCM' }, 'RSAES-PKCS1-V1_5': function (algorithm) { return 'RSA1_5' }, 'RSASSA-PKCS1-V1_5': function (algorithm) { return 'RS' + hashSize(algorithm) }, 'RSA-OAEP': function (algorithm) { if (algorithm.hash.name.toUpperCase() === 'SHA-1') { return 'RSA-OAEP' } return 'RSA-OAEP-' + hashSize(algorithm) }, 'RSA-PSS': function (algorithm) { return 'PS' + hashSize(algorithm) }, ECDSA: function (algorithm) { return ( 'EC-' + algorithm.namedCurve.substring( algorithm.namedCurve.indexOf('-') + 1, ) ) }, } function keyToJwk(keyHandle, keyData) { var key = {} key.kty = getKeyType(keyHandle) key.ext = keyHandle.extractable if (algorithmMap[keyHandle.algorithm.name.toUpperCase()]) { key.alg = algorithmMap[keyHandle.algorithm.name.toUpperCase()]( keyHandle.algorithm, ) } key.key_ops = keyHandle.usages if (keyData.pop) { key.k = utils.toBase64(keyData, true) } else { for (var property in keyData) { if (keyData[property].pop && property !== 'key_ops') { key[property] = utils.toBase64(keyData[property], true) } } } if (keyHandle.algorithm.namedCurve) { key.crv = keyHandle.algorithm.namedCurve } return key } function findUsage(usage, usages) { for (var i = 0; i < usages.length; i++) { if (usage.toUpperCase() === usages[i].toUpperCase()) { return true } } return false } function keyToJwkOld(keyHandle, keyData) { var key = {} key.kty = getKeyType(keyHandle) key.extractable = keyHandle.extractable if (keyData.pop) { key.k = utils.toBase64(keyData, true) } else { for (var property in keyData) { if (keyData[property].pop) { key[property] = utils.toBase64(keyData[property], true) } } } if (keyHandle.algorithm.namedCurve) { key.crv = keyHandle.algorithm.namedCurve } var stringData = JSON.stringify(key, null, '\t') return stringToArray(stringData) } function jwkToKey(keyData, algorithm, propsToArray) { var jsonKeyObject = JSON.parse(JSON.stringify(keyData)) for (var i = 0; i < propsToArray.length; i += 1) { var propValue = jsonKeyObject[propsToArray[i]] if (propValue) { jsonKeyObject[propsToArray[i]] = utils.fromBase64(propValue) } } return jsonKeyObject } return { keyToJwkOld: keyToJwkOld, keyToJwk: keyToJwk, jwkToKey: jwkToKey, } })() function msrcryptoMath() { var DIGIT_BITS = 24 var DIGIT_NUM_BYTES = Math.floor(DIGIT_BITS / 8) var DIGIT_MASK = (1 << DIGIT_BITS) - 1 var DIGIT_BASE = 1 << DIGIT_BITS var DIGIT_MAX = DIGIT_MASK var DIG_INV = 1 / DIGIT_BASE var DIGIT_MAX_ADDS = 31 var DIGIT_SCALER = [1, 256] for (var ds = 2; ds <= DIGIT_NUM_BYTES; ds++) { DIGIT_SCALER[ds] = DIGIT_SCALER[ds - 1] * 256 } var Zero = [0] var One = [1] function createArray(parameter) { var i, array = null if (!arguments.length || typeof arguments[0] === 'number') { array = new Array(parameter) for (i = 0; i < parameter; i += 1) { array[i] = 0 } } else if (typeof arguments[0] === 'object') { array = new Array(parameter.length) for (i = 0; i < parameter.length; i += 1) { array[i] = parameter[i] } } return array } function stringToDigits(numberStr, radix) { numberStr = numberStr.replace(/^\s+|\s+$/g, '') var num = [0] var buffer = [0] radix = radix || 10 for (var i = 0; i < numberStr.length; i += 1) { var char = parseInt(numberStr[i], radix) if (isNaN(char)) { throw new Error( 'Failed to convert string to integer in radix ' + radix.toString(), ) } multiply(num, radix, buffer) add(buffer, [char], num) normalizeDigitArray(num) } return num } function digitsToString(digits, radix) { radix = radix || 10 if (DIGIT_BASE <= radix) { throw new Error('DIGIT_BASE is smaller than RADIX; cannot convert.') } var wordLength = digits.length var quotient = [] var remainder = [] var temp1 = [] var temp2 = [] var divisor = [] var a = [] var i var sb = '' var pad = '0' divisor[0] = radix while (Math.floor(DIGIT_BASE / divisor[0]) >= radix) { divisor[0] = divisor[0] * radix pad = pad.concat('0') } for (i = 0; i < wordLength; i += 1) { a[i] = digits[i] } do { var allZeros = true for (i = 0; i < a.length; i += 1) { if (a[i] !== 0) { allZeros = false break } } if (allZeros) { break } divRem(a, divisor, quotient, remainder, temp1, temp2) normalizeDigitArray(quotient, a.length, true) var newDigits = remainder[0].toString(radix) sb = pad.substring(0, pad.length - newDigits.length) + newDigits + sb var swap = a a = quotient quotient = swap } while (true) while (sb.length !== 0 && sb[0] === '0') { sb = sb.substring(1, sb.length) } if (sb.length === 0) { sb = '0' } return sb } function computeBitArray(bytes) { var out = createArray(bytes.length * 8) var bitLength = 0 var i = bytes.length - 1 while (i >= 0) { var j = 0 while (j < 8) { var mask = 1 << j var bit = (bytes[i] & mask) === mask ? 1 : 0 var thisBitIndex = 8 * (bytes.length - i - 1) + j if (bit === 1) { bitLength = thisBitIndex + 1 } out[thisBitIndex] = bit j += 1 } i-- } return out.slice(0, bitLength) } function bitScanForward(digit) { var index = 0 for (var i = 0; i < DIGIT_BITS; i++) { index = Math.max(index, -((digit >>> i) & 1) & i) } return index } function highestSetBit(bytes) { var i = 0 var bitLength = 0 while (i < bytes.length) { if (bitLength === 0) { var j = 7 while (j >= 0 && bitLength === 0) { var mask = 1 << j if ((bytes[i] & mask) === mask) { bitLength = j + 1 } j-- } } else { bitLength += 8 } i += 1 } return bitLength } function fixedWindowRecode(digits, windowSize, t) { digits = digits.slice() var recodedDigits = [], windowSizeBits = Math.pow(2, windowSize), windowSizeMinus1Bits = Math.pow(2, windowSize - 1) for (var i = 0; i < t; i++) { recodedDigits[i] = (digits[0] % windowSizeBits) - windowSizeMinus1Bits digits[0] = digits[0] - recodedDigits[i] cryptoMath.shiftRight(digits, digits, windowSize - 1) } recodedDigits[i] = digits[0] return recodedDigits } function fixedWindowRecode2(digits, windowSize) { var digLen = digits.length, bits = new Array(digLen * DIGIT_BITS), i = 0, j = 0, k = 0, r = 0, dig, result = new Array(Math.ceil((digLen * DIGIT_BITS) / windowSize)) for (k = 0, result[0] = 0; i < digLen; i++) { for (j = 0, dig = digits[i]; j < DIGIT_BITS; j++, dig >>>= 1) { if (k === windowSize) { result[++r] = 0 k = 0 } result[r] += (dig & 1) << k++ } } return result } function fetchBits(digits, startBit, count) { var startDigit = Math.floor(startBit / cryptoMath.DIGIT_BITS) var endDigit = startDigit + 1 var shiftRight = startBit % cryptoMath.DIGIT_BITS var shiftLeft = cryptoMath.DIGIT_BITS - shiftRight var bits = (digits[startDigit] >>> shiftRight) | (digits[endDigit] << shiftLeft) return ( bits & (cryptoMath.DIGIT_MASK >>> (cryptoMath.DIGIT_BITS - count)) ) } function fetchBits2(digits, startBit, count) { var startDigit = Math.floor(startBit / DIGIT_BITS), shiftRight = startBit % DIGIT_BITS return ( (digits[startDigit] >>> shiftRight) | ((digits[startDigit + 1] << (DIGIT_BITS - shiftRight)) & (DIGIT_MASK >>> (DIGIT_BITS - count))) ) } function copyArray(source, sourceIndex, destination, destIndex, length) { while (length-- > 0) { destination[destIndex + length] = source[sourceIndex + length] } } function isZero(array) { var i, result = 0 for (i = 0; i < array.length; i += 1) { result = result | array[i] } return !result } function isEven(array) { return (array[0] & 0x1) === 0x0 } function sequenceEqual(left, right) { var equal = left.length === right.length for (var i = 0; i < Math.min(left.length, right.length); i += 1) { if (left[i] !== right[i]) { equal = false } } return equal } function bytesToDigits(bytes) { var arrayLength = Math.floor( (bytes.length + DIGIT_NUM_BYTES - 1) / DIGIT_NUM_BYTES, ) var array = new Array(arrayLength) array[0] = 0 var digit = 0, index = 0, scIndex = 0 for (var i = bytes.length - 1; i >= 0; i--) { digit = digit + DIGIT_SCALER[scIndex++] * (bytes[i] & 0x0ff) if (DIGIT_SCALER[scIndex] === DIGIT_BASE) { scIndex = 0 array[index++] = digit digit = 0 } } if (digit !== 0) { array[index] = digit } while (array[--arrayLength] == null) { array[arrayLength] = 0 } return array } function digitsToBytes(digits, trim, minTrimLength) { var i, j, byte1 var bytes = [0] if (typeof trim === 'undefined') { trim = true } for (i = 0; i < digits.length; i += 1) { byte1 = digits[i] for (j = 0; j < DIGIT_NUM_BYTES; j += 1) { bytes[i * DIGIT_NUM_BYTES + j] = byte1 & 0x0ff byte1 = Math.floor(byte1 / 256) } } bytes.reverse() if (minTrimLength === undefined) { minTrimLength = 1 } if (trim) { while (bytes.length > minTrimLength && bytes[0] === 0) { bytes.shift() } } return bytes } function intToDigits(value, numDigits) { if (typeof numDigits === 'undefined') { if (value <= 1) { numDigits = 1 } else { var numBits = Math.log(value) / Math.LN2 numDigits = Math.ceil(numBits / DIGIT_BITS) } } var digitRepresentation = [] while (value > 0) { digitRepresentation.push(value % DIGIT_BASE) value = Math.floor(value / DIGIT_BASE) } while (digitRepresentation.length < numDigits) { digitRepresentation.push(0) } return digitRepresentation } function mswIndex(digits) { for (var i = digits.length - 1; i >= 0; i--) { if (digits[i] !== undefined && digits[i] !== 0) { return i } } return digits[0] === 0 ? -1 : 0 } function compareDigits(left, right) { var result = 0, val, i for (i = 0; i < Math.max(left.length, right.length); i++) { val = ~~left[i] - ~~right[i] result = val + (result & -!val) } return result } function normalizeDigitArray(digits, length, pad) { var i = mswIndex(digits) digits.length = length || i + 1 if (pad) { while (++i < digits.length) { digits[i] = 0 } } if (digits.length <= 0) { digits[0] = 0 digits.length = 1 } return digits } function shiftRight(source, destination, bits, length) { if (bits === undefined) { bits = 1 } else if (bits >= DIGIT_BITS || bits < 0) { throw new Error('Invalid bit count for shiftRight') } if (length === undefined) { length = source.length } var n = length - 1 var leftShiftBitCount = DIGIT_BITS - bits for (var i = 0; i < n; i++) { destination[i] = ((source[i + 1] << leftShiftBitCount) | (source[i] >>> bits)) & DIGIT_MASK } destination[n] = source[n] >>> bits } function shiftLeft(source, destination, bits, length) { if (bits === undefined) { bits = 1 } else if (bits >= DIGIT_BITS || bits < 0) { throw new Error( 'bit count must be smaller than DIGIT_BITS and positive in shiftLeft', ) } if (length === undefined) { length = source.length } var rightShiftBitCount = DIGIT_BITS - bits destination[length] = source[length - 1] >>> (DIGIT_BITS - bits) || destination[length] for (var i = length - 1; i > 0; i--) { destination[i] = ((source[i] << bits) | (source[i - 1] >>> rightShiftBitCount)) & DIGIT_MASK } destination[0] = (source[0] << bits) & DIGIT_MASK } function add(addend1, addend2, sum) { var shortArray = addend1 var longArray = addend2 if (addend2.length < addend1.length) { shortArray = addend2 longArray = addend1 } var s = shortArray.length var carry = 0 var i for (i = 0; i < s; i += 1) { carry += shortArray[i] + longArray[i] sum[i] = carry & DIGIT_MASK carry = carry >> DIGIT_BITS } for (i = s; i < longArray.length; i += 1) { carry += longArray[i] sum[i] = carry & DIGIT_MASK carry = carry >> DIGIT_BITS } sum.length = longArray.length if (carry !== 0) { sum[i] = carry & DIGIT_MASK } return carry } function subtract(minuend, subtrahend, difference) { var s = subtrahend.length if (minuend.length < subtrahend.length) { s = mswIndex(subtrahend) + 1 if (minuend.length < s) { throw new Error('Subtrahend is longer than minuend, not supported.') } } var i, carry = 0 for (i = 0; i < s; i += 1) { carry += minuend[i] - subtrahend[i] difference[i] = carry & DIGIT_MASK carry = carry >> DIGIT_BITS } while (i < minuend.length) { carry += minuend[i] difference[i++] = carry & DIGIT_MASK carry = carry >> DIGIT_BITS } return carry } function multiply(a, b, p) { b = typeof b === 'number' ? [b] : b var i, j, k, l, c, t1, t2, alen = a.length, blen = b.length, bi for (i = 0; i < alen + blen; i += 1) { p[i] = 0 } i = 0 l = 0 var maxRounds = 31 var ks = 0 while (i < blen) { l = Math.min(l + maxRounds, blen) for (; i < l; i++) { bi = b[i] for (j = 0; j < alen; j++) { p[i + j] += a[j] * bi } } c = 0 for (k = ks; k < i + alen; k++) { t1 = p[k] + c t2 = t1 & DIGIT_MASK p[k] = t2 c = (t1 - t2) * DIG_INV } p[k] = c ks += maxRounds } p.length = alen + blen return p } function divRem(dividend, divisor, quotient, remainder, temp1, temp2) { var m = mswIndex(dividend) + 1 var n = mswIndex(divisor) + 1 var qhat, rhat, carry, p, t, i, j if (m < n) { copyArray(dividend, 0, remainder, 0, dividend.length) remainder.length = dividend.length normalizeDigitArray(remainder) quotient[0] = 0 quotient.length = 1 return } else if (n === 0 || (n === 1 && divisor[n - 1] === 0)) { throw new Error('Division by zero.') } else if (n === 1) { t = divisor[0] rhat = 0 for (j = m - 1; j >= 0; j--) { p = rhat * DIGIT_BASE + dividend[j] quotient[j] = (p / t) & DIGIT_MASK rhat = (p - quotient[j] * t) & DIGIT_MASK } quotient.length = m normalizeDigitArray(quotient) remainder[0] = rhat remainder.length = 1 return } var s = DIGIT_BITS - 1 - bitScanForward(divisor[n - 1]) var vn = temp1 || [] vn.length = n shiftLeft(divisor, vn, s, n) var un = temp2 || [] un.length = m shiftLeft(dividend, un, s, m) un[m] = un[m] || 0 quotient.length = m - n + 1 remainder.length = n for (j = m - n; j >= 0; j--) { qhat = Math.floor( (un[j + n] * DIGIT_BASE + un[j + n - 1]) / vn[n - 1], ) rhat = un[j + n] * DIGIT_BASE + un[j + n - 1] - qhat * vn[n - 1] while (true) { if ( qhat >= DIGIT_BASE || qhat * vn[n - 2] > rhat * DIGIT_BASE + un[j + n - 2] ) { qhat = qhat - 1 rhat = rhat + vn[n - 1] if (rhat < DIGIT_BASE) { continue } } break } carry = 0 for (i = 0; i < n; i++) { p = qhat * vn[i] t = un[i + j] - carry - (p & DIGIT_MASK) un[i + j] = t & DIGIT_MASK carry = Math.floor(p / DIGIT_BASE) - Math.floor(t / DIGIT_BASE) } t = un[j + n] - carry un[j + n] = t & DIGIT_MASK quotient[j] = qhat & DIGIT_MASK if (t < 0) { quotient[j] = quotient[j] - 1 carry = 0 for (i = 0; i < n; i++) { t = un[i + j] + vn[i] + carry un[i + j] = t & DIGIT_MASK carry = t >> DIGIT_BITS } un[j + n] = (un[j + n] + carry) & DIGIT_MASK } } for (i = 0; i < n; i++) { remainder[i] = ((un[i] >>> s) | (un[i + 1] << (DIGIT_BITS - s))) & DIGIT_MASK } normalizeDigitArray(quotient) normalizeDigitArray(remainder) } function reduce(number, modulus, remainder, temp1, temp2) { var quotient = [] divRem(number, modulus, quotient, remainder, temp1, temp2) return remainder } function modMul( multiplicand, multiplier, modulus, product, temp1, temp2, ) { var quotient = [] multiply(multiplicand, multiplier, quotient) divRem(quotient, modulus, quotient, product, temp1, temp2) return product } function eea(a, b, upp, vpp, rpp) { var rp if (isZero(a)) { copyArray(b, 0, rpp, 0, b.length) rpp.length = b.length return 0 } else if (isZero(b)) { copyArray(a, 0, rpp, 0, a.length) rpp.length = a.length return 0 } else if (compareDigits(a, b) < 0) { rp = a.slice(0) copyArray(b, 0, rpp, 0, b.length) rpp.length = b.length } else { rp = b.slice(0) copyArray(a, 0, rpp, 0, a.length) rpp.length = a.length } normalizeDigitArray(rpp) normalizeDigitArray(rp) var q = new Array(rpp.length) var r = new Array(rpp.length) var v = new Array(rpp.length) var vppPresent = vpp !== undefined var vp if (vppPresent) { vp = new Array(rpp.length) vp[0] = 1 vp.length = 1 vpp[0] = 0 vpp.length = 1 } var up var u = new Array(rpp.length) var uppPresent = upp !== undefined if (uppPresent) { up = new Array(rpp.length) up[0] = 0 up.length = 1 upp[0] = 1 upp.length = 1 } var k = -1 var upp_out = upp var vpp_out = vpp var rpp_out = rpp var save while (!isZero(rp)) { divRem(rpp, rp, q, r, u, v) if (uppPresent) { multiply(q, up, u) add(u, upp, u) normalizeDigitArray(u) save = upp upp = up up = u u = save } if (vppPresent) { multiply(q, vp, v) add(v, vpp, v) normalizeDigitArray(v) save = vpp vpp = vp vp = v v = save } save = rpp rpp = rp rp = r r = save k++ } if (uppPresent) { copyArray(upp, 0, upp_out, 0, upp.length) upp_out.length = upp.length } if (vppPresent) { copyArray(vpp, 0, vpp_out, 0, vpp.length) vpp_out.length = vpp.length } copyArray(rpp, 0, rpp_out, 0, rpp.length) rpp_out.length = rpp.length return k } function gcd(a, b, output) { var aa = a var bb = b if (compareDigits(a, b) > 0) { aa = b bb = a } eea(aa, bb, undefined, undefined, output) return normalizeDigitArray(output) } function modInv(a, n, aInv, pad) { var upp = new Array(n.length) var vpp = new Array(n.length) var rpp = new Array(n.length) var k = eea(a, n, vpp, upp, rpp) aInv = aInv || [] if (compareDigits(rpp, One) !== 0) { aInv[0] = NaN aInv.length = 1 } else { if ((k & 1) === 1) { subtract(n, upp, aInv) } else { copyArray(upp, 0, aInv, 0, upp.length) aInv.length = upp.length } if (pad) { normalizeDigitArray(aInv, n.length, true) } else { normalizeDigitArray(aInv) } } return aInv } function modInvCT(a, n, aInv, pad) { var nMinus2 = [] aInv = aInv || [] subtract(n, [2], nMinus2) modExp(a, nMinus2, n, aInv) normalizeDigitArray(aInv) return aInv } function modExp(base, exponent, modulus, result) { result = result || [] if (compareDigits(exponent, Zero) === 0) { result[0] = 1 } else if (compareDigits(exponent, One) === 0) { copyArray(base, 0, result, 0, base.length) result.length = base.length } else { var montmul = new MontgomeryMultiplier(modulus) normalizeDigitArray(base, montmul.s, true) montmul.modExp(base, exponent, result) result.length = modulus.length } return result } function MontgomeryMultiplier(modulus, context) { function computeM0Prime(m0) { var m0Pr = 1 var a = 2 var b = 3 var c = b & m0 for (var i = 2; i <= DIGIT_BITS; i += 1) { if (a < c) { m0Pr += a } a = a << 1 b = (b << 1) | 1 c = (m0 * m0Pr) & b } var result = (~m0Pr & DIGIT_MASK) + 1 return result } function montgomeryReduction(t, m, result) { var m0 = m[0] var mPrime = computeM0Prime(m0) var n = m.length var A = t.slice(0) var ui = [] var uimbi = [] var uim = [] var bi = [1] for (var i = 0; i < n; i++) { ui = (A[i] * mPrime) % DIGIT_BASE multiply(m, [ui], uim) multiply(uim, bi, uimbi) add(A, uimbi, A) bi.unshift(0) } A = A.slice(n) for (i = 0; i < A.length; i++) { result[i] = A[i] } } function montgomeryMultiply(multiplicand, multiplier, result, ctx) { ctx = ctx || this var m = ctx.m, s = m.length, mPrime = ctx.mPrime, m0 = ctx.m0, rightI, r0, q, i = 0, j, jm1, t1, t2, carry, rounds = 0 var temp = createArray(s + 2) while (i < s) { rounds = Math.min(s, rounds + 16) for (; i < rounds; ) { rightI = ~~multiplier[i] r0 = temp[0] + multiplicand[0] * rightI q = ((r0 & DIGIT_MASK) * mPrime) & DIGIT_MASK temp[1] += ((m0 * q + r0) * DIG_INV) | 0 for (j = 1, jm1 = 0; j < s; jm1 = j, j += 1) { temp[jm1] = temp[j] + m[j] * q + multiplicand[j] * rightI } temp[jm1] = temp[j] temp[j] = 0 i++ } carry = 0 for (j = 0; j < s; j++) { t1 = temp[j] + carry t2 = t1 & DIGIT_MASK temp[j] = t2 carry = (t1 - t2) * DIG_INV } temp[j] = carry } for (i = 0; i < s; i += 1) { result[i] = temp[i] } result.length = s var needSubtract = +(cryptoMath.compareDigits(temp, m) > 0) cryptoMath.subtract(result, m, ctx.temp2) ctSetArray(needSubtract, result, ctx.temp2) return } function convertToMontgomeryForm(digits) { if (digits.length < this.s) { digits.length = this.s for (var i = 0; i < this.s; i++) { digits[i] = isNaN(digits[i]) ? 0 : digits[i] } } var result = createArray(digits.length) this.montgomeryMultiply(digits, this.rSquaredModm, result) for (i = 0; i < this.s; i += 1) { digits[i] = result[i] } } function convertToStandardForm(digits) { this.montgomeryMultiply(digits, this.one, this.temp1) for (var i = 0; i < this.s; i += 1) { digits[i] = this.temp1[i] } } function optimalWindowSize(length) { var i = 2, t1, t0, bits = length * DIGIT_BITS t0 = 4 + Math.ceil(bits / 2) * 3 + 1 do { i++ t1 = t0 t0 = Math.pow(2, i) + Math.ceil(bits / i) * (i + 1) + 1 } while (t0 < t1) return i - 1 } function modExp(base, exponent, result, skipSideChannel) { skipSideChannel = !!skipSideChannel var windowBits = optimalWindowSize(exponent.length) var i, j, expBits = fixedWindowRecode2(exponent, windowBits).reverse(), partialResult = this.rModM.slice(0), baseTableLen = Math.pow(2, windowBits), bt = baseTable bt.length = baseTableLen bt[0] = this.rModM for (i = 1; i < baseTableLen; i++) { bt[i] = [] multiply(bt[i - 1], base, bt[i]) this.reduce(bt[i]) } var tableVal = [] var exp for (i = 0; i < expBits.length; i++) { for (j = 0; j < windowBits; j++) { this.montgomeryMultiply( partialResult, partialResult, partialResult, ) } exp = expBits[i] skipSideChannel ? (tableVal = bt[exp]) : getTableEntry(bt, exp, tableVal) this.montgomeryMultiply(partialResult, tableVal, partialResult) } this.montgomeryMultiply(partialResult, this.one, result) return result } function getTableEntry(bt, exp, tableVal) { var z, t, mask, tableEntry, k for (z = 0; z < bt[0].length; z++) { tableVal[z] = 0 } for (t = 0; t < bt.length; t++) { tableEntry = bt[t] mask = -(exp === t) for (k = 0; k < tableEntry.length; k++) { tableVal[k] = tableVal[k] | (tableEntry[k] & mask) } } } function ctSetArray(condition, a, b) { var bMask = -condition var aMask = ~bMask for (var i = 0; i < a.length; i++) { a[i] = (a[i] & aMask) | (b[i] & bMask) } } function reduce(x, result) { var k = this.m.length, q1, q2, q3, r1, r2, i, needSubtract, temp = [] result = result || x q1 = x.slice(k - 1) q2 = [] multiply(q1, this.mu, q2) q3 = q2.slice(k + 1) r1 = x.slice(0, k + 1) r2 = [] multiply(q3, m, r2) r2 = r2.slice(0, k + 1) r1[k + 1] = compareDigits(r1, r2) >>> 31 for (i = 0; i < result.length; i++) { result[i] = 0 } subtract(r1, r2, result) needSubtract = +(compareDigits(result, m) > 0) cryptoMath.subtract(result, m, temp) ctSetArray(needSubtract, result, temp) normalizeDigitArray(result) return } function computeContext(modulus) { var s = modulus.length var m0 = modulus[0] var ctx = { m: modulus, mPrime: computeM0Prime(m0), m0: m0, temp1: createArray(2 * s + 1), temp2: createArray(2 * s + 1), } var R = createArray(modulus.length * 2) R[R.length] = 1 ctx.mu = [] divRem(R, modulus, ctx.mu, []) var quotient = createArray(2 * s + 1) var rRemainder = createArray(s + 1) var temp1 = createArray(2 * s + 1) var temp2 = createArray(2 * s + 1) var rDigits = rRemainder rDigits[s] = 1 divRem(rDigits, modulus, quotient, rRemainder, temp1, temp2) ctx.rModM = normalizeDigitArray(rRemainder, s, true) var rSquaredModm = createArray(2 * s + 1) var rSquaredDigits = rSquaredModm rSquaredDigits[s * 2] = 1 divRem(rSquaredDigits, modulus, quotient, rSquaredModm, temp1, temp2) ctx.rSquaredModm = normalizeDigitArray(rSquaredModm, s, true) ctx.rCubedModm = createArray(s) montgomeryMultiply(rSquaredModm, rSquaredModm, ctx.rCubedModm, ctx) return ctx } context = context || computeContext(modulus) var m = context.m var mu = context.mu var m0 = context.m0 var s = m.length var zeros = createArray(s + 1) var one = zeros.slice(0, s) one[0] = 1 var mPrime = context.mPrime var rModM = context.rModM var rSquaredModm = context.rSquaredModm var rCubedModm = context.rCubedModm var temp1 = createArray(2 * s + 1) var temp2 = createArray(2 * s + 1) var baseTable = new Array(4) baseTable[0] = rModM baseTable[1] = new Array(s) baseTable[2] = new Array(s) baseTable[3] = new Array(s) return { m: m, m0: m0, mPrime: mPrime, mu: mu, rSquaredModm: rSquaredModm, s: s, rModM: rModM, rCubedModm: rCubedModm, one: one, temp1: temp1, temp2: temp2, convertToMontgomeryForm: convertToMontgomeryForm, convertToStandardForm: convertToStandardForm, montgomeryMultiply: montgomeryMultiply, modExp: modExp, reduce: reduce, ctx: context, } } function IntegerGroup(modulusBytes) { var m_modulus = bytesToDigits(modulusBytes) var m_digitWidth = m_modulus.length var m_zero = intToDigits(0, m_digitWidth) var m_one = intToDigits(1, m_digitWidth) var temp0 = createArray(m_digitWidth) var temp1 = createArray(m_digitWidth) var montmul = new MontgomeryMultiplier(m_modulus) function createElementFromBytes(bytes) { var digits = bytesToDigits(bytes) if (cryptoMath.compareDigits(digits, this.m_modulus) >= 0) { throw new Error( 'The number provided is not an element of this group', ) } normalizeDigitArray(digits, this.m_digitWidth, true) return integerGroupElement(digits, this) } function createElementFromInteger(integer) { var digits = intToDigits(integer, this.m_digitWidth) return integerGroupElement(digits, this) } function createElementFromDigits(digits) { cryptoMath.normalizeDigitArray(digits, this.m_digitWidth, true) return integerGroupElement(digits, this) } function equals(otherGroup) { return compareDigits(this.m_modulus, otherGroup.m_modulus) === 0 } function add(addend1, addend2, sum) { var i var s = this.m_digitWidth var result = sum.m_digits cryptoMath.add(addend1.m_digits, addend2.m_digits, result) var mask = ((compareDigits(result, this.m_modulus) >>> 31) - 1) & DIGIT_MASK var carry = 0 for (i = 0; i < s; i += 1) { carry = result[i] - (this.m_modulus[i] & mask) + carry result[i] = carry & DIGIT_MASK carry = carry >> DIGIT_BITS } result.length = s } function subtract(leftElement, rightElement, outputElement) { var i, s = this.m_digitWidth var result = outputElement.m_digits var carry = cryptoMath.subtract( leftElement.m_digits, rightElement.m_digits, outputElement.m_digits, ) if (carry === -1) { carry = 0 for (i = 0; i < s; i += 1) { carry += result[i] + this.m_modulus[i] result[i] = carry & DIGIT_MASK carry = carry >> DIGIT_BITS } } } function inverse(element, outputElement) { cryptoMath.modInv( element.m_digits, this.m_modulus, outputElement.m_digits, ) } function multiply(multiplicand, multiplier, product) { return cryptoMath.modMul( multiplicand.m_digits, multiplier.m_digits, this.m_modulus, product.m_digits, temp0, temp1, ) } function modexp(valueElement, exponent, outputElement) { outputElement = outputElement || integerGroupElement([], this) if (compareDigits(exponent, m_zero) === 0) { outputElement.m_digits = intToDigits(1, this.m_digitWidth) } else if (compareDigits(exponent, m_one) === 0) { for (var i = 0; i < valueElement.m_digits.length; i++) { outputElement.m_digits[i] = valueElement.m_digits[i] } outputElement.m_digits.length = valueElement.m_digits.length } else { this.montmul.modExp( valueElement.m_digits, exponent, outputElement.m_digits, ) outputElement.m_digits.length = this.montmul.s } return outputElement } function integerGroupElement(digits, group) { return { m_digits: digits, m_group: group, equals: function (element) { return ( compareDigits(this.m_digits, element.m_digits) === 0 && this.m_group.equals(this.m_group, element.m_group) ) }, } } return { m_modulus: m_modulus, m_digitWidth: m_digitWidth, montmul: montmul, createElementFromInteger: createElementFromInteger, createElementFromBytes: createElementFromBytes, createElementFromDigits: createElementFromDigits, equals: equals, add: add, subtract: subtract, multiply: multiply, inverse: inverse, modexp: modexp, } } return { DIGIT_BITS: DIGIT_BITS, DIGIT_NUM_BYTES: DIGIT_NUM_BYTES, DIGIT_MASK: DIGIT_MASK, DIGIT_BASE: DIGIT_BASE, DIGIT_MAX: DIGIT_MAX, Zero: Zero, One: One, normalizeDigitArray: normalizeDigitArray, bytesToDigits: bytesToDigits, stringToDigits: stringToDigits, digitsToString: digitsToString, intToDigits: intToDigits, digitsToBytes: digitsToBytes, isZero: isZero, isEven: isEven, shiftRight: shiftRight, shiftLeft: shiftLeft, compareDigits: compareDigits, bitLength: highestSetBit, fixedWindowRecode: fixedWindowRecode, IntegerGroup: IntegerGroup, add: add, subtract: subtract, multiply: multiply, divRem: divRem, reduce: reduce, modInv: modInv, modInvCT: modInvCT, modExp: modExp, modMul: modMul, MontgomeryMultiplier: MontgomeryMultiplier, gcd: gcd, sequenceEqual: sequenceEqual, swapEndianness: function (bytes) { return bytes.reverse() }, computeBitArray: computeBitArray, } } var cryptoMath = cryptoMath || msrcryptoMath() function MsrcryptoECC() { var btd = cryptoMath.bytesToDigits function createArray(parameter) { var i, array = null if (!arguments.length || typeof arguments[0] === 'number') { array = [] for (i = 0; i < parameter; i += 1) { array[i] = 0 } } else if (typeof arguments[0] === 'object') { array = [] for (i = 0; i < parameter.length; i += 1) { array[i] = parameter[i] } } return array } var EllipticCurveFp = function (p1, a1, b1, order, gx, gy) { var fieldStorageBitLength = p1.length var generator = EllipticCurvePointFp(this, false, gx, gy, null, false) return { p: p1, a: a1, b: b1, order: order, generator: generator, allocatePointStorage: function () { return EllipticCurvePointFp( this, false, cryptoMath.intToDigits(0, fieldStorageBitLength), cryptoMath.intToDigits(0, fieldStorageBitLength), ) }, createPointAtInfinity: function () { return EllipticCurvePointFp( this, true, cryptoMath.intToDigits(0, fieldStorageBitLength), cryptoMath.intToDigits(0, fieldStorageBitLength), ) }, } } var createWeierstrassCurve = function (curveData) { var newCurve = new EllipticCurveFp( btd(curveData.p), btd(curveData.a), btd(curveData.b), btd(curveData.order), btd(curveData.gx), btd(curveData.gy), ) newCurve.type = curveData.type newCurve.name = curveData.name newCurve.generator.curve = newCurve return newCurve } var createTedCurve = function (curveData) { var newCurve = new EllipticCurveFp( btd(curveData.p), btd(curveData.a), btd(curveData.d), btd(curveData.order), btd(curveData.gx), btd(curveData.gy), ) newCurve.type = curveData.type if (newCurve.type === 1) { newCurve.d = newCurve.b.slice() delete newCurve.b } newCurve.rbits = curveData.info[2] newCurve.name = curveData.name newCurve.generator.curve = newCurve return newCurve } var EllipticCurvePointFp = function ( curve, isInfinity, x, y, z, isInMontgomeryForm, ) { var returnObj if (typeof z === 'undefined') { z = null } if (typeof isInMontgomeryForm === 'undefined') { isInMontgomeryForm = false } function equals(ellipticCurvePointFp) { if (!ellipticCurvePointFp) { return false } if (returnObj.isInfinity && ellipticCurvePointFp.isInfinity) { return true } if (returnObj.z === null && ellipticCurvePointFp.z !== null) { return false } if (returnObj.z !== null && ellipticCurvePointFp.z === null) { return false } if (returnObj.z === null) { return ( cryptoMath.compareDigits(returnObj.x, ellipticCurvePointFp.x) === 0 && cryptoMath.compareDigits(returnObj.y, ellipticCurvePointFp.y) === 0 && returnObj.isInMontgomeryForm === ellipticCurvePointFp.isInMontgomeryForm ) } return ( cryptoMath.compareDigits(returnObj.x, ellipticCurvePointFp.x) === 0 && cryptoMath.compareDigits(returnObj.y, ellipticCurvePointFp.y) === 0 && cryptoMath.compareDigits(returnObj.z, ellipticCurvePointFp.z) === 0 && returnObj.isInMontgomeryForm === ellipticCurvePointFp.isInMontgomeryForm ) } function copyTo(source, destination) { destination.curve = source.curve destination.x = source.x.slice() destination.y = source.y.slice() if (source.z !== null) { destination.z = source.z.slice() } else { destination.z = null } setterSupport || (destination.isAffine = source.isAffine) destination.isInMontgomeryForm = source.isInMontgomeryForm destination.isInfinity = source.isInfinity if (!destination.equals(source)) { throw new Error('Instances should be equal.') } } function clone() { var clonePoint = EllipticCurvePointFp( returnObj.curve, returnObj.isInfinity, createArray(returnObj.x), createArray(returnObj.y), returnObj.z ? createArray(returnObj.z) : null, returnObj.isInMontgomeryForm, ) returnObj.ta && (clonePoint.ta = createArray(returnObj.ta)) returnObj.tb && (clonePoint.tb = createArray(returnObj.tb)) return clonePoint } returnObj = { equals: function (ellipticCurvePointFp) { return equals(ellipticCurvePointFp) }, copy: function (destination) { copyTo(this, destination) return }, clone: function () { return clone() }, } createProperty( returnObj, 'curve', curve, function () { return curve }, function (val) { curve = val }, ) createProperty( returnObj, 'x', x, function () { return x }, function (val) { x = val }, ) createProperty( returnObj, 'y', y, function () { return y }, function (val) { y = val }, ) createProperty( returnObj, 'z', z, function () { return z }, function (val) { z = val }, ) createProperty( returnObj, 'isInMontgomeryForm', isInMontgomeryForm, function () { return isInMontgomeryForm }, function (val) { isInMontgomeryForm = val }, ) createProperty( returnObj, 'isInfinity', isInfinity, function () { return isInfinity }, function (val) { isInfinity = val }, ) createProperty(returnObj, 'isAffine', z === null, function () { return z === null }) return returnObj } var EllipticCurveOperatorFp = function (curve) { var m_curve = curve var tedCurve = curve.type === 1 var fieldElementWidth = curve.p.length var montgomeryMultiplier = cryptoMath.MontgomeryMultiplier(curve.p) var montgomerizedA = curve.a.slice() montgomeryMultiplier.convertToMontgomeryForm(montgomerizedA) var aequalsZero = cryptoMath.isZero(curve.a) var one = cryptoMath.One var onemontgomery = createArray(fieldElementWidth) onemontgomery[0] = 1 montgomeryMultiplier.convertToMontgomeryForm(onemontgomery) var group = cryptoMath.IntegerGroup( cryptoMath.digitsToBytes(montgomeryMultiplier.m), true, ) var temp0 = createArray(fieldElementWidth) var temp1 = createArray(fieldElementWidth) var temp2 = createArray(fieldElementWidth) var temp3 = createArray(fieldElementWidth) var temp4 = createArray(fieldElementWidth) var temp5 = createArray(fieldElementWidth) var temp6 = createArray(fieldElementWidth) var temp7 = createArray(fieldElementWidth) var swap0 = createArray(fieldElementWidth) var conversionTemp0 = createArray(fieldElementWidth) var conversionTemp1 = createArray(fieldElementWidth) var conversionTemp2 = createArray(fieldElementWidth) function modSub(left, right, result) { var resultElement = group.createElementFromInteger(0) resultElement.m_digits = result group.subtract( group.createElementFromDigits(left), group.createElementFromDigits(right), resultElement, ) } function modAdd(left, right, result) { var resultElement = group.createElementFromInteger(0) resultElement.m_digits = result group.add( group.createElementFromDigits(left), group.createElementFromDigits(right), resultElement, ) } function modInv(number, result) { cryptoMath.modInv(number, m_curve.p, result) } function modDivByTwo(dividend, result) { var s = dividend.length var modulus = curve.p if ((dividend[0] & 0x1) === 0x1) { var carry = 0 for (var i = 0; i < s; i += 1) { carry += dividend[i] + modulus[i] result[i] = carry & cryptoMath.DIGIT_MASK carry = carry >>> cryptoMath.DIGIT_BITS } carry = carry << (cryptoMath.DIGIT_BITS - 1) cryptoMath.shiftRight(result, result) result[s - 1] |= carry } else { cryptoMath.shiftRight(dividend, result) } } function montgomeryMultiply(left, right, result) { montgomeryMultiplier.montgomeryMultiply(left, right, result) } function montgomerySquare(left, result) { montgomeryMultiplier.montgomeryMultiply(left, left, result) } function correctInversion(digits) { var results = createArray(digits.length) montgomeryMultiply(digits, montgomeryMultiplier.rCubedModm, results) for (var i = 0; i < results.length; i += 1) { digits[i] = results[i] } } function doubleAequalsNeg3(point, outputPoint) { if (point.isInfinity) { outputPoint.isInfinity = true return } montgomerySquare(point.z, temp1) montgomeryMultiply(point.z, point.y, temp4) modAdd(point.x, temp1, temp2) modSub(point.x, temp1, temp1) outputPoint.z = temp4.slice() montgomeryMultiply(temp1, temp2, temp3) modDivByTwo(temp3, temp2) modAdd(temp3, temp2, temp1) montgomerySquare(point.y, temp2) montgomerySquare(temp1, temp4) montgomeryMultiply(point.x, temp2, temp3) modSub(temp4, temp3, temp4) modSub(temp4, temp3, outputPoint.x) modSub(temp3, outputPoint.x, temp4) montgomerySquare(temp2, temp3) montgomeryMultiply(temp1, temp4, temp2) modSub(temp2, temp3, outputPoint.y) outputPoint.isInfinity = false outputPoint.isInMontgomeryForm = true } function doubleAequals0(point, outputPoint) { if (point.isInfinity) { outputPoint.isInfinity = true return } montgomerySquare(point.y, temp3) montgomerySquare(point.x, temp4) modAdd(temp4, temp4, temp0) modAdd(temp0, temp4, temp4) montgomeryMultiply(point.x, temp3, temp5) montgomerySquare(temp3, temp0) modDivByTwo(temp4, temp1) montgomerySquare(temp1, temp3) montgomeryMultiply(point.y, point.z, swap0) for (var i = 0; i < swap0.length; i += 1) { outputPoint.z[i] = swap0[i] } modSub(temp3, temp5, outputPoint.x) modSub(outputPoint.x, temp5, outputPoint.x) modSub(temp5, outputPoint.x, temp4) montgomeryMultiply(temp1, temp4, temp2) modSub(temp2, temp0, outputPoint.y) outputPoint.isInfinity = false outputPoint.isInMontgomeryForm = true } function generatePrecomputationTable(w, generatorPoint) { var validationPoint = generatorPoint.clone() convertToStandardForm(validationPoint) if (!validatePoint(validationPoint)) { throw new Error('Invalid Parameter') } var pointJac = generatorPoint.clone() convertToJacobianForm(pointJac) var tablePos = [generatorPoint.clone()] var qJac = pointJac.clone() var px2 = pointJac.clone() double(pointJac, px2) convertToAffineForm(px2) var qAff for (var i = 1; i < Math.pow(2, w - 2); i++) { mixedAdd(qJac, px2, qJac) qAff = qJac.clone() convertToAffineForm(qAff) tablePos[i] = qAff } return tablePos } function double(point, outputPoint) { if (typeof point === 'undefined') { throw new Error('point undefined') } if (typeof outputPoint === 'undefined') { throw new Error('outputPoint undefined') } if (point.isAffine) { throw new Error( 'Given point was in Affine form. Use convertToJacobian() first.', ) } if (!point.isInMontgomeryForm) { throw new Error( 'Given point must be in Montgomery form. Use montgomeryize() first.', ) } if (aequalsZero) { doubleAequals0(point, outputPoint) } else { doubleAequalsNeg3(point, outputPoint) } } function mixedDoubleAdd(jacobianPoint, affinePoint, outputPoint) { if (jacobianPoint.isInfinity) { affinePoint.copy(outputPoint) this.convertToJacobianForm(outputPoint) return } if (affinePoint.isInfinity) { jacobianPoint.copy(outputPoint) return } montgomerySquare(jacobianPoint.z, temp5) montgomeryMultiply(jacobianPoint.z, temp5, temp6) montgomeryMultiply(affinePoint.x, temp5, temp4) montgomeryMultiply(affinePoint.y, temp6, temp5) modSub(temp4, jacobianPoint.x, temp1) modSub(temp5, jacobianPoint.y, temp2) if (cryptoMath.isZero(temp1)) { if (cryptoMath.isZero(temp2)) { double(jacobianPoint, outputPoint) mixedAdd(outputPoint, affinePoint, outputPoint) return } else { outputPoint.x = jacobianPoint.x.slice(0) outputPoint.y = jacobianPoint.y.slice(0) outputPoint.z = jacobianPoint.z.slice(0) return } } montgomerySquare(temp2, temp4) montgomerySquare(temp1, temp6) montgomeryMultiply(temp6, jacobianPoint.x, temp5) montgomeryMultiply(temp1, temp6, temp0) modSub(temp4, temp5, temp3) modSub(temp3, temp5, temp3) montgomeryMultiply(jacobianPoint.z, temp1, temp4) modSub(temp3, temp5, temp3) montgomeryMultiply(temp0, jacobianPoint.y, temp6) modSub(temp3, temp0, temp3) if (cryptoMath.isZero(temp3)) { for (i = 0; i < outputPoint.x.length; i++) { outputPoint.x[i] = 0 outputPoint.y[i] = 0 outputPoint.z[i] = 0 } outputPoint.y[0] = 1 return } modAdd(temp6, temp6, temp1) montgomeryMultiply(temp4, temp3, outputPoint.z) montgomeryMultiply(temp2, temp3, temp4) montgomerySquare(temp3, temp0) modAdd(temp1, temp4, temp1) montgomeryMultiply(temp0, temp5, temp4) montgomerySquare(temp1, temp7) montgomeryMultiply(temp0, temp3, temp5) modSub(temp7, temp4, outputPoint.x) modSub(outputPoint.x, temp4, outputPoint.x) modSub(outputPoint.x, temp5, outputPoint.x) modSub(outputPoint.x, temp4, temp3) montgomeryMultiply(temp5, temp6, temp0) montgomeryMultiply(temp1, temp3, temp4) modSub(temp4, temp0, outputPoint.y) outputPoint.isInfinity = false outputPoint.isInMontgomeryForm = true } function mixedAdd(jacobianPoint, affinePoint, outputPoint) { if (jacobianPoint === null) { throw new Error('jacobianPoint') } if (affinePoint === null) { throw new Error('affinePoint') } if (outputPoint === null) { throw new Error('outputPoint') } if ( jacobianPoint.curve !== affinePoint.curve || jacobianPoint.curve !== outputPoint.curve ) { throw new Error('All points must be from the same curve object.') } if (jacobianPoint.isAffine) { throw new Error( 'Given jacobianPoint was in Affine form. Use ConvertToJacobian()\ before calling DoubleJacobianAddAffinePoints().', ) } if (!affinePoint.isAffine) { throw new Error( 'Given affinePoint was in Jacobian form. Use ConvertToAffine() before \ calling DoubleJacobianAddAffinePoints().', ) } if (outputPoint.isAffine) { throw new Error( 'Given jacobianPoint was in Jacobian form. Use ConvertToJacobian() before \ calling DoubleJacobianAddAffinePoints().', ) } if (!jacobianPoint.isInMontgomeryForm) { throw new Error('Jacobian point must be in Montgomery form') } if (!affinePoint.isInMontgomeryForm) { throw new Error('Affine point must be in Montgomery form') } if (jacobianPoint.isInfinity) { affinePoint.copy(outputPoint) this.convertToJacobianForm(outputPoint) return } if (affinePoint.isInfinity) { jacobianPoint.copy(outputPoint) return } montgomerySquare(jacobianPoint.z, temp1) montgomeryMultiply(temp1, jacobianPoint.z, temp2) montgomeryMultiply(temp1, affinePoint.x, temp3) montgomeryMultiply(temp2, affinePoint.y, temp4) modSub(temp3, jacobianPoint.x, temp1) modSub(temp4, jacobianPoint.y, temp2) var i for (i = 0; i < temp1.length; i += 1) { if (temp1[i] !== 0) { montgomeryMultiply(jacobianPoint.z, temp1, temp0) for (var j = 0; j < fieldElementWidth; j += 1) { outputPoint.z[j] = temp0[j] } montgomerySquare(temp1, temp3) montgomeryMultiply(temp3, temp1, temp4) montgomeryMultiply(temp3, jacobianPoint.x, temp5) modAdd(temp5, temp5, temp1) montgomerySquare(temp2, outputPoint.x) modSub(outputPoint.x, temp1, outputPoint.x) modSub(outputPoint.x, temp4, outputPoint.x) modSub(temp5, outputPoint.x, temp3) montgomeryMultiply(temp2, temp3, temp5) montgomeryMultiply(jacobianPoint.y, temp4, temp6) modSub(temp5, temp6, outputPoint.y) outputPoint.isInfinity = false outputPoint.isInMontgomeryForm = true return } } for (i = 0; i < temp2.length; i += 1) { if (temp2[i] !== 0) { outputPoint.isInfinity = true outputPoint.isInMontgomeryForm = true return } } affinePoint.copy(outputPoint) this.convertToJacobianForm(outputPoint) this.double(outputPoint, outputPoint) outputPoint.isInMontgomeryForm = true } function scalarMultiply(k, point, outputPoint, multiplyBy4) { if (point.isInfinity || cryptoMath.isZero(k)) { outputPoint.isInfinity = true return } if (cryptoMath.compareDigits(k, curve.order) >= 0) { throw new Error('The scalar k must be in the range 1 <= k < order.') } k = k.slice() if (point.curve.type === 1) { var pointIsEP = typeof point.ta !== 'undefined' if (!pointIsEP) { convertToExtendedProjective(point) } scalarMultiplyTed(k, point, outputPoint, multiplyBy4) if (!pointIsEP) { normalizeTed(point) } } else { var pointIsMF = point.isInMontgomeryForm, outputIsMF = outputPoint.isInMontgomeryForm, outputIsAffine = outputPoint.isAffine if (!pointIsMF) { convertToMontgomeryForm(point) } if (!outputIsMF) { convertToMontgomeryForm(outputPoint) } scalarMultiplyW(k, point, outputPoint) if (outputIsAffine) { convertToAffineForm(outputPoint) } if (!pointIsMF) { convertToStandardForm(point) } if (!outputIsMF) { convertToStandardForm(outputPoint) } } return } function scalarMultiplyW(k, point, outputPoint) { var validationPoint = point.clone() convertToStandardForm(validationPoint) if (!validatePoint(validationPoint)) { throw new Error('Invalid Parameters.') } var odd = k[0] & 1, tempk = [] modSub(point.curve.order, k, tempk) for (i = 0; i < k.length; i++) { k[i] = ((odd - 1) & (k[i] ^ tempk[i])) ^ k[i] } var w = fieldElementWidth <= 8 ? 5 : 6 var m = point.curve.p.length * cryptoMath.DIGIT_BITS var t = Math.ceil(m / (w - 1)) var kDigits = cryptoMath.fixedWindowRecode(k, w, t) var Tm = generatePrecomputationTable(w, point) var position = Math.floor(Math.abs(kDigits[t]) - 1) / 2 var Q = Tm[position].clone() convertToJacobianForm(Q) for (var i = t - 1; i >= 0; i--) { for (var j = 0; j < w - 2; j++) { double(Q, Q) } position = Math.floor((Math.abs(kDigits[i]) - 1) / 2) var L = tableLookupW(Tm, position) modSub(L.curve.p, L.y, tempk) var mask = -(kDigits[i] >>> 31) for (var n = 0; n < L.y.length; n++) { L.y[n] = (L.y[n] & ~mask) | (tempk[n] & mask) } mixedDoubleAdd(Q, L, Q) } modSub(point.curve.p, Q.y, tempk) for (i = 0; i < Q.y.length; i++) { Q.y[i] = ((odd - 1) & (Q.y[i] ^ tempk[i])) ^ Q.y[i] } Q.copy(outputPoint) return } function tableLookupW(table, index) { var mask, L for (var i = 0; i < table.length; i++) { mask = +(i === index) L = [L, table[i].clone()][mask] } return L } function tableLookupW0(table, index) { var pos = (index + 1) % table.length for (var i = 0; i < table.length; i++) { var L = table[pos].clone() pos = (pos + 1) % table.length } return L } function negate(point, outputPoint) { if (point !== outputPoint) { point.copy(outputPoint) } modSub(point.curve.p, point.y, outputPoint.y) } function convertToMontgomeryForm(point) { if (point.isInMontgomeryForm) { throw new Error('The given point is already in Montgomery form.') } if (!point.isInfinity) { montgomeryMultiplier.convertToMontgomeryForm(point.x) montgomeryMultiplier.convertToMontgomeryForm(point.y) if (point.z !== null) { montgomeryMultiplier.convertToMontgomeryForm(point.z) } if (typeof point.ta !== 'undefined') { montgomeryMultiplier.convertToMontgomeryForm(point.ta) montgomeryMultiplier.convertToMontgomeryForm(point.tb) } } point.isInMontgomeryForm = true } function convertToStandardForm(point) { if (!point.isInMontgomeryForm) { throw new Error('The given point is not in montgomery form.') } if (!point.isInfinity) { montgomeryMultiplier.convertToStandardForm(point.x) montgomeryMultiplier.convertToStandardForm(point.y) if (point.z !== null) { montgomeryMultiplier.convertToStandardForm(point.z) } if (typeof point.ta !== 'undefined') { montgomeryMultiplier.convertToStandardForm(point.ta) montgomeryMultiplier.convertToStandardForm(point.tb) } } point.isInMontgomeryForm = false } function convertToAffineForm(point) { if (point.isInfinity) { point.z = null setterSupport || (point.isAffine = true) return } cryptoMath.modInv(point.z, curve.p, conversionTemp2, true) if (point.isInMontgomeryForm) { montgomeryMultiply( conversionTemp2, montgomeryMultiplier.rCubedModm, conversionTemp1, ) var swap = conversionTemp2 conversionTemp2 = conversionTemp1 conversionTemp1 = swap } montgomerySquare(conversionTemp2, conversionTemp0) montgomeryMultiply(point.x, conversionTemp0, conversionTemp1) for (var i = 0; i < fieldElementWidth; i += 1) { point.x[i] = conversionTemp1[i] } montgomeryMultiply(point.y, conversionTemp0, conversionTemp1) montgomeryMultiply(conversionTemp1, conversionTemp2, point.y) point.z = null delete point.ta delete point.tb setterSupport || (point.isAffine = true) } function convertToJacobianForm(point) { if (!point.isAffine) { throw new Error('The given point is not in Affine form.') } setterSupport || (point.isAffine = false) var clonedDigits, i, zOne = point.isInMontgomeryForm ? onemontgomery : one clonedDigits = createArray(zOne.length) for (i = 0; i < zOne.length; i += 1) { clonedDigits[i] = zOne[i] } point.z = clonedDigits return } function validatePoint(point) { if (point.isInfinity) { return false } cryptoMath.modMul(point.y, point.y, point.curve.p, temp1) cryptoMath.modMul(point.x, point.x, point.curve.p, temp2) cryptoMath.modMul(point.x, temp2, point.curve.p, temp3) modAdd(temp3, point.curve.b, temp2) cryptoMath.modMul(point.x, point.curve.a, point.curve.p, temp3) modAdd(temp2, temp3, temp2) modSub(temp1, temp2, temp1) if (cryptoMath.isZero(temp1) === false) { return false } return true } function validatePointTed(point) { if (point.ta) { point = point.clone() normalizeTed(point) } cryptoMath.modMul(point.y, point.y, point.curve.p, temp3) cryptoMath.modMul(point.x, point.x, point.curve.p, temp2) cryptoMath.add(temp2, temp3, temp1) cryptoMath.reduce(temp4, point.curve.p, temp4) cryptoMath.modMul(temp2, temp3, point.curve.p, temp4) cryptoMath.modMul(point.curve.d, temp4, point.curve.p, temp3) cryptoMath.add(temp3, [1], temp2) cryptoMath.reduce(temp2, point.curve.p, temp2) cryptoMath.subtract(temp1, temp2, temp1) if (cryptoMath.isZero(temp1) === false) { cryptoMath.reduce(temp1, point.curve.p, temp1) if (cryptoMath.isZero(temp1) === false) { return false } } return true } function generatePrecomputationTableTed(npoints, point) { var Q = point.clone(), P2 = Q.clone(), T = [] T[0] = convert_R1_to_R2(point) doubleTed(Q, Q) P2 = convert_R1_to_R2(Q) Q = point.clone() for (var i = 1; i < npoints; i++) { addTedExtended(P2, Q, Q) T[i] = convert_R1_to_R2(Q) } return T } function convertToExtendedProjective(affinePoint) { affinePoint.ta = affinePoint.x.slice() affinePoint.tb = affinePoint.y.slice() affinePoint.z = [1] } function scalarMultiplyTed(k, point, outputPoint, multiplyBy4) { if (!validatePointTed(point)) { throw new Error('Invalid Parameter') } var rbits = point.curve.rbits multiplyBy4 = typeof multiplyBy4 === 'undefined' ? true : multiplyBy4 var w = fieldElementWidth <= 8 ? 5 : 6 var t = Math.floor((rbits + (w - 2)) / (w - 1)) var i, j k = k.slice() var T = point.clone() convertToExtendedProjective(T) if (multiplyBy4) { doubleTed(T, T) doubleTed(T, T) } var precomputationTable = generatePrecomputationTableTed( 1 << (w - 2), T, ) var odd = k[0] & 1, tempk = [], kisNeg modSub(point.curve.order, k, tempk) for (i = 0; i < k.length; i++) { k[i] = ((odd - 1) & (k[i] ^ tempk[i])) ^ k[i] } var kDigits = cryptoMath.fixedWindowRecode(k, w, t) var position = Math.floor(Math.abs(kDigits[t]) - 1) / 2 var R = precomputationTable[position] T.x = R.x.slice() T.y = R.y.slice() T.z = R.z.slice() for (i = t - 1; i >= 0; i--) { for (j = 0; j < w - 1; j++) { doubleTed(T, T) } position = Math.floor((Math.abs(kDigits[i]) - 1) / 2) var L = tableLookupTed(precomputationTable, position) var mask = -(kDigits[i] >>> 31) modSub(point.curve.p, L.x, tempk) for (var m = 0; m < L.x.length; m++) { L.x[m] = (L.x[m] & ~mask) | (tempk[m] & mask) } modSub(point.curve.p, L.td, tempk) for (m = 0; m < L.td.length; m++) { L.td[m] = (L.td[m] & ~mask) | (tempk[m] & mask) } addTedExtended(L, T, T) } modSub(point.curve.p, T.x, tempk) for (i = 0; i < T.x.length; i++) { T.x[i] = ((odd - 1) & (T.x[i] ^ tempk[i])) ^ T.x[i] } normalizeTed(T) outputPoint.x = T.x.slice() outputPoint.y = T.y.slice() return } function tableLookupTed(table, index) { var pos = (index + 1) % table.length for (var i = 0; i < table.length; i++) { var L = { x: table[pos].x.slice(), y: table[pos].y.slice(), z: table[pos].z.slice(), td: table[pos].td.slice(), } pos = (pos + 1) % table.length } return L } function normalizeTed(point) { cryptoMath.modInv(point.z, curve.p, conversionTemp2, true) cryptoMath.modMul(point.x, conversionTemp2, curve.p, point.x) cryptoMath.modMul(point.y, conversionTemp2, curve.p, point.y) delete point.ta delete point.tb point.z = null return } function doubleTed(point, outputPoint) { if (typeof point.ta === 'undefined') { throw new Error('Point should be in Extended Projective form.') } cryptoMath.modMul(point.x, point.x, point.curve.p, temp0) cryptoMath.modMul(point.y, point.y, point.curve.p, temp1) cryptoMath.modMul(point.z, point.z, point.curve.p, point.ta) modSub(temp1, temp0, outputPoint.tb) modAdd(temp0, temp1, temp0) modAdd(point.ta, point.ta, point.ta) modAdd(point.y, point.y, point.y) modSub(point.ta, temp0, temp1) cryptoMath.modMul(point.x, point.y, point.curve.p, outputPoint.ta) cryptoMath.modMul(temp0, outputPoint.tb, point.curve.p, outputPoint.y) cryptoMath.modMul(temp1, outputPoint.ta, point.curve.p, outputPoint.x) cryptoMath.modMul(temp0, temp1, point.curve.p, outputPoint.z) return } function addTed(point1, point2, outputPoint) { var cm = cryptoMath if (typeof point1.ta === 'undefined') { throw new Error('Point1 should be in Extended Projective form.') } if (typeof point2.ta === 'undefined') { throw new Error('Point2 should be in Extended Projective form.') } var qq = convert_R1_to_R2(point1) addTedExtended(qq, point2, outputPoint) return } function convert_R1_to_R2(point) { var curve = point.curve, modulus = curve.p, qq = { x: point.x.slice(), y: point.y.slice(), z: point.z.slice(), td: [], curve: point.curve, } cryptoMath.modMul(point.ta, point.tb, modulus, conversionTemp0) cryptoMath.modMul(conversionTemp0, curve.d, modulus, qq.td) return qq } function addTedExtended(qq, point2, outputPoint) { var cm = cryptoMath var modulus = point2.curve.p temp1 = [] temp2 = [] temp3 = [] cm.modMul(point2.z, qq.z, modulus, temp3) cm.modMul(point2.ta, point2.tb, modulus, temp1) modAdd(point2.x, point2.y, point2.ta) cm.modMul(temp1, qq.td, modulus, temp2) modAdd(qq.x, qq.y, point2.tb) modSub(temp3, temp2, temp1) modAdd(temp3, temp2, temp3) cm.modMul(point2.ta, point2.tb, modulus, temp2) cm.modMul(point2.x, qq.x, modulus, point2.z) cm.modMul(point2.y, qq.y, modulus, point2.x) modSub(temp2, point2.z, temp2) modSub(point2.x, point2.z, outputPoint.ta) modSub(temp2, point2.x, outputPoint.tb) cm.modMul(outputPoint.ta, temp3, modulus, outputPoint.y) cm.modMul(outputPoint.tb, temp1, modulus, outputPoint.x) cm.modMul(temp3, temp1, modulus, outputPoint.z) return } function convertTedToWeierstrass(tedPoint, wPoint) { var a = tedPoint.curve.a.slice(), d = tedPoint.curve.d.slice(), p = tedPoint.curve.p, modMul = cryptoMath.modMul, modInv = cryptoMath.modInv temp1 = [5] modMul(a, temp1, p, temp2) modSub(temp2, d, temp2) modMul(d, temp1, p, temp3) modSub(a, temp3, temp1) modMul(tedPoint.y, temp1, p, temp3) modAdd(temp3, temp2, temp2) temp1 = [1] modSub(temp1, tedPoint.y, temp3) temp1 = [12] modMul(temp1, temp3, p, temp4) modInv(temp4, p, temp4, true) modMul(tedPoint.x, temp3, p, temp1) modAdd(temp1, temp1, temp3) modAdd(temp3, temp3, temp3) modInv(temp3, p, temp3, true) modMul(temp4, temp2, p, wPoint.x) temp1 = [1] modAdd(tedPoint.y, temp1, temp1) modSub(a, d, temp2) modMul(temp1, temp2, p, temp4) modMul(temp4, temp3, p, wPoint.y) return } function convertWeierstrassToTed(wPoint, tedPoint) { var a = tedPoint.curve.a.slice(), d = tedPoint.curve.d.slice(), p = tedPoint.curve.p, modMul = cryptoMath.modMul, modInv = cryptoMath.modInv modAdd(wPoint.x, wPoint.x, temp1) modAdd(wPoint.x, temp1, temp1) modAdd(temp1, temp1, temp1) modSub(temp1, a, temp2) modSub(temp2, d, temp2) modAdd(wPoint.y, wPoint.y, temp3) modAdd(wPoint.y, temp3, temp3) modAdd(temp3, temp3, temp3) modInv(temp3, p, temp3, true) modMul(temp2, temp3, p, tedPoint.x) modAdd(temp1, temp1, temp1) modAdd(temp1, d, temp2) modAdd(temp1, a, temp1) modAdd(a, a, temp3) modSub(temp2, temp3, temp2) modSub(temp2, temp3, temp2) modSub(temp2, a, temp2) modAdd(d, d, temp3) modSub(temp1, temp3, temp1) modSub(temp1, temp3, temp1) modSub(temp1, d, temp1) modInv(temp1, p, temp1, true) modMul(temp1, temp2, p, tedPoint.y) return } var methods = { convertToMontgomeryForm: convertToMontgomeryForm, convertToStandardForm: convertToStandardForm, convertToAffineForm: convertToAffineForm, convertToJacobianForm: convertToJacobianForm, generatePrecomputationTable: function (w, generatorPoint) { return generatePrecomputationTable(w, generatorPoint) }, } if (tedCurve) { methods.double = doubleTed methods.add = addTed methods.scalarMultiply = scalarMultiply methods.normalize = normalizeTed methods.convertToExtendedProjective = convertToExtendedProjective methods.convertTedToWeierstrass = convertTedToWeierstrass methods.convertWeierstrassToTed = convertWeierstrassToTed methods.validatePoint = validatePointTed methods.generatePrecomputationTable = function (w, generatorPoint) { return generatePrecomputationTableTed(w, generatorPoint) } } else { methods.double = double methods.mixedDoubleAdd = mixedDoubleAdd methods.mixedAdd = mixedAdd methods.scalarMultiply = scalarMultiply methods.negate = negate methods.validatePoint = validatePoint } return methods } var sec1EncodingFp = function () { return { encodePoint: function (point) { if (!point) { throw new Error('point') } if (!point.isAffine) { throw new Error('Point must be in affine form.') } if (point.isInMontgomeryForm) { throw new Error('Point must not be in Montgomery form.') } if (point.isInfinity) { return createArray(1) } else { var xOctetString = cryptoMath.digitsToBytes(point.x) var yOctetString = cryptoMath.digitsToBytes(point.y) var pOctetString = cryptoMath.digitsToBytes(point.curve.p) var mlen = pOctetString.length if (mlen < xOctetString.length || mlen < yOctetString.length) { throw new Error( 'Point coordinate(s) are bigger than the field order.', ) } var output = createArray(2 * mlen + 1) output[0] = 0x04 var offset = mlen - xOctetString.length for (var i = 0; i < xOctetString.length; i++) { output[i + 1 + offset] = xOctetString[i] } offset = mlen - yOctetString.length for (i = 0; i < yOctetString.length; i++) { output[mlen + i + 1 + offset] = yOctetString[i] } return output } }, decodePoint: function (encoded, curve) { if (encoded.length < 1) { throw new Error('Byte array must have non-zero length') } var pOctetString = cryptoMath.digitsToBytes(curve.p) var mlen = pOctetString.length if (encoded[0] === 0x0 && encoded.length === 1) { return curve.createPointAtInfinity() } else if (encoded[0] === 0x04 && encoded.length === 1 + 2 * mlen) { var xbytes = createArray(mlen) var ybytes = createArray(mlen) for (var i = 0; i < mlen; i++) { xbytes[i] = encoded[i + 1] ybytes[i] = encoded[mlen + i + 1] } var x = cryptoMath.bytesToDigits(xbytes) var y = cryptoMath.bytesToDigits(ybytes) return EllipticCurvePointFp(curve, false, x, y) } else { throw new Error('Unsupported encoding format') } }, } } var ModularSquareRootSolver = function (modulus) { var p = modulus var specialK = [] if (typeof modulus === 'undefined') { throw new Error('modulus') } if (cryptoMath.isEven(modulus)) { throw new Error('Only odd moduli are supported') } var mul = cryptoMath.MontgomeryMultiplier(p) if (p[0] % 4 === 3) { cryptoMath.add(p, cryptoMath.One, specialK) cryptoMath.shiftRight(specialK, specialK, 2) } else { specialK = null } var temp0 = new Array(p.length) var temp1 = new Array(p.length) function squareRootNistCurves(a) { var beta = cryptoMath.intToDigits(0, 16) mul.modExp(a, specialK, beta) var aPrime = [0] cryptoMath.modMul(beta, beta, mul.m, aPrime) if (cryptoMath.compareDigits(a, aPrime) !== 0) { return null } return beta } var publicMethods = { squareRoot: function (a) { if (specialK !== null) { return squareRootNistCurves(a) } else { throw new Error('GeneralCase not supported.') } }, jacobiSymbol: function (a) { var modEightMask = 0x7, modFourMask = 0x3, aPrime, pPrime aPrime = a.slice() pPrime = p.slice() cryptoMath.reduce(aPrime, pPrime, aPrime, temp0, temp1) var t = 1 while (!cryptoMath.isZero(aPrime)) { while (cryptoMath.isEven(aPrime)) { cryptoMath.shiftRight(aPrime, aPrime) var pMod8 = pPrime[0] & modEightMask if (pMod8 === 3 || pMod8 === 5) { t = -t } } var tmp = aPrime aPrime = pPrime pPrime = tmp var aMod4 = aPrime[0] & modFourMask var pMod4 = pPrime[0] & modFourMask if (aMod4 === 3 && pMod4 === 3) { t = -t } cryptoMath.reduce(aPrime, pPrime, aPrime, temp0, temp1) } if (cryptoMath.compareDigits(pPrime, cryptoMath.One) === 0) { return t } else { return 0 } }, } return publicMethods } var curvesInternal = {} var createCurve = function (curveName) { var curveData = curvesInternal[curveName.toUpperCase()] if (!curveData) { throw new Error(curveName + ' Unsupported curve.') } if (curveData.type === 0) { return createWeierstrassCurve(curveData) } if (curveData.type === 1) { return createTedCurve(curveData) } throw new Error(curveName + ' Unsupported curve type.') } var validateEccPoint = function (curveName, x, y, z) { var curve = createCurve(curveName) var point = new EllipticCurvePointFp( curve, false, btd(x), btd(y), z && btd(z), false, ) var opp = new EllipticCurveOperatorFp(curve) return opp.validatePoint(point) } return { createCurve: createCurve, curves: curvesInternal, sec1EncodingFp: sec1EncodingFp, validatePoint: validateEccPoint, EllipticCurvePointFp: EllipticCurvePointFp, EllipticCurveOperatorFp: EllipticCurveOperatorFp, ModularSquareRootSolver: ModularSquareRootSolver, } } var cryptoECC = cryptoECC || MsrcryptoECC() var curve_P256 = { name: 'P-256', type: 0, p: [ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ], a: [ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, ], b: [ 0x5a, 0xc6, 0x35, 0xd8, 0xaa, 0x3a, 0x93, 0xe7, 0xb3, 0xeb, 0xbd, 0x55, 0x76, 0x98, 0x86, 0xbc, 0x65, 0x1d, 0x06, 0xb0, 0xcc, 0x53, 0xb0, 0xf6, 0x3b, 0xce, 0x3c, 0x3e, 0x27, 0xd2, 0x60, 0x4b, ], order: [ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbc, 0xe6, 0xfa, 0xad, 0xa7, 0x17, 0x9e, 0x84, 0xf3, 0xb9, 0xca, 0xc2, 0xfc, 0x63, 0x25, 0x51, ], gx: [ 0x6b, 0x17, 0xd1, 0xf2, 0xe1, 0x2c, 0x42, 0x47, 0xf8, 0xbc, 0xe6, 0xe5, 0x63, 0xa4, 0x40, 0xf2, 0x77, 0x03, 0x7d, 0x81, 0x2d, 0xeb, 0x33, 0xa0, 0xf4, 0xa1, 0x39, 0x45, 0xd8, 0x98, 0xc2, 0x96, ], gy: [ 0x4f, 0xe3, 0x42, 0xe2, 0xfe, 0x1a, 0x7f, 0x9b, 0x8e, 0xe7, 0xeb, 0x4a, 0x7c, 0x0f, 0x9e, 0x16, 0x2b, 0xce, 0x33, 0x57, 0x6b, 0x31, 0x5e, 0xce, 0xcb, 0xb6, 0x40, 0x68, 0x37, 0xbf, 0x51, 0xf5, ], cf: 1, } var curve_P384 = { name: 'P-384', type: 0, p: [ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, ], a: [ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xfc, ], b: [ 0xb3, 0x31, 0x2f, 0xa7, 0xe2, 0x3e, 0xe7, 0xe4, 0x98, 0x8e, 0x05, 0x6b, 0xe3, 0xf8, 0x2d, 0x19, 0x18, 0x1d, 0x9c, 0x6e, 0xfe, 0x81, 0x41, 0x12, 0x03, 0x14, 0x08, 0x8f, 0x50, 0x13, 0x87, 0x5a, 0xc6, 0x56, 0x39, 0x8d, 0x8a, 0x2e, 0xd1, 0x9d, 0x2a, 0x85, 0xc8, 0xed, 0xd3, 0xec, 0x2a, 0xef, ], order: [ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0x63, 0x4d, 0x81, 0xf4, 0x37, 0x2d, 0xdf, 0x58, 0x1a, 0x0d, 0xb2, 0x48, 0xb0, 0xa7, 0x7a, 0xec, 0xec, 0x19, 0x6a, 0xcc, 0xc5, 0x29, 0x73, ], gx: [ 0xaa, 0x87, 0xca, 0x22, 0xbe, 0x8b, 0x05, 0x37, 0x8e, 0xb1, 0xc7, 0x1e, 0xf3, 0x20, 0xad, 0x74, 0x6e, 0x1d, 0x3b, 0x62, 0x8b, 0xa7, 0x9b, 0x98, 0x59, 0xf7, 0x41, 0xe0, 0x82, 0x54, 0x2a, 0x38, 0x55, 0x02, 0xf2, 0x5d, 0xbf, 0x55, 0x29, 0x6c, 0x3a, 0x54, 0x5e, 0x38, 0x72, 0x76, 0x0a, 0xb7, ], gy: [ 0x36, 0x17, 0xde, 0x4a, 0x96, 0x26, 0x2c, 0x6f, 0x5d, 0x9e, 0x98, 0xbf, 0x92, 0x92, 0xdc, 0x29, 0xf8, 0xf4, 0x1d, 0xbd, 0x28, 0x9a, 0x14, 0x7c, 0xe9, 0xda, 0x31, 0x13, 0xb5, 0xf0, 0xb8, 0xc0, 0x0a, 0x60, 0xb1, 0xce, 0x1d, 0x7e, 0x81, 0x9d, 0x7a, 0x43, 0x1d, 0x7c, 0x90, 0xea, 0x0e, 0x5f, ], cf: 1, } var curve_P521 = { name: 'P-521', type: 0, p: [ 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ], a: [ 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, ], b: [ 0x00, 0x51, 0x95, 0x3e, 0xb9, 0x61, 0x8e, 0x1c, 0x9a, 0x1f, 0x92, 0x9a, 0x21, 0xa0, 0xb6, 0x85, 0x40, 0xee, 0xa2, 0xda, 0x72, 0x5b, 0x99, 0xb3, 0x15, 0xf3, 0xb8, 0xb4, 0x89, 0x91, 0x8e, 0xf1, 0x09, 0xe1, 0x56, 0x19, 0x39, 0x51, 0xec, 0x7e, 0x93, 0x7b, 0x16, 0x52, 0xc0, 0xbd, 0x3b, 0xb1, 0xbf, 0x07, 0x35, 0x73, 0xdf, 0x88, 0x3d, 0x2c, 0x34, 0xf1, 0xef, 0x45, 0x1f, 0xd4, 0x6b, 0x50, 0x3f, 0x00, ], order: [ 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfa, 0x51, 0x86, 0x87, 0x83, 0xbf, 0x2f, 0x96, 0x6b, 0x7f, 0xcc, 0x01, 0x48, 0xf7, 0x09, 0xa5, 0xd0, 0x3b, 0xb5, 0xc9, 0xb8, 0x89, 0x9c, 0x47, 0xae, 0xbb, 0x6f, 0xb7, 0x1e, 0x91, 0x38, 0x64, 0x09, ], gx: [ 0x00, 0xc6, 0x85, 0x8e, 0x06, 0xb7, 0x04, 0x04, 0xe9, 0xcd, 0x9e, 0x3e, 0xcb, 0x66, 0x23, 0x95, 0xb4, 0x42, 0x9c, 0x64, 0x81, 0x39, 0x05, 0x3f, 0xb5, 0x21, 0xf8, 0x28, 0xaf, 0x60, 0x6b, 0x4d, 0x3d, 0xba, 0xa1, 0x4b, 0x5e, 0x77, 0xef, 0xe7, 0x59, 0x28, 0xfe, 0x1d, 0xc1, 0x27, 0xa2, 0xff, 0xa8, 0xde, 0x33, 0x48, 0xb3, 0xc1, 0x85, 0x6a, 0x42, 0x9b, 0xf9, 0x7e, 0x7e, 0x31, 0xc2, 0xe5, 0xbd, 0x66, ], gy: [ 0x01, 0x18, 0x39, 0x29, 0x6a, 0x78, 0x9a, 0x3b, 0xc0, 0x04, 0x5c, 0x8a, 0x5f, 0xb4, 0x2c, 0x7d, 0x1b, 0xd9, 0x98, 0xf5, 0x44, 0x49, 0x57, 0x9b, 0x44, 0x68, 0x17, 0xaf, 0xbd, 0x17, 0x27, 0x3e, 0x66, 0x2c, 0x97, 0xee, 0x72, 0x99, 0x5e, 0xf4, 0x26, 0x40, 0xc5, 0x50, 0xb9, 0x01, 0x3f, 0xad, 0x07, 0x61, 0x35, 0x3c, 0x70, 0x86, 0xa2, 0x72, 0xc2, 0x40, 0x88, 0xbe, 0x94, 0x76, 0x9f, 0xd1, 0x66, 0x50, ], cf: 1, } if (typeof cryptoECC !== 'undefined') { cryptoECC.curves['P-256'] = curve_P256 cryptoECC.curves['P-384'] = curve_P384 cryptoECC.curves['P-521'] = curve_P521 } var curve_BN254 = { name: 'BN-254', type: 0, p: [ 0x25, 0x23, 0x64, 0x82, 0x40, 0x00, 0x00, 0x01, 0xba, 0x34, 0x4d, 0x80, 0x00, 0x00, 0x00, 0x08, 0x61, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0xa7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, ], a: [0x00], b: [0x02], order: [ 0x25, 0x23, 0x64, 0x82, 0x40, 0x00, 0x00, 0x01, 0xba, 0x34, 0x4d, 0x80, 0x00, 0x00, 0x00, 0x07, 0xff, 0x9f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x10, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, ], gx: [ 0x25, 0x23, 0x64, 0x82, 0x40, 0x00, 0x00, 0x01, 0xba, 0x34, 0x4d, 0x80, 0x00, 0x00, 0x00, 0x08, 0x61, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0xa7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, ], gy: [0x01], cf: 1, } if (typeof cryptoECC !== 'undefined') { cryptoECC.curves['BN-254'] = curve_BN254 } var curve_numsp256d1 = { info: ['numsp256d1', 256, 256, 256], type: 0, p: [ 0x43, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ].reverse(), a: [ 0x40, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ].reverse(), b: [0x81, 0x55, 0x02].reverse(), order: [ 0x25, 0xa8, 0x51, 0x47, 0x29, 0x20, 0xab, 0x20, 0x60, 0x5c, 0x26, 0xea, 0x75, 0x82, 0x3c, 0xe4, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ].reverse(), gx: [ 0xb1, 0xac, 0x1a, 0xb2, 0x1e, 0xee, 0x52, 0xbc, 0x3a, 0xc7, 0xd4, 0x03, 0x09, 0x9b, 0x57, 0x83, 0x09, 0xcb, 0x42, 0x4f, 0xa0, 0x95, 0x7a, 0x29, 0x61, 0xdb, 0xaa, 0x5a, 0xb6, 0xd6, 0x9e, 0xbc, ].reverse(), gy: [ 0x9f, 0xde, 0x84, 0x21, 0xcb, 0xb9, 0xb5, 0x80, 0xbb, 0x0f, 0x31, 0x15, 0xd1, 0xc3, 0x55, 0xc9, 0x35, 0xe0, 0x04, 0x7e, 0xf7, 0x8b, 0x44, 0x73, 0xa6, 0xb6, 0x99, 0x33, 0xf1, 0xc0, 0x8f, 0xd0, ].reverse(), cf: 1, } var curve_numsp256t1 = { info: ['numsp256t1', 256, 255, 256], name: 'numsp256t1', type: 1, p: [ 0x43, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ].reverse(), a: [0x01], d: [ 0x55, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ].reverse(), order: [ 0xf5, 0x4a, 0xdd, 0xee, 0x90, 0xb1, 0x47, 0x1a, 0x9b, 0x43, 0x59, 0x2f, 0xa5, 0x5a, 0x95, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ].reverse(), gx: [ 0xda, 0x13, 0xed, 0x2e, 0x90, 0xc0, 0xde, 0xa0, 0x86, 0x35, 0x08, 0xe3, 0x0e, 0x8a, 0x39, 0x0c, 0xd6, 0x9b, 0x20, 0x69, 0x5f, 0x3d, 0x1e, 0xcd, 0x7d, 0x23, 0xea, 0x6a, 0xfb, 0x14, 0x75, 0x8a, ].reverse(), gy: [ 0xe6, 0x89, 0x8a, 0x79, 0xe7, 0x16, 0xa6, 0x2f, 0xd3, 0x6e, 0x85, 0x10, 0xd8, 0x61, 0x5f, 0x71, 0x10, 0x80, 0x4b, 0xa6, 0xd9, 0x65, 0x96, 0xce, 0xc7, 0x25, 0xd9, 0xd9, 0x9f, 0x3e, 0xd5, 0x44, ].reverse(), cf: 4, } var curve_numsp384d1 = { info: ['numsp384d1', 384, 384, 384], name: 'numsp384d1', type: 0, p: [ 0xc3, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ].reverse(), a: [ 0xc0, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ].reverse(), b: [ 0xbb, 0x77, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ].reverse(), order: [ 0xb9, 0x61, 0x0e, 0x7b, 0xf6, 0x81, 0x4d, 0x60, 0x7a, 0xe2, 0x37, 0x4c, 0x3d, 0x9d, 0xda, 0xbe, 0x81, 0x68, 0x5d, 0xeb, 0x1e, 0xaf, 0x1e, 0xd6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ].reverse(), gx: [ 0x2a, 0x15, 0x98, 0x20, 0x04, 0xba, 0x9c, 0xeb, 0x7b, 0xc4, 0x61, 0x0f, 0x10, 0xed, 0x2e, 0x52, 0x42, 0xc7, 0x6c, 0x2a, 0x1b, 0x29, 0xbd, 0xf3, 0xf4, 0xf9, 0x81, 0xfb, 0xcd, 0xc1, 0x25, 0x02, 0xa6, 0xf1, 0x05, 0x41, 0x22, 0xca, 0x80, 0x48, 0x1c, 0x18, 0x6f, 0xb1, 0xf0, 0x56, 0x79, 0x75, ].reverse(), gy: [ 0x16, 0x07, 0x18, 0x66, 0xec, 0xb8, 0x74, 0x5c, 0x26, 0xad, 0xf4, 0xbf, 0xdb, 0xb4, 0xd6, 0xbc, 0x7e, 0x83, 0x1a, 0x12, 0x7d, 0x83, 0x20, 0xb9, 0x9c, 0x73, 0x7f, 0xf8, 0x77, 0x69, 0x04, 0xb0, 0x7e, 0xcf, 0x84, 0x05, 0x30, 0x3d, 0xe3, 0xd7, 0x38, 0x8e, 0x9b, 0xe1, 0x68, 0xe3, 0xde, 0xac, ].reverse(), cf: 1, } var curve_numsp384t1 = { info: ['numsp384t1', 384, 382, 384], name: 'numsp384t1', type: 1, p: [ 0xc3, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ].reverse(), a: [0x01], d: [ 0x9f, 0xd1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ].reverse(), order: [ 0x7d, 0x89, 0xa3, 0xe6, 0xc4, 0xdc, 0xb9, 0x20, 0x79, 0xc8, 0x35, 0xab, 0x5a, 0x55, 0xe4, 0x61, 0xcf, 0xe1, 0x6b, 0xb4, 0x1c, 0x1a, 0x47, 0xe2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, ].reverse(), gx: [ 0xde, 0x6b, 0x20, 0x6c, 0xe4, 0x40, 0xd5, 0x50, 0x13, 0x94, 0x45, 0x65, 0xb1, 0x92, 0xf2, 0x6f, 0x40, 0x63, 0x31, 0xf3, 0xa8, 0xff, 0x63, 0x57, 0x00, 0x4c, 0xbe, 0xe5, 0x46, 0xf4, 0x0b, 0xb3, 0xb5, 0x5d, 0xe5, 0x9a, 0x12, 0xa2, 0xb6, 0xc0, 0x6c, 0x26, 0xa9, 0x45, 0xfb, 0x11, 0xb1, 0x61, ].reverse(), gy: [ 0x92, 0x93, 0x72, 0xf0, 0xe1, 0x03, 0x8d, 0x9d, 0xdc, 0x48, 0xec, 0x46, 0xf9, 0xb0, 0x72, 0x00, 0x4b, 0x96, 0x45, 0xf6, 0xf7, 0x98, 0x0f, 0x83, 0x56, 0x5f, 0x42, 0xf1, 0x74, 0x82, 0xad, 0x16, 0xd7, 0x0d, 0xb1, 0x23, 0xa4, 0xb1, 0x38, 0x87, 0xb0, 0xee, 0xa6, 0xb9, 0x67, 0x3e, 0x98, 0x82, ].reverse(), cf: 4, } var curve_numsp512d1 = { info: ['numsp512d1', 512, 512, 512], name: 'numsp512d1', type: 0, p: [ 0xc7, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ].reverse(), a: [ 0xc4, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ].reverse(), b: [0x9b, 0xd9, 0x01].reverse(), order: [ 0x5d, 0x55, 0x33, 0x04, 0x39, 0x3f, 0x15, 0xce, 0x43, 0xd2, 0x7c, 0x60, 0x36, 0x8b, 0x56, 0x3b, 0xc6, 0xbd, 0xd0, 0x97, 0xed, 0x58, 0xc2, 0x4f, 0x1b, 0x83, 0xe7, 0x94, 0xfb, 0xa4, 0x3c, 0x5b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ].reverse(), gx: [ 0x57, 0xae, 0xab, 0x8c, 0x95, 0x87, 0x82, 0xdc, 0xe2, 0x5d, 0x6f, 0x7d, 0x13, 0x60, 0x5d, 0x1d, 0x83, 0x15, 0x56, 0x25, 0x86, 0x42, 0x79, 0x93, 0x9e, 0x35, 0x6b, 0x07, 0x51, 0xa1, 0x21, 0x50, 0xf9, 0xd9, 0x06, 0x53, 0xc2, 0xe0, 0x06, 0x45, 0x85, 0xf6, 0x01, 0xb5, 0x3b, 0xd8, 0xca, 0x98, 0x52, 0x3b, 0x3d, 0xa0, 0x02, 0x70, 0x2b, 0xda, 0x93, 0x0a, 0x1d, 0x14, 0x47, 0x34, 0xc0, 0x3a, ].reverse(), gy: [ 0xa6, 0x27, 0x35, 0x38, 0x60, 0x87, 0xa0, 0x23, 0xe9, 0x0f, 0xfd, 0x4c, 0x1e, 0x5c, 0x2b, 0xcf, 0x02, 0x56, 0x5a, 0xb2, 0x40, 0xa8, 0x21, 0xc1, 0xe9, 0xed, 0x0e, 0x8b, 0xda, 0x15, 0x84, 0xa2, 0x14, 0x4f, 0xd1, 0x7b, 0x0c, 0x26, 0x4b, 0x8f, 0x8c, 0xbb, 0xbc, 0xab, 0xde, 0xdb, 0x97, 0x4b, 0x00, 0xb1, 0xeb, 0x63, 0xdc, 0xee, 0x0e, 0xce, 0xb3, 0x56, 0xad, 0x29, 0xca, 0x54, 0x3a, 0x94, ].reverse(), cf: 4, } var curve_numsp512t1 = { info: ['numsp512t1', 512, 510, 512], name: 'numsp512t1', type: 1, p: [ 0xc7, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ].reverse(), a: [0x01].reverse(), d: [ 0xef, 0xcb, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ].reverse(), order: [ 0x6d, 0xd4, 0xee, 0x1b, 0xf5, 0x8c, 0x46, 0x67, 0xff, 0xec, 0xef, 0x6d, 0x78, 0x05, 0x46, 0x2a, 0xf5, 0x86, 0xb6, 0x70, 0xc9, 0xd8, 0x3f, 0x9e, 0xba, 0x91, 0xcf, 0x2f, 0x6d, 0x63, 0xf0, 0xb4, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, ].reverse(), gx: [ 0xfe, 0x57, 0xec, 0x99, 0x29, 0xab, 0xb9, 0xc5, 0x15, 0xf0, 0xc4, 0x7c, 0x42, 0x25, 0xe5, 0x0f, 0xad, 0x04, 0x89, 0x56, 0x92, 0xc9, 0xbd, 0x78, 0x0f, 0x73, 0x46, 0xee, 0x4e, 0xc1, 0x21, 0x46, 0x47, 0x81, 0x3b, 0x27, 0xbe, 0x7e, 0xa1, 0x27, 0x82, 0xa3, 0xc4, 0x4d, 0x9f, 0xe7, 0xd1, 0x2f, 0x33, 0xc5, 0xd3, 0x88, 0x78, 0xcb, 0x18, 0x7a, 0x9c, 0xb6, 0x8d, 0x12, 0x6d, 0x31, 0x8e, 0xdf, ].reverse(), gy: [ 0xe1, 0xf5, 0xe2, 0xc1, 0xc0, 0xde, 0x6d, 0x32, 0x1f, 0xd0, 0xf1, 0x9b, 0x8a, 0xd3, 0x66, 0x02, 0xfd, 0xc1, 0xec, 0x2a, 0x86, 0x06, 0x1a, 0x60, 0x62, 0x35, 0x96, 0xe9, 0xf2, 0x53, 0xca, 0x20, 0x41, 0x83, 0x9e, 0x90, 0x95, 0x6b, 0x2b, 0xa9, 0x22, 0x9d, 0x25, 0xd8, 0x26, 0xf7, 0x76, 0xe4, 0x6e, 0x25, 0x2a, 0xa8, 0x77, 0xf5, 0xb0, 0x98, 0x71, 0xca, 0x49, 0x9d, 0xf3, 0xbf, 0x09, 0x6d, ].reverse(), cf: 4, } if (typeof cryptoECC !== 'undefined') { cryptoECC.curves.NUMSP256D1 = curve_numsp256d1 cryptoECC.curves.NUMSP384D1 = curve_numsp384d1 cryptoECC.curves.NUMSP512D1 = curve_numsp512d1 cryptoECC.curves.NUMSP256T1 = curve_numsp256t1 cryptoECC.curves.NUMSP384T1 = curve_numsp384t1 cryptoECC.curves.NUMSP512T1 = curve_numsp512t1 } var msrcryptoSha = function ( name, der, h, k, blockBytes, blockFunction, truncateTo, ) { var utils = msrcryptoUtilities var hv = h.slice(), w = new Array(blockBytes), buffer = [], blocksProcessed = 0 function hashBlocks(message) { var blockCount = Math.floor(message.length / blockBytes) for (var block = 0; block < blockCount; block++) { blockFunction(message, block, hv, k, w) } blocksProcessed += blockCount return message.slice(blockCount * blockBytes) } function hashToBytes() { var hash = [] for (var i = 0; i < hv.length; i++) { hash = hash.concat(utils.int32ToBytes(hv[i])) } hash.length = truncateTo / 8 return hash } function addPadding(messageBytes) { var padLen = blockBytes - (messageBytes.length % blockBytes) padLen <= blockBytes / 8 && (padLen += blockBytes) var padding = utils.getVector(padLen) padding[0] = 128 var messageLenBits = (messageBytes.length + blocksProcessed * blockBytes) * 8 for (var i = 1; i <= 8; i++) { padding[padLen - i] = messageLenBits % 0x100 messageLenBits = Math.floor(messageLenBits / 0x100) } return messageBytes.concat(padding) } function computeHash(messageBytes) { buffer = hashBlocks(messageBytes) return finish() } function process(messageBytes) { buffer = buffer.concat(messageBytes) if (buffer.length >= blockBytes) { buffer = hashBlocks(buffer) } return } function finish() { if (hashBlocks(addPadding(buffer)).length !== 0) { throw new Error('buffer.length !== 0') } var result = hashToBytes() buffer = [] hv = h.slice() blocksProcessed = 0 return result } return { name: name, computeHash: computeHash, process: process, finish: finish, der: der, hashLen: truncateTo, maxMessageSize: 0xffffffff, } } var msrcryptoSha1 = (function () { function hashBlock(message, blockIndex, hv, k, w) { var t, i, temp, x0, blockSize = 64, mask = 0xffffffff var ra = hv[0], rb = hv[1], rc = hv[2], rd = hv[3], re = hv[4] for (i = 0; i < 16; i++) { w[i] = utils.bytesToInt32(message, blockIndex * blockSize + i * 4) } for (t = 16; t < 80; t++) { x0 = w[t - 3] ^ w[t - 8] ^ w[t - 14] ^ w[t - 16] w[t] = (x0 << 1) | (x0 >>> 31) } for (i = 0; i < 80; i++) { temp = (ra << 5) | (ra >>> 27) temp += i >= 60 ? rb ^ rc ^ rd : i >= 40 ? (rb & rc) ^ (rb & rd) ^ (rc & rd) : i >= 20 ? rb ^ rc ^ rd : (rb & rc) ^ (~rb & rd) temp += re + k[i] + w[i] re = rd rd = rc rc = (rb << 30) | (rb >>> 2) rb = ra ra = temp } hv[0] += ra & mask hv[1] += rb & mask hv[2] += rc & mask hv[3] += rd & mask hv[4] += re & mask return hv } var utils = msrcryptoUtilities, upd = utils.unpackData, h = upd('Z0UjAe/Nq4mYutz+EDJUdsPS4fA=', 4, 1), k = upd( 'WoJ5mVqCeZlagnmZWoJ5mVqCeZlagnmZWoJ5mVqCeZlagnmZWoJ5mVqCeZlagnmZWoJ5mVqCeZlagnmZWoJ5mVqCeZlagnmZWoJ5mVqCeZlu2euhbtnroW7Z66Fu2euhbtnroW7Z66Fu2euhbtnroW7Z66Fu2euhbtnroW7Z66Fu2euhbtnroW7Z66Fu2euhbtnroW7Z66Fu2euhbtnroY8bvNyPG7zcjxu83I8bvNyPG7zcjxu83I8bvNyPG7zcjxu83I8bvNyPG7zcjxu83I8bvNyPG7zcjxu83I8bvNyPG7zcjxu83I8bvNyPG7zcymLB1spiwdbKYsHWymLB1spiwdbKYsHWymLB1spiwdbKYsHWymLB1spiwdbKYsHWymLB1spiwdbKYsHWymLB1spiwdbKYsHWymLB1spiwdY', 4, 1, ), der = upd('MCEwCQYFKw4DAhoFAAQU') return { sha1: function () { return msrcryptoSha('SHA-1', der, h, k, 64, hashBlock, 160) }, } })() if (typeof operations !== 'undefined') { msrcryptoSha1.instances = {} msrcryptoSha1.getInstance = function (id) { return ( msrcryptoSha1.instances[id] || (msrcryptoSha1.instances[id] = msrcryptoSha1.sha1()) ) } msrcryptoSha1.deleteInstance = function (id) { msrcryptoSha1.instances[id] = null delete msrcryptoSha1.instances[id] } msrcryptoSha1.hash = function (p) { if (p.operationSubType === 'process') { msrcryptoSha1.sha1.process(p.buffer) return } if (p.operationSubType === 'finish') { return msrcryptoSha1.sha1.finish() } return msrcryptoSha1.sha1().computeHash(p.buffer) } operations.register('digest', 'SHA-1', msrcryptoSha1.hash) } msrcryptoHashFunctions['SHA-1'] = msrcryptoSha1.sha1 var msrcryptoSha256 = (function () { var utils = msrcryptoUtilities function hashBlock(message, blockIndex, hv, k, w) { var t, i, temp, x0, x1, blockSize = 64, mask = 0xffffffff var ra = hv[0], rb = hv[1], rc = hv[2], rd = hv[3], re = hv[4], rf = hv[5], rg = hv[6], rh = hv[7] for (i = 0; i < 16; i++) { w[i] = utils.bytesToInt32(message, blockIndex * blockSize + i * 4) } for (t = 16; t < 64; t++) { x0 = w[t - 15] x1 = w[t - 2] w[t] = (((x1 >>> 17) | (x1 << 15)) ^ ((x1 >>> 19) | (x1 << 13)) ^ (x1 >>> 10)) + w[t - 7] + (((x0 >>> 7) | (x0 << 25)) ^ ((x0 >>> 18) | (x0 << 14)) ^ (x0 >>> 3)) + w[t - 16] w[t] = w[t] & mask } for (i = 0; i < 64; i++) { temp = rh + (((re >>> 6) | (re << 26)) ^ ((re >>> 11) | (re << 21)) ^ ((re >>> 25) | (re << 7))) + ((re & rf) ^ (~re & rg)) + k[i] + w[i] rd += temp temp += (((ra >>> 2) | (ra << 30)) ^ ((ra >>> 13) | (ra << 19)) ^ ((ra >>> 22) | (ra << 10))) + ((ra & (rb ^ rc)) ^ (rb & rc)) rh = rg rg = rf rf = re re = rd rd = rc rc = rb rb = ra ra = temp } hv[0] = (hv[0] + ra) >>> 0 hv[1] = (hv[1] + rb) >>> 0 hv[2] = (hv[2] + rc) >>> 0 hv[3] = (hv[3] + rd) >>> 0 hv[4] = (hv[4] + re) >>> 0 hv[5] = (hv[5] + rf) >>> 0 hv[6] = (hv[6] + rg) >>> 0 hv[7] = (hv[7] + rh) >>> 0 return hv } var k256, h224, h256, der224, der256, upd = utils.unpackData h224 = upd('wQWe2DZ81QcwcN0X9w5ZOf/ACzFoWBURZPmPp776T6Q', 4, 1) h256 = upd('agnmZ7tnroU8bvNypU/1OlEOUn+bBWiMH4PZq1vgzRk', 4, 1) k256 = upd( 'QoovmHE3RJG1wPvP6bXbpTlWwltZ8RHxkj+CpKscXtXYB6qYEoNbASQxhb5VDH3Dcr5ddIDesf6b3AanwZvxdOSbacHvvkeGD8GdxiQMocwt6SxvSnSEqlywqdx2+YjamD5RUqgxxm2wAyfIv1l/x8bgC/PVp5FHBspjURQpKWcntwqFLhshOE0sbfxTOA0TZQpzVHZqCruBwskuknIshaK/6KGoGmZLwkuLcMdsUaPRkugZ1pkGJPQONYUQaqBwGaTBFh43bAgnSHdMNLC8tTkcDLNO2KpKW5zKT2gub/N0j4LueKVjb4TIeBSMxwIIkL7/+qRQbOu++aP3xnF48g', 4, 1, ) der224 = upd('MC0wDQYJYIZIAWUDBAIEBQAEHA') der256 = upd('MDEwDQYJYIZIAWUDBAIBBQAEIA') return { sha224: function () { return msrcryptoSha('SHA-224', der224, h224, k256, 64, hashBlock, 224) }, sha256: function () { return msrcryptoSha('SHA-256', der256, h256, k256, 64, hashBlock, 256) }, } })() if (typeof operations !== 'undefined') { msrcryptoSha256.instance224 = msrcryptoSha256.instance224 || msrcryptoSha256.sha224() msrcryptoSha256.instance256 = msrcryptoSha256.instance256 || msrcryptoSha256.sha256() msrcryptoSha256.instances = {} msrcryptoSha256.getInstance224 = function (id) { return ( msrcryptoSha256.instances[id] || (msrcryptoSha256.instances[id] = msrcryptoSha256.sha224()) ) } msrcryptoSha256.getInstance256 = function (id) { return ( msrcryptoSha256.instances[id] || (msrcryptoSha256.instances[id] = msrcryptoSha256.sha256()) ) } msrcryptoSha256.deleteInstance = function (id) { msrcryptoSha256.instances[id] = null delete msrcryptoSha256.instances[id] } msrcryptoSha256.hash256 = function (p) { if (p.operationSubType === 'process') { msrcryptoSha256.getInstance256(p.workerid).process(p.buffer) return null } if (p.operationSubType === 'finish') { var result = msrcryptoSha256.getInstance256(p.workerid).finish() msrcryptoSha256.deleteInstance(p.workerid) return result } if (p.operationSubType === 'abort') { msrcryptoSha256.deleteInstance(p.workerid) return } return msrcryptoSha256.instance256.computeHash(p.buffer) } msrcryptoSha256.hash224 = function (p) { if (p.operationSubType === 'process') { msrcryptoSha256.getInstance224(p.workerid).process(p.buffer) return } if (p.operationSubType === 'finish') { var result = msrcryptoSha256.getInstance224(p.workerid).finish() } if (p.operationSubType === 'abort') { msrcryptoSha224.deleteInstance(p.workerid) return } return msrcryptoSha256.instance224.computeHash(p.buffer) } operations.register('digest', 'SHA-224', msrcryptoSha256.hash224) operations.register('digest', 'SHA-256', msrcryptoSha256.hash256) } msrcryptoHashFunctions['SHA-224'] = msrcryptoSha256.sha224 msrcryptoHashFunctions['SHA-256'] = msrcryptoSha256.sha256 var msrcryptoSha512 = (function () { var utils = msrcryptoUtilities function add(x0, x1, y0, y1, resultArray) { var lowSum = (x1 + y1) | 0 var carry = lowSum >>> 0 < y1 >>> 0 resultArray[0] = (x0 + y0 + carry) | 0 resultArray[1] = lowSum return } function hashBlock(message, blockIndex, hv, k, w) { var t, i, blockBytes = 128, tah, tal, tbh, tbl, xh, xl, tc = [], td = [], te = [], index var ah = hv[0], al = hv[1], bh = hv[2], bl = hv[3], ch = hv[4], cl = hv[5], dh = hv[6], dl = hv[7], eh = hv[8], el = hv[9], fh = hv[10], fl = hv[11], gh = hv[12], gl = hv[13], hh = hv[14], hl = hv[15] for (t = 0; t < 32; t++) { index = blockIndex * blockBytes + t * 4 w[t] = message.slice(index, index + 4) w[t] = (w[t][0] << 24) | (w[t][1] << 16) | (w[t][2] << 8) | w[t][3] } for (t = 32; t < 160; t += 2) { xh = w[t - 30] xl = w[t - 29] tah = ((xh >>> 1) | (xl << 31)) ^ ((xh >>> 8) | (xl << 24)) ^ (xh >>> 7) tal = ((xl >>> 1) | (xh << 31)) ^ ((xl >>> 8) | (xh << 24)) ^ ((xl >>> 7) | (xh << 25)) xh = w[t - 4] xl = w[t - 3] tbh = ((xh >>> 19) | (xl << 13)) ^ ((xl >>> 29) | (xh << 3)) ^ (xh >>> 6) tbl = ((xl >>> 19) | (xh << 13)) ^ ((xh >>> 29) | (xl << 3)) ^ ((xl >>> 6) | (xh << 26)) add(tbh, tbl, w[t - 14], w[t - 13], tc) add(tah, tal, tc[0], tc[1], tc) add(w[t - 32], w[t - 31], tc[0], tc[1], tc) w[t] = tc[0] w[t + 1] = tc[1] } for (i = 0; i < 160; i += 2) { tah = ((eh >>> 14) | (el << 18)) ^ ((eh >>> 18) | (el << 14)) ^ ((el >>> 9) | (eh << 23)) tal = ((el >>> 14) | (eh << 18)) ^ ((el >>> 18) | (eh << 14)) ^ ((eh >>> 9) | (el << 23)) tbh = (eh & fh) ^ (gh & ~eh) tbl = (el & fl) ^ (gl & ~el) add(hh, hl, tah, tal, tc) add(tbh, tbl, k[i], k[i + 1], td) add(tc[0], tc[1], w[i], w[i + 1], te) add(td[0], td[1], te[0], te[1], te) add(te[0], te[1], dh, dl, tc) dh = tc[0] dl = tc[1] tal = ((al >>> 28) | (ah << 4)) ^ ((ah >>> 2) | (al << 30)) ^ ((ah >>> 7) | (al << 25)) tah = ((ah >>> 28) | (al << 4)) ^ ((al >>> 2) | (ah << 30)) ^ ((al >>> 7) | (ah << 25)) tbl = (al & (bl ^ cl)) ^ (bl & cl) tbh = (ah & (bh ^ ch)) ^ (bh & ch) add(te[0], te[1], tah, tal, tc) tah = tc[0] tal = tc[1] add(tbh, tbl, tah, tal, tc) tah = tc[0] tal = tc[1] hh = gh hl = gl gh = fh gl = fl fh = eh fl = el eh = dh el = dl dh = ch dl = cl ch = bh cl = bl bh = ah bl = al ah = tah al = tal } add(hv[0], hv[1], ah, al, tc) hv[0] = tc[0] hv[1] = tc[1] add(hv[2], hv[3], bh, bl, tc) hv[2] = tc[0] hv[3] = tc[1] add(hv[4], hv[5], ch, cl, tc) hv[4] = tc[0] hv[5] = tc[1] add(hv[6], hv[7], dh, dl, tc) hv[6] = tc[0] hv[7] = tc[1] add(hv[8], hv[9], eh, el, tc) hv[8] = tc[0] hv[9] = tc[1] add(hv[10], hv[11], fh, fl, tc) hv[10] = tc[0] hv[11] = tc[1] add(hv[12], hv[13], gh, gl, tc) hv[12] = tc[0] hv[13] = tc[1] add(hv[14], hv[15], hh, hl, tc) hv[14] = tc[0] hv[15] = tc[1] return hv } var h384, h512, k512, der384, der512, der512_224, der512_256, upd = utils.unpackData h384 = upd( 'y7udXcEFnthimikqNnzVB5FZAVowcN0XFS/s2PcOWTlnMyZn/8ALMY60SodoWBUR2wwuDWT5j6dHtUgdvvpPpA==', 4, 1, ) h512 = upd( 'agnmZ/O8yQi7Z66FhMqnOzxu83L+lPgrpU/1Ol8dNvFRDlJ/reaC0ZsFaIwrPmwfH4PZq/tBvWtb4M0ZE34heQ', 4, 1, ) k512 = upd( 'QoovmNcoriJxN0SRI+9lzbXA+8/sTTsv6bXbpYGJ27w5VsJb80i1OFnxEfG2BdAZkj+CpK8ZT5urHF7' + 'V2m2BGNgHqpijAwJCEoNbAUVwb74kMYW+TuSyjFUMfcPV/7Ticr5ddPJ7iW+A3rH+OxaWsZvcBqclxx' + 'I1wZvxdM9pJpTkm2nBnvFK0u++R4Y4TyXjD8GdxouM1bUkDKHMd6ycZS3pLG9ZKwJ1SnSEqm6m5INcs' + 'KncvUH71Hb5iNqDEVO1mD5RUu5m36uoMcZtLbQyELADJ8iY+yE/v1l/x77vDuTG4AvzPaiPwtWnkUeT' + 'CqclBspjUeADgm8UKSlnCg5ucCe3CoVG0i/8LhshOFwmySZNLG38WsQq7VM4DROdlbPfZQpzVIuvY95' + '2agq7PHeyqIHCyS5H7a7mknIshRSCNTuiv+ihTPEDZKgaZku8QjABwkuLcND4l5HHbFGjBlS+MNGS6B' + 'nW71IY1pkGJFVlqRD0DjWFV3EgKhBqoHAyu9G4GaTBFrjS0MgeN2wIUUGrUydId0zfjuuZNLC8teGbS' + 'Kg5HAyzxclaY07YqkrjQYrLW5zKT3dj43NoLm/z1rK4o3SPgu5d77L8eKVjb0MXL2CEyHgUofCrcozH' + 'AggaZDnskL7/+iNjHiikUGzr3oK96b75o/eyxnkVxnF48uNyUyvKJz7O6iZhnNGGuMchwMIH6tp91s3' + 'g6x71fU9/7m7ReAbwZ6pyF2+6CmN9xaLImKYRP5gEvvkNrhtxCzUTHEcbKNt39SMEfYQyyqt7QMckkz' + 'yevgoVyb68Qx1nxJwQDUxMxdS+yz5Ctll/KZz8ZX4qX8tvqzrW+uxsRBmMSkdYFw==', 4, 1, ) der384 = upd('MEEwDQYJYIZIAWUDBAICBQAEMA') der512 = upd('MFEwDQYJYIZIAWUDBAIDBQAEQA') der512_224 = upd('MC0wDQYJYIZIAWUDBAIFBQAEHA') der512_256 = upd('MDEwDQYJYIZIAWUDBAIGBQAEIA') return { sha384: function () { return msrcryptoSha( 'SHA-384', der384, h384, k512, 128, hashBlock, 384, ) }, sha512: function () { return msrcryptoSha( 'SHA-512', der512, h512, k512, 128, hashBlock, 512, ) }, sha512_224: function () { return msrcryptoSha( 'SHA-512.224', der512_224, h512, k512, 128, hashBlock, 224, ) }, sha512_256: function () { return msrcryptoSha( 'SHA-512.256', der512_256, h512, k512, 128, hashBlock, 256, ) }, } })() if (typeof operations !== 'undefined') { msrcryptoSha512.instances = {} msrcryptoSha512.getInstance384 = function (id) { return ( msrcryptoSha512.instances[id] || (msrcryptoSha512.instances[id] = msrcryptoSha512.sha384()) ) } msrcryptoSha512.getInstance512 = function (id) { return ( msrcryptoSha512.instances[id] || (msrcryptoSha512.instances[id] = msrcryptoSha512.sha512()) ) } msrcryptoSha512.deleteInstance = function (id) { msrcryptoSha512.instances[id] = null delete msrcryptoSha512.instances[id] } msrcryptoSha512.hash384 = function (p) { if (p.operationSubType === 'process') { msrcryptoSha512.sha384.process(p.buffer) return } if (p.operationSubType === 'finish') { return msrcryptoSha512.sha384.finish() } return msrcryptoSha512.sha384().computeHash(p.buffer) } msrcryptoSha512.hash512 = function (p) { if (p.operationSubType === 'process') { msrcryptoSha512.sha512.process(p.buffer) return } if (p.operationSubType === 'finish') { return msrcryptoSha512.sha512.finish() } return msrcryptoSha512.sha512().computeHash(p.buffer) } operations.register('digest', 'SHA-384', msrcryptoSha512.hash384) operations.register('digest', 'SHA-512', msrcryptoSha512.hash512) } msrcryptoHashFunctions['SHA-384'] = msrcryptoSha512.sha384 msrcryptoHashFunctions['SHA-512'] = msrcryptoSha512.sha512 var msrcryptoHmac = function (keyBytes, hashFunction) { var blockSize = { 384: 128, 512: 128, }[hashFunction.name.replace(/SHA-/, '')] || 64 var ipad var opad var paddedKey = padKey() var keyXorOpad var keyXorIpad var k0IpadText function xorArrays(array1, array2) { var newArray = new Array(array1) for (var j = 0; j < array1.length; j++) { newArray[j] = array1[j] ^ array2[j] } return newArray } function padZeros(bytes, paddedLength) { var paddedArray = bytes.slice() for (var j = bytes.length; j < paddedLength; j++) { paddedArray.push(0) } return paddedArray } function padKey() { if (keyBytes.length === blockSize) { return keyBytes } if (keyBytes.length > blockSize) { return padZeros(hashFunction.computeHash(keyBytes), blockSize) } return padZeros(keyBytes, blockSize) } function processHmac(messageBytes) { if (!k0IpadText) { k0IpadText = keyXorIpad.concat(messageBytes) hashFunction.process(k0IpadText) } else { hashFunction.process(messageBytes) } return } function finishHmac() { var hashK0IpadText = hashFunction.finish() var k0IpadK0OpadText = keyXorOpad.concat(hashK0IpadText) return hashFunction.computeHash(k0IpadK0OpadText) } function clearState() { keyBytes = null hashFunction = null paddedKey = null } ipad = new Array(blockSize) opad = new Array(blockSize) for (var i = 0; i < blockSize; i++) { ipad[i] = 0x36 opad[i] = 0x5c } keyXorIpad = xorArrays(paddedKey, ipad) keyXorOpad = xorArrays(paddedKey, opad) return { computeHmac: function (dataBytes, key, hashAlgorithm) { processHmac(dataBytes) var result = finishHmac() clearState() return result }, process: function (dataBytes, key, hashAlgorithm) { processHmac(dataBytes) return null }, finish: function (key, hashAlgorithm) { var result = finishHmac() clearState() return result }, } } if (typeof operations !== 'undefined') { var hmacInstances = {} msrcryptoHmac.signHmac = function (p) { var hashName = p.keyHandle.algorithm.hash.name.toUpperCase(), hashAlg = msrcryptoHashFunctions[hashName](), result, id = p.workerid if (!hmacInstances[id]) { hmacInstances[id] = msrcryptoHmac(p.keyData, hashAlg) } if (p.operationSubType === 'process') { hmacInstances[id].process(p.buffer) return null } if (p.operationSubType === 'finish') { result = hmacInstances[id].finish() hmacInstances[id] = null return result } result = hmacInstances[id].computeHmac(p.buffer) hmacInstances[id] = null return result } msrcryptoHmac.verifyHmac = function (p) { var hashName = p.keyHandle.algorithm.hash.name.toUpperCase(), hashAlg = msrcryptoHashFunctions[hashName](), result, id = p.workerid if (!hmacInstances[id]) { hmacInstances[id] = msrcryptoHmac(p.keyData, hashAlg) } if (p.operationSubType === 'process') { hmacInstances[id].process(p.buffer) return null } if (p.operationSubType === 'finish') { result = hmacInstances[id].finish() result = msrcryptoUtilities.arraysEqual(result, p.signature) hmacInstances[id] = null return result } result = hmacInstances[id].computeHmac(p.buffer) result = msrcryptoUtilities.arraysEqual(result, p.signature) hmacInstances[id] = null return result } msrcryptoHmac.generateKey = function (p) { var defaultKeyLengths = { 'SHA-1': 64, 'SHA-224': 64, 'SHA-256': 64, 'SHA-384': 128, 'SHA-512': 128, } var keyLength = p.algorithm.length if (!keyLength) { keyLength = defaultKeyLengths[p.algorithm.hash.name.toUpperCase()] } return { type: 'keyGeneration', keyData: msrcryptoPseudoRandom.getBytes(keyLength), keyHandle: { algorithm: p.algorithm, extractable: p.extractable, usages: null || p.usages, type: 'secret', }, } } msrcryptoHmac.importKey = function (p) { var keyObject, keyBits = p.keyData.length * 8 if (p.format === 'jwk') { keyObject = msrcryptoJwk.jwkToKey(p.keyData, p.algorithm, ['k']) keyObject.alg = keyObject.alg.replace('HS', 'SHA-') } else if (p.format === 'raw') { keyObject = { k: msrcryptoUtilities.toArray(p.keyData), } } else { throw new Error('unsupported import format') } return { type: 'keyImport', keyData: keyObject.k, keyHandle: { algorithm: { name: 'HMAC', hash: { name: p.algorithm.hash.name, }, }, extractable: p.extractable || keyObject.extractable, usages: p.usages, type: 'secret', }, } } msrcryptoHmac.exportKey = function (p) { if (p.format === 'jwk') { return { type: 'keyExport', keyHandle: msrcryptoJwk.keyToJwk(p.keyHandle, p.keyData), } } if (p.format === 'raw') { return { type: 'keyExport', keyHandle: p.keyData, } } throw new Error('unsupported export format') } operations.register('importKey', 'HMAC', msrcryptoHmac.importKey) operations.register('exportKey', 'HMAC', msrcryptoHmac.exportKey) operations.register('generateKey', 'HMAC', msrcryptoHmac.generateKey) operations.register('sign', 'HMAC', msrcryptoHmac.signHmac) operations.register('verify', 'HMAC', msrcryptoHmac.verifyHmac) } var msrcryptoBlockCipher = (function () { var aesConstants, x2, x3, x14, x13, x11, x9, sBoxTable, invSBoxTable, rConTable return { aes: function (keyBytes) { if (!aesConstants) { aesConstants = msrcryptoUtilities.unpackData( 'AAIEBggKDA4QEhQWGBocHiAiJCYoKiwuMDI0Njg6PD5AQkRGSEpMTlBSVFZYWlxeYGJkZmhqbG5wcnR2eHp8foCChIaIioyOkJKUlpianJ6goqSmqKqsrrCytLa4ury+wMLExsjKzM7Q0tTW2Nrc3uDi5Obo6uzu8PL09vj6/P4bGR8dExEXFQsJDw0DAQcFOzk/PTMxNzUrKS8tIyEnJVtZX11TUVdVS0lPTUNBR0V7eX99c3F3dWtpb21jYWdlm5mfnZORl5WLiY+Ng4GHhbu5v72zsbe1q6mvraOhp6Xb2d/d09HX1cvJz83DwcfF+/n//fPx9/Xr6e/t4+Hn5QADBgUMDwoJGBseHRQXEhEwMzY1PD86OSgrLi0kJyIhYGNmZWxvaml4e359dHdycVBTVlVcX1pZSEtOTURHQkHAw8bFzM/Kydjb3t3U19LR8PP29fz/+vno6+7t5Ofi4aCjpqWsr6qpuLu+vbS3srGQk5aVnJ+amYiLjo2Eh4KBm5idnpeUkZKDgIWGj4yJiquora6npKGis7C1tr+8ubr7+P3+9/Tx8uPg5ebv7Onqy8jNzsfEwcLT0NXW39zZ2ltYXV5XVFFSQ0BFRk9MSUpraG1uZ2RhYnNwdXZ/fHl6Ozg9Pjc0MTIjICUmLywpKgsIDQ4HBAECExAVFh8cGRoADhwSODYkKnB+bGJIRlRa4O788tjWxMqQnoyCqKa0utvVx8nj7f/xq6W3uZOdj4E7NScpAw0fEUtFV1lzfW9hraOxv5WbiYfd08HP5ev5901DUV91e2lnPTMhLwULGRd2eGpkTkBSXAYIGhQ+MCIslpiKhK6gsrzm6Pr03tDCzEFPXVN5d2VrMT8tIwkHFRuhr72zmZeFi9HfzcPp5/X7mpSGiKKsvrDq5Pb40tzOwHp0ZmhCTF5QCgQWGDI8LiDs4vD+1NrIxpySgI6kqri2DAIQHjQ6KCZ8cmBuREpYVjc5KyUPARMdR0lbVX9xY23X2cvF7+Hz/aepu7WfkYONAA0aFzQ5LiNoZXJ/XFFGS9Ddysfk6f7zuLWir4yBlpu7tqGsj4KVmNPeycTn6v3wa2ZxfF9SRUgDDhkUNzotIG1gd3pZVENOBQgfEjE8Kya9sKeqiYSTntXYz8Lh7Pv21tvMweLv+PW+s6SpioeQnQYLHBEyPyglbmN0eVpXQE3a18DN7uP0+bK/qKWGi5yRCgcQHT4zJClib3h1VltMQWFse3ZVWE9CCQQTHj0wJyqxvKumhYifktnUw87t4Pf6t7qtoIOOmZTf0sXI6+bx/GdqfXBTXklEDwIVGDs2ISwMARYbODUiL2RpfnNQXUpH3NHGy+jl8v+0ua6jgI2alwALFh0sJzoxWFNORXR/Ymmwu6atnJeKgejj/vXEz9LZe3BtZldcQUojKDU+DwQZEsvA3dbn7PH6k5iFjr+0qaL2/eDr2tHMx66luLOCiZSfRk1QW2phfHceFQgDMjkkL42Gm5Chqre81d7DyPny7+Q9NisgERoHDGVuc3hJQl9U9/zh6tvQzcavpLmyg4iVnkdMUVprYH12HxQJAjM4JS6Mh5qRoKu2vdTfwsn48+7lPDcqIRAbBg1kb3J5SENeVQEKFxwtJjswWVJPRHV+Y2ixuqesnZaLgOni//TFztPYenFsZ1ZdQEsiKTQ/DgUYE8rB3Nfm7fD7kpmEj761qKMACRIbJC02P0hBWlNsZX53kJmCi7S9pq/Y0crD/PXu5zsyKSAfFg0Ec3phaFdeRUyrormwj4adlOPq8fjHztXcdn9kbVJbQEk+NywlGhMIAebv9P3Cy9DZrqe8tYqDmJFNRF9WaWB7cgUMFx4hKDM63dTPxvnw6+KVnIeOsbijquzl/vfIwdrTpK22v4CJkpt8dW5nWFFKQzQ9Ji8QGQIL197FzPP64eiflo2Eu7KpoEdOVVxjanF4DwYdFCsiOTCak4iBvrespdLbwMn2/+TtCgMYES4nPDVCS1BZZm90faGos7qFjJee6eD78s3E39YxOCMqFRwHDnlwa2JdVE9GY3x3e/Jrb8UwAWcr/terdsqCyX36WUfwrdSir5ykcsC3/ZMmNj/3zDSl5fFx2DEVBMcjwxiWBZoHEoDi6yeydQmDLBobblqgUjvWsynjL4RT0QDtIPyxW2rLvjlKTFjP0O+q+0NNM4VF+QJ/UDyfqFGjQI+SnTj1vLbaIRD/89LNDBPsX5dEF8Snfj1kXRlzYIFP3CIqkIhG7rgU3l4L2+AyOgpJBiRcwtOsYpGV5HnnyDdtjdVOqWxW9Opleq4IunglLhymtMbo3XQfS72LinA+tWZIA/YOYTVXuYbBHZ7h+JgRadmOlJseh+nOVSjfjKGJDb/mQmhBmS0PsFS7FlIJatUwNqU4v0CjnoHz1/t84zmCmy//hzSOQ0TE3unLVHuUMqbCIz3uTJULQvrDTgguoWYo2SSydluiSW2L0SVy+PZkhmiYFtSkXMxdZbaSbHBIUP3tudpeFUZXp42dhJDYqwCMvNMK9+RYBbizRQbQLB6Pyj8PAsGvvQMBE4prOpERQU9n3OqX8s/O8LTmc5asdCLnrTWF4vk36Bx1325H8RpxHSnFiW+3Yg6qGL4b/FY+S8bSeSCa28D+eM1a9B/dqDOIB8cxsRIQWSeA7F9gUX+pGbVKDS3lep+TyZzvoOA7Ta4q9bDI67s8g1OZYRcrBH66d9Ym4WkUY1UhDH2NAQIECBAgQIAbNmzYq02aL168Y8aXNWrUs33678WROXLk071hwp8lSpQzZsyDHTp06MuNAQIECBAgQIAbNmzYq02aL168Y8aXNWrUs33678WROXLk071hwp8lSpQzZsyDHTp06MuNAQIECBAgQIAbNmzYq02aL168Y8aXNWrUs33678WROXLk071hwp8lSpQzZsyDHTp06MuNAQIECBAgQIAbNmzYq02aL168Y8aXNWrUs33678WROXLk071hwp8lSpQzZsyDHTp06MuNAQIECBAgQIAbNmzYq02aL168Y8aXNWrUs33678WROXLk071hwp8lSpQzZsyDHTp06MuN', 256, false, ) x2 = aesConstants[0] x3 = aesConstants[1] x14 = aesConstants[2] x13 = aesConstants[3] x11 = aesConstants[4] x9 = aesConstants[5] sBoxTable = aesConstants[6] invSBoxTable = aesConstants[7] rConTable = aesConstants[8] } var blockSize = 128, keyLength, nK, nB = 4, nR, key keyLength = keyBytes.length * 8 switch (keyLength) { case 128: case 192: case 256: break default: throw new Error('Unsupported keyLength') } nK = keyLength / 32 nR = nK + 6 var shiftRows = function (a) { var tmp = a[1] a[1] = a[5] a[5] = a[9] a[9] = a[13] a[13] = tmp tmp = a[2] a[2] = a[10] a[10] = tmp tmp = a[6] a[6] = a[14] a[14] = tmp tmp = a[15] a[15] = a[11] a[11] = a[7] a[7] = a[3] a[3] = tmp } var invShiftRows = function (a) { var tmp = a[13] a[13] = a[9] a[9] = a[5] a[5] = a[1] a[1] = tmp tmp = a[10] a[10] = a[2] a[2] = tmp tmp = a[14] a[14] = a[6] a[6] = tmp tmp = a[3] a[3] = a[7] a[7] = a[11] a[11] = a[15] a[15] = tmp } var mixColumns = function (state) { var a = state[0], b = state[1], c = state[2], d = state[3], e = state[4], f = state[5], g = state[6], h = state[7], i = state[8], j = state[9], k = state[10], l = state[11], m = state[12], n = state[13], o = state[14], p = state[15] state[0] = x2[a] ^ x3[b] ^ c ^ d state[1] = a ^ x2[b] ^ x3[c] ^ d state[2] = a ^ b ^ x2[c] ^ x3[d] state[3] = x3[a] ^ b ^ c ^ x2[d] state[4] = x2[e] ^ x3[f] ^ g ^ h state[5] = e ^ x2[f] ^ x3[g] ^ h state[6] = e ^ f ^ x2[g] ^ x3[h] state[7] = x3[e] ^ f ^ g ^ x2[h] state[8] = x2[i] ^ x3[j] ^ k ^ l state[9] = i ^ x2[j] ^ x3[k] ^ l state[10] = i ^ j ^ x2[k] ^ x3[l] state[11] = x3[i] ^ j ^ k ^ x2[l] state[12] = x2[m] ^ x3[n] ^ o ^ p state[13] = m ^ x2[n] ^ x3[o] ^ p state[14] = m ^ n ^ x2[o] ^ x3[p] state[15] = x3[m] ^ n ^ o ^ x2[p] } var invMixColumns = function (state) { var a = state[0], b = state[1], c = state[2], d = state[3], e = state[4], f = state[5], g = state[6], h = state[7], i = state[8], j = state[9], k = state[10], l = state[11], m = state[12], n = state[13], o = state[14], p = state[15] state[0] = x14[a] ^ x11[b] ^ x13[c] ^ x9[d] state[1] = x9[a] ^ x14[b] ^ x11[c] ^ x13[d] state[2] = x13[a] ^ x9[b] ^ x14[c] ^ x11[d] state[3] = x11[a] ^ x13[b] ^ x9[c] ^ x14[d] state[4] = x14[e] ^ x11[f] ^ x13[g] ^ x9[h] state[5] = x9[e] ^ x14[f] ^ x11[g] ^ x13[h] state[6] = x13[e] ^ x9[f] ^ x14[g] ^ x11[h] state[7] = x11[e] ^ x13[f] ^ x9[g] ^ x14[h] state[8] = x14[i] ^ x11[j] ^ x13[k] ^ x9[l] state[9] = x9[i] ^ x14[j] ^ x11[k] ^ x13[l] state[10] = x13[i] ^ x9[j] ^ x14[k] ^ x11[l] state[11] = x11[i] ^ x13[j] ^ x9[k] ^ x14[l] state[12] = x14[m] ^ x11[n] ^ x13[o] ^ x9[p] state[13] = x9[m] ^ x14[n] ^ x11[o] ^ x13[p] state[14] = x13[m] ^ x9[n] ^ x14[o] ^ x11[p] state[15] = x11[m] ^ x13[n] ^ x9[o] ^ x14[p] } var xorWord = function (a, b) { return [a[0] ^ b[0], a[1] ^ b[1], a[2] ^ b[2], a[3] ^ b[3]] } var addRoundKey = function (state, keySchedule, offset) { for (var i = 0; i < state.length; i += 1) { state[i] ^= keySchedule[i + offset] } } var rotWord = function (word) { var a = word[0] word[0] = word[1] word[1] = word[2] word[2] = word[3] word[3] = a } var subWord = function (word) { for (var i = 0; i < word.length; i += 1) { word[i] = sBoxTable[word[i]] } } var invSubWord = function (word) { for (var i = 0; i < word.length; i += 1) { word[i] = invSBoxTable[word[i]] } } var getWord = function (tab, i) { return [tab[4 * i], tab[4 * i + 1], tab[4 * i + 2], tab[4 * i + 3]] } var setWord = function (left, right, indexL, indexR) { left[4 * indexL] = right[4 * indexR] left[4 * indexL + 1] = right[4 * indexR + 1] left[4 * indexL + 2] = right[4 * indexR + 2] left[4 * indexL + 3] = right[4 * indexR + 3] } var expandKey = function (keyIn) { var temp, res = [], i = 0 while (i < 4 * nK) { res.push(keyIn[i++]) } i = nK while (i < nB * (nR + 1)) { temp = getWord(res, i - 1) if (i % nK === 0) { var index = i / nK var rcon = [rConTable[index], 0, 0, 0] rotWord(temp) subWord(temp) temp = xorWord(temp, rcon) } else if (nK > 6 && i % nK === 4) { subWord(temp) } var newWord = xorWord(getWord(res, i - nK), temp) setWord(res, newWord, i, 0) i += 1 } return res } key = expandKey(keyBytes) return { encrypt: function (dataBytes) { var state = dataBytes, round addRoundKey(state, key, 0) for (round = 1; round <= nR - 1; round += 1) { subWord(state) shiftRows(state) mixColumns(state) addRoundKey(state, key, 4 * round * nB) } subWord(state) shiftRows(state) addRoundKey(state, key, 4 * nR * nB) return state }, decrypt: function (dataBytes) { var state = dataBytes, round addRoundKey(state, key, 4 * nR * nB) for (round = nR - 1; round >= 1; round -= 1) { invShiftRows(state) invSubWord(state) addRoundKey(state, key, 4 * round * nB) invMixColumns(state) } invShiftRows(state) invSubWord(state) addRoundKey(state, key, 0) return state }, clear: function () {}, keyLength: keyLength, blockSize: blockSize, } }, } })() var msrcryptoPadding = msrcryptoPadding || {} msrcryptoPadding.pkcsv7 = function (blockSize) { function pad(messageBlocks) { var lastIndex = messageBlocks.length - 1 >= 0 ? messageBlocks.length - 1 : 0 var lastBlock = messageBlocks[lastIndex] var lastBlockLength = lastBlock.length var createNewBlock = lastBlockLength === blockSize if (createNewBlock) { var newBlock = [] var i for (i = 0; i < blockSize; i += 1) { newBlock.push(blockSize) } messageBlocks.push(newBlock) } else { var byteToAdd = (blockSize - lastBlockLength) & 0xff while (lastBlock.length !== blockSize) { lastBlock.push(byteToAdd) } } } function unpad(messageBytes) { var verified = true if (messageBytes.length % blockSize !== 0) { verified = false } var lastBlock = messageBytes.slice(-blockSize) var padLen = lastBlock[lastBlock.length - 1] for (var i = 0; i < blockSize; i++) { var isPaddingElement = blockSize - i <= padLen var isCorrectValue = lastBlock[i] === padLen verified = (isPaddingElement ? isCorrectValue : true) && verified } var trimLen = verified ? padLen : 0 messageBytes.length -= trimLen return verified } return { pad: pad, unpad: unpad, } } var msrcryptoCbc = function (blockCipher) { var blockSize = blockCipher.blockSize / 8 var paddingScheme = msrcryptoPadding.pkcsv7(blockSize) var mergeBlocks = function (tab) { var res = [], i, j for (i = 0; i < tab.length; i += 1) { var block = tab[i] for (j = 0; j < block.length; j += 1) { res.push(block[j]) } } return res } function getBlocks(dataBytes) { var blocks = [] mBuffer = mBuffer.concat(dataBytes) var blockCount = Math.floor(mBuffer.length / blockSize) for (var i = 0; i < blockCount; i++) { blocks.push(mBuffer.slice(i * blockSize, (i + 1) * blockSize)) } mBuffer = mBuffer.slice(blockCount * blockSize) return blocks } function encryptBlocks(blocks) { var result = [], toEncrypt for (var i = 0; i < blocks.length; i++) { toEncrypt = msrcryptoUtilities.xorVectors(mIvBytes, blocks[i]) result.push(blockCipher.encrypt(toEncrypt)) mIvBytes = result[i] } return result } function decryptBlocks(blocks) { var result = [], toDecrypt, decrypted for (var i = 0; i < blocks.length; i += 1) { toDecrypt = blocks[i].slice(0, blocks[i].length) decrypted = blockCipher.decrypt(toDecrypt) result.push(msrcryptoUtilities.xorVectors(mIvBytes, decrypted)) mIvBytes = blocks[i] } return result } function clearState() { mBuffer = [] mResultBuffer = [] mIvBytes = null } var mBuffer = [], mResultBuffer = [], mIvBytes return { init: function (ivBytes) { if (ivBytes.length !== blockSize) { throw new Error('Invalid iv size') } mIvBytes = ivBytes.slice() }, encrypt: function (plainBytes) { var result = encryptBlocks(getBlocks(plainBytes)) mResultBuffer = mResultBuffer.concat(mergeBlocks(result)) return this.finishEncrypt() }, processEncrypt: function (plainBytes) { var result = mergeBlocks(encryptBlocks(getBlocks(plainBytes))) return result }, finishEncrypt: function () { var blocks = mBuffer.length === 1 ? [[mBuffer[0]]] : [mBuffer] paddingScheme.pad(blocks) var result = mResultBuffer.concat(mergeBlocks(encryptBlocks(blocks))) clearState() return result }, decrypt: function (cipherBytes) { this.processDecrypt(cipherBytes) return this.finishDecrypt() }, processDecrypt: function (cipherBytes) { var result = decryptBlocks(getBlocks(cipherBytes)) mResultBuffer = mResultBuffer.concat(mergeBlocks(result)) return }, finishDecrypt: function () { var result = mResultBuffer var verified = paddingScheme.unpad(result) clearState() return result }, } } if (typeof operations !== 'undefined') { var cbcInstances = {} msrcryptoCbc.workerEncrypt = function (p) { var result, id = p.workerid if (!cbcInstances[id]) { cbcInstances[id] = msrcryptoCbc(msrcryptoBlockCipher.aes(p.keyData)) cbcInstances[id].init(p.algorithm.iv) } if (p.operationSubType === 'process') { return cbcInstances[id].processEncrypt(p.buffer) } if (p.operationSubType === 'finish') { result = cbcInstances[id].finishEncrypt() cbcInstances[id] = null return result } result = cbcInstances[id].encrypt(p.buffer) cbcInstances[id] = null return result } msrcryptoCbc.workerDecrypt = function (p) { var result, id = p.workerid if (!cbcInstances[id]) { cbcInstances[id] = msrcryptoCbc(msrcryptoBlockCipher.aes(p.keyData)) cbcInstances[id].init(p.algorithm.iv) } if (p.operationSubType === 'process') { cbcInstances[id].processDecrypt(p.buffer) return } if (p.operationSubType === 'finish') { result = cbcInstances[id].finishDecrypt() cbcInstances[id] = null return result } result = cbcInstances[id].decrypt(p.buffer) cbcInstances[id] = null return result } msrcryptoCbc.generateKey = function (p) { if (p.algorithm.length % 8 !== 0) { throw new Error() } return { type: 'keyGeneration', keyData: msrcryptoPseudoRandom.getBytes( Math.floor(p.algorithm.length / 8), ), keyHandle: { algorithm: p.algorithm, extractable: p.extractable, usages: null || p.usages, type: 'secret', }, } } msrcryptoCbc.importKey = function (p) { var keyObject var keyBits = p.keyData.length * 8 if (p.format === 'jwk') { keyObject = msrcryptoJwk.jwkToKey(p.keyData, p.algorithm, ['k']) } else if (p.format === 'raw') { if (keyBits !== 128 && keyBits !== 192 && keyBits !== 256) { throw new Error( 'invalid key length (should be 128, 192, or 256 bits)', ) } keyObject = { k: msrcryptoUtilities.toArray(p.keyData), } } else { throw new Error('unsupported import format') } p.algorithm.length = keyObject.k.length * 8 return { keyData: keyObject.k, keyHandle: { algorithm: p.algorithm, extractable: p.extractable || keyObject.extractable, usages: null || p.usages, type: 'secret', }, type: 'keyImport', } } msrcryptoCbc.exportKey = function (p) { if (p.format === 'jwk') { return { type: 'keyExport', keyHandle: msrcryptoJwk.keyToJwk(p.keyHandle, p.keyData), } } if (p.format === 'raw') { return { type: 'keyExport', keyHandle: p.keyData, } } throw new Error('unsupported export format') } operations.register('importKey', 'AES-CBC', msrcryptoCbc.importKey) operations.register('exportKey', 'AES-CBC', msrcryptoCbc.exportKey) operations.register('generateKey', 'AES-CBC', msrcryptoCbc.generateKey) operations.register('encrypt', 'AES-CBC', msrcryptoCbc.workerEncrypt) operations.register('decrypt', 'AES-CBC', msrcryptoCbc.workerDecrypt) } var msrcryptoGcm = function (blockCipher) { var utils = msrcryptoUtilities var mBuffer = [], mIvBytes, mAdditionalBytes, mTagLength, mJ0, mJ0inc, mH = blockCipher.encrypt(utils.getVector(16)), mGHashState = utils.getVector(16), mGHashBuffer = [], mCipherText = [], mGctrCb, mBytesProcessed = 0 function ghash(hashSubkey, dataBytes) { var blockCount = Math.floor(dataBytes.length / 16), dataBlock for (var i = 0; i < blockCount; i++) { dataBlock = dataBytes.slice(i * 16, i * 16 + 16) mGHashState = blockMultiplication( utils.xorVectors(mGHashState, dataBlock), hashSubkey, ) } mGHashBuffer = dataBytes.slice(blockCount * 16) return mGHashState } function finishGHash() { var u = 16 * Math.ceil(mBytesProcessed / 16) - mBytesProcessed var lenA = numberTo8Bytes(mAdditionalBytes.length * 8), lenC = numberTo8Bytes(mBytesProcessed * 8) var p = mGHashBuffer .concat(utils.getVector(u)) .concat(lenA) .concat(lenC) return ghash(mH, p) } function blockMultiplication(blockX, blockY) { var z = utils.getVector(16), v = blockY.slice(0), mask, j, i for (i = 0; i < 128; i++) { mask = -getBit(blockX, i) & 0xff for (j = 0; j < 16; j++) { z[j] = z[j] ^ (v[j] & mask) } mask = -(v[15] & 1) & 0xff shiftRight(v) v[0] ^= 0xe1 & mask } return z } function shiftRight(dataBytes) { for (var i = dataBytes.length - 1; i > 0; i--) { dataBytes[i] = ((dataBytes[i - 1] & 1) << 7) | (dataBytes[i] >>> 1) } dataBytes[0] = dataBytes[0] >>> 1 return dataBytes } function getBit(byteArray, bitNumber) { var byteIndex = Math.floor(bitNumber / 8) return (byteArray[byteIndex] >> (7 - (bitNumber % 8))) & 1 } function inc(dataBytes) { var carry = 256 for (var i = 1; i <= 4; i++) { carry = (carry >>> 8) + dataBytes[dataBytes.length - i] dataBytes[dataBytes.length - i] = carry & 255 } return dataBytes } function gctr(icb, dataBytes) { var blockCount = Math.ceil(dataBytes.length / 16), dataBlock, result = [] if (mGctrCb !== icb) { mGctrCb = icb.slice() } for (var block = 0; block < blockCount; block++) { dataBlock = dataBytes.slice(block * 16, block * 16 + 16) var e = blockCipher.encrypt(mGctrCb.slice()) result = result.concat(utils.xorVectors(dataBlock, e)) mGctrCb = inc(mGctrCb) } return result } function numberTo8Bytes(integer) { return [ 0, 0, 0, 0, (integer >>> 24) & 255, (integer >>> 16) & 255, (integer >>> 8) & 255, integer & 255, ] } function padBlocks(dataBytes) { var padLen = 16 * Math.ceil(mAdditionalBytes.length / 16) - mAdditionalBytes.length return dataBytes.concat(utils.getVector(padLen)) } function clearState() { mBytesProcessed = 0 mBuffer = [] mCipherText = [] mGHashState = utils.getVector(16) mGHashBuffer = [] mGctrCb = mIvBytes = mAdditionalBytes = null } function init(ivBytes, additionalBytes, tagLength) { mAdditionalBytes = additionalBytes || [] mTagLength = isNaN(tagLength) ? 128 : tagLength if (mTagLength % 8 !== 0) { throw new Error('DataError') } mIvBytes = ivBytes if (mIvBytes.length === 12) { mJ0 = mIvBytes.concat([0, 0, 0, 1]) } else { var l = 16 * Math.ceil(mIvBytes.length / 16) - mIvBytes.length mJ0 = ghash( mH, mIvBytes .concat(utils.getVector(l + 8)) .concat(numberTo8Bytes(mIvBytes.length * 8)), ) mGHashState = utils.getVector(16) } mJ0inc = inc(mJ0.slice()) ghash(mH, padBlocks(mAdditionalBytes)) } function encrypt(plainBytes) { mBytesProcessed = plainBytes.length var c = gctr(mJ0inc, plainBytes) ghash(mH, c) var s = finishGHash() var t = gctr(mJ0, s).slice(0, mTagLength / 8) clearState() return c.slice().concat(t) } function decrypt(cipherBytes, tagBytes) { mBytesProcessed = cipherBytes.length var p = gctr(mJ0inc, cipherBytes) ghash(mH, cipherBytes) var s = finishGHash() var t = gctr(mJ0, s).slice(0, mTagLength / 8) clearState() if (utils.arraysEqual(t, tagBytes)) { return p } else { return null } } function processEncrypt(plainBytes) { mBuffer = mBuffer.concat(plainBytes) var fullBlocks = mBuffer.slice(0, Math.floor(mBuffer.length / 16) * 16) mBytesProcessed += fullBlocks.length mBuffer = mBuffer.slice(fullBlocks.length) var c = gctr(mGctrCb || mJ0inc, fullBlocks) mCipherText = mCipherText.concat(c) ghash(mH, c) } function processDecrypt(cipherBytes) { mBuffer = mBuffer.concat(cipherBytes) var fullBlocks = mBuffer.slice( 0, Math.floor((mBuffer.length - mTagLength / 8) / 16) * 16, ) mBytesProcessed += fullBlocks.length mBuffer = mBuffer.slice(fullBlocks.length) var c = gctr(mGctrCb || mJ0inc, fullBlocks) mCipherText = mCipherText.concat(c) ghash(mH, fullBlocks) } function finishEncrypt() { var c = gctr(mGctrCb, mBuffer) mCipherText = mCipherText.concat(c) mBytesProcessed += mBuffer.length var s = finishGHash() var t = gctr(mJ0, s).slice(0, mTagLength / 8) var result = mCipherText.slice().concat(t) clearState() return result } function finishDecrypt() { var tagLength = Math.floor(mTagLength / 8) var tagBytes = mBuffer.slice(-tagLength) mBuffer = mBuffer.slice(0, mBuffer.length - tagLength) var c = gctr(mGctrCb, mBuffer) mCipherText = mCipherText.concat(c) mBytesProcessed += mBuffer.length var s = finishGHash() var t = gctr(mJ0, s).slice(0, mTagLength / 8) var result = mCipherText.slice() clearState() if (utils.arraysEqual(t, tagBytes)) { return result } else { return null } } return { init: init, encrypt: encrypt, decrypt: decrypt, processEncrypt: processEncrypt, processDecrypt: processDecrypt, finishEncrypt: finishEncrypt, finishDecrypt: finishDecrypt, } } if (typeof operations !== 'undefined') { var gcmInstances = {} msrcryptoGcm.encrypt = function (p) { var result, id = p.workerid if (!gcmInstances[id]) { gcmInstances[id] = msrcryptoGcm(msrcryptoBlockCipher.aes(p.keyData)) gcmInstances[id].init( p.algorithm.iv, p.algorithm.additionalData, p.algorithm.tagLength, ) } if (p.operationSubType === 'process') { gcmInstances[id].processEncrypt(p.buffer) return } if (p.operationSubType === 'finish') { result = gcmInstances[id].finishEncrypt() gcmInstances[id] = null return result } result = gcmInstances[id].encrypt(p.buffer) gcmInstances[id] = null return result } msrcryptoGcm.decrypt = function (p) { var result, id = p.workerid if (!gcmInstances[id]) { gcmInstances[id] = msrcryptoGcm(msrcryptoBlockCipher.aes(p.keyData)) gcmInstances[id].init( p.algorithm.iv, p.algorithm.additionalData, p.algorithm.tagLength, ) } if (p.operationSubType === 'process') { gcmInstances[id].processDecrypt(p.buffer) return } if (p.operationSubType === 'finish') { result = gcmInstances[id].finishDecrypt() gcmInstances[id] = null if (result === null) { throw new Error('OperationError') } return result } var tagLength = p.algorithm.tagLength ? Math.floor(p.algorithm.tagLength / 8) : 16 var cipherBytes = p.buffer.slice(0, p.buffer.length - tagLength) var tagBytes = p.buffer.slice(-tagLength) result = gcmInstances[id].decrypt(cipherBytes, tagBytes) gcmInstances[id] = null if (result === null) { throw new Error('OperationError') } return result } msrcryptoGcm.generateKey = function (p) { if (p.algorithm.length % 8 !== 0) { throw new Error() } return { type: 'keyGeneration', keyData: msrcryptoPseudoRandom.getBytes( Math.floor(p.algorithm.length / 8), ), keyHandle: { algorithm: p.algorithm, extractable: p.extractable, usages: null || p.usages, type: 'secret', }, } } msrcryptoGcm.importKey = function (p) { var keyObject, keyBits = p.keyData.length * 8 if (p.format === 'jwk') { keyObject = msrcryptoJwk.jwkToKey(p.keyData, p.algorithm, ['k']) } else if (p.format === 'raw') { if (keyBits !== 128 && keyBits !== 192 && keyBits !== 256) { throw new Error( 'invalid key length (should be 128, 192, or 256 bits)', ) } keyObject = { k: msrcryptoUtilities.toArray(p.keyData), } } else { throw new Error('unsupported import format') } return { type: 'keyImport', keyData: keyObject.k, keyHandle: { algorithm: p.algorithm, extractable: p.extractable || keyObject.extractable, usages: null || p.usages, type: 'secret', }, } } msrcryptoGcm.exportKey = function (p) { if (p.format === 'jwk') { return { type: 'keyExport', keyHandle: msrcryptoJwk.keyToJwk(p.keyHandle, p.keyData), } } if (p.format === 'raw') { return { type: 'keyExport', keyHandle: p.keyData, } } throw new Error('unsupported export format') } operations.register('importKey', 'AES-GCM', msrcryptoGcm.importKey) operations.register('exportKey', 'AES-GCM', msrcryptoGcm.exportKey) operations.register('generateKey', 'AES-GCM', msrcryptoGcm.generateKey) operations.register('encrypt', 'AES-GCM', msrcryptoGcm.encrypt) operations.register('decrypt', 'AES-GCM', msrcryptoGcm.decrypt) } function MsrcryptoPrng() { if (!(this instanceof MsrcryptoPrng)) { throw new Error('create MsrcryptoPrng object with new keyword') } var initialized = false var key var v var keyLen var seedLen var reseedCounter = 1 var reseedInterval = Math.pow(2, 48) initialize() function addOne(counter) { var i for (i = counter.length - 1; i >= 0; i -= 1) { counter[i] += 1 if (counter[i] >= 256) { counter[i] = 0 } if (counter[i]) { break } } } function initialize() { key = msrcryptoUtilities.getVector(32) v = msrcryptoUtilities.getVector(16) keyLen = 32 seedLen = 48 reseedCounter = 1 } function reseed(entropy, additionalEntropy) { additionalEntropy = additionalEntropy || [0] if (additionalEntropy.length > seedLen) { throw new Error('Incorrect entropy or additionalEntropy length') } additionalEntropy = additionalEntropy.concat( msrcryptoUtilities.getVector(seedLen - additionalEntropy.length), ) entropy = entropy.concat( msrcryptoUtilities.getVector( (seedLen - (entropy.length % seedLen)) % seedLen, ), ) for (var i = 0; i < entropy.length; i += seedLen) { var seedMaterial = msrcryptoUtilities.xorVectors( entropy.slice(i, i + seedLen), additionalEntropy, ) update(seedMaterial) } reseedCounter = 1 } function update(providedData) { var temp = [] var blockCipher = new msrcryptoBlockCipher.aes(key) while (temp.length < seedLen) { addOne(v) var toEncrypt = v.slice(0, 16) var outputBlock = blockCipher.encrypt(toEncrypt) temp = temp.concat(outputBlock) } temp = msrcryptoUtilities.xorVectors(temp, providedData) key = temp.slice(0, keyLen) v = temp.slice(keyLen) } function generate(requestedBytes, additionalInput) { if (requestedBytes >= 65536) { throw new Error('too much random requested') } if (reseedCounter > reseedInterval) { throw new Error('Reseeding is required') } if (additionalInput && additionalInput.length > 0) { while (additionalInput.length < seedLen) { additionalInput = additionalInput.concat( msrcryptoUtilities.getVector(seedLen - additionalInput.length), ) } update(additionalInput) } else { additionalInput = msrcryptoUtilities.getVector(seedLen) } var temp = [] var blockCipher = new msrcryptoBlockCipher.aes(key) while (temp.length < requestedBytes) { addOne(v) var toEncrypt = v.slice(0, v.length) var outputBlock = blockCipher.encrypt(toEncrypt) temp = temp.concat(outputBlock) } temp = temp.slice(0, requestedBytes) update(additionalInput) reseedCounter += 1 return temp } return { reseed: reseed, getBytes: function (length, additionalInput) { if (!initialized) { throw new Error("can't get randomness before initialization") } return generate(length, additionalInput) }, getNonZeroBytes: function (length, additionalInput) { if (!initialized) { throw new Error("can't get randomness before initialization") } var result = [] var buff while (result.length < length) { buff = generate(length, additionalInput) for (var i = 0; i < buff.length; i += 1) { if (buff[i] !== 0) { result.push(buff[i]) } } } return result.slice(0, length) }, init: function (entropy, personalization) { if (entropy.length < seedLen) { throw new Error('Initial entropy length too short') } initialize() reseed(entropy, personalization) initialized = true }, } } var msrcryptoPseudoRandom = new MsrcryptoPrng() function MsrcryptoEntropy(global) { var poolLength = 48 var collectorPool = [] var collectorPoolLength = 128 var collectorsRegistered = 0 var entropyPoolPrng = new MsrcryptoPrng() var initialized = false var cryptographicPRNGPresent = false var globalScope = global function collectEntropy() { var headerList = [ 'Cookie', 'RedirectUri', 'ETag', 'x-ms-client-antiforgery-id', 'x-ms-client-request-id', 'x-ms-client-session-id', 'SubscriptionPool', ] var i, pool = [] for (i = 0; i < poolLength; i += 1) { pool[i] = Math.floor(Math.random() * 256) } var prngCrypto = globalScope.crypto || globalScope.msCrypto if (prngCrypto && typeof prngCrypto.getRandomValues === 'function') { if (global.Uint8Array) { var res = new global.Uint8Array(poolLength) prngCrypto.getRandomValues(res) pool = pool.concat(Array.apply(null, res)) cryptographicPRNGPresent = true } } if (typeof XMLHttpRequest !== 'undefined') { var req = new XMLHttpRequest() for (i = 0; i < headerList.length; i += 1) { try { var header = req.getResponseHeader(headerList[i]) if (header) { var arr = msrcryptoUtilities.stringToBytes(header) pool = pool.concat(arr) } } catch (err) {} } } if (!cryptographicPRNGPresent && canCollect) { pool = pool.concat(collectorPool.splice(0, collectorPool.length)) collectors.startCollectors() } initialized ? entropyPoolPrng.reseed(pool) : entropyPoolPrng.init(pool) initialized = true } function updatePool(entropyData) { for (var i = 0; i < entropyData.length; ++i) { collectorPool.push(entropyData[i]) } if (collectorPool.length >= collectorPoolLength) { collectors.stopCollectors() } } var canCollect = (global && global.addEventListener) || (typeof document !== 'undefined' && document.attachEvent) var collectors = (function () { return { startCollectors: function () { if (!this.collectorsRegistered) { if (global.addEventListener) { global.addEventListener( 'mousemove', this.MouseEventCallBack, true, ) global.addEventListener('load', this.LoadTimeCallBack, true) } else if (document.attachEvent) { document.attachEvent('onmousemove', this.MouseEventCallBack) document.attachEvent('onload', this.LoadTimeCallBack) } else { throw new Error("Can't attach events for entropy collection") } this.collectorsRegistered = 1 } }, stopCollectors: function () { if (this.collectorsRegistered) { if (global.removeEventListener) { global.removeEventListener( 'mousemove', this.MouseEventCallBack, 1, ) global.removeEventListener('load', this.LoadTimeCallBack, 1) } else if (global.detachEvent) { global.detachEvent('onmousemove', this.MouseEventCallBack) global.detachEvent('onload', this.LoadTimeCallBack) } this.collectorsRegistered = 0 } }, MouseEventCallBack: function (eventData) { var d = new Date().valueOf() var x = eventData.x || eventData.clientX || eventData.offsetX || 0 var y = eventData.y || eventData.clientY || eventData.offsetY || 0 var arr = [ d & 0x0ff, (d >> 8) & 0x0ff, (d >> 16) & 0x0ff, (d >> 24) & 0x0ff, x & 0x0ff, (x >> 8) & 0x0ff, y & 0x0ff, (y >> 8) & 0x0ff, ] updatePool(arr) }, LoadTimeCallBack: function () { var d = new Date().valueOf() var dateArray = [ d & 0x0ff, (d >> 8) & 0x0ff, (d >> 16) & 0x0ff, (d >> 24) & 0x0ff, ] updatePool(dateArray) }, } })() return { init: function () { collectEntropy() if ( !cryptographicPRNGPresent && !collectorsRegistered && canCollect ) { try { collectors.startCollectors() } catch (e) {} } }, reseed: function (entropy) { entropyPoolPrng.reseed(entropy) }, read: function (length) { if (!initialized) { throw new Error('Entropy pool is not initialized.') } var ret = entropyPoolPrng.getBytes(length) collectEntropy() return ret }, } } var prime = (function () { var smallPrimes = [] var trialValues = [] var MAX_SMALL_PRIMES = 4096 * 4 function primeSieve(max) { var numbers = new Array(max + 1), results = [], i, j, limit = Math.sqrt(max) | 0 for (i = 3; i <= limit; i += 2) { for (j = i * i; j <= max; j += i * 2) { numbers[j] = 0 } } for (i = 3; i <= max; i += 2) { if (numbers[i] !== 0) { results.push(i) } } return results } function incrementalTrialDivision(increment) { var i, len = trialValues.length for (i = 0; i < len; i++) { if ((trialValues[i] + increment) % smallPrimes[i] === 0) { return false } } return true } function setupIncrementalTrialDivision(candidate) { var i, j, r, p, y, primeCount, len = candidate.length - 1, db = cryptoMath.DIGIT_BASE, h = candidate[len] if (smallPrimes.length === 0) { smallPrimes = primeSieve(MAX_SMALL_PRIMES) } primeCount = smallPrimes.length trialValues = new Array(primeCount) for (i = 0; i < primeCount; i++) { j = len y = smallPrimes[i] if (h < y) { r = h j-- } else { r = 0 } while (j >= 0) { p = r * db + candidate[j--] r = p - ((p / y) | 0) * y } trialValues[i] = r } return } function largestDivisibleByPowerOfTwo(number) { var k = 0, i = 0, s = 0, j if (cryptoMath.isZero(number)) { return 0 } for (k = 0; number[k] === 0; k++) {} for (i = 0, j = 2; number[k] % j === 0; j *= 2, i++) {} return k * cryptoMath.DIGIT_BITS + i } function sizeInBits(digits) { var k = 0, i = 0, j = 0 if (cryptoMath.isZero(digits)) { return 0 } for (k = digits.length - 1; digits[k] === 0; k--) {} for ( i = cryptoMath.DIGIT_BITS - 1, j = 1 << i; i > 0; j = j >>> 1, i-- ) { if ((digits[k] & j) !== 0) { break } } return k * cryptoMath.DIGIT_BITS + i } function millerRabin(number, iterations) { var w = number var wminus1 = [] cryptoMath.subtract(w, [1], wminus1) var a = largestDivisibleByPowerOfTwo(wminus1) var m = [] cryptoMath.shiftRight(wminus1, m, a) var wlen = sizeInBits(w) var b var montmul = cryptoMath.MontgomeryMultiplier(w) for (var i = 1; i <= iterations; i++) { var status = false do { b = getRandomOddNumber(wlen) } while (cryptoMath.compareDigits(b, wminus1) >= 0) var z = [] montmul.modExp(b, m, z, true) if ( cryptoMath.compareDigits(z, [1]) === 0 || cryptoMath.compareDigits(z, wminus1) === 0 ) { continue } for (var j = 1; j < a; j++) { montmul.montgomeryMultiply(z, z, z) if (cryptoMath.compareDigits(z, wminus1) === 0) { status = true break } if (cryptoMath.compareDigits(z, [1]) === 0) { return false } } if (status === false) { return false } } return true } function generatePrime(bits) { var candidate = getRandomOddNumber(bits), inc = 0, possiblePrime, isPrime = false, candidatePlusInc = [] setupIncrementalTrialDivision(candidate) while (true) { possiblePrime = incrementalTrialDivision(inc) if (possiblePrime) { cryptoMath.add(candidate, [inc], candidatePlusInc) if (millerRabin(candidatePlusInc, 6) === true) { return candidatePlusInc } } inc += 2 } } function getRandomOddNumber(bits) { var numBytes = Math.ceil(bits / 8), bytes = msrcryptoPseudoRandom.getBytes(numBytes), digits bytes[0] |= 128 bytes[bytes.length - 1] |= 1 return cryptoMath.bytesToDigits(bytes) } return { generatePrime: generatePrime, } })() var msrcryptoRsaBase = function (keyStruct) { var utils = msrcryptoUtilities, keyIsPrivate = keyStruct.hasOwnProperty('n') && keyStruct.hasOwnProperty('d'), keyIsCrt = keyStruct.hasOwnProperty('p') && keyStruct.hasOwnProperty('q'), modulusLength = keyStruct.n.length function toBytes(digits) { var bytes = cryptoMath.digitsToBytes(digits) utils.padFront(bytes, 0, modulusLength) return bytes } function modExp(dataBytes, expBytes, modulusBytes) { var exponent = cryptoMath.bytesToDigits(expBytes) var group = cryptoMath.IntegerGroup(modulusBytes) var base = group.createElementFromBytes(dataBytes) var result = group.modexp(base, exponent) return result.m_digits } function decryptModExp(cipherBytes) { var resultElement = modExp(cipherBytes, keyStruct.d, keyStruct.n) return toBytes(resultElement) } function decryptCrt(cipherBytes) { var b2d = cryptoMath.bytesToDigits, p = keyStruct.p, q = keyStruct.q, dp = keyStruct.dp, dq = keyStruct.dq, invQ = keyStruct.qi, pDigits = b2d(p), qDigits = b2d(q), temp = new Array(pDigits.length + qDigits.length), m1Digits = new Array(pDigits.length + 1), m2Digits = new Array(qDigits.length + 1), cDigits = b2d(cipherBytes), mm = cryptoMath.MontgomeryMultiplier, mmp = new mm(keyStruct.ctxp ? undefined : pDigits, keyStruct.ctxp), mmq = new mm(keyStruct.ctxq ? undefined : qDigits, keyStruct.ctxq) mmp.reduce(cDigits, temp) mmp.modExp(temp, b2d(dp), m1Digits) mmq.reduce(cDigits, temp) mmq.modExp(temp, b2d(dq), m2Digits) var carry = cryptoMath.subtract(m1Digits, m2Digits, temp) if (carry !== 0) { cryptoMath.subtract(m2Digits, m1Digits, temp) } cryptoMath.modMul(temp, b2d(invQ), pDigits, cDigits) if (carry !== 0) { cryptoMath.subtract(pDigits, cDigits, cDigits) } cryptoMath.multiply(cDigits, qDigits, temp) cryptoMath.add(m2Digits, temp, m1Digits) return toBytes(m1Digits) } return { encrypt: function (messageBytes) { var bytes = toBytes( modExp(messageBytes, keyStruct.e, keyStruct.n, true), ) return bytes }, decrypt: function (cipherBytes) { if (keyIsCrt) { return decryptCrt(cipherBytes) } if (keyIsPrivate) { return decryptModExp(cipherBytes) } throw new Error('missing private key') }, } } var rsaShared = { mgf1: function (seedBytes, maskLen, hashFunction) { var t = [], bytes, hash, counter, hashByteLen = hashFunction.hashLen / 8 for ( counter = 0; counter <= Math.floor(maskLen / hashByteLen); counter += 1 ) { bytes = [ (counter >>> 24) & 0xff, (counter >>> 16) & 0xff, (counter >>> 8) & 0xff, counter & 0xff, ] hash = hashFunction.computeHash(seedBytes.concat(bytes)) t = t.concat(hash) } return t.slice(0, maskLen) }, checkMessageVsMaxHash: function (messageBytes, hashFunction) { if (messageBytes.length > (hashFunction.maxMessageSize || 0xffffffff)) { throw new Error('message too long') } return }, } var rsaMode = rsaMode || {} rsaMode.oaep = function (keyStruct, hashFunction) { var utils = msrcryptoUtilities, random = msrcryptoPseudoRandom, size = keyStruct.n.length if (hashFunction === null) { throw new Error('must supply hashFunction') } function pad(message, label) { var lHash, psLen, psArray, i, db, seed var dbMask, maskeddb, seedMask, maskedSeed var encodedMessage if (message.length > size - 2 * (hashFunction.hashLen / 8) - 2) { throw new Error('Message too long.') } if (label == null) { label = [] } lHash = hashFunction.computeHash(label) psLen = size - message.length - 2 * lHash.length - 2 psArray = utils.getVector(psLen) db = lHash.concat(psArray, [1], message) seed = random.getBytes(lHash.length) dbMask = rsaShared.mgf1(seed, size - lHash.length - 1, hashFunction) maskeddb = utils.xorVectors(db, dbMask) seedMask = rsaShared.mgf1(maskeddb, lHash.length, hashFunction) maskedSeed = utils.xorVectors(seed, seedMask) encodedMessage = [0].concat(maskedSeed).concat(maskeddb) message = encodedMessage.slice() return message } function unpad(encodedBytes, labelBytes) { var lHash, maskedSeed, maskeddb, seedMask var seed, dbMask, db var lHashp, i = 0 var valid = encodedBytes[0] === 0 if (!labelBytes) { labelBytes = [] } lHash = hashFunction.computeHash(labelBytes) maskedSeed = encodedBytes.slice(1, lHash.length + 1) maskeddb = encodedBytes.slice(lHash.length + 1) seedMask = rsaShared.mgf1(maskeddb, lHash.length, hashFunction) seed = utils.xorVectors(maskedSeed, seedMask) dbMask = rsaShared.mgf1(seed, size - lHash.length - 1, hashFunction) db = utils.xorVectors(maskeddb, dbMask) lHashp = db.slice(0, lHash.length) valid = valid && utils.arraysEqual(lHash, lHashp) db = db.slice(lHash.length) while (!db[i++]) {} return { valid: valid, data: db.slice(i), } } return { pad: function (messageBytes, labelBytes) { return pad(messageBytes, labelBytes) }, unpad: function (encodedBytes, labelBytes) { return unpad(encodedBytes, labelBytes) }, } } var rsaMode = rsaMode || {} rsaMode.pkcs1Encrypt = function (keyStruct) { var random = msrcryptoPseudoRandom, size = keyStruct.n.length function pad(data) { var randomness if (data.length > size - 11) { throw new Error('message too long') } randomness = random.getNonZeroBytes(size - data.length - 3) return [0, 2].concat(randomness, [0], data) } function validatePadding(paddedData) { var paddingValid = paddedData[0] === 0 && paddedData[1] === 2 for (var i = 2; i < 10; i++) { paddingValid = paddingValid && !!paddedData[i] } return paddingValid } function unpad(paddedData) { var i, paddingIsValid = validatePadding(paddedData), startOfData = 0 for (i = 1; i < paddedData.length; i += 1) { startOfData = startOfData || (+!paddedData[i] && i + 1) } startOfData = -paddingIsValid && startOfData return { data: paddedData.slice(startOfData), valid: paddingIsValid, } } return { pad: function (messageBytes) { return pad(messageBytes) }, unpad: function (encodedBytes) { return unpad(encodedBytes) }, } } rsaMode.pkcs1Sign = function (keyStruct, hashFunction) { var utils = msrcryptoUtilities, size = keyStruct.n.length function emsa_pkcs1_v15_encode(messageBytes) { var paddedData, hash, tlen hash = hashFunction.computeHash(messageBytes.slice()) paddedData = hashFunction.der.concat(hash) tlen = paddedData.length if (size < tlen + 11) { throw new Error('intended encoded message length too short') } return [0x00, 0x01].concat( utils.getVector(size - tlen - 3, 0xff), [0], paddedData, ) } return { sign: function (messageBytes) { return emsa_pkcs1_v15_encode(messageBytes) }, verify: function (signatureBytes, messageBytes) { var emp = emsa_pkcs1_v15_encode(messageBytes) return utils.arraysEqual(signatureBytes, emp) }, } } var rsaMode = rsaMode || {} rsaMode.pss = function (keyStruct, hashFunction) { var utils = msrcryptoUtilities, random = msrcryptoPseudoRandom function emsa_pss_encode(messageBytes, saltLength, salt) { var modulusBits = cryptoMath.bitLength(keyStruct.n), emBits = modulusBits - 1, emLen = Math.ceil(emBits / 8), mHash = hashFunction.computeHash(messageBytes) saltLength = salt ? salt.length : saltLength == null ? mHash.length : saltLength if (emLen < mHash.length + saltLength + 2) { throw new Error('encoding error') } salt = salt || random.getBytes(saltLength) var mp = [0, 0, 0, 0, 0, 0, 0, 0].concat(mHash, salt) var h = hashFunction.computeHash(mp) var ps = utils.getVector(emLen - salt.length - h.length - 2) var db = ps.concat([1], salt) var dbMask = rsaShared.mgf1(h, emLen - h.length - 1, hashFunction) var maskedDb = utils.xorVectors(db, dbMask) var mask = 0 for (var i = 0; i < 8 - (8 * emLen - emBits); i++) { mask += 1 << i } maskedDb[0] &= mask var em = maskedDb.concat(h, [0xbc]) return em } function emsa_pss_verify(signatureBytes, messageBytes, saltLength) { var modulusBits = cryptoMath.bitLength(keyStruct.n) var emBits = modulusBits - 1 var emLen = Math.ceil(emBits / 8) var mHash = hashFunction.computeHash(messageBytes) var hLen = mHash.length saltLength = saltLength == null ? hLen : saltLength if (emLen < hLen + saltLength + 2) { return false } var maskedDb = signatureBytes.slice(0, emLen - hLen - 1) var h = signatureBytes.slice(maskedDb.length, maskedDb.length + hLen) var dbMask = rsaShared.mgf1(h, emLen - hLen - 1, hashFunction) var db = utils.xorVectors(maskedDb, dbMask) db[0] &= 0xff >>> (8 - (8 * emLen - emBits)) for (var i = 0; i < emLen - hLen - saltLength - 2; i++) { if (db[i] !== 0) { return false } } if (db[emLen - hLen - saltLength - 2] !== 0x01) { return false } var salt = db.slice(db.length - saltLength) var mp = [0, 0, 0, 0, 0, 0, 0, 0].concat(mHash, salt) var hp = hashFunction.computeHash(mp) return utils.arraysEqual(hp, h) } return { sign: function (messageBytes, saltLength, salt) { return emsa_pss_encode(messageBytes, saltLength, salt) }, verify: function (signatureBytes, messageBytes, saltLength) { return emsa_pss_verify(signatureBytes, messageBytes, saltLength) }, } } var msrcryptoRsa = function (keyStruct, mode, hashFunction) { var rsaBase = msrcryptoRsaBase(keyStruct) if (!mode) { throw new Error('padding mode') } function checkHash() { if (!hashFunction || !hashFunction.computeHash) { throw new Error('missing hash function') } } var paddingFunction = null, unPaddingFunction = null var padding switch (mode) { case 'RSAES-PKCS1-V1_5': padding = rsaMode.pkcs1Encrypt(keyStruct) break case 'RSASSA-PKCS1-V1_5': checkHash() padding = rsaMode.pkcs1Sign(keyStruct, hashFunction) break case 'RSA-OAEP': checkHash() padding = rsaMode.oaep(keyStruct, hashFunction) break case 'RSA-PSS': checkHash() padding = rsaMode.pss(keyStruct, hashFunction) break case 'raw': padding = { pad: function (mb) { return mb }, unpad: function (eb) { return eb }, } break default: throw new Error('invalid mode') } if (padding) { paddingFunction = padding.pad || padding.sign unPaddingFunction = padding.unpad || padding.verify } var returnObj = { encrypt: function (dataBytes, labelBytes) { var paddedData var encryptedData if (paddingFunction !== null) { paddedData = paddingFunction(dataBytes, labelBytes) } else { paddedData = dataBytes.slice() } encryptedData = rsaBase.encrypt(paddedData) return encryptedData }, decrypt: function (cipherBytes, labelBytes) { var decryptedData = rsaBase.decrypt(cipherBytes) if (unPaddingFunction !== null) { decryptedData = unPaddingFunction(decryptedData, labelBytes) if (decryptedData.valid === false) { throw new Error('OperationError') } decryptedData = decryptedData.data } else { decryptedData = decryptedData.slice(0) } return decryptedData }, signData: function (messageBytes, saltLength, salt) { return rsaBase.decrypt( paddingFunction(messageBytes, saltLength, salt), ) }, verifySignature: function (signature, messageBytes, saltLength) { var decryptedSig = rsaBase.encrypt(signature) return unPaddingFunction(decryptedSig, messageBytes, saltLength) }, generateKeyPair: function (bits) { var keyPair = genRsaKeyFromRandom(bits) }, mode: mode, } return returnObj } if (typeof operations !== 'undefined') { msrcryptoRsa.sign = function (p) { var rsaObj, hashName = p.keyHandle.algorithm.hash.name, hashFunc = msrcryptoHashFunctions[hashName.toUpperCase()](), saltLength = p.algorithm.saltLength, salt = p.algorithm.salt rsaObj = msrcryptoRsa(p.keyData, p.algorithm.name, hashFunc) return rsaObj.signData(p.buffer, saltLength, salt) } msrcryptoRsa.verify = function (p) { var hashName = p.keyHandle.algorithm.hash.name, hashFunc = msrcryptoHashFunctions[hashName.toUpperCase()](), rsaObj, saltLength = p.algorithm.saltLength rsaObj = msrcryptoRsa(p.keyData, p.algorithm.name, hashFunc) return rsaObj.verifySignature(p.signature, p.buffer, saltLength) } msrcryptoRsa.workerEncrypt = function (p) { var result, rsaObj, hashFunc, hashName switch (p.algorithm.name) { case 'RSAES-PKCS1-V1_5': rsaObj = msrcryptoRsa(p.keyData, p.algorithm.name) result = rsaObj.encrypt(p.buffer) break case 'RSA-OAEP': hashName = p.keyHandle.algorithm.hash.name if (!hashName) { throw new Error('unsupported hash algorithm') } hashFunc = msrcryptoHashFunctions[hashName.toUpperCase()]() rsaObj = msrcryptoRsa(p.keyData, p.algorithm.name, hashFunc) result = rsaObj.encrypt(p.buffer) break default: throw new Error('unsupported algorithm') } return result } msrcryptoRsa.workerDecrypt = function (p) { var result, rsaObj, hashFunc switch (p.algorithm.name) { case 'RSAES-PKCS1-V1_5': rsaObj = msrcryptoRsa(p.keyData, p.algorithm.name) result = rsaObj.decrypt(p.buffer) break case 'RSA-OAEP': var hashName = p.keyHandle.algorithm.hash.name if (!hashName) { throw new Error('unsupported hash algorithm') } hashFunc = msrcryptoHashFunctions[hashName.toUpperCase()]() rsaObj = msrcryptoRsa(p.keyData, p.algorithm.name, hashFunc) result = rsaObj.decrypt(p.buffer) break default: throw new Error('unsupported algorithm') } return result } msrcryptoRsa.importKey = function (p) { var keyObject if (p.format === 'jwk') { keyObject = msrcryptoJwk.jwkToKey(p.keyData, p.algorithm, [ 'n', 'e', 'd', 'q', 'p', 'dq', 'dp', 'qi', ]) if (keyObject.d) { keyObject.ctxp = new cryptoMath.MontgomeryMultiplier( cryptoMath.bytesToDigits(keyObject.p), ).ctx keyObject.ctxq = new cryptoMath.MontgomeryMultiplier( cryptoMath.bytesToDigits(keyObject.q), ).ctx } } else if (p.format === 'spki') { var publicKeyInfo = asn1.parse(p.keyData) if (publicKeyInfo == null) { throw new Error('invalid key data.') } var bitString = publicKeyInfo[1] var keySequence = asn1.parse( bitString.data.slice(bitString.header + 1), true, ) if (keySequence == null) { throw new Error('invalid key data.') } var n = keySequence[0], e = keySequence[1] if (n.type !== 'INTEGER' || e.type !== 'INTEGER') { throw new Error('invalid key data.') } n = n.data.slice(n.header) e = e.data.slice(e.header) if (n[0] === 0 && n[1] & 128) { n = n.slice(1) } if (e[0] === 0 && e[1] & 128) { e = e.slice(1) } keyObject = { n: n, e: e, } } else { throw new Error('unsupported key import format.') } return { type: 'keyImport', keyData: keyObject, keyHandle: { algorithm: p.algorithm, extractable: p.extractable, usages: p.usages, type: keyObject.d || keyObject.dq ? 'private' : 'public', }, } } msrcryptoRsa.exportKey = function (p) { var jsonKeyStringArray = msrcryptoJwk.keyToJwk(p.keyHandle, p.keyData) return { type: 'keyExport', keyHandle: jsonKeyStringArray, } } msrcryptoRsa.genRsaKeyFromRandom = function (bits, e) { var exp = e ? cryptoMath.bytesToDigits(e) : [65537] do { var p = prime.generatePrime(bits / 2) var q = prime.generatePrime(bits / 2) if (cryptoMath.compareDigits(q, p) > 0) { var t = p p = q q = t } var n = [] cryptoMath.multiply(p, q, n) var p_1 = [] cryptoMath.subtract(p, [1], p_1) var q_1 = [] cryptoMath.subtract(q, [1], q_1) var p_1q_1 = [] cryptoMath.multiply(p_1, q_1, p_1q_1) var gcd = [] cryptoMath.gcd(exp, p_1q_1, gcd) var gcdEqual1 = cryptoMath.compareDigits(gcd, cryptoMath.One) === 0 } while (!gcdEqual1) var d = [] cryptoMath.modInv(exp, p_1q_1, d) var dp = [] cryptoMath.reduce(d, p_1, dp) var dq = [] cryptoMath.reduce(d, q_1, dq) var qi = [] cryptoMath.modInv(q, p, qi) var d2b = cryptoMath.digitsToBytes return { privateKey: { n: d2b(n), e: d2b(exp), d: d2b(d), p: d2b(p), q: d2b(q), dp: d2b(dp), dq: d2b(dq), qi: d2b(qi), }, publicKey: { n: d2b(n), e: d2b(exp), }, } } msrcryptoRsa.generateKeyPair = function (p) { if (typeof p.algorithm.modulusLength === 'undefined') { throw new Error('missing modulusLength') } var keyPair var b2d = cryptoMath.bytesToDigits switch (p.algorithm.modulusLength) { case 1024: case 2048: case 4096: keyPair = msrcryptoRsa.genRsaKeyFromRandom( p.algorithm.modulusLength, p.algorithm.publicExponent, ) break default: throw new Error('invalid modulusLength') } var pk = keyPair.privateKey pk.ctxp = new cryptoMath.MontgomeryMultiplier(b2d(pk.p)).ctx pk.ctxq = new cryptoMath.MontgomeryMultiplier(b2d(pk.q)).ctx var algName = p.algorithm.name var rsaKeyType = algName.slice(algName.indexOf('-') + 1).toUpperCase() var publicUsage, privateUsage if (algName === 'RSASSA-PKCS1-V1_5' || algName === 'RSA-PSS') { publicUsage = ['verify'] privateUsage = ['sign'] } else { publicUsage = ['encrypt'] privateUsage = ['decrypt'] } return { type: 'keyGeneration', keyPair: { publicKey: { keyData: keyPair.publicKey, keyHandle: { algorithm: p.algorithm, extractable: p.extractable, usages: null || publicUsage, type: 'public', }, }, privateKey: { keyData: keyPair.privateKey, keyHandle: { algorithm: p.algorithm, extractable: p.extractable, usages: null || privateUsage, type: 'private', }, }, }, } } operations.register('sign', 'RSASSA-PKCS1-V1_5', msrcryptoRsa.sign) operations.register('sign', 'RSA-PSS', msrcryptoRsa.sign) operations.register('verify', 'RSASSA-PKCS1-V1_5', msrcryptoRsa.verify) operations.register('verify', 'RSA-PSS', msrcryptoRsa.verify) operations.register( 'encrypt', 'RSAES-PKCS1-V1_5', msrcryptoRsa.workerEncrypt, ) operations.register( 'decrypt', 'RSAES-PKCS1-V1_5', msrcryptoRsa.workerDecrypt, ) operations.register('encrypt', 'RSA-OAEP', msrcryptoRsa.workerEncrypt) operations.register('decrypt', 'RSA-OAEP', msrcryptoRsa.workerDecrypt) operations.register('importKey', 'RSA-OAEP', msrcryptoRsa.importKey) operations.register( 'importKey', 'RSAES-PKCS1-V1_5', msrcryptoRsa.importKey, ) operations.register( 'importKey', 'RSASSA-PKCS1-V1_5', msrcryptoRsa.importKey, ) operations.register('importKey', 'RSA-PSS', msrcryptoRsa.importKey) operations.register('exportKey', 'RSA-OAEP', msrcryptoRsa.exportKey) operations.register( 'exportKey', 'RSAES-PKCS1-V1_5', msrcryptoRsa.exportKey, ) operations.register( 'exportKey', 'RSASSA-PKCS1-V1_5', msrcryptoRsa.exportKey, ) operations.register('exportKey', 'RSA-PSS', msrcryptoRsa.exportKey) operations.register( 'generateKey', 'RSA-OAEP', msrcryptoRsa.generateKeyPair, ) operations.register( 'generateKey', 'RSAES-PKCS1-V1_5', msrcryptoRsa.generateKeyPair, ) operations.register( 'generateKey', 'RSASSA-PKCS1-V1_5', msrcryptoRsa.generateKeyPair, ) operations.register( 'generateKey', 'RSA-PSS', msrcryptoRsa.generateKeyPair, ) } var msrcryptoConcatKdf = (function () { function deriveBits(p) { var hashName = p.algorithm.hash.name, hashFunction = msrcryptoHashFunctions[hashName.toUpperCase()](), alg = p.algorithm var otherInfo = utils .toArray(alg.algorithmId) .concat( utils.toArray(alg.partyUInfo), utils.toArray(alg.partyVInfo), utils.toArray(alg.publicInfo) || [], utils.toArray(alg.privateInfo) || [], ) var reps = Math.ceil(p.length / hashFunction.hashLen), counter = 1, digest = p.keyData.concat(otherInfo), output = [] for (var i = 0; i < reps; i++) { var data = utils.int32ToBytes(counter++).concat(digest) var h = hashFunction.computeHash(data) output = output.concat(h) } return output.slice(0, p.length / 8) } return { deriveBits: deriveBits, } })() var msrcryptoConcatKdfInstance = null if (typeof operations !== 'undefined') { msrcryptoConcatKdf.importKey = function (p) { var keyData if (p.format === 'raw') { keyData = msrcryptoUtilities.toArray(p.keyData) } else { throw new Error('unsupported import format') } if (p.extractable !== false) { throw new Error('only extractable=false is supported.') } return { type: 'keyImport', keyData: keyData, keyHandle: { algorithm: { name: 'CONCAT', }, extractable: false, usages: p.usages, type: 'secret', }, } } operations.register('deriveBits', 'CONCAT', msrcryptoConcatKdf.deriveBits) operations.register('importKey', 'CONCAT', msrcryptoConcatKdf.importKey) } var msrcryptoPbkdf2 = (function () { function deriveBits(p) { var algorithm = p.algorithm, keyBytes = p.keyData, bits = p.length, iterations = algorithm.iterations, saltBytes = Array.apply(null, algorithm.salt), byteLen = Math.ceil(bits / 8), hLen, blockCount, output = [] switch (algorithm.hash.name.toUpperCase()) { case 'SHA-1': hLen = 20 break case 'SHA-256': hLen = 32 break case 'SHA-384': hLen = 48 break case 'SHA-512': hLen = 64 break default: throw new Error('Unsupported hash algorithm') } blockCount = Math.ceil(byteLen / hLen) var hmacKey = msrcryptoHmac.importKey({ format: 'raw', keyData: keyBytes, algorithm: { name: 'HMAC', hash: algorithm.hash, }, }) var hmacContext = { algorithm: algorithm, keyHandle: hmacKey.keyHandle, keyData: hmacKey.keyData, workerid: 0, buffer: null, } function F(S, c, i) { var result = [], u = S.concat([ (i >>> 24) & 0xff, (i >>> 16) & 0xff, (i >>> 8) & 0xff, i & 0xff, ]) for (var j = 0; j < c; j++) { hmacContext.buffer = u u = msrcryptoHmac.signHmac(hmacContext) for (var k = 0; k < hLen; k++) { result[k] = ~~result[k] ^ u[k] } } return result } for (var block = 1; block <= blockCount; block++) { output = output.concat(F(saltBytes, iterations, block)) } output.length = byteLen return output } return { deriveBits: deriveBits, } })() var msrcryptoKdfInstance = null if (typeof operations !== 'undefined') { msrcryptoPbkdf2.importKey = function (p) { var keyData if (p.format === 'raw') { keyData = msrcryptoUtilities.toArray(p.keyData) } else { throw new Error('unsupported import format') } if (p.extractable !== false) { throw new Error('only extractable=false is supported.') } return { type: 'keyImport', keyData: keyData, keyHandle: { algorithm: { name: 'PBKDF2', }, extractable: false, usages: p.usages, type: 'secret', }, } } operations.register('deriveBits', 'PBKDF2', msrcryptoPbkdf2.deriveBits) operations.register('importKey', 'PBKDF2', msrcryptoPbkdf2.importKey) } var msrcryptoHkdf = (function () { function deriveBits(p) { var algorithm = p.algorithm, keyBytes = p.keyData, bits = p.length, saltBytes = algorithm.salt, byteLen = Math.ceil(bits / 8), hLen, output = [], infoBytes = msrcryptoUtilities.toArray(algorithm.info), t = [], i, hmacContext switch (algorithm.hash.name.toUpperCase()) { case 'SHA-1': hLen = 20 break case 'SHA-256': hLen = 32 break case 'SHA-384': hLen = 48 break case 'SHA-512': hLen = 64 break default: throw new Error('Unsupported hash algorithm.') } if (algorithm.salt == null) { throw new Error('HkdfParams: salt: Missing required property.') } if (algorithm.info == null) { throw new Error('HkdfParams: info: Missing required property.') } if (bits % 8 !== 0) { throw new Error( 'The length provided for HKDF is not a multiple of 8 bits.', ) } if (byteLen > 255 * hLen) { throw new Error('The length provided for HKDF is too large.') } if (saltBytes.length === 0) { saltBytes = msrcryptoUtilities.getVector(hLen) } hmacContext = { workerid: 0, keyHandle: { algorithm: algorithm, }, keyData: saltBytes, buffer: keyBytes, } hmacContext.keyData = msrcryptoHmac.signHmac(hmacContext) for (i = 0; i < Math.ceil(byteLen / hLen); i++) { hmacContext.buffer = t.concat(infoBytes).concat([1 + i]) t = msrcryptoHmac.signHmac(hmacContext) output = output.concat(t) } return output.slice(0, byteLen) } return { deriveBits: deriveBits, } })() var msrcryptoKdfInstance = null if (typeof operations !== 'undefined') { msrcryptoHkdf.importKey = function (p) { var keyData if (p.format === 'raw') { keyData = msrcryptoUtilities.toArray(p.keyData) } else { throw new Error('unsupported import format') } if (p.extractable !== false) { throw new Error('only extractable=false is supported.') } return { type: 'keyImport', keyData: keyData, keyHandle: { algorithm: { name: 'HKDF', }, extractable: false, usages: p.usages, type: 'secret', }, } } operations.register('deriveBits', 'HKDF', msrcryptoHkdf.deriveBits) operations.register('importKey', 'HKDF', msrcryptoHkdf.importKey) } var msrcryptoHkdfCtr = (function () { function deriveBits(p) { var algorithm = p.algorithm, keyBytes = p.keyData, bits = p.length, labelBytes = algorithm.label, contextBytes = algorithm.context, byteLen = Math.ceil(bits / 8), hLen, output = [], i, hmacContext switch (algorithm.hash.name.toUpperCase()) { case 'SHA-1': hLen = 20 break case 'SHA-256': hLen = 32 break case 'SHA-384': hLen = 48 break case 'SHA-512': hLen = 64 break default: throw new Error('Unsupported hash algorithm.') } if (algorithm.label == null) { throw new Error('HkdfCtrParams: label: Missing required property.') } if (algorithm.context == null) { throw new Error('HkdfCtrParams: context: Missing required property.') } if (bits % 8 !== 0) { throw new Error( 'The length provided for HKDF-CTR is not a multiple of 8 bits.', ) } if (byteLen > 255 * hLen) { throw new Error('The length provided for HKDF-CTR is too large.') } hmacContext = { workerid: 0, keyHandle: { algorithm: algorithm, }, keyData: keyBytes, buffer: keyBytes, } var fixed = labelBytes.concat( [0], contextBytes, utils.int32ToBytes(bits), ) for (i = 1; i <= Math.ceil(byteLen / hLen); i++) { hmacContext.buffer = utils.int32ToBytes(i).concat(fixed) output = output.concat(msrcryptoHmac.signHmac(hmacContext)) } return output.slice(0, byteLen) } return { deriveBits: deriveBits, } })() if (typeof operations !== 'undefined') { msrcryptoHkdfCtr.importKey = function (p) { var keyData if (p.format === 'raw') { keyData = msrcryptoUtilities.toArray(p.keyData) } else { throw new Error('unsupported import format') } if (p.extractable !== false) { throw new Error('only extractable=false is supported.') } return { type: 'keyImport', keyData: keyData, keyHandle: { algorithm: { name: 'HKDF-CTR', }, extractable: false, usages: p.usages, type: 'secret', }, } } operations.register('deriveBits', 'HKDF-CTR', msrcryptoHkdfCtr.deriveBits) operations.register('importKey', 'HKDF-CTR', msrcryptoHkdfCtr.importKey) } var msrcryptoEcdh = function (curve) { var btd = cryptoMath.bytesToDigits, dtb = cryptoMath.digitsToBytes, e = curve, ecop = new cryptoECC.EllipticCurveOperatorFp(curve) function generateKey(privateKeyBytes) { var privateKey = [], randomBytes = msrcryptoPseudoRandom.getBytes( curve.order.length * cryptoMath.DIGIT_NUM_BYTES, ) cryptoMath.reduce( cryptoMath.bytesToDigits(randomBytes), e.order, privateKey, ) var publicKey = e.allocatePointStorage() ecop.scalarMultiply(privateKey, e.generator, publicKey) return { privateKey: { x: dtb(publicKey.x), y: dtb(publicKey.y), d: dtb(privateKey), }, publicKey: { x: dtb(publicKey.x), y: dtb(publicKey.y), }, } } function deriveBits(privateKey, publicKey, length) { var publicPoint = new cryptoECC.EllipticCurvePointFp( e, false, btd(publicKey.x), btd(publicKey.y), null, false, ) var sharedSecretPoint = e.allocatePointStorage() ecop.convertToJacobianForm(sharedSecretPoint) ecop.convertToMontgomeryForm(sharedSecretPoint) ecop.scalarMultiply(btd(privateKey.d), publicPoint, sharedSecretPoint) ecop.convertToAffineForm(sharedSecretPoint) ecop.convertToStandardForm(sharedSecretPoint) var secretBytes = cryptoMath.digitsToBytes( sharedSecretPoint.x, true, publicKey.x.length, ) if (length && secretBytes.length * 8 < length) { throw new Error('DataError') } secretBytes = length ? secretBytes.slice(0, Math.ceil(length / 8)) : secretBytes var bits = length % 8 var mask = bits === 0 ? 0xff : 0xff00 >>> bits secretBytes[secretBytes.length - 1] = secretBytes[secretBytes.length - 1] & mask return secretBytes } function computePublicKey(privateKeyBytes) { if (!e.generator.isInMontgomeryForm) { ecop.convertToMontgomeryForm(e.generator) } var publicKey = e.allocatePointStorage() ecop.convertToJacobianForm(publicKey) ecop.convertToMontgomeryForm(publicKey) ecop.scalarMultiply(btd(privateKeyBytes), e.generator, publicKey) return { x: dtb(publicKey.x), y: dtb(publicKey.y), } } return { generateKey: generateKey, deriveBits: deriveBits, computePublicKey: computePublicKey, } } var ecdhInstance = null if (typeof operations !== 'undefined') { msrcryptoEcdh.deriveBits = function (p) { var curve = cryptoECC.createCurve(p.algorithm.namedCurve.toUpperCase()) var privateKey = p.keyData var publicKey = p.additionalKeyData ecdhInstance = msrcryptoEcdh(curve) var secretBytes = ecdhInstance.deriveBits( privateKey, publicKey, p.length, ) return secretBytes } msrcryptoEcdh.deriveKey = function (p) { throw new Error('not supported') return secretBytes } msrcryptoEcdh.generateKey = function (p) { var curve = cryptoECC.createCurve(p.algorithm.namedCurve.toUpperCase()) ecdhInstance = msrcryptoEcdh(curve) var keyPairData = ecdhInstance.generateKey() return { type: 'keyPairGeneration', keyPair: { publicKey: { keyData: keyPairData.publicKey, keyHandle: { algorithm: p.algorithm, extractable: p.extractable, usages: [], type: 'public', }, }, privateKey: { keyData: keyPairData.privateKey, keyHandle: { algorithm: p.algorithm, extractable: p.extractable, usages: p.usages, type: 'private', }, }, }, } } msrcryptoEcdh.importKey = function (p) { if (p.format === 'raw') { var keyData = p.keyData if (keyData[0] !== 4) { throw new Error('DataError') } var elementSize = ~~((keyData.length - 1) / 2) var curveName = p.algorithm.namedCurve.toUpperCase() var x = keyData.slice(1, elementSize + 1), y = keyData.slice(elementSize + 1) if (cryptoECC.validatePoint(curveName, x, y) === false) { throw new Error('DataError') } return { type: 'keyImport', keyData: { x: x, y: y, }, keyHandle: { algorithm: p.algorithm, extractable: p.extractable || false, usages: p.usages, type: 'public', }, } } if (p.format === 'jwk') { var keyObject = msrcryptoJwk.jwkToKey(p.keyData, p.algorithm, [ 'x', 'y', 'd', 'crv', ]) if (keyObject.d && (!keyObject.x || !keyObject.y)) { var curve = cryptoECC.createCurve( p.algorithm.namedCurve.toUpperCase(), ) ecdhInstance = msrcryptoEcdh(curve) var publicKey = ecdhInstance.computePublicKey(keyObject.d) keyObject.x = publicKey.x keyObject.y = publicKey.y } if ( cryptoECC.validatePoint( p.algorithm.namedCurve.toUpperCase(), keyObject.x, keyObject.y, ) === false ) { throw new Error('DataError') } return { type: 'keyImport', keyData: keyObject, keyHandle: { algorithm: p.algorithm, extractable: p.extractable || keyObject.extractable, usages: p.usages, type: keyObject.d ? 'private' : 'public', }, } } } msrcryptoEcdh.exportKey = function (p) { if (p.format === 'raw' && p.keyHandle.type === 'public') { var keyData = [4].concat(p.keyData.x, p.keyData.y) return { type: 'keyExport', keyHandle: keyData, } } if (p.format === 'jwk') { var jsonKeyStringArray = msrcryptoJwk.keyToJwk(p.keyHandle, p.keyData) return { type: 'keyExport', keyHandle: jsonKeyStringArray, } } throw new Error('unsupported export format.') } operations.register('importKey', 'ECDH', msrcryptoEcdh.importKey) operations.register('exportKey', 'ECDH', msrcryptoEcdh.exportKey) operations.register('generateKey', 'ECDH', msrcryptoEcdh.generateKey) operations.register('deriveBits', 'ECDH', msrcryptoEcdh.deriveBits) operations.register('deriveKey', 'ECDH', msrcryptoEcdh.deriveKey) } var msrcryptoEcdsa = function (curve) { var btd = cryptoMath.bytesToDigits, dtb = cryptoMath.digitsToBytes, ecop = new cryptoECC.EllipticCurveOperatorFp(curve), orderByteLength = dtb(curve.order).length, tedCurve = curve.type === 1 function createKey(privateKeyBytes) { return createKeyInternal(btd(privateKeyBytes)) } function createKeyInternal(privateKeyDigits) { var publicKey = curve.allocatePointStorage() ecop.scalarMultiply(privateKeyDigits, curve.generator, publicKey) return { publicKey: publicKey, privateKey: privateKeyDigits, } } function generateKey(randomBytes) { var privateKey = [] if (!randomBytes) { randomBytes = msrcryptoPseudoRandom.getBytes( curve.order.length * cryptoMath.DIGIT_NUM_BYTES, ) } cryptoMath.reduce( cryptoMath.bytesToDigits(randomBytes), curve.order, privateKey, ) return createKeyInternal(privateKey) } function getDigest(messageBytes) { if (messageBytes.length > orderByteLength) { messageBytes.length = orderByteLength } var digest = btd(messageBytes) if (tedCurve) { var shift = 8 - (curve.rbits % 8) cryptoMath.shiftRight(digest, digest, shift) } cryptoMath.reduce(digest, curve.order, digest) return digest } function sign(privateKey, messageBytes, ephemeralKey) { if (!ephemeralKey) { ephemeralKey = generateKey() } var r = ephemeralKey.publicKey.x, k = ephemeralKey.privateKey, d = btd(privateKey.d), digest = getDigest(messageBytes.slice()), s = [], tmp = [], signature = null cryptoMath.reduce(r, curve.order, r) cryptoMath.modMul(r, d, curve.order, s) cryptoMath.add(s, digest, s) cryptoMath.reduce(s, curve.order, s) cryptoMath.modInvCT(k, curve.order, tmp) cryptoMath.modMul(s, tmp, curve.order, s) var rBytes = msrcryptoUtilities.padFront( dtb(r, true, orderByteLength), 0, orderByteLength, ) var sBytes = msrcryptoUtilities.padFront( dtb(s, true, orderByteLength), 0, orderByteLength, ) signature = rBytes.concat(sBytes) return signature } function verify(publicKey, signatureBytes, messageBytes) { var split = Math.floor(signatureBytes.length / 2), r = btd(signatureBytes.slice(0, split)), s = btd(signatureBytes.slice(split)), digest = getDigest(messageBytes.slice()), u1 = [], u2 = [] var publicPoint = new cryptoECC.EllipticCurvePointFp( curve, false, btd(publicKey.x), btd(publicKey.y), null, false, ) cryptoMath.modInv(s, curve.order, s) cryptoMath.modMul(digest, s, curve.order, u1) cryptoMath.modMul(r, s, curve.order, u2) var r0 = curve.allocatePointStorage() var r1 = curve.allocatePointStorage() if (tedCurve) { cryptoMath.add(u1, u1, u1) cryptoMath.add(u1, u1, u1) cryptoMath.reduce(u1, curve.order, u1) ecop.scalarMultiply(u1, curve.generator, r0, false) ecop.scalarMultiply(u2, publicPoint, r1, false) ecop.convertToExtendedProjective(r0) ecop.convertToExtendedProjective(r1) ecop.add(r1, r0, r0) ecop.normalize(r0) } else { ecop.scalarMultiply(u1, curve.generator, r0) ecop.scalarMultiply(u2, publicPoint, r1) ecop.convertToJacobianForm(r0) ecop.convertToMontgomeryForm(r0) ecop.convertToMontgomeryForm(r1) ecop.mixedAdd(r0, r1, r0) ecop.convertToAffineForm(r0) ecop.convertToStandardForm(r0) } if (r0.isInfinity) { return false } cryptoMath.reduce(r0.x, curve.order, r0.x) return cryptoMath.compareDigits(r0.x, r) === 0 } return { createKey: createKey, generateKey: generateKey, sign: sign, verify: verify, } } if (typeof operations !== 'undefined') { msrcryptoEcdsa.sign = function (p) { msrcryptoUtilities.checkParam( p.algorithm.hash, 'Object', 'algorithm.hash', ) msrcryptoUtilities.checkParam( p.algorithm.hash.name, 'String', 'algorithm.hash.name', ) msrcryptoUtilities.checkParam( p.keyHandle.algorithm.namedCurve, 'String', 'p.keyHandle.algorithm.namedCurve', ) var hashName = p.algorithm.hash.name, curve = cryptoECC.createCurve( p.keyHandle.algorithm.namedCurve.toUpperCase(), ), hashFunc = msrcryptoHashFunctions[hashName.toUpperCase()](), digest = hashFunc.computeHash(p.buffer) var ecdsa = msrcryptoEcdsa(curve) return ecdsa.sign(p.keyData, digest) } msrcryptoEcdsa.verify = function (p) { var hashName = p.algorithm.hash.name, curve = cryptoECC.createCurve( p.keyHandle.algorithm.namedCurve.toUpperCase(), ), hashFunc = msrcryptoHashFunctions[hashName.toUpperCase()](), digest = hashFunc.computeHash(p.buffer) var ecdsa = msrcryptoEcdsa(curve) return ecdsa.verify(p.keyData, p.signature, digest) } msrcryptoEcdsa.generateKey = function (p) { var curve = cryptoECC.createCurve(p.algorithm.namedCurve.toUpperCase()) var ecdsa = msrcryptoEcdsa(curve) var keyPairData = ecdsa.generateKey() var dtb = cryptoMath.digitsToBytes function padTo8BytesIncrement(array) { return array } var x = padTo8BytesIncrement(dtb(keyPairData.publicKey.x)) var y = padTo8BytesIncrement(dtb(keyPairData.publicKey.y)) var d = padTo8BytesIncrement(dtb(keyPairData.privateKey)) return { type: 'keyPairGeneration', keyPair: { publicKey: { keyData: { x: x, y: y, }, keyHandle: { algorithm: p.algorithm, extractable: p.extractable, usages: ['verify'], type: 'public', }, }, privateKey: { keyData: { x: x, y: y, d: d, }, keyHandle: { algorithm: p.algorithm, extractable: p.extractable, usages: ['sign'], type: 'private', }, }, }, } } msrcryptoEcdsa.importKey = function (p) { if (p.format === 'raw') { var keyData = p.keyData if (keyData[0] !== 4) { throw new Error('DataError') } var elementSize = ~~((keyData.length - 1) / 2) var curveName = p.algorithm.namedCurve.toUpperCase() var x = keyData.slice(1, elementSize + 1), y = keyData.slice(elementSize + 1) if (cryptoECC.validatePoint(curveName, x, y) === false) { throw new Error('DataError') } return { type: 'keyImport', keyData: { x: x, y: y, }, keyHandle: { algorithm: p.algorithm, extractable: p.extractable || false, usages: p.usages, type: 'public', }, } } if (p.format === 'jwk') { var keyObject = msrcryptoJwk.jwkToKey(p.keyData, p.algorithm, [ 'x', 'y', 'd', 'crv', ]) if (keyObject.d && (!keyObject.x || !keyObject.y)) { var curve = msrcryptoEcdsa.curves[p.algorithm.namedCurve]() var ecdsa = msrcryptoEcdsa(curve) var publicKey = ecdsa.computePublicKey(keyObject.d) keyObject.x = publicKey.x keyObject.y = publicKey.y } if ( cryptoECC.validatePoint( p.algorithm.namedCurve.toUpperCase(), keyObject.x, keyObject.y, ) === false ) { throw new Error('DataError') } return { type: 'keyImport', keyData: keyObject, keyHandle: { algorithm: p.algorithm, extractable: p.extractable || keyObject.extractable, usages: null || p.usages, type: keyObject.d ? 'private' : 'public', }, } } } msrcryptoEcdsa.exportKey = function (p) { if (p.format === 'raw' && p.keyHandle.type === 'public') { var keyData = [4].concat(p.keyData.x, p.keyData.y) return { type: 'keyExport', keyHandle: keyData, } } if (p.format === 'jwk') { var jsonKeyStringArray = msrcryptoJwk.keyToJwk(p.keyHandle, p.keyData) return { type: 'keyExport', keyHandle: jsonKeyStringArray, } } throw new Error('unsupported export format.') } operations.register('sign', 'ECDSA', msrcryptoEcdsa.sign) operations.register('verify', 'ECDSA', msrcryptoEcdsa.verify) operations.register('generateKey', 'ECDSA', msrcryptoEcdsa.generateKey) operations.register('importKey', 'ECDSA', msrcryptoEcdsa.importKey) operations.register('exportKey', 'ECDSA', msrcryptoEcdsa.exportKey) } var msrcryptoSubtle var utils = msrcryptoUtilities msrcryptoSubtle = (function () { function syncWorker() { var result function postMessage(data) { try { data.workerid = this.id result = msrcryptoWorker.jsCryptoRunner({ data: data, }) } catch (ex) { this.onerror({ data: ex, type: 'error', }) return } this.onmessage({ data: result, }) } return { postMessage: postMessage, onmessage: null, onerror: null, terminate: function () {}, } } var streamObject = function (op) { return { process: function (buffer) { return op.process(buffer) }, finish: function () { return op.finish() }, abort: function () { return op.abort() }, } } function baseOperation(processResults) { var result = null, oncompleteCallback = null, onerrorCallback = null, retObj, promise, resolveFunc, rejectFunc promise = new Promise(function (resolve, reject) { resolveFunc = resolve rejectFunc = reject }) function opDispatchEvent(e) { if (e.type === 'error') { if (rejectFunc) { rejectFunc.apply(promise, [e]) } return } if (e.data.type === 'process') { processResults(e.data.result, true) return } if (e.data.type === 'finish') { processResults(e.data.result, true) return } this.result = processResults(e.data) resolveFunc.apply(promise, [this.result]) return } retObj = { dispatchEvent: opDispatchEvent, promise: promise, result: null, } return retObj } function keyOperation() { function processResult(result) { var publicKey, privateKey switch (result.type) { case 'keyGeneration': case 'keyImport': case 'keyDerive': if (result.keyPair) { keys.add( result.keyPair.publicKey.keyHandle, result.keyPair.publicKey.keyData, ) keys.add( result.keyPair.privateKey.keyHandle, result.keyPair.privateKey.keyData, ) return { publicKey: result.keyPair.publicKey.keyHandle, privateKey: result.keyPair.privateKey.keyHandle, } } else { keys.add(result.keyHandle, result.keyData) return result.keyHandle } case 'keyExport': return result.keyHandle case 'keyPairGeneration': privateKey = result.keyPair.privateKey publicKey = result.keyPair.publicKey keys.add(publicKey.keyHandle, publicKey.keyData) keys.add(privateKey.keyHandle, privateKey.keyData) return { publicKey: publicKey.keyHandle, privateKey: privateKey.keyHandle, } default: throw new Error('Unknown key operation') } } return baseOperation(processResult) } function toArrayBufferIfSupported(dataArray) { if (typedArraySupport && dataArray.pop) { return new Uint8Array(dataArray).buffer } return dataArray } function cryptoOperation(cryptoContext) { function processResult(result, isProcessCall) { result = result && toArrayBufferIfSupported(result) if (isProcessCall) { promiseQueue.resolve(result) return } return result } var promiseQueue = [], op = baseOperation(processResult) op.stream = cryptoContext.algorithm.stream promiseQueue.add = function (label) { var resolveFunc, rejectFunc, promise = new Promise(function (resolve, reject) { resolveFunc = resolve rejectFunc = reject }) promise.label = label promiseQueue.push({ resolve: resolveFunc, reject: rejectFunc, promise: promise, }) return promise } promiseQueue.resolve = function (result) { var queueItem = promiseQueue.shift() queueItem.resolve.apply(queueItem.promise, [result]) } op.process = function (buffer) { cryptoContext.operationSubType = 'process' cryptoContext.buffer = utils.toArray(buffer) workerManager.continueJob(this, utils.clone(cryptoContext)) return promiseQueue.add('process') } op.finish = function () { cryptoContext.operationSubType = 'finish' cryptoContext.buffer = [] workerManager.continueJob(this, utils.clone(cryptoContext)) return promiseQueue.add('finish') } op.abort = function () { workerManager.abortJob(this) } op.algorithm = cryptoContext.algorithm || null op.key = cryptoContext.keyHandle || null return op } var keys = [] keys.add = function (keyHandle, keyData) { keys.push({ keyHandle: keyHandle, keyData: keyData, }) } keys.remove = function (keyHandle) { for (var i = 0; i < keys.length; i += 1) { if (keys[i].keyHandle === keyHandle) { keys = keys.splice(i, 1) return } } } keys.lookup = function (keyHandle) { for (var i = 0; i < keys.length; i += 1) { if (keys[i].keyHandle === keyHandle) { return keys[i].keyData } } return null } var workerManager = (function () { var maxWorkers = 12 var maxFreeWorkers = 2 var workerPool = [] var jobQueue = [] var jobId = 0 var workerId = 0 var callbackQueue = [] var setFunction = typeof setImmediate === 'undefined' ? setTimeout : setImmediate function executeNextCallback() { callbackQueue.shift()() } function queueCallback(callback) { callbackQueue.push(callback) setFunction(executeNextCallback, 0) } var workerStatus = webWorkerSupport ? 'available' : 'unavailable' function getFreeWorker() { purgeWorkerType(!asyncMode) for (var i = 0; i < workerPool.length; i++) { if (!workerPool[i].busy) { return workerPool[i] } } return null } function purgeWorkerType(webWorker) { for (var i = workerPool.length - 1; i >= 0; i -= 1) { if (workerPool[i].isWebWorker === webWorker) { workerPool[i].terminate() workerPool.splice(i, 1) } } } function freeWorkerCount() { var freeWorkers = 0 for (var i = 0; i < workerPool.length; i++) { if (!workerPool[i].busy) { freeWorkers += 1 } } return freeWorkers } function addWorkerToPool(worker) { workerPool.push(worker) } function removeWorkerFromPool(worker) { for (var i = 0; i < workerPool.length; i++) { if (workerPool[i] === worker) { worker.terminate() workerPool.splice(i, 1) return } } } function lookupWorkerByOperation(operation) { for (var i = 0; i < workerPool.length; i++) { if (workerPool[i].operation === operation) { return workerPool[i] } } return null } function queueJob(operation, data) { jobQueue.push({ operation: operation, data: data, id: jobId++, }) } function jobCompleted(worker) { worker.busy = false if (asyncMode) { if (jobQueue.length > 0) { var job = jobQueue.shift(), i continueJob(job.operation, job.data) if (job.data.operationSubType === 'process') { for (i = 0; i < jobQueue.length; i++) { if (job.operation === jobQueue[i].operation) { continueJob(jobQueue[i].operation, jobQueue[i].data) } } for (i = jobQueue.length - 1; i >= 0; i--) { if (job.operation === jobQueue[i].operation) { jobQueue.splice(i, 1) } } } } else if (freeWorkerCount() > maxFreeWorkers) { removeWorkerFromPool(worker) } } } function createNewWorker(operation) { var worker if (workerStatus === 'pending') { throw new Error('Creating new worker while workerstatus=pending') } if (workerStatus === 'ready') { try { worker = new Worker(scriptUrl) worker.postMessage({ prngSeed: msrcryptoPseudoRandom.getBytes(48), }) worker.isWebWorker = true } catch (ex) { asyncMode = false workerStatus = 'failed' worker.terminate() worker = syncWorker() worker.isWebWorker = false } } else { worker = syncWorker() worker.isWebWorker = false } worker.operation = operation worker.id = workerId++ worker.busy = false worker.onmessage = function (e) { if (e.data.initialized === true) { return } var op = worker.operation e.target || (e.target = { data: worker.data, }) for (var i = 0; i < jobQueue.length; i++) { if (jobQueue[i].operation === worker.operation) { var job = jobQueue[i] jobQueue.splice(i, 1) postMessageToWorker(worker, job.data) return } } if (!(e.data.hasOwnProperty('type') && e.data.type === 'process')) { jobCompleted(worker) } op.dispatchEvent(e) } worker.onerror = function (e) { var op = worker.operation jobCompleted(worker) op.dispatchEvent(e) } addWorkerToPool(worker) return worker } function useWebWorkers(enable) { if (workerStatus === 'unavailable') { utils.consoleLog('web workers not available in this browser.') return } if (enable === true && workerStatus === 'ready') { return } if (enable === false && workerStatus === 'available') { return } if (enable === false && workerStatus === 'ready') { asyncMode = false workerStatus = 'available' utils.consoleLog('web workers disabled.') return } if (workerStatus === 'pending') { return } workerStatus = 'pending' var worker = new Worker(scriptUrl) function setWorkerStatus(e) { var succeeded = !!(e.data && e.data.initialized === true) worker.removeEventListener('message', setWorkerStatus, false) worker.removeEventListener('error', setWorkerStatus, false) worker.terminate() workerStatus = succeeded ? 'ready' : 'failed' asyncMode = succeeded utils.consoleLog( 'web worker initialization ' + (succeeded ? 'succeeded. Now using web workers.' : 'failed. running synchronously.' + (e.message || '')), ) if (jobQueue.length > 0) { var job = jobQueue.shift() runJob(job.operation, job.data) } return } worker.addEventListener('message', setWorkerStatus, false) worker.addEventListener('error', setWorkerStatus, false) worker.postMessage({ prngSeed: msrcryptoPseudoRandom.getBytes(48), }) return } function abortJob(cryptoOperationObject) { var worker = lookupWorkerByOperation(cryptoOperationObject) if (worker) { removeWorkerFromPool(worker) } } function runJob(operation, data) { var worker = null if (workerStatus === 'pending') { queueJob(operation, data) return } worker = getFreeWorker() if (asyncMode && worker === null && workerPool.length >= maxWorkers) { queueJob(operation, data) return } if (worker === null) { worker = createNewWorker(operation) } if (worker === null) { queueJob(operation, data) throw new Error('could not create new worker') } worker.operation = operation worker.busy = true data.workerid = worker.id postMessageToWorker(worker, data) } function continueJob(operation, data) { var worker = lookupWorkerByOperation(operation) if (worker) { postMessageToWorker(worker, data) return } runJob(operation, data) } function postMessageToWorker(worker, data) { data.workerid = worker.id if (asyncMode) { worker.postMessage(data) } else { var func = (function (postData) { return function () { return worker.postMessage(postData) } })(data) queueCallback(func) } return } return { runJob: runJob, continueJob: continueJob, abortJob: abortJob, useWebWorkers: useWebWorkers, } })() function checkOperation(operationType, algorithmName) { if (!operations.exists(operationType, algorithmName)) { throw new Error('unsupported algorithm') } } var subtleParameters = [ { name: 'algorithm', type: 'Object', required: true, }, { name: 'keyHandle', type: 'Object', required: true, }, { name: 'buffer', type: 'Array', required: false, }, { name: 'signature', type: 'Array', required: true, }, { name: 'format', type: 'String', required: true, }, { name: 'keyData', type: 'Object', required: true, }, { name: 'extractable', type: 'Boolean', required: false, }, { name: 'usages', type: 'Array', required: false, }, { name: 'derivedKeyType', type: 'Object', required: true, }, { name: 'length', type: 'Number', required: false, }, { name: 'extractable', type: 'Boolean', required: true, }, { name: 'usages', type: 'Array', required: true, }, { name: 'keyData', type: 'Array', required: true, }, ] var subtleParametersSets = { encrypt: [0, 1, 2], decrypt: [0, 1, 2], sign: [0, 1, 2], verify: [0, 1, 3, 2], digest: [0, 2], generateKey: [0, 6, 7], importKeyRaw: [4, 12, 0, 10, 11], importKeyJwk: [4, 5, 0, 10, 11], exportKey: [0, 4, 1, 6, 7], deriveKey: [0, 1, 8, 6, 7], deriveBits: [0, 1, 9], wrapKey: [1, 1, 0], unwrapKey: [2, 0, 1, 6, 7], } function lookupKeyData(handle) { var data = keys.lookup(handle) if (!data) { throw new Error('key not found') } return data } function buildParameterCollection(operationName, parameterSet) { var parameterCollection = { operationType: operationName, }, operationParameterSet, expectedParam, actualParam, i if ( operationName === 'importKey' && (parameterSet[0] === 'raw' || parameterSet[0] === 'spki') ) { operationName = 'importKeyRaw' } if (operationName === 'importKey' && parameterSet[0] === 'jwk') { operationName = 'importKeyJwk' } operationParameterSet = subtleParametersSets[operationName] for (i = 0; i < operationParameterSet.length; i += 1) { expectedParam = subtleParameters[operationParameterSet[i]] actualParam = parameterSet[i] if (actualParam == null) { if (expectedParam.required) { throw new Error(expectedParam.name) } else { continue } } if (actualParam.subarray) { actualParam = utils.toArray(actualParam) } if (utils.getObjectType(actualParam) === 'ArrayBuffer') { actualParam = utils.toArray(actualParam) } if ( msrcryptoUtilities.getObjectType(actualParam) !== expectedParam.type ) { throw new Error(expectedParam.name) } if (expectedParam.name === 'algorithm') { actualParam.name = actualParam.name.toUpperCase() if (actualParam.iv) { actualParam.iv = utils.toArray(actualParam.iv) } if (actualParam.publicExponent) { actualParam.publicExponent = utils.toArray( actualParam.publicExponent, ) } if (actualParam.salt) { actualParam.salt = utils.toArray(actualParam.salt) } if (actualParam.additionalData) { actualParam.additionalData = utils.toArray( actualParam.additionalData, ) } if ( actualParam.hash && !actualParam.hash.name && utils.getObjectType(actualParam.hash) === 'String' ) { actualParam.hash = { name: actualParam.hash, } } } if (parameterCollection.hasOwnProperty(expectedParam.name)) { parameterCollection[expectedParam.name + '1'] = actualParam } else { parameterCollection[expectedParam.name] = actualParam } } return parameterCollection } function executeOperation(operationName, parameterSet, keyFunc) { var pc = buildParameterCollection(operationName, parameterSet) checkOperation(operationName, pc.algorithm.name) if (pc.keyHandle) { pc.keyData = lookupKeyData(pc.keyHandle) } if (pc.keyHandle1) { pc.keyData1 = lookupKeyData(pc.keyHandle1) } if (pc.algorithm && pc.algorithm.public) { pc.additionalKeyData = lookupKeyData(pc.algorithm.public) } var op = keyFunc ? keyOperation(pc) : cryptoOperation(pc) if ( keyFunc || pc.buffer || operationName === 'deriveBits' || operationName === 'wrapKey' ) { workerManager.runJob(op, pc) } if (op.stream) { return Promise.resolve(streamObject(op)) } return op.promise } var publicMethods = { encrypt: function (algorithm, keyHandle, buffer) { return executeOperation('encrypt', arguments, 0) }, decrypt: function (algorithm, keyHandle, buffer) { return executeOperation('decrypt', arguments, 0) }, sign: function (algorithm, keyHandle, buffer) { return executeOperation('sign', arguments, 0) }, verify: function (algorithm, keyHandle, signature, buffer) { return executeOperation('verify', arguments, 0) }, digest: function (algorithm, buffer) { return executeOperation('digest', arguments, 0) }, generateKey: function (algorithm, extractable, keyUsage) { return executeOperation('generateKey', arguments, 1) }, deriveKey: function ( algorithm, baseKey, derivedKeyType, extractable, keyUsage, ) { var deriveBits = this.deriveBits, importKey = this.importKey return new Promise(function (resolve, reject) { var keyLength switch (derivedKeyType.name.toUpperCase()) { case 'AES-CBC': case 'AES-GCM': keyLength = derivedKeyType.length break case 'HMAC': keyLength = derivedKeyType.length || { 'SHA-1': 512, 'SHA-224': 512, 'SHA-256': 512, 'SHA-384': 1024, 'SHA-512': 1024, }[derivedKeyType.hash.name.toUpperCase()] break default: reject(new Error('No Supported')) return } deriveBits(algorithm, baseKey, keyLength) .then(function (bits) { return importKey( 'raw', bits, derivedKeyType, extractable, keyUsage, ) }) .then(function (key) { resolve(key) }) ['catch'](function (err) { reject(err) }) }) }, deriveBits: function (algorithm, baseKey, length) { return executeOperation('deriveBits', arguments, 0) }, importKey: function ( format, keyData, algorithm, extractable, keyUsage, ) { return executeOperation('importKey', arguments, 1) }, exportKey: function (format, keyHandle) { return executeOperation( 'exportKey', [keyHandle.algorithm, format, keyHandle], 1, ) }, wrapKey: function (format, key, wrappingKey, wrappingKeyAlgorithm) { var encrypt = this.encrypt, exportKey = this.exportKey return new Promise(function (resolve, reject) { if ( key.extractable === false || key.usages.indexOf('wrapKey') < 0 || wrappingKey.algorithm.name.toUpperCase() !== wrappingKeyAlgorithm.name ) { reject(new Error('InvalidAccessError')) return } exportKey(format, key) .then(function (keyData) { return encrypt( wrappingKeyAlgorithm, wrappingKey, format === 'jwk' ? utils.stringToBytes(JSON.stringify(keyData, null, 0)) : keyData, ) }) .then(function (cipherArrayBuffer) { resolve(cipherArrayBuffer) }) ['catch'](function (err) { reject(err) }) }) }, unwrapKey: function ( format, wrappedKey, unwrappingKey, unwrapAlgorithm, unwrappedKeyAlgorithm, extractable, keyUsages, ) { var decrypt = this.decrypt, importKey = this.importKey return new Promise(function (resolve, reject) { if ( unwrappingKey.usages.indexOf('unwrapKey') < 0 || unwrappingKey.algorithm.name.toUpperCase() !== unwrapAlgorithm.name ) { reject(new Error('InvalidAccessError')) return } decrypt(unwrapAlgorithm, unwrappingKey, wrappedKey) .then(function (keyPlain) { return importKey( format, format === 'jwk' ? JSON.parse(utils.bytesToString(keyPlain)) : keyPlain, unwrappedKeyAlgorithm, extractable, keyUsages, ) }) .then(function (key) { resolve(key) }) ['catch'](function (err) { reject(err) }) }) }, } var internalMethods = { useWebWorkers: workerManager.useWebWorkers, } return { publicMethods: publicMethods, internalMethods: internalMethods, } })() var msrcryptoWrapKey = (function () { var utils = msrcryptoUtilities function wrapKey(params) { var rsaObj = msrcryptoRsa( params.keyData1, params.keyHandle1.algorithm.name, msrcryptoHashFunctions['SHA-1'], )() var tagLength = 128 var keyToWrapJwk = msrcryptoJwk.keyToJwkOld( params.keyHandle, params.keyData, ) var jweHeader = { alg: params.keyHandle1.algorithm.name.toUpperCase(), enc: 'A128GCM', } var encodedJweHeader = utils.toBase64(JSON.stringify(jweHeader), true) var cmk = msrcryptoPseudoRandom.getBytes(32) var jweEncryptedKey = rsaObj.encrypt(cmk) var encodedJweEncryptedKey = utils.toBase64(jweEncryptedKey, true) var jweIv = msrcryptoPseudoRandom.getBytes(12) var encodedJweIv = utils.toBase64(jweIv, true) var additionalData = encodedJweHeader.concat( '.', encodedJweEncryptedKey, '.', encodedJweIv, ) var gcm = msrcryptoGcm(msrcryptoBlockCipher.aes(cmk)) gcm.init(jweIv, utils.stringToBytes(additionalData), tagLength) var ciphertextPlusTag = gcm.encrypt(keyToWrapJwk) var tag = ciphertextPlusTag.slice(-(tagLength / 8)) var encodedIntegrityValue = utils.toBase64(tag, true) var encodedCiphertext = utils.toBase64( ciphertextPlusTag.slice(0, ciphertextPlusTag.length - tag.length), true, ) var jwe = { recipients: [ { header: encodedJweHeader, encrypted_key: encodedJweEncryptedKey, integrity_value: encodedIntegrityValue, }, ], initialization_vector: encodedJweIv, ciphertext: encodedCiphertext, } return utils.stringToBytes(JSON.stringify(jwe)) } function unwrapKey(params) { var b64Tobytes = utils.fromBase64 var keyDataJwk = JSON.parse( String.fromCharCode.apply(null, params.buffer), ) var header = utils.fromBase64(keyDataJwk.recipients[0].header) var encrypted_key = b64Tobytes(keyDataJwk.recipients[0].encrypted_key) var integrity_value = b64Tobytes( keyDataJwk.recipients[0].integrity_value, ) var initialization_vector = b64Tobytes(keyDataJwk.initialization_vector) var ciphertext = b64Tobytes(keyDataJwk.ciphertext) var hashFunc = msrcryptoHashFunctions['SHA-1']() var rsaObj = msrcryptoRsa( params.keyData, params.keyHandle.algorithm.name, hashFunc, ) var inKey = rsaObj.decrypt(encrypted_key) var additionalData = keyDataJwk.recipients[0].header.concat( '.', keyDataJwk.recipients[0].encrypted_key, '.', keyDataJwk.initialization_vector, ) var gcm = msrcryptoGcm(msrcryptoBlockCipher.aes(inKey)) gcm.init( initialization_vector, utils.stringToBytes(additionalData), 128, ) var result = gcm.decrypt(ciphertext, integrity_value) var keyObject = msrcryptoJwk.jwkToKey(result, params.algorithm, ['k']) return { type: 'keyImport', keyData: keyObject.k, keyHandle: { algorithm: { name: params.algorithm.name, }, extractable: params.extractable || keyObject.extractable, usages: params.usages, type: 'secret', }, } } return { wrapKey: wrapKey, unwrapKey: unwrapKey, } })() if (typeof operations !== 'undefined') { operations.register('wrapKey', 'AES-GCM', msrcryptoWrapKey.wrapKey) operations.register('unwrapKey', 'AES-CBC', msrcryptoWrapKey.unwrapKey) } var publicMethods = { subtle: msrcryptoSubtle ? msrcryptoSubtle.publicMethods : null, getRandomValues: function (array) { var i var randomValues = msrcryptoPseudoRandom.getBytes(array.length) for (i = 0; i < array.length; i += 1) { array[i] = randomValues[i] } return array }, initPrng: function (entropyData) { var entropyDataType = Object.prototype.toString.call(entropyData) if ( entropyDataType !== '[object Array]' && entropyDataType !== '[object Uint8Array]' ) { throw new Error('entropyData must be a Array or Uint8Array') } entropyPool && entropyPool.reseed(entropyData) msrcryptoPseudoRandom.reseed(entropyPool.read(48)) fprngEntropyProvided = true }, toBase64: function (data, base64Url) { return msrcryptoUtilities.toBase64(data, base64Url) }, fromBase64: function (base64String) { return msrcryptoUtilities.fromBase64(base64String) }, textToBytes: function (text) { return msrcryptoUtilities.stringToBytes(text) }, bytesToText: function (byteArray) { return msrcryptoUtilities.bytesToString(byteArray) }, asn1: asn1, url: scriptUrl, version: msrCryptoVersion, useWebWorkers: function (useWebWorkers) { return msrcryptoSubtle ? msrcryptoSubtle.internalMethods.useWebWorkers(useWebWorkers) : null }, } var entropyPool entropyPool = entropyPool || new MsrcryptoEntropy(global) entropyPool.init() var localEntropy = entropyPool.read(48) msrcryptoPseudoRandom.init(localEntropy) return publicMethods } return msrCrypto() }) ;(function (root, factory) { if (typeof Promise !== 'undefined') { return } root.Promise = factory() })(this, function () { var Promise = function (executor, id) { if (!(this instanceof Promise)) { throw new Error("use 'new' keyword with Promise constructor") } var successResult = null, failReason = null, thenResolved = [], thenRejected = [], rejectThenPromise = [], resolveThenPromise = [] this.then = function (onCompleted, onRejected) { var thenFunctionResult if (successResult) { thenFunctionResult = onCompleted(successResult.result) if (thenFunctionResult && thenFunctionResult.then) { return thenFunctionResult } return Promise.resolve(thenFunctionResult) } if (failReason) { thenFunctionResult = onRejected ? onRejected(failReason.result) : failReason.result if (thenFunctionResult && thenFunctionResult.then) { return thenFunctionResult } return Promise.resolve(thenFunctionResult) } thenResolved.push(onCompleted) if (onRejected) { thenRejected.push(onRejected) } return new Promise(function (resolve, reject) { resolveThenPromise.push(resolve) rejectThenPromise.push(reject) }) } this['catch'] = function (onRejected) { var catchFunctionResult if (failReason) { catchFunctionResult = onRejected(failReason.result) if (catchFunctionResult && catchFunctionResult.then) { return catchFunctionResult } return Promise.resolve(catchFunctionResult) } thenRejected.push(onRejected) return new Promise(function (resolve, reject) { resolveThenPromise.push(resolve) rejectThenPromise.push(reject) }) } function resolve(param) { var result, i for (i = 0; i < thenResolved.length; i += 1) { result = thenResolved[i](param) if (result && result.then) { result.then(resolveThenPromise[i]) if (rejectThenPromise[i]) { result['catch'](rejectThenPromise[i]) } } else { if (resolveThenPromise[i]) { resolveThenPromise[i](result) } } } successResult = { result: param, } return } function reject(param) { var reason, i for (i = 0; i < thenRejected.length; i += 1) { reason = thenRejected[i](param) if (reason && reason.then) { reason.then(resolveThenPromise[i], rejectThenPromise[i]) } else { if (resolveThenPromise[i]) { resolveThenPromise[i](reason) } } } failReason = { result: param, } return } executor(resolve, reject) return } Promise.all = function (promiseArray) { var results = [], resultCount = 0, promiseAll function then(index, resolve) { return function (result) { results[index] = result resultCount += 1 if (resultCount === promiseArray.length) { resolve(results) } } } promiseAll = new Promise(function (resolve, reject) { var i function r(reason) { reject(reason) } for (i = 0; i < promiseArray.length; i += 1) { if (promiseArray[i].then) { promiseArray[i].then(then(i, resolve)) promiseArray[i]['catch'](r) continue } Promise.resolve(promiseArray[i]).then(then(i, resolve)) } }) return promiseAll } Promise.race = function (promiseArray) { var resolved = false, promiseRace function then(resolveFunction) { return function (result) { if (!resolved) { resolved = true resolveFunction(result) } } } promiseRace = new Promise(function (resolve, reject) { for (var i = 0; i < promiseArray.length; i += 1) { promiseArray[i].then(then(resolve), then(reject)) } }) return promiseRace } Promise.reject = function (rejectReason) { return new Promise(function (resolve, reject) { reject(rejectReason) }) } Promise.resolve = function (resolveResult) { return new Promise(function (resolve, reject) { resolve(resolveResult) }) } return Promise })