From 6b32698b3e020e5910c92b72a1677e7cd56287d6 Mon Sep 17 00:00:00 2001 From: Paul Frazee Date: Tue, 19 Jul 2022 14:40:06 -0500 Subject: [PATCH] Bundle official msrcrypto distro in the source (solves some bugs, probably safer) --- package.json | 1 - src/platform/polyfills.native.ts | 2 +- src/third-party/msrcrypto.js | 10144 +++++++++++++++++++++++++++++ 3 files changed, 10145 insertions(+), 2 deletions(-) create mode 100644 src/third-party/msrcrypto.js diff --git a/package.json b/package.json index bcc66615..ed5c2025 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,6 @@ "mobx": "^6.6.0", "mobx-react-lite": "^3.4.0", "mobx-state-tree": "^5.1.5", - "msrcrypto": "^1.5.8", "react": "17.0.2", "react-dom": "17.0.2", "react-native": "0.68.2", diff --git a/src/platform/polyfills.native.ts b/src/platform/polyfills.native.ts index dd1ecf7e..e37a7695 100644 --- a/src/platform/polyfills.native.ts +++ b/src/platform/polyfills.native.ts @@ -2,7 +2,7 @@ import {NativeModules} from 'react-native' const {AppSecureRandomModule} = NativeModules import {toByteArray} from 'base64-js' // @ts-ignore we dont have types for this -prf -import crypto from 'msrcrypto' +import crypto from '../third-party/msrcrypto' import '@zxing/text-encoding' // TextEncoder / TextDecoder async function generateSecureRandom(bytes: number) { diff --git a/src/third-party/msrcrypto.js b/src/third-party/msrcrypto.js new file mode 100644 index 00000000..b24885a6 --- /dev/null +++ b/src/third-party/msrcrypto.js @@ -0,0 +1,10144 @@ +// 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 +})