tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

common.js (54582B)


      1 /*
      2 * Copyright (c) 2014, GMO GlobalSign
      3 * Copyright (c) 2015, Peculiar Ventures
      4 * All rights reserved.
      5 *
      6 * Author 2014-2015, Yury Strozhevsky <www.strozhevsky.com>.
      7 *
      8 * Redistribution and use in source and binary forms, with or without modification, 
      9 * are permitted provided that the following conditions are met:
     10 *
     11 * 1. Redistributions of source code must retain the above copyright notice, 
     12 *    this list of conditions and the following disclaimer.
     13 *
     14 * 2. Redistributions in binary form must reproduce the above copyright notice, 
     15 *    this list of conditions and the following disclaimer in the documentation 
     16 *    and/or other materials provided with the distribution.
     17 *
     18 * 3. Neither the name of the copyright holder nor the names of its contributors 
     19 *    may be used to endorse or promote products derived from this software without 
     20 *    specific prior written permission.
     21 *
     22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
     23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
     24 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
     25 * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
     26 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
     27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
     28 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
     29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
     30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
     31 * OF SUCH DAMAGE. 
     32 *
     33 */
     34 (
     35 function(in_window)
     36 {
     37    //**************************************************************************************
     38    // #region Declaration of global variables 
     39    //**************************************************************************************
     40    // #region "org" namespace 
     41    if(typeof in_window.org === "undefined")
     42        in_window.org = {};
     43    else
     44    {
     45        if(typeof in_window.org !== "object")
     46            throw new Error("Name org already exists and it's not an object");
     47    }
     48    // #endregion 
     49 
     50    // #region "org.pkijs" namespace 
     51    if(typeof in_window.org.pkijs === "undefined")
     52        in_window.org.pkijs = {};
     53    else
     54    {
     55        if(typeof in_window.org.pkijs !== "object")
     56            throw new Error("Name org.pkijs already exists and it's not an object" + " but " + (typeof in_window.org.pkijs));
     57    }
     58    // #endregion 
     59 
     60    // #region "local" namespace 
     61    var local = {};
     62    // #endregion   
     63    //**************************************************************************************
     64    // #endregion 
     65    //**************************************************************************************
     66    // #region Settings for "crypto engine" 
     67    //**************************************************************************************
     68    local.engine = {
     69        name: "none",
     70        crypto: null,
     71        subtle: null
     72    };
     73 
     74    if(typeof window != "undefined")
     75    {
     76        if("crypto" in window)
     77        {
     78            var engineName = "webcrypto";
     79            var cryptoObject = window.crypto;
     80            var subtleObject = null;
     81 
     82            // Apple Safari support
     83            if("webkitSubtle" in window.crypto)
     84                subtleObject = window.crypto.webkitSubtle;
     85 
     86            if("subtle" in window.crypto)
     87                subtleObject = window.crypto.subtle;
     88 
     89            local.engine = {
     90                name: engineName,
     91                crypto: cryptoObject,
     92                subtle: subtleObject
     93            };
     94        }
     95    }
     96    //**************************************************************************************
     97    in_window.org.pkijs.setEngine =
     98    function(name, crypto, subtle)
     99    {
    100        /// <summary>Setting the global "crypto engine" parameters</summary>
    101        /// <param name="name" type="String">Auxiliary name for "crypto engine"</param>
    102        /// <param name="crypto" type="Object">Object handling all root cryptographic requests (in fact currently it must handle only "getRandomValues")</param>
    103        /// <param name="subtle" type="Object">Object handling all main cryptographic requests</param>
    104 
    105        local.engine = {
    106            name: name,
    107            crypto: crypto,
    108            subtle: subtle
    109        };
    110    };
    111    //**************************************************************************************
    112    in_window.org.pkijs.getEngine =
    113    function()
    114    {
    115        return local.engine;
    116    };
    117    //**************************************************************************************
    118    // #endregion 
    119    //**************************************************************************************
    120    // #region Declaration of common functions 
    121    //**************************************************************************************
    122    in_window.org.pkijs.emptyObject =
    123    function()
    124    {
    125        this.toJSON = function()
    126        {
    127            return {};
    128        };
    129        this.toSchema = function()
    130        {
    131            return {};
    132        };
    133    };
    134    //**************************************************************************************
    135    in_window.org.pkijs.getNames =
    136    function(arg)
    137    {
    138        /// <summary>Get correct "names" array for all "schema" objects</summary>
    139 
    140        var names = {};
    141 
    142        if(arg instanceof Object)
    143            names = (arg.names || {});
    144 
    145        return names;
    146    };
    147    //**************************************************************************************
    148    in_window.org.pkijs.inheriteObjectFields =
    149    function(from)
    150    {
    151        for(var i in from.prototype)
    152        {
    153            if(typeof from.prototype[i] === "function")
    154                continue;
    155 
    156            this[i] = from.prototype[i];
    157        }
    158    };
    159    //**************************************************************************************
    160    in_window.org.pkijs.getUTCDate =
    161    function(date)
    162    {
    163        /// <summary>Making UTC date from local date</summary>
    164        /// <param name="date" type="Date">Date to convert from</param>
    165 
    166        var current_date = date;
    167        return new Date(current_date.getTime() + (current_date.getTimezoneOffset() * 60000));
    168    };
    169    //**************************************************************************************
    170    in_window.org.pkijs.padNumber =
    171    function(input_number, full_length)
    172    {
    173        var str = input_number.toString(10);
    174        var dif = full_length - str.length;
    175 
    176        var padding = new Array(dif);
    177        for(var i = 0; i < dif; i++)
    178            padding[i] = '0';
    179 
    180        var padding_string = padding.join('');
    181 
    182        return padding_string.concat(str);
    183    };
    184    //**************************************************************************************
    185    in_window.org.pkijs.getValue =
    186    function(args, item, default_value)
    187    {
    188        if(item in args)
    189            return args[item];
    190        else
    191            return default_value;
    192    };
    193    //**************************************************************************************
    194    in_window.org.pkijs.isEqual_view =
    195    function(input_view1, input_view2)
    196    {
    197        /// <summary>Compare two Uint8Arrays</summary>
    198        /// <param name="input_view1" type="Uint8Array">First Uint8Array for comparision</param>
    199        /// <param name="input_view2" type="Uint8Array">Second Uint8Array for comparision</param>
    200 
    201        if(input_view1.length !== input_view2.length)
    202            return false;
    203 
    204        for(var i = 0; i < input_view1.length; i++)
    205        {
    206            if(input_view1[i] != input_view2[i])
    207                return false;
    208        }
    209 
    210        return true;
    211    };
    212    //**************************************************************************************
    213    in_window.org.pkijs.isEqual_buffer =
    214    function(input_buffer1, input_buffer2)
    215    {
    216        /// <summary>Compare two array buffers</summary>
    217        /// <param name="input_buffer1" type="ArrayBuffer">First ArrayBuffer for comparision</param>
    218        /// <param name="input_buffer2" type="ArrayBuffer">Second ArrayBuffer for comparision</param>
    219 
    220        if(input_buffer1.byteLength != input_buffer2.byteLength)
    221            return false;
    222 
    223        var view1 = new Uint8Array(input_buffer1);
    224        var view2 = new Uint8Array(input_buffer2);
    225 
    226        return in_window.org.pkijs.isEqual_view(view1, view2);
    227    };
    228    //**************************************************************************************
    229    in_window.org.pkijs.concat_buffers =
    230    function(input_buf1, input_buf2)
    231    {
    232        /// <summary>Concatenate two ArrayBuffers</summary>
    233        /// <param name="input_buf1" type="ArrayBuffer">First ArrayBuffer (first part of concatenated array)</param>
    234        /// <param name="input_buf2" type="ArrayBuffer">Second ArrayBuffer (second part of concatenated array)</param>
    235 
    236        var input_view1 = new Uint8Array(input_buf1);
    237        var input_view2 = new Uint8Array(input_buf2);
    238 
    239        var ret_buf = new ArrayBuffer(input_buf1.byteLength + input_buf2.byteLength);
    240        var ret_view = new Uint8Array(ret_buf);
    241 
    242        for(var i = 0; i < input_buf1.byteLength; i++)
    243            ret_view[i] = input_view1[i];
    244 
    245        for(var j = 0; j < input_buf2.byteLength; j++)
    246            ret_view[input_buf1.byteLength + j] = input_view2[j];
    247 
    248        return ret_buf;
    249    };
    250    //**************************************************************************************
    251    in_window.org.pkijs.copyBuffer =
    252    function(input_buffer)
    253    {
    254        var result = new ArrayBuffer(input_buffer.byteLength);
    255 
    256        var resultView = new Uint8Array(result);
    257        var inputView = new Uint8Array(input_buffer);
    258 
    259        for(var i = 0; i < inputView.length; i++)
    260            resultView[i] = inputView[i];
    261 
    262        return result;
    263    };
    264    //**************************************************************************************
    265    in_window.org.pkijs.getCrypto =
    266    function()
    267    {
    268        var crypto_temp;
    269 
    270        if(local.engine.subtle !== null)
    271            crypto_temp = local.engine.subtle;
    272 
    273        return crypto_temp;
    274    };
    275    //**************************************************************************************
    276    in_window.org.pkijs.stringPrep =
    277    function(input_string)
    278    {
    279        /// <summary>String preparation function. In a future here will be realization of algorithm from RFC4518.</summary>
    280        /// <param name="input_string" type="String">JavaScript string. As soon as for each ASN.1 string type we have a specific transformation function here we will work with pure JavaScript string</param>
    281        /// <returns type="String">Formated string</returns>
    282 
    283        var result = input_string.replace(/^\s+|\s+$/g, ""); // Trim input string
    284        result = result.replace(/\s+/g, " "); // Change all sequence of SPACE down to SPACE char
    285        result = result.toLowerCase();
    286 
    287        return result;
    288    };
    289    //**************************************************************************************
    290    in_window.org.pkijs.bufferToHexCodes =
    291    function(input_buffer, input_offset, input_lenght)
    292    {
    293        var result = "";
    294 
    295        var int_buffer = new Uint8Array(input_buffer, input_offset, input_lenght);
    296 
    297        for(var i = 0; i < int_buffer.length; i++)
    298        {
    299            var str = int_buffer[i].toString(16).toUpperCase();
    300            result = result + ((str.length === 1) ? "0" : "") + str;
    301        }
    302 
    303        return result;
    304    };
    305    //**************************************************************************************
    306    in_window.org.pkijs.bufferFromHexCodes =
    307    function(hexString)
    308    {
    309        /// <summary>Create an ArrayBuffer from string having hexdecimal codes</summary>
    310        /// <param name="hexString" type="String">String to create ArrayBuffer from</param>
    311 
    312        // #region Initial variables 
    313        var stringLength = hexString.length;
    314 
    315        var resultBuffer = new ArrayBuffer(stringLength >> 1);
    316        var resultView = new Uint8Array(resultBuffer);
    317 
    318        var hex_map = {};
    319 
    320        hex_map['0'] = 0x00;
    321        hex_map['1'] = 0x01;
    322        hex_map['2'] = 0x02;
    323        hex_map['3'] = 0x03;
    324        hex_map['4'] = 0x04;
    325        hex_map['5'] = 0x05;
    326        hex_map['6'] = 0x06;
    327        hex_map['7'] = 0x07;
    328        hex_map['8'] = 0x08;
    329        hex_map['9'] = 0x09;
    330        hex_map['A'] = 0x0A;
    331        hex_map['a'] = 0x0A;
    332        hex_map['B'] = 0x0B;
    333        hex_map['b'] = 0x0B;
    334        hex_map['C'] = 0x0C;
    335        hex_map['c'] = 0x0C;
    336        hex_map['D'] = 0x0D;
    337        hex_map['d'] = 0x0D;
    338        hex_map['E'] = 0x0E;
    339        hex_map['e'] = 0x0E;
    340        hex_map['F'] = 0x0F;
    341        hex_map['f'] = 0x0F;
    342 
    343        var j = 0;
    344        var temp = 0x00;
    345        // #endregion 
    346 
    347        // #region Convert char-by-char 
    348        for(var i = 0; i < stringLength; i++)
    349        {
    350            if(!(i % 2))
    351                temp = hex_map[hexString.charAt(i)] << 4;
    352            else
    353            {
    354                temp |= hex_map[hexString.charAt(i)];
    355 
    356                resultView[j] = temp;
    357                j++;
    358            }
    359        }
    360        // #endregion 
    361 
    362        return resultBuffer;
    363    };
    364    //**************************************************************************************
    365    in_window.org.pkijs.getRandomValues =
    366    function(view)
    367    {
    368        /// <param name="view" type="Uint8Array">New array which gives a length for random value</param>
    369 
    370        if(local.engine.crypto !== null)
    371            return local.engine.crypto.getRandomValues(view);
    372        else
    373            throw new Error("No support for Web Cryptography API");
    374    };
    375    //**************************************************************************************
    376    in_window.org.pkijs.getAlgorithmParameters =
    377    function(algorithmName, operation)
    378    {
    379        /// <param name="algorithmName" type="String">Algorithm name to get common parameters for</param>
    380        /// <param name="operation" type="String">Kind of operation: "sign", "encrypt", "generatekey", "importkey", "exportkey", "verify"</param>
    381 
    382        var result = {
    383            algorithm: {},
    384            usages: []
    385        };
    386 
    387        switch(algorithmName.toUpperCase())
    388        {
    389            case "RSASSA-PKCS1-V1_5":
    390                switch(operation.toLowerCase())
    391                {
    392                    case "generatekey":
    393                        result = {
    394                            algorithm: {
    395                                name: "RSASSA-PKCS1-v1_5",
    396                                modulusLength: 2048,
    397                                publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
    398                                hash: {
    399                                    name: "SHA-256"
    400                                }
    401                            },
    402                            usages: ["sign", "verify"]
    403                        };
    404                        break;
    405                    case "verify":
    406                    case "sign":
    407                    case "importkey":
    408                        result = {
    409                            algorithm: {
    410                                name: "RSASSA-PKCS1-v1_5",
    411                                hash: {
    412                                    name: "SHA-256"
    413                                }
    414                            },
    415                            usages: ["verify"] // For importKey("pkcs8") usage must be "sign" only
    416                        };
    417                        break;
    418                    case "exportkey":
    419                    default:
    420                        return {
    421                            algorithm: {
    422                                name: "RSASSA-PKCS1-v1_5"
    423                            },
    424                            usages: []
    425                        };
    426                }
    427                break;
    428            case "RSA-PSS":
    429                switch(operation.toLowerCase())
    430                {
    431                    case "sign":
    432                    case "verify":
    433                        result = {
    434                            algorithm: {
    435                                name: "RSA-PSS",
    436                                hash: {
    437                                    name: "SHA-1"
    438                                },
    439                                saltLength: 20
    440                            },
    441                            usages: ["sign", "verify"]
    442                        };
    443                        break;
    444                    case "generatekey":
    445                        result = {
    446                            algorithm: {
    447                                name: "RSA-PSS",
    448                                modulusLength: 2048,
    449                                publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
    450                                hash: {
    451                                    name: "SHA-1"
    452                                }
    453                            },
    454                            usages: ["sign", "verify"]
    455                        };
    456                        break;
    457                    case "importkey":
    458                        result = {
    459                            algorithm: {
    460                                name: "RSA-PSS",
    461                                hash: {
    462                                    name: "SHA-1"
    463                                }
    464                            },
    465                            usages: ["verify"] // For importKey("pkcs8") usage must be "sign" only
    466                        };
    467                        break;
    468                    case "exportkey":
    469                    default:
    470                        return {
    471                            algorithm: {
    472                                name: "RSA-PSS"
    473                            },
    474                            usages: []
    475                        };
    476                }
    477                break;
    478            case "RSA-OAEP":
    479                switch(operation.toLowerCase())
    480                {
    481                    case "encrypt":
    482                    case "decrypt":
    483                        result = {
    484                            algorithm: {
    485                                name: "RSA-OAEP"
    486                            },
    487                            usages: ["encrypt", "decrypt"]
    488                        };
    489                        break;
    490                        break;
    491                    case "generatekey":
    492                        result = {
    493                            algorithm: {
    494                                name: "RSA-OAEP",
    495                                modulusLength: 2048,
    496                                publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
    497                                hash: {
    498                                    name: "SHA-256"
    499                                }
    500                            },
    501                            usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"]
    502                        };
    503                        break;
    504                    case "importkey":
    505                        result = {
    506                            algorithm: {
    507                                name: "RSA-OAEP",
    508                                hash: {
    509                                    name: "SHA-256"
    510                                }
    511                            },
    512                            usages: ["encrypt"] // encrypt for "spki" and decrypt for "pkcs8"
    513                        };
    514                        break;
    515                    case "exportkey":
    516                    default:
    517                        return {
    518                            algorithm: {
    519                                name: "RSA-OAEP"
    520                            },
    521                            usages: []
    522                        };
    523                }
    524                break;
    525            case "ECDSA":
    526                switch(operation.toLowerCase())
    527                {
    528                    case "generatekey":
    529                        result = {
    530                            algorithm: {
    531                                name: "ECDSA",
    532                                namedCurve: "P-256"
    533                            },
    534                            usages: ["sign", "verify"]
    535                        };
    536                        break;
    537                    case "importkey":
    538                        result = {
    539                            algorithm: {
    540                                name: "ECDSA",
    541                                namedCurve: "P-256"
    542                            },
    543                            usages: ["verify"] // "sign" for "pkcs8"
    544                        };
    545                        break;
    546                    case "verify":
    547                    case "sign":
    548                        result = {
    549                            algorithm: {
    550                                name: "ECDSA",
    551                                hash: {
    552                                    name: "SHA-256"
    553                                }
    554                            },
    555                            usages: ["sign"]
    556                        };
    557                        break;
    558                    default:
    559                        return {
    560                            algorithm: {
    561                                name: "ECDSA"
    562                            },
    563                            usages: []
    564                        };
    565                }
    566                break;
    567            case "ECDH":
    568                switch(operation.toLowerCase())
    569                {
    570                    case "exportkey":
    571                    case "importkey":
    572                    case "generatekey":
    573                        result = {
    574                            algorithm: {
    575                                name: "ECDH",
    576                                namedCurve: "P-256"
    577                            },
    578                            usages: ["deriveKey", "deriveBits"]
    579                        };
    580                        break;
    581                    case "derivekey":
    582                    case "derivebits":
    583                        result = {
    584                            algorithm: {
    585                                name: "ECDH",
    586                                namedCurve: "P-256",
    587                                public: [] // Must be a "publicKey"
    588                            },
    589                            usages: ["encrypt", "decrypt"]
    590                        };
    591                        break;
    592                    default:
    593                        return {
    594                            algorithm: {
    595                                name: "ECDH"
    596                            },
    597                            usages: []
    598                        };
    599                }
    600                break;
    601            case "AES-CTR":
    602                switch(operation.toLowerCase())
    603                {
    604                    case "importkey":
    605                    case "exportkey":
    606                    case "generatekey":
    607                        result = {
    608                            algorithm: {
    609                                name: "AES-CTR",
    610                                length: 256
    611                            },
    612                            usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"]
    613                        };
    614                        break;
    615                    case "decrypt":
    616                    case "encrypt":
    617                        result = {
    618                            algorithm: {
    619                                name: "AES-CTR",
    620                                counter: new Uint8Array(16),
    621                                length: 10
    622                            },
    623                            usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"]
    624                        };
    625                        break;
    626                    default:
    627                        return {
    628                            algorithm: {
    629                                name: "AES-CTR"
    630                            },
    631                            usages: []
    632                        };
    633                }
    634                break;
    635            case "AES-CBC":
    636                switch(operation.toLowerCase())
    637                {
    638                    case "importkey":
    639                    case "exportkey":
    640                    case "generatekey":
    641                        result = {
    642                            algorithm: {
    643                                name: "AES-CBC",
    644                                length: 256
    645                            },
    646                            usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"]
    647                        };
    648                        break;
    649                    case "decrypt":
    650                    case "encrypt":
    651                        result = {
    652                            algorithm: {
    653                                name: "AES-CBC",
    654                                iv: in_window.org.pkijs.getRandomValues(new Uint8Array(16)) // For "decrypt" the value should be replaced with value got on "encrypt" step
    655                            },
    656                            usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"]
    657                        };
    658                        break;
    659                    default:
    660                        return {
    661                            algorithm: {
    662                                name: "AES-CBC"
    663                            },
    664                            usages: []
    665                        };
    666                }
    667                break;
    668            case "AES-GCM":
    669                switch(operation.toLowerCase())
    670                {
    671                    case "importkey":
    672                    case "exportkey":
    673                    case "generatekey":
    674                        result = {
    675                            algorithm: {
    676                                name: "AES-GCM",
    677                                length: 256
    678                            },
    679                            usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"]
    680                        };
    681                        break;
    682                    case "decrypt":
    683                    case "encrypt":
    684                        result = {
    685                            algorithm: {
    686                                name: "AES-GCM",
    687                                iv: in_window.org.pkijs.getRandomValues(new Uint8Array(16)) // For "decrypt" the value should be replaced with value got on "encrypt" step
    688                            },
    689                            usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"]
    690                        };
    691                        break;
    692                    default:
    693                        return {
    694                            algorithm: {
    695                                name: "AES-GCM"
    696                            },
    697                            usages: []
    698                        };
    699                }
    700                break;
    701            case "AES-KW":
    702                switch(operation.toLowerCase())
    703                {
    704                    case "importkey":
    705                    case "exportkey":
    706                    case "generatekey":
    707                    case "wrapkey":
    708                    case "unwrapkey":
    709                        result = {
    710                            algorithm: {
    711                                name: "AES-KW",
    712                                length: 256
    713                            },
    714                            usages: ["wrapKey", "unwrapKey"]
    715                        };
    716                        break;
    717                    default:
    718                        return {
    719                            algorithm: {
    720                                name: "AES-KW"
    721                            },
    722                            usages: []
    723                        };
    724                }
    725                break;
    726            case "HMAC":
    727                switch(operation.toLowerCase())
    728                {
    729                    case "sign":
    730                    case "verify":
    731                        result = {
    732                            algorithm: {
    733                                name: "HMAC"
    734                            },
    735                            usages: ["sign", "verify"]
    736                        };
    737                        break;
    738                    case "importkey":
    739                    case "exportkey":
    740                    case "generatekey":
    741                        result = {
    742                            algorithm: {
    743                                name: "HMAC",
    744                                length: 32,
    745                                hash: {
    746                                    name: "SHA-256"
    747                                }
    748                            },
    749                            usages: ["sign", "verify"]
    750                        };
    751                        break;
    752                    default:
    753                        return {
    754                            algorithm: {
    755                                name: "HMAC"
    756                            },
    757                            usages: []
    758                        };
    759                }
    760                break;
    761            case "HKDF":
    762                switch(operation.toLowerCase())
    763                {
    764                    case "derivekey":
    765                        result = {
    766                            algorithm: {
    767                                name: "HKDF",
    768                                hash: "SHA-256",
    769                                salt: new Uint8Array(),
    770                                info: new Uint8Array()
    771                            },
    772                            usages: ["encrypt", "decrypt"]
    773                        };
    774                        break;
    775                    default:
    776                        return {
    777                            algorithm: {
    778                                name: "HKDF"
    779                            },
    780                            usages: []
    781                        };
    782                }
    783                break;
    784            case "PBKDF2":
    785                switch(operation.toLowerCase())
    786                {
    787                    case "derivekey":
    788                        result = {
    789                            algorithm: {
    790                                name: "PBKDF2",
    791                                hash: { name: "SHA-256" },
    792                                salt: new Uint8Array(),
    793                                iterations: 1000
    794                            },
    795                            usages: ["encrypt", "decrypt"]
    796                        };
    797                        break;
    798                    default:
    799                        return {
    800                            algorithm: {
    801                                name: "PBKDF2"
    802                            },
    803                            usages: []
    804                        };
    805                }
    806                break;
    807            default:
    808        }
    809 
    810        return result;
    811    };
    812    //**************************************************************************************
    813    in_window.org.pkijs.getOIDByAlgorithm =
    814    function(algorithm)
    815    {
    816        /// <summary>Get OID for each specific WebCrypto algorithm</summary>
    817        /// <param name="algorithm" type="Object">WebCrypto algorithm</param>
    818 
    819        var result = "";
    820 
    821        switch(algorithm.name.toUpperCase())
    822        {
    823            case "RSASSA-PKCS1-V1_5":
    824                switch(algorithm.hash.name.toUpperCase())
    825                {
    826                    case "SHA-1":
    827                        result = "1.2.840.113549.1.1.5";
    828                        break;
    829                    case "SHA-256":
    830                        result = "1.2.840.113549.1.1.11";
    831                        break;
    832                    case "SHA-384":
    833                        result = "1.2.840.113549.1.1.12";
    834                        break;
    835                    case "SHA-512":
    836                        result = "1.2.840.113549.1.1.13";
    837                        break;
    838                    default:
    839                }
    840                break;
    841            case "RSA-PSS":
    842                result = "1.2.840.113549.1.1.10";
    843                break;
    844            case "RSA-OAEP":
    845                result = "1.2.840.113549.1.1.7";
    846                break;
    847            case "ECDSA":
    848                switch(algorithm.hash.name.toUpperCase())
    849                {
    850                    case "SHA-1":
    851                        result = "1.2.840.10045.4.1";
    852                        break;
    853                    case "SHA-256":
    854                        result = "1.2.840.10045.4.3.2";
    855                        break;
    856                    case "SHA-384":
    857                        result = "1.2.840.10045.4.3.3";
    858                        break;
    859                    case "SHA-512":
    860                        result = "1.2.840.10045.4.3.4";
    861                        break;
    862                    default:
    863                }
    864                break;
    865            case "ECDH":
    866                switch(algorithm.kdf.toUpperCase()) // Non-standard addition - hash algorithm of KDF function
    867                {
    868                    case "SHA-1":
    869                        result = "1.3.133.16.840.63.0.2"; // dhSinglePass-stdDH-sha1kdf-scheme
    870                        break;
    871                    case "SHA-256":
    872                        result = "1.3.132.1.11.1"; // dhSinglePass-stdDH-sha256kdf-scheme 
    873                        break;
    874                    case "SHA-384":
    875                        result = "1.3.132.1.11.2"; // dhSinglePass-stdDH-sha384kdf-scheme
    876                        break;
    877                    case "SHA-512":
    878                        result = "1.3.132.1.11.3"; // dhSinglePass-stdDH-sha512kdf-scheme
    879                        break;
    880                    default:
    881                }
    882                break;
    883            case "AES-CTR":
    884                break;
    885            case "AES-CBC":
    886                switch(algorithm.length)
    887                {
    888                    case 128:
    889                        result = "2.16.840.1.101.3.4.1.2";
    890                        break;
    891                    case 192:
    892                        result = "2.16.840.1.101.3.4.1.22";
    893                        break;
    894                    case 256:
    895                        result = "2.16.840.1.101.3.4.1.42";
    896                        break;
    897                    default:
    898                }
    899                break;
    900            case "AES-CMAC":
    901                break;
    902            case "AES-GCM":
    903                switch(algorithm.length)
    904                {
    905                    case 128:
    906                        result = "2.16.840.1.101.3.4.1.6";
    907                        break;
    908                    case 192:
    909                        result = "2.16.840.1.101.3.4.1.26";
    910                        break;
    911                    case 256:
    912                        result = "2.16.840.1.101.3.4.1.46";
    913                        break;
    914                    default:
    915                }
    916                break;
    917            case "AES-CFB":
    918                switch(algorithm.length)
    919                {
    920                    case 128:
    921                        result = "2.16.840.1.101.3.4.1.4";
    922                        break;
    923                    case 192:
    924                        result = "2.16.840.1.101.3.4.1.24";
    925                        break;
    926                    case 256:
    927                        result = "2.16.840.1.101.3.4.1.44";
    928                        break;
    929                    default:
    930                }
    931                break;
    932            case "AES-KW":
    933                switch(algorithm.length)
    934                {
    935                    case 128:
    936                        result = "2.16.840.1.101.3.4.1.5";
    937                        break;
    938                    case 192:
    939                        result = "2.16.840.1.101.3.4.1.25";
    940                        break;
    941                    case 256:
    942                        result = "2.16.840.1.101.3.4.1.45";
    943                        break;
    944                    default:
    945                }
    946                break;
    947            case "HMAC":
    948                switch(algorithm.hash.name.toUpperCase())
    949                {
    950                    case "SHA-1":
    951                        result = "1.2.840.113549.2.7";
    952                        break;
    953                    case "SHA-256":
    954                        result = "1.2.840.113549.2.9";
    955                        break;
    956                    case "SHA-384":
    957                        result = "1.2.840.113549.2.10";
    958                        break;
    959                    case "SHA-512":
    960                        result = "1.2.840.113549.2.11";
    961                        break;
    962                    default:
    963                }
    964                break;
    965            case "DH":
    966                result = "1.2.840.113549.1.9.16.3.5";
    967                break;
    968            case "SHA-1":
    969                result = "1.3.14.3.2.26";
    970                break;
    971            case "SHA-256":
    972                result = "2.16.840.1.101.3.4.2.1";
    973                break;
    974            case "SHA-384":
    975                result = "2.16.840.1.101.3.4.2.2";
    976                break;
    977            case "SHA-512":
    978                result = "2.16.840.1.101.3.4.2.3";
    979                break;
    980            case "CONCAT":
    981                break;
    982            case "HKDF":
    983                break;
    984            case "PBKDF2":
    985                result = "1.2.840.113549.1.5.12";
    986                break;
    987            // #region Special case - OIDs for ECC curves 
    988            case "P-256":
    989                result = "1.2.840.10045.3.1.7";
    990                break;
    991            case "P-384":
    992                result = "1.3.132.0.34";
    993                break;
    994            case "P-521":
    995                result = "1.3.132.0.35";
    996                break;
    997            // #endregion 
    998 
    999            default:
   1000        }
   1001 
   1002        return result;
   1003    };
   1004    //**************************************************************************************
   1005    in_window.org.pkijs.getAlgorithmByOID =
   1006    function(oid)
   1007    {
   1008        /// <summary>Get WebCrypto algorithm by wel-known OID</summary>
   1009        /// <param name="oid" type="String">Wel-known OID to search for</param>
   1010 
   1011        var result = {};
   1012 
   1013        switch(oid)
   1014        {
   1015            case "1.2.840.113549.1.1.5":
   1016                result = {
   1017                    name: "RSASSA-PKCS1-v1_5",
   1018                    hash: {
   1019                        name: "SHA-1"
   1020                    }
   1021                };
   1022                break;
   1023            case "1.2.840.113549.1.1.11":
   1024                result = {
   1025                    name: "RSASSA-PKCS1-v1_5",
   1026                    hash: {
   1027                        name: "SHA-256"
   1028                    }
   1029                };
   1030                break;
   1031            case "1.2.840.113549.1.1.12":
   1032                result = {
   1033                    name: "RSASSA-PKCS1-v1_5",
   1034                    hash: {
   1035                        name: "SHA-384"
   1036                    }
   1037                };
   1038                break;
   1039            case "1.2.840.113549.1.1.13":
   1040                result = {
   1041                    name: "RSASSA-PKCS1-v1_5",
   1042                    hash: {
   1043                        name: "SHA-512"
   1044                    }
   1045                };
   1046                break;
   1047            case "1.2.840.113549.1.1.10":
   1048                result = {
   1049                    name: "RSA-PSS"
   1050                };
   1051                break;
   1052            case "1.2.840.113549.1.1.7":
   1053                result = {
   1054                    name: "RSA-OAEP"
   1055                };
   1056                break;
   1057            case "1.2.840.10045.4.1":
   1058                result = {
   1059                    name: "ECDSA",
   1060                    hash: {
   1061                        name: "SHA-1"
   1062                    }
   1063                };
   1064                break;
   1065            case "1.2.840.10045.4.3.2":
   1066                result = {
   1067                    name: "ECDSA",
   1068                    hash: {
   1069                        name: "SHA-256"
   1070                    }
   1071                };
   1072                break;
   1073            case "1.2.840.10045.4.3.3":
   1074                result = {
   1075                    name: "ECDSA",
   1076                    hash: {
   1077                        name: "SHA-384"
   1078                    }
   1079                };
   1080                break;
   1081            case "1.2.840.10045.4.3.4":
   1082                result = {
   1083                    name: "ECDSA",
   1084                    hash: {
   1085                        name: "SHA-512"
   1086                    }
   1087                };
   1088                break;
   1089            case "1.3.133.16.840.63.0.2":
   1090                result = {
   1091                    name: "ECDH",
   1092                    kdf: "SHA-1"
   1093                };
   1094                break;
   1095            case "1.3.132.1.11.1":
   1096                result = {
   1097                    name: "ECDH",
   1098                    kdf: "SHA-256"
   1099                };
   1100                break;
   1101            case "1.3.132.1.11.2":
   1102                result = {
   1103                    name: "ECDH",
   1104                    kdf: "SHA-384"
   1105                };
   1106                break;
   1107            case "1.3.132.1.11.3":
   1108                result = {
   1109                    name: "ECDH",
   1110                    kdf: "SHA-512"
   1111                };
   1112                break;
   1113            case "2.16.840.1.101.3.4.1.2":
   1114                result = {
   1115                    name: "AES-CBC",
   1116                    length: 128
   1117                };
   1118                break;
   1119            case "2.16.840.1.101.3.4.1.22":
   1120                result = {
   1121                    name: "AES-CBC",
   1122                    length: 192
   1123                };
   1124                break;
   1125            case "2.16.840.1.101.3.4.1.42":
   1126                result = {
   1127                    name: "AES-CBC",
   1128                    length: 256
   1129                };
   1130                break;
   1131            case "2.16.840.1.101.3.4.1.6":
   1132                result = {
   1133                    name: "AES-GCM",
   1134                    length: 128
   1135                };
   1136                break;
   1137            case "2.16.840.1.101.3.4.1.26":
   1138                result = {
   1139                    name: "AES-GCM",
   1140                    length: 192
   1141                };
   1142                break;
   1143            case "2.16.840.1.101.3.4.1.46":
   1144                result = {
   1145                    name: "AES-GCM",
   1146                    length: 256
   1147                };
   1148                break;
   1149            case "2.16.840.1.101.3.4.1.4":
   1150                result = {
   1151                    name: "AES-CFB",
   1152                    length: 128
   1153                };
   1154                break;
   1155            case "2.16.840.1.101.3.4.1.24":
   1156                result = {
   1157                    name: "AES-CFB",
   1158                    length: 192
   1159                };
   1160                break;
   1161            case "2.16.840.1.101.3.4.1.44":
   1162                result = {
   1163                    name: "AES-CFB",
   1164                    length: 256
   1165                };
   1166                break;
   1167            case "2.16.840.1.101.3.4.1.5":
   1168                result = {
   1169                    name: "AES-KW",
   1170                    length: 128
   1171                };
   1172                break;
   1173            case "2.16.840.1.101.3.4.1.25":
   1174                result = {
   1175                    name: "AES-KW",
   1176                    length: 192
   1177                };
   1178                break;
   1179            case "2.16.840.1.101.3.4.1.45":
   1180                result = {
   1181                    name: "AES-KW",
   1182                    length: 256
   1183                };
   1184                break;
   1185            case "1.2.840.113549.2.7":
   1186                result = {
   1187                    name: "HMAC",
   1188                    hash: {
   1189                        name: "SHA-1"
   1190                    }
   1191                };
   1192                break;
   1193            case "1.2.840.113549.2.9":
   1194                result = {
   1195                    name: "HMAC",
   1196                    hash: {
   1197                        name: "SHA-256"
   1198                    }
   1199                };
   1200                break;
   1201            case "1.2.840.113549.2.10":
   1202                result = {
   1203                    name: "HMAC",
   1204                    hash: {
   1205                        name: "SHA-384"
   1206                    }
   1207                };
   1208                break;
   1209            case "1.2.840.113549.2.11":
   1210                result = {
   1211                    name: "HMAC",
   1212                    hash: {
   1213                        name: "SHA-512"
   1214                    }
   1215                };
   1216                break;
   1217            case "1.2.840.113549.1.9.16.3.5":
   1218                result = {
   1219                    name: "DH"
   1220                };
   1221                break;
   1222            case "1.3.14.3.2.26":
   1223                result = {
   1224                    name: "SHA-1"
   1225                };
   1226                break;
   1227            case "2.16.840.1.101.3.4.2.1":
   1228                result = {
   1229                    name: "SHA-256"
   1230                };
   1231                break;
   1232            case "2.16.840.1.101.3.4.2.2":
   1233                result = {
   1234                    name: "SHA-384"
   1235                };
   1236                break;
   1237            case "2.16.840.1.101.3.4.2.3":
   1238                result = {
   1239                    name: "SHA-512"
   1240                };
   1241                break;
   1242            case "1.2.840.113549.1.5.12":
   1243                result = {
   1244                    name: "PBKDF2"
   1245                };
   1246                break;
   1247            // #region Special case - OIDs for ECC curves 
   1248            case "1.2.840.10045.3.1.7":
   1249                result = {
   1250                    name: "P-256"
   1251                };
   1252                break;
   1253            case "1.3.132.0.34":
   1254                result = {
   1255                    name: "P-384"
   1256                };
   1257                break;
   1258            case "1.3.132.0.35":
   1259                result = {
   1260                    name: "P-521"
   1261                };
   1262                break;
   1263            // #endregion 
   1264 
   1265            default:
   1266        }
   1267 
   1268        return result;
   1269    };
   1270    //**************************************************************************************
   1271    in_window.org.pkijs.getHashAlgorithm =
   1272    function(signatureAlgorithm)
   1273    {
   1274        /// <summary>Getting hash algorithm by signature algorithm</summary>
   1275        /// <param name="signatureAlgorithm" type="in_window.org.pkijs.simpl.ALGORITHM_IDENTIFIER">Signature algorithm</param>
   1276 
   1277        var result = "";
   1278 
   1279        switch(signatureAlgorithm.algorithm_id)
   1280        {
   1281            case "1.2.840.10045.4.1": // ecdsa-with-SHA1
   1282            case "1.2.840.113549.1.1.5":
   1283                result = "SHA-1";
   1284                break;
   1285            case "1.2.840.10045.4.3.2": // ecdsa-with-SHA256
   1286            case "1.2.840.113549.1.1.11":
   1287                result = "SHA-256";
   1288                break;
   1289            case "1.2.840.10045.4.3.3": // ecdsa-with-SHA384
   1290            case "1.2.840.113549.1.1.12":
   1291                result = "SHA-384";
   1292                break;
   1293            case "1.2.840.10045.4.3.4": // ecdsa-with-SHA512
   1294            case "1.2.840.113549.1.1.13":
   1295                result = "SHA-512";
   1296                break;
   1297            case "1.2.840.113549.1.1.10": // RSA-PSS
   1298                {
   1299                    var params;
   1300 
   1301                    try
   1302                    {
   1303                        params = new in_window.org.pkijs.simpl.x509.RSASSA_PSS_params({ schema: signatureAlgorithm.algorithm_params });
   1304                        if("hashAlgorithm" in params)
   1305                        {
   1306                            var algorithm = in_window.org.pkijs.getAlgorithmByOID(params.hashAlgorithm.algorithm_id);
   1307                            if(("name" in algorithm) === false)
   1308                                return "";
   1309 
   1310                            result = algorithm.name;
   1311                        }
   1312                        else
   1313                            result = "SHA-1";
   1314                    }
   1315                    catch(ex)
   1316                    {
   1317                    }
   1318                }
   1319                break;
   1320            default:
   1321        }
   1322 
   1323        return result;
   1324    };
   1325    //**************************************************************************************
   1326    in_window.org.pkijs.createCMSECDSASignature =
   1327    function(signatureBuffer)
   1328    {
   1329        /// <summary>Create CMS ECDSA signature from WebCrypto ECDSA signature</summary>
   1330        /// <param name="signatureBuffer" type="ArrayBuffer">WebCrypto result of "sign" function</param>
   1331 
   1332        // #region Initial check for correct length 
   1333        if((signatureBuffer.byteLength % 2) != 0)
   1334            return new ArrayBuffer(0);
   1335        // #endregion 
   1336 
   1337        // #region Initial variables 
   1338        var i = 0;
   1339        var length = signatureBuffer.byteLength / 2; // There are two equal parts inside incoming ArrayBuffer
   1340 
   1341        var signatureView = new Uint8Array(signatureBuffer);
   1342 
   1343        var r_buffer = new ArrayBuffer(length);
   1344        var r_view = new Uint8Array(r_buffer);
   1345        var r_corrected_buffer;
   1346        var r_corrected_view;
   1347 
   1348        var s_buffer = new ArrayBuffer(length);
   1349        var s_view = new Uint8Array(s_buffer);
   1350        var s_corrected_buffer;
   1351        var s_corrected_view;
   1352        // #endregion   
   1353 
   1354        // #region Get "r" part of ECDSA signature 
   1355        for(; i < length; i++)
   1356            r_view[i] = signatureView[i];
   1357 
   1358        if(r_view[0] & 0x80)
   1359        {
   1360            r_corrected_buffer = new ArrayBuffer(length + 1);
   1361            r_corrected_view = new Uint8Array(r_corrected_buffer);
   1362 
   1363            r_corrected_view[0] = 0x00;
   1364 
   1365            for(var j = 0; j < length; j++)
   1366                r_corrected_view[j + 1] = r_view[j];
   1367        }
   1368        else
   1369        {
   1370            r_corrected_buffer = r_buffer;
   1371            r_corrected_view = r_view;
   1372        }
   1373        // #endregion 
   1374 
   1375        // #region Get "s" part of ECDSA signature 
   1376        for(; i < signatureBuffer.byteLength; i++)
   1377            s_view[i - length] = signatureView[i];
   1378 
   1379 
   1380        if(s_view[0] & 0x80)
   1381        {
   1382            s_corrected_buffer = new ArrayBuffer(length + 1);
   1383            s_corrected_view = new Uint8Array(s_corrected_buffer);
   1384 
   1385            s_corrected_view[0] = 0x00;
   1386 
   1387            for(var j = 0; j < length; j++)
   1388                s_corrected_view[j + 1] = s_view[j];
   1389        }
   1390        else
   1391        {
   1392            s_corrected_buffer = s_buffer;
   1393            s_corrected_view = s_view;
   1394        }
   1395        // #endregion 
   1396 
   1397        // #region Create ASN.1 structure of CMS ECDSA signature 
   1398        var r_integer = new in_window.org.pkijs.asn1.INTEGER();
   1399        r_integer.value_block.is_hex_only = true;
   1400        r_integer.value_block.value_hex = in_window.org.pkijs.copyBuffer(r_corrected_buffer);
   1401 
   1402        var s_integer = new in_window.org.pkijs.asn1.INTEGER();
   1403        s_integer.value_block.is_hex_only = true;
   1404        s_integer.value_block.value_hex = in_window.org.pkijs.copyBuffer(s_corrected_buffer);
   1405 
   1406        var asn1 = new in_window.org.pkijs.asn1.SEQUENCE({
   1407            value: [
   1408                r_integer,
   1409                s_integer
   1410            ]
   1411        });
   1412        // #endregion   
   1413 
   1414        return asn1.toBER(false);
   1415    };
   1416    //**************************************************************************************
   1417    in_window.org.pkijs.createECDSASignatureFromCMS =
   1418    function(cmsSignature)
   1419    {
   1420        /// <summary>Create a single ArrayBuffer from CMS ECDSA signature</summary>
   1421        /// <param name="cmsSignature" type="in_window.org.pkijs.asn1.SEQUENCE">ASN.1 SEQUENCE contains CMS ECDSA signature</param>
   1422 
   1423        // #region Initial variables 
   1424        var length = 0;
   1425 
   1426        var r_start = 0;
   1427        var s_start = 0;
   1428 
   1429        var r_length = cmsSignature.value_block.value[0].value_block.value_hex.byteLength;
   1430        var s_length = cmsSignature.value_block.value[1].value_block.value_hex.byteLength;
   1431        // #endregion 
   1432 
   1433        // #region Get length of final "ArrayBuffer" 
   1434        var r_view = new Uint8Array(cmsSignature.value_block.value[0].value_block.value_hex);
   1435        if((r_view[0] === 0x00) && (r_view[1] & 0x80))
   1436        {
   1437            length = r_length - 1;
   1438            r_start = 1;
   1439        }
   1440        else
   1441            length = r_length;
   1442 
   1443        var s_view = new Uint8Array(cmsSignature.value_block.value[1].value_block.value_hex);
   1444        if((s_view[0] === 0x00) && (s_view[1] & 0x80))
   1445        {
   1446            length += s_length - 1;
   1447            s_start = 1;
   1448        }
   1449        else
   1450            length += s_length;
   1451        // #endregion 
   1452 
   1453        // #region Copy values from CMS ECDSA signature 
   1454        var result = new ArrayBuffer(length);
   1455        var result_view = new Uint8Array(result);
   1456 
   1457        for(var i = r_start; i < r_length; i++)
   1458            result_view[i - r_start] = r_view[i];
   1459 
   1460        for(var i = s_start; i < s_length; i++)
   1461            result_view[i - s_start + r_length - r_start] = s_view[i];
   1462        // #endregion 
   1463 
   1464        return result;
   1465    };
   1466    //**************************************************************************************
   1467    in_window.org.pkijs.getEncryptionAlgorithm =
   1468    function(algorithm)
   1469    {
   1470        /// <summary>Get encryption algorithm OID by WebCrypto algorithm's object</summary>
   1471        /// <param name="algorithm" type="WebCryptoAlgorithm">WebCrypto algorithm object</param>
   1472 
   1473        var result = "";
   1474 
   1475        switch(algorithm.name.toUpperCase())
   1476        {
   1477            case "AES-CBC":
   1478                switch(algorithm.length)
   1479                {
   1480                    case 128:
   1481                        result = "2.16.840.1.101.3.4.1.2";
   1482                        break;
   1483                    case 192:
   1484                        result = "2.16.840.1.101.3.4.1.22";
   1485                        break;
   1486                    case 256:
   1487                        result = "2.16.840.1.101.3.4.1.42";
   1488                        break;
   1489                    default:
   1490                }
   1491                break;
   1492            case "AES-GCM":
   1493                switch(algorithm.length)
   1494                {
   1495                    case 128:
   1496                        result = "2.16.840.1.101.3.4.1.6";
   1497                        break;
   1498                    case 192:
   1499                        result = "2.16.840.1.101.3.4.1.26";
   1500                        break;
   1501                    case 256:
   1502                        result = "2.16.840.1.101.3.4.1.46";
   1503                        break;
   1504                    default:
   1505                }
   1506                break;
   1507            default:
   1508        }
   1509 
   1510        return result;
   1511    };
   1512    //**************************************************************************************
   1513    in_window.org.pkijs.getAlgorithmByEncryptionOID =
   1514    function(oid)
   1515    {
   1516        /// <summary>Get encryption algorithm name by OID</summary>
   1517        /// <param name="oid" type="String">OID of encryption algorithm</param>
   1518 
   1519        var result = "";
   1520 
   1521        switch(oid)
   1522        {
   1523            case "2.16.840.1.101.3.4.1.2":
   1524            case "2.16.840.1.101.3.4.1.22":
   1525            case "2.16.840.1.101.3.4.1.42":
   1526                result = "AES-CBC";
   1527                break;
   1528            case "2.16.840.1.101.3.4.1.6":
   1529            case "2.16.840.1.101.3.4.1.26":
   1530            case "2.16.840.1.101.3.4.1.46":
   1531                result = "AES-GCM";
   1532                break;
   1533            default:
   1534        }
   1535 
   1536        return result;
   1537    };
   1538    //**************************************************************************************
   1539    // #endregion 
   1540    //**************************************************************************************
   1541 }
   1542 )(typeof exports !== "undefined" ? exports : window);