UNPKG

cyberchef

Version:

The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.

1,514 lines (1,338 loc) 76.5 kB
/** * GOST 28147-89/GOST R 34.12-2015/GOST R 32.13-2015 Encryption Algorithm * 1.76 * 2014-2016, Rudolf Nickolaev. All rights reserved. * * Exported for CyberChef by mshwed [m@ttshwed.com] */ /* * 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. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ import GostRandom from './gostRandom.mjs'; import crypto from 'crypto' /* * Initial parameters and common algortithms of GOST 28147-89 * * http://tools.ietf.org/html/rfc5830 * */ // <editor-fold defaultstate="collapsed"> var root = {}; var rootCrypto = crypto; var CryptoOperationData = ArrayBuffer; var SyntaxError = Error, DataError = Error, NotSupportedError = Error; /* * Check supported * This implementation support only Little Endian arhitecture */ var littleEndian = (function () { var buffer = new CryptoOperationData(2); new DataView(buffer).setInt16(0, 256, true); return new Int16Array(buffer)[0] === 256; })(); // Default initial vector var defaultIV = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0]); // Predefined sBox collection var sBoxes = { 'E-TEST': [ 0x4, 0x2, 0xF, 0x5, 0x9, 0x1, 0x0, 0x8, 0xE, 0x3, 0xB, 0xC, 0xD, 0x7, 0xA, 0x6, 0xC, 0x9, 0xF, 0xE, 0x8, 0x1, 0x3, 0xA, 0x2, 0x7, 0x4, 0xD, 0x6, 0x0, 0xB, 0x5, 0xD, 0x8, 0xE, 0xC, 0x7, 0x3, 0x9, 0xA, 0x1, 0x5, 0x2, 0x4, 0x6, 0xF, 0x0, 0xB, 0xE, 0x9, 0xB, 0x2, 0x5, 0xF, 0x7, 0x1, 0x0, 0xD, 0xC, 0x6, 0xA, 0x4, 0x3, 0x8, 0x3, 0xE, 0x5, 0x9, 0x6, 0x8, 0x0, 0xD, 0xA, 0xB, 0x7, 0xC, 0x2, 0x1, 0xF, 0x4, 0x8, 0xF, 0x6, 0xB, 0x1, 0x9, 0xC, 0x5, 0xD, 0x3, 0x7, 0xA, 0x0, 0xE, 0x2, 0x4, 0x9, 0xB, 0xC, 0x0, 0x3, 0x6, 0x7, 0x5, 0x4, 0x8, 0xE, 0xF, 0x1, 0xA, 0x2, 0xD, 0xC, 0x6, 0x5, 0x2, 0xB, 0x0, 0x9, 0xD, 0x3, 0xE, 0x7, 0xA, 0xF, 0x4, 0x1, 0x8 ], 'E-A': [ 0x9, 0x6, 0x3, 0x2, 0x8, 0xB, 0x1, 0x7, 0xA, 0x4, 0xE, 0xF, 0xC, 0x0, 0xD, 0x5, 0x3, 0x7, 0xE, 0x9, 0x8, 0xA, 0xF, 0x0, 0x5, 0x2, 0x6, 0xC, 0xB, 0x4, 0xD, 0x1, 0xE, 0x4, 0x6, 0x2, 0xB, 0x3, 0xD, 0x8, 0xC, 0xF, 0x5, 0xA, 0x0, 0x7, 0x1, 0x9, 0xE, 0x7, 0xA, 0xC, 0xD, 0x1, 0x3, 0x9, 0x0, 0x2, 0xB, 0x4, 0xF, 0x8, 0x5, 0x6, 0xB, 0x5, 0x1, 0x9, 0x8, 0xD, 0xF, 0x0, 0xE, 0x4, 0x2, 0x3, 0xC, 0x7, 0xA, 0x6, 0x3, 0xA, 0xD, 0xC, 0x1, 0x2, 0x0, 0xB, 0x7, 0x5, 0x9, 0x4, 0x8, 0xF, 0xE, 0x6, 0x1, 0xD, 0x2, 0x9, 0x7, 0xA, 0x6, 0x0, 0x8, 0xC, 0x4, 0x5, 0xF, 0x3, 0xB, 0xE, 0xB, 0xA, 0xF, 0x5, 0x0, 0xC, 0xE, 0x8, 0x6, 0x2, 0x3, 0x9, 0x1, 0x7, 0xD, 0x4 ], 'E-B': [ 0x8, 0x4, 0xB, 0x1, 0x3, 0x5, 0x0, 0x9, 0x2, 0xE, 0xA, 0xC, 0xD, 0x6, 0x7, 0xF, 0x0, 0x1, 0x2, 0xA, 0x4, 0xD, 0x5, 0xC, 0x9, 0x7, 0x3, 0xF, 0xB, 0x8, 0x6, 0xE, 0xE, 0xC, 0x0, 0xA, 0x9, 0x2, 0xD, 0xB, 0x7, 0x5, 0x8, 0xF, 0x3, 0x6, 0x1, 0x4, 0x7, 0x5, 0x0, 0xD, 0xB, 0x6, 0x1, 0x2, 0x3, 0xA, 0xC, 0xF, 0x4, 0xE, 0x9, 0x8, 0x2, 0x7, 0xC, 0xF, 0x9, 0x5, 0xA, 0xB, 0x1, 0x4, 0x0, 0xD, 0x6, 0x8, 0xE, 0x3, 0x8, 0x3, 0x2, 0x6, 0x4, 0xD, 0xE, 0xB, 0xC, 0x1, 0x7, 0xF, 0xA, 0x0, 0x9, 0x5, 0x5, 0x2, 0xA, 0xB, 0x9, 0x1, 0xC, 0x3, 0x7, 0x4, 0xD, 0x0, 0x6, 0xF, 0x8, 0xE, 0x0, 0x4, 0xB, 0xE, 0x8, 0x3, 0x7, 0x1, 0xA, 0x2, 0x9, 0x6, 0xF, 0xD, 0x5, 0xC ], 'E-C': [ 0x1, 0xB, 0xC, 0x2, 0x9, 0xD, 0x0, 0xF, 0x4, 0x5, 0x8, 0xE, 0xA, 0x7, 0x6, 0x3, 0x0, 0x1, 0x7, 0xD, 0xB, 0x4, 0x5, 0x2, 0x8, 0xE, 0xF, 0xC, 0x9, 0xA, 0x6, 0x3, 0x8, 0x2, 0x5, 0x0, 0x4, 0x9, 0xF, 0xA, 0x3, 0x7, 0xC, 0xD, 0x6, 0xE, 0x1, 0xB, 0x3, 0x6, 0x0, 0x1, 0x5, 0xD, 0xA, 0x8, 0xB, 0x2, 0x9, 0x7, 0xE, 0xF, 0xC, 0x4, 0x8, 0xD, 0xB, 0x0, 0x4, 0x5, 0x1, 0x2, 0x9, 0x3, 0xC, 0xE, 0x6, 0xF, 0xA, 0x7, 0xC, 0x9, 0xB, 0x1, 0x8, 0xE, 0x2, 0x4, 0x7, 0x3, 0x6, 0x5, 0xA, 0x0, 0xF, 0xD, 0xA, 0x9, 0x6, 0x8, 0xD, 0xE, 0x2, 0x0, 0xF, 0x3, 0x5, 0xB, 0x4, 0x1, 0xC, 0x7, 0x7, 0x4, 0x0, 0x5, 0xA, 0x2, 0xF, 0xE, 0xC, 0x6, 0x1, 0xB, 0xD, 0x9, 0x3, 0x8 ], 'E-D': [ 0xF, 0xC, 0x2, 0xA, 0x6, 0x4, 0x5, 0x0, 0x7, 0x9, 0xE, 0xD, 0x1, 0xB, 0x8, 0x3, 0xB, 0x6, 0x3, 0x4, 0xC, 0xF, 0xE, 0x2, 0x7, 0xD, 0x8, 0x0, 0x5, 0xA, 0x9, 0x1, 0x1, 0xC, 0xB, 0x0, 0xF, 0xE, 0x6, 0x5, 0xA, 0xD, 0x4, 0x8, 0x9, 0x3, 0x7, 0x2, 0x1, 0x5, 0xE, 0xC, 0xA, 0x7, 0x0, 0xD, 0x6, 0x2, 0xB, 0x4, 0x9, 0x3, 0xF, 0x8, 0x0, 0xC, 0x8, 0x9, 0xD, 0x2, 0xA, 0xB, 0x7, 0x3, 0x6, 0x5, 0x4, 0xE, 0xF, 0x1, 0x8, 0x0, 0xF, 0x3, 0x2, 0x5, 0xE, 0xB, 0x1, 0xA, 0x4, 0x7, 0xC, 0x9, 0xD, 0x6, 0x3, 0x0, 0x6, 0xF, 0x1, 0xE, 0x9, 0x2, 0xD, 0x8, 0xC, 0x4, 0xB, 0xA, 0x5, 0x7, 0x1, 0xA, 0x6, 0x8, 0xF, 0xB, 0x0, 0x4, 0xC, 0x3, 0x5, 0x9, 0x7, 0xD, 0x2, 0xE ], 'E-SC': [ 0x3, 0x6, 0x1, 0x0, 0x5, 0x7, 0xd, 0x9, 0x4, 0xb, 0x8, 0xc, 0xe, 0xf, 0x2, 0xa, 0x7, 0x1, 0x5, 0x2, 0x8, 0xb, 0x9, 0xc, 0xd, 0x0, 0x3, 0xa, 0xf, 0xe, 0x4, 0x6, 0xf, 0x1, 0x4, 0x6, 0xc, 0x8, 0x9, 0x2, 0xe, 0x3, 0x7, 0xa, 0xb, 0xd, 0x5, 0x0, 0x3, 0x4, 0xf, 0xc, 0x5, 0x9, 0xe, 0x0, 0x6, 0x8, 0x7, 0xa, 0x1, 0xb, 0xd, 0x2, 0x6, 0x9, 0x0, 0x7, 0xb, 0x8, 0x4, 0xc, 0x2, 0xe, 0xa, 0xf, 0x1, 0xd, 0x5, 0x3, 0x6, 0x1, 0x2, 0xf, 0x0, 0xb, 0x9, 0xc, 0x7, 0xd, 0xa, 0x5, 0x8, 0x4, 0xe, 0x3, 0x0, 0x2, 0xe, 0xc, 0x9, 0x1, 0x4, 0x7, 0x3, 0xf, 0x6, 0x8, 0xa, 0xd, 0xb, 0x5, 0x5, 0x2, 0xb, 0x8, 0x4, 0xc, 0x7, 0x1, 0xa, 0x6, 0xe, 0x0, 0x9, 0x3, 0xd, 0xf ], 'E-Z': [// This is default S-box in according to draft of new standard 0xc, 0x4, 0x6, 0x2, 0xa, 0x5, 0xb, 0x9, 0xe, 0x8, 0xd, 0x7, 0x0, 0x3, 0xf, 0x1, 0x6, 0x8, 0x2, 0x3, 0x9, 0xa, 0x5, 0xc, 0x1, 0xe, 0x4, 0x7, 0xb, 0xd, 0x0, 0xf, 0xb, 0x3, 0x5, 0x8, 0x2, 0xf, 0xa, 0xd, 0xe, 0x1, 0x7, 0x4, 0xc, 0x9, 0x6, 0x0, 0xc, 0x8, 0x2, 0x1, 0xd, 0x4, 0xf, 0x6, 0x7, 0x0, 0xa, 0x5, 0x3, 0xe, 0x9, 0xb, 0x7, 0xf, 0x5, 0xa, 0x8, 0x1, 0x6, 0xd, 0x0, 0x9, 0x3, 0xe, 0xb, 0x4, 0x2, 0xc, 0x5, 0xd, 0xf, 0x6, 0x9, 0x2, 0xc, 0xa, 0xb, 0x7, 0x8, 0x1, 0x4, 0x3, 0xe, 0x0, 0x8, 0xe, 0x2, 0x5, 0x6, 0x9, 0x1, 0xc, 0xf, 0x4, 0xb, 0x0, 0xd, 0xa, 0x3, 0x7, 0x1, 0x7, 0xe, 0xd, 0x0, 0x5, 0x8, 0x3, 0x4, 0xf, 0xa, 0x6, 0x9, 0xc, 0xb, 0x2 ], //S-box for digest 'D-TEST': [ 0x4, 0xA, 0x9, 0x2, 0xD, 0x8, 0x0, 0xE, 0x6, 0xB, 0x1, 0xC, 0x7, 0xF, 0x5, 0x3, 0xE, 0xB, 0x4, 0xC, 0x6, 0xD, 0xF, 0xA, 0x2, 0x3, 0x8, 0x1, 0x0, 0x7, 0x5, 0x9, 0x5, 0x8, 0x1, 0xD, 0xA, 0x3, 0x4, 0x2, 0xE, 0xF, 0xC, 0x7, 0x6, 0x0, 0x9, 0xB, 0x7, 0xD, 0xA, 0x1, 0x0, 0x8, 0x9, 0xF, 0xE, 0x4, 0x6, 0xC, 0xB, 0x2, 0x5, 0x3, 0x6, 0xC, 0x7, 0x1, 0x5, 0xF, 0xD, 0x8, 0x4, 0xA, 0x9, 0xE, 0x0, 0x3, 0xB, 0x2, 0x4, 0xB, 0xA, 0x0, 0x7, 0x2, 0x1, 0xD, 0x3, 0x6, 0x8, 0x5, 0x9, 0xC, 0xF, 0xE, 0xD, 0xB, 0x4, 0x1, 0x3, 0xF, 0x5, 0x9, 0x0, 0xA, 0xE, 0x7, 0x6, 0x8, 0x2, 0xC, 0x1, 0xF, 0xD, 0x0, 0x5, 0x7, 0xA, 0x4, 0x9, 0x2, 0x3, 0xE, 0x6, 0xB, 0x8, 0xC ], 'D-A': [ 0xA, 0x4, 0x5, 0x6, 0x8, 0x1, 0x3, 0x7, 0xD, 0xC, 0xE, 0x0, 0x9, 0x2, 0xB, 0xF, 0x5, 0xF, 0x4, 0x0, 0x2, 0xD, 0xB, 0x9, 0x1, 0x7, 0x6, 0x3, 0xC, 0xE, 0xA, 0x8, 0x7, 0xF, 0xC, 0xE, 0x9, 0x4, 0x1, 0x0, 0x3, 0xB, 0x5, 0x2, 0x6, 0xA, 0x8, 0xD, 0x4, 0xA, 0x7, 0xC, 0x0, 0xF, 0x2, 0x8, 0xE, 0x1, 0x6, 0x5, 0xD, 0xB, 0x9, 0x3, 0x7, 0x6, 0x4, 0xB, 0x9, 0xC, 0x2, 0xA, 0x1, 0x8, 0x0, 0xE, 0xF, 0xD, 0x3, 0x5, 0x7, 0x6, 0x2, 0x4, 0xD, 0x9, 0xF, 0x0, 0xA, 0x1, 0x5, 0xB, 0x8, 0xE, 0xC, 0x3, 0xD, 0xE, 0x4, 0x1, 0x7, 0x0, 0x5, 0xA, 0x3, 0xC, 0x8, 0xF, 0x6, 0x2, 0x9, 0xB, 0x1, 0x3, 0xA, 0x9, 0x5, 0xB, 0x4, 0xF, 0x8, 0x6, 0x7, 0xE, 0xD, 0x0, 0x2, 0xC ], 'D-SC': [ 0xb, 0xd, 0x7, 0x0, 0x5, 0x4, 0x1, 0xf, 0x9, 0xe, 0x6, 0xa, 0x3, 0xc, 0x8, 0x2, 0x1, 0x2, 0x7, 0x9, 0xd, 0xb, 0xf, 0x8, 0xe, 0xc, 0x4, 0x0, 0x5, 0x6, 0xa, 0x3, 0x5, 0x1, 0xd, 0x3, 0xf, 0x6, 0xc, 0x7, 0x9, 0x8, 0xb, 0x2, 0x4, 0xe, 0x0, 0xa, 0xd, 0x1, 0xb, 0x4, 0x9, 0xc, 0xe, 0x0, 0x7, 0x5, 0x8, 0xf, 0x6, 0x2, 0xa, 0x3, 0x2, 0xd, 0xa, 0xf, 0x9, 0xb, 0x3, 0x7, 0x8, 0xc, 0x5, 0xe, 0x6, 0x0, 0x1, 0x4, 0x0, 0x4, 0x6, 0xc, 0x5, 0x3, 0x8, 0xd, 0xa, 0xb, 0xf, 0x2, 0x1, 0x9, 0x7, 0xe, 0x1, 0x3, 0xc, 0x8, 0xa, 0x6, 0xb, 0x0, 0x2, 0xe, 0x7, 0x9, 0xf, 0x4, 0x5, 0xd, 0xa, 0xb, 0x6, 0x0, 0x1, 0x3, 0x4, 0x7, 0xe, 0xd, 0x5, 0xf, 0x8, 0x2, 0x9, 0xc ] }; var C = new Uint8Array([ 0x69, 0x00, 0x72, 0x22, 0x64, 0xC9, 0x04, 0x23, 0x8D, 0x3A, 0xDB, 0x96, 0x46, 0xE9, 0x2A, 0xC4, 0x18, 0xFE, 0xAC, 0x94, 0x00, 0xED, 0x07, 0x12, 0xC0, 0x86, 0xDC, 0xC2, 0xEF, 0x4C, 0xA9, 0x2B ]); function signed(x) { return x >= 0x80000000 ? x - 0x100000000 : x; } function unsigned(x) { return x < 0 ? x + 0x100000000 : x; } // Set random values into Uint8Arry // Random generator function randomSeed(e) { GostRandom = GostRandom || root.GostRandom; var randomSource = GostRandom ? new (GostRandom || root.GostRandom) : rootCrypto; if (randomSource.getRandomValues) randomSource.getRandomValues(e); else throw new NotSupportedError('Random generator not found'); } // Get buffer function buffer(d) { if (d instanceof CryptoOperationData) return d; else if (d && d?.buffer instanceof CryptoOperationData) return d.byteOffset === 0 && d.byteLength === d.buffer.byteLength ? d.buffer : new Uint8Array(new Uint8Array(d, d.byteOffset, d.byteLength)).buffer; else throw new DataError('CryptoOperationData required'); } // Get byte array function byteArray(d) { return new Uint8Array(buffer(d)); } // Clone byte array function cloneArray(d) { return new Uint8Array(byteArray(d)); } // Get int32 array function intArray(d) { return new Int32Array(buffer(d)); } // Swap bytes for version 2015 function swap32(b) { return ((b & 0xff) << 24) | ((b & 0xff00) << 8) | ((b >> 8) & 0xff00) | ((b >> 24) & 0xff); } // </editor-fold> /* * Initial parameters and common algortithms of GOST R 34.12-15 * Algorithm "Kuznechik" 128bit * */ // <editor-fold defaultstate="collapsed"> // Default initial vector var defaultIV128 = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); // Mult table for R function var multTable = (function () { // Multiply two numbers in the GF(2^8) finite field defined // by the polynomial x^8 + x^7 + x^6 + x + 1 = 0 */ function gmul(a, b) { var p = 0, counter, carry; for (counter = 0; counter < 8; counter++) { if (b & 1) p ^= a; carry = a & 0x80; // detect if x^8 term is about to be generated a = (a << 1) & 0xff; if (carry) a ^= 0xc3; // replace x^8 with x^7 + x^6 + x + 1 b >>= 1; } return p & 0xff; } // It is required only this values for R function // 0 1 2 3 4 5 6 7 var x = [1, 16, 32, 133, 148, 192, 194, 251]; var m = []; for (var i = 0; i < 8; i++) { m[i] = []; for (var j = 0; j < 256; j++) m[i][j] = gmul(x[i], j); } return m; })(); // 148, 32, 133, 16, 194, 192, 1, 251, 1, 192, 194, 16, 133, 32, 148, 1 var kB = [4, 2, 3, 1, 6, 5, 0, 7, 0, 5, 6, 1, 3, 2, 4, 0]; // R - function function funcR(d) { var sum = 0; for (var i = 0; i < 16; i++) sum ^= multTable[kB[i]][d[i]]; for (var i = 16; i > 0; --i) d[i] = d[i - 1]; d[0] = sum; } function funcReverseR(d) { var tmp = d[0]; for (var i = 0; i < 15; i++) d[i] = d[i + 1]; d[15] = tmp; var sum = 0; for (i = 0; i < 16; i++) sum ^= multTable[kB[i]][d[i]]; d[15] = sum; } // Nonlinear transformation var kPi = [ 252, 238, 221, 17, 207, 110, 49, 22, 251, 196, 250, 218, 35, 197, 4, 77, 233, 119, 240, 219, 147, 46, 153, 186, 23, 54, 241, 187, 20, 205, 95, 193, 249, 24, 101, 90, 226, 92, 239, 33, 129, 28, 60, 66, 139, 1, 142, 79, 5, 132, 2, 174, 227, 106, 143, 160, 6, 11, 237, 152, 127, 212, 211, 31, 235, 52, 44, 81, 234, 200, 72, 171, 242, 42, 104, 162, 253, 58, 206, 204, 181, 112, 14, 86, 8, 12, 118, 18, 191, 114, 19, 71, 156, 183, 93, 135, 21, 161, 150, 41, 16, 123, 154, 199, 243, 145, 120, 111, 157, 158, 178, 177, 50, 117, 25, 61, 255, 53, 138, 126, 109, 84, 198, 128, 195, 189, 13, 87, 223, 245, 36, 169, 62, 168, 67, 201, 215, 121, 214, 246, 124, 34, 185, 3, 224, 15, 236, 222, 122, 148, 176, 188, 220, 232, 40, 80, 78, 51, 10, 74, 167, 151, 96, 115, 30, 0, 98, 68, 26, 184, 56, 130, 100, 159, 38, 65, 173, 69, 70, 146, 39, 94, 85, 47, 140, 163, 165, 125, 105, 213, 149, 59, 7, 88, 179, 64, 134, 172, 29, 247, 48, 55, 107, 228, 136, 217, 231, 137, 225, 27, 131, 73, 76, 63, 248, 254, 141, 83, 170, 144, 202, 216, 133, 97, 32, 113, 103, 164, 45, 43, 9, 91, 203, 155, 37, 208, 190, 229, 108, 82, 89, 166, 116, 210, 230, 244, 180, 192, 209, 102, 175, 194, 57, 75, 99, 182 ]; var kReversePi = (function () { var m = []; for (var i = 0, n = kPi.length; i < n; i++) m[kPi[i]] = i; return m; })(); function funcS(d) { for (var i = 0; i < 16; ++i) d[i] = kPi[d[i]]; } function funcReverseS(d) { for (var i = 0; i < 16; ++i) d[i] = kReversePi[d[i]]; } function funcX(a, b) { for (var i = 0; i < 16; ++i) a[i] ^= b[i]; } function funcL(d) { for (var i = 0; i < 16; ++i) funcR(d); } function funcReverseL(d) { for (var i = 0; i < 16; ++i) funcReverseR(d); } function funcLSX(a, b) { funcX(a, b); funcS(a); funcL(a); } function funcReverseLSX(a, b) { funcX(a, b); funcReverseL(a); funcReverseS(a); } function funcF(inputKey, inputKeySecond, iterationConst) { var tmp = new Uint8Array(inputKey); funcLSX(inputKey, iterationConst); funcX(inputKey, inputKeySecond); inputKeySecond.set(tmp); } function funcC(number, d) { for (var i = 0; i < 15; i++) d[i] = 0; d[15] = number; funcL(d); } // </editor-fold> /** * Key schedule for GOST R 34.12-15 128bits * * @memberOf GostCipher * @private * @instance * @method keySchedule * @param {type} k * @returns {Uint8Array} */ function keySchedule128(k) // <editor-fold defaultstate="collapsed"> { var keys = new Uint8Array(160), c = new Uint8Array(16); keys.set(byteArray(k)); for (var j = 0; j < 4; j++) { var j0 = 32 * j, j1 = 32 * (j + 1); keys.set(new Uint8Array(keys.buffer, j0, 32), j1); for (var i = 1; i < 9; i++) { funcC(j * 8 + i, c); funcF(new Uint8Array(keys.buffer, j1, 16), new Uint8Array(keys.buffer, j1 + 16, 16), c); } } return keys; } // </editor-fold> /** * GOST R 34.12-15 128 bits encrypt/decrypt process * * @memberOf GostCipher * @private * @instance * @method round * @param {Uint8Array} k Scheduled key * @param {Uint8Array} d Data * @param {number} ofs Offsec * @param {number} e true - decrypt */ function process128(k, d, ofs, e) // <editor-fold defaultstate="collapsed"> { ofs = ofs || d.byteOffset; var r = new Uint8Array(d.buffer, ofs, 16); if (e) { for (var i = 0; i < 9; i++) funcReverseLSX(r, new Uint8Array(k.buffer, (9 - i) * 16, 16)); funcX(r, new Uint8Array(k.buffer, 0, 16)); } else { for (var i = 0; i < 9; i++) funcLSX(r, new Uint8Array(k.buffer, 16 * i, 16)); funcX(r, new Uint8Array(k.buffer, 16 * 9, 16)); } } // </editor-fold> /** * One GOST encryption round * * @memberOf GostCipher * @private * @instance * @method round * @param {Int8Array} S sBox * @param {Int32Array} m 2x32 bits cipher block * @param {Int32Array} k 32 bits key[i] */ function round(S, m, k) // <editor-fold defaultstate="collapsed"> { var cm = (m[0] + k) & 0xffffffff; var om = S[ 0 + ((cm >> (0 * 4)) & 0xF)] << (0 * 4); om |= S[ 16 + ((cm >> (1 * 4)) & 0xF)] << (1 * 4); om |= S[ 32 + ((cm >> (2 * 4)) & 0xF)] << (2 * 4); om |= S[ 48 + ((cm >> (3 * 4)) & 0xF)] << (3 * 4); om |= S[ 64 + ((cm >> (4 * 4)) & 0xF)] << (4 * 4); om |= S[ 80 + ((cm >> (5 * 4)) & 0xF)] << (5 * 4); om |= S[ 96 + ((cm >> (6 * 4)) & 0xF)] << (6 * 4); om |= S[112 + ((cm >> (7 * 4)) & 0xF)] << (7 * 4); cm = om << 11 | om >>> (32 - 11); cm ^= m[1]; m[1] = m[0]; m[0] = cm; } // </editor-fold> /** * Process encrypt/decrypt block with key K using GOST 28147-89 * * @memberOf GostCipher * @private * @instance * @method process * @param k {Int32Array} 8x32 bits key * @param d {Int32Array} 8x8 bits cipher block * @param ofs {number} offset */ function process89(k, d, ofs) // <editor-fold defaultstate="collapsed"> { ofs = ofs || d.byteOffset; var s = this.sBox, m = new Int32Array(d.buffer, ofs, 2); for (var i = 0; i < 32; i++) round(s, m, k[i]); var r = m[0]; m[0] = m[1]; m[1] = r; } // </editor-fold> /** * Process encrypt/decrypt block with key K using GOST R 34.12-15 64bit block * * @memberOf GostCipher * @private * @instance * @method process * @param k {Int32Array} 8x32 bits key * @param d {Int32Array} 8x8 bits cipher block * @param ofs {number} offset */ function process15(k, d, ofs) // <editor-fold defaultstate="collapsed"> { ofs = ofs || d.byteOffset; var s = this.sBox, m = new Int32Array(d.buffer, ofs, 2), r = swap32(m[0]); m[0] = swap32(m[1]); m[1] = r; for (var i = 0; i < 32; i++) round(s, m, k[i]); m[0] = swap32(m[0]); m[1] = swap32(m[1]); } // </editor-fold> /** * Key keySchedule algorithm for GOST 28147-89 64bit cipher * * @memberOf GostCipher * @private * @instance * @method process * @param k {Uint8Array} 8 bit key array * @param e {boolean} true - decrypt * @returns {Int32Array} keyScheduled 32-bit key */ function keySchedule89(k, e) // <editor-fold defaultstate="collapsed"> { var sch = new Int32Array(32), key = new Int32Array(buffer(k)); for (var i = 0; i < 8; i++) sch[i] = key[i]; if (e) { for (var i = 0; i < 8; i++) sch[i + 8] = sch[7 - i]; for (var i = 0; i < 8; i++) sch[i + 16] = sch[7 - i]; } else { for (var i = 0; i < 8; i++) sch[i + 8] = sch[i]; for (var i = 0; i < 8; i++) sch[i + 16] = sch[i]; } for (var i = 0; i < 8; i++) sch[i + 24] = sch[7 - i]; return sch; } // </editor-fold> /** * Key keySchedule algorithm for GOST R 34.12-15 64bit cipher * * @memberOf GostCipher * @private * @instance * @method process * @param k {Uint8Array} 8 bit key array * @param e {boolean} true - decrypt * @returns {Int32Array} keyScheduled 32-bit key */ function keySchedule15(k, e) // <editor-fold defaultstate="collapsed"> { var sch = new Int32Array(32), key = new Int32Array(buffer(k)); for (var i = 0; i < 8; i++) sch[i] = swap32(key[i]); if (e) { for (var i = 0; i < 8; i++) sch[i + 8] = sch[7 - i]; for (var i = 0; i < 8; i++) sch[i + 16] = sch[7 - i]; } else { for (var i = 0; i < 8; i++) sch[i + 8] = sch[i]; for (var i = 0; i < 8; i++) sch[i + 16] = sch[i]; } for (var i = 0; i < 8; i++) sch[i + 24] = sch[7 - i]; return sch; } // </editor-fold> /** * Key schedule for RC2 * * https://tools.ietf.org/html/rfc2268 * * @memberOf GostCipher * @private * @instance * @method keySchedule * @param {Uint8Array} k * @returns {Uint16Array} */ var keyScheduleRC2 = (function () // <editor-fold defaultstate="collapsed"> { // an array of "random" bytes based on the digits of PI = 3.14159... var PITABLE = new Uint8Array([ 0xd9, 0x78, 0xf9, 0xc4, 0x19, 0xdd, 0xb5, 0xed, 0x28, 0xe9, 0xfd, 0x79, 0x4a, 0xa0, 0xd8, 0x9d, 0xc6, 0x7e, 0x37, 0x83, 0x2b, 0x76, 0x53, 0x8e, 0x62, 0x4c, 0x64, 0x88, 0x44, 0x8b, 0xfb, 0xa2, 0x17, 0x9a, 0x59, 0xf5, 0x87, 0xb3, 0x4f, 0x13, 0x61, 0x45, 0x6d, 0x8d, 0x09, 0x81, 0x7d, 0x32, 0xbd, 0x8f, 0x40, 0xeb, 0x86, 0xb7, 0x7b, 0x0b, 0xf0, 0x95, 0x21, 0x22, 0x5c, 0x6b, 0x4e, 0x82, 0x54, 0xd6, 0x65, 0x93, 0xce, 0x60, 0xb2, 0x1c, 0x73, 0x56, 0xc0, 0x14, 0xa7, 0x8c, 0xf1, 0xdc, 0x12, 0x75, 0xca, 0x1f, 0x3b, 0xbe, 0xe4, 0xd1, 0x42, 0x3d, 0xd4, 0x30, 0xa3, 0x3c, 0xb6, 0x26, 0x6f, 0xbf, 0x0e, 0xda, 0x46, 0x69, 0x07, 0x57, 0x27, 0xf2, 0x1d, 0x9b, 0xbc, 0x94, 0x43, 0x03, 0xf8, 0x11, 0xc7, 0xf6, 0x90, 0xef, 0x3e, 0xe7, 0x06, 0xc3, 0xd5, 0x2f, 0xc8, 0x66, 0x1e, 0xd7, 0x08, 0xe8, 0xea, 0xde, 0x80, 0x52, 0xee, 0xf7, 0x84, 0xaa, 0x72, 0xac, 0x35, 0x4d, 0x6a, 0x2a, 0x96, 0x1a, 0xd2, 0x71, 0x5a, 0x15, 0x49, 0x74, 0x4b, 0x9f, 0xd0, 0x5e, 0x04, 0x18, 0xa4, 0xec, 0xc2, 0xe0, 0x41, 0x6e, 0x0f, 0x51, 0xcb, 0xcc, 0x24, 0x91, 0xaf, 0x50, 0xa1, 0xf4, 0x70, 0x39, 0x99, 0x7c, 0x3a, 0x85, 0x23, 0xb8, 0xb4, 0x7a, 0xfc, 0x02, 0x36, 0x5b, 0x25, 0x55, 0x97, 0x31, 0x2d, 0x5d, 0xfa, 0x98, 0xe3, 0x8a, 0x92, 0xae, 0x05, 0xdf, 0x29, 0x10, 0x67, 0x6c, 0xba, 0xc9, 0xd3, 0x00, 0xe6, 0xcf, 0xe1, 0x9e, 0xa8, 0x2c, 0x63, 0x16, 0x01, 0x3f, 0x58, 0xe2, 0x89, 0xa9, 0x0d, 0x38, 0x34, 0x1b, 0xab, 0x33, 0xff, 0xb0, 0xbb, 0x48, 0x0c, 0x5f, 0xb9, 0xb1, 0xcd, 0x2e, 0xc5, 0xf3, 0xdb, 0x47, 0xe5, 0xa5, 0x9c, 0x77, 0x0a, 0xa6, 0x20, 0x68, 0xfe, 0x7f, 0xc1, 0xad ]); return function (k) { var key = new Uint8Array(buffer(k)), T = Math.min(key.length, 128), T1 = this.effectiveLength, T8 = Math.floor((T1 + 7) / 8), TM = 0xff % Math.pow(2, 8 + T1 - 8 * T8); var L = new Uint8Array(128), K = new Uint16Array(L.buffer); for (var i = 0; i < T; i++) L[i] = key[i]; for (var i = T; i < 128; i++) L[i] = PITABLE[(L[i - 1] + L[i - T]) % 256]; L[128 - T8] = PITABLE[L[128 - T8] & TM]; for (var i = 127 - T8; i >= 0; --i) L[i] = PITABLE[L[i + 1] ^ L[i + T8]]; return K; }; } // </editor-fold> )(); /** * RC2 encrypt/decrypt process * * https://tools.ietf.org/html/rfc2268 * * @memberOf GostCipher * @private * @instance * @method round * @param {CryptoOperationData} k Scheduled key * @param {CryptoOperationData} d Data * @param {number} ofs Offsec * @param {number} e true - decrypt */ var processRC2 = (function () // <editor-fold defaultstate="collapsed"> { var K, j, R = new Uint16Array(4), s = new Uint16Array([1, 2, 3, 5]), reverse; function rol(R, s) { return (R << s | R >>> (16 - s)) & 0xffff; } function ror(R, s) { return (R >>> s | R << (16 - s)) & 0xffff; } function mix(i) { if (reverse) { R[i] = ror(R[i], s[i]); R[i] = R[i] - K[j] - (R[(i + 3) % 4] & R[(i + 2) % 4]) - ((~R[(i + 3) % 4]) & R[(i + 1) % 4]); j = j - 1; } else { R[i] = R[i] + K[j] + (R[(i + 3) % 4] & R[(i + 2) % 4]) + ((~R[(i + 3) % 4]) & R[(i + 1) % 4]); j = j + 1; R[i] = rol(R[i], s[i]); } } function mash(i) { if (reverse) { R[i] = R[i] - K[R[(i + 3) % 4] & 63]; } else { R[i] = R[i] + K[R[(i + 3) % 4] & 63]; } } function perform(method, count) { count = count || 1; for (var j = 0; j < count; j++) { if (reverse) { for (var i = 3; i >= 0; --i) method(i); } else { for (var i = 0; i < 4; i++) method(i); } } } return function (k, d, ofs, e) { reverse = e; // 1. Initialize words R[0], ..., R[3] to contain the 64-bit // ciphertext value. R = new Uint16Array(d.buffer, ofs || d.byteOffset, 4); // 2. Expand the key, so that words K[0], ..., K[63] become // defined. K = k; // 3. Initialize j to zero (enc) j to 63 (dec). j = e ? 63 : 0; // 4. Perform five mixing rounds. perform(mix, 5); // 5. Perform one mashing round. perform(mash); // 6. Perform six mixing rounds. perform(mix, 6); // 7. Perform one mashing round. perform(mash); // 8. Perform five mixing rounds. perform(mix, 5); }; } // </editor-fold> )(); /** * Algorithm name GOST 28147-ECB<br><br> * * encryptECB (K, D) is D, encrypted with key k using GOST 28147/GOST R 34.13 in * "prostaya zamena" (Electronic Codebook, ECB) mode. * @memberOf GostCipher * @method encrypt * @instance * @param k {CryptoOperationData} 8x32 bit key * @param d {CryptoOperationData} 8 bits message * @return {CryptoOperationData} result */ function encryptECB(k, d) // <editor-fold defaultstate="collapsed"> { var p = this.pad(byteArray(d)), n = this.blockSize, b = p.byteLength / n, key = this.keySchedule(k); for (var i = 0; i < b; i++) this.process(key, p, n * i); return p.buffer; } // </editor-fold> /** * Algorithm name GOST 28147-ECB<br><br> * * decryptECB (K, D) is D, decrypted with key K using GOST 28147/GOST R 34.13 in * "prostaya zamena" (Electronic Codebook, ECB) mode. * * @memberOf GostCipher * @method decrypt * @instance * @param k {CryptoOperationData} 8x32 bits key * @param d {CryptoOperationData} 8 bits message * @return {CryptoOperationData} result */ function decryptECB(k, d) // <editor-fold defaultstate="collapsed"> { var p = cloneArray(d), n = this.blockSize, b = p.byteLength / n, key = this.keySchedule(k, 1); for (var i = 0; i < b; i++) this.process(key, p, n * i, 1); return this.unpad(p).buffer; } // </editor-fold> /** * Algorithm name GOST 28147-CFB<br><br> * * encryptCFB (IV, K, D) is D, encrypted with key K using GOST 28147/GOST R 34.13 * in "gammirovanie s obratnoj svyaziyu" (Cipher Feedback, CFB) mode, and IV is * used as the initialization vector. * * @memberOf GostCipher * @method encrypt * @instance * @param {CryptoOperationData} k 8x32 bits key * @param {CryptoOperationData} d 8 bits array with data * @param {CryptoOperationData} iv initial vector * @return {CryptoOperationData} result */ function encryptCFB(k, d, iv) // <editor-fold defaultstate="collapsed"> { var s = new Uint8Array(iv || this.iv), c = cloneArray(d), m = s.length, t = new Uint8Array(m), b = this.shiftBits >> 3, cb = c.length, r = cb % b, q = (cb - r) / b, key = this.keySchedule(k); for (var i = 0; i < q; i++) { for (var j = 0; j < m; j++) t[j] = s[j]; this.process(key, s); for (var j = 0; j < b; j++) c[i * b + j] ^= s[j]; for (var j = 0; j < m - b; j++) s[j] = t[b + j]; for (var j = 0; j < b; j++) s[m - b + j] = c[i * b + j]; k = this.keyMeshing(k, s, i, key); } if (r > 0) { this.process(key, s); for (var i = 0; i < r; i++) c[q * b + i] ^= s[i]; } return c.buffer; } // </editor-fold> /** * Algorithm name GOST 28147-CFB<br><br> * * decryptCFB (IV, K, D) is D, decrypted with key K using GOST 28147/GOST R 34.13 * in "gammirovanie s obratnoj svyaziyu po shifrotekstu" (Cipher Feedback, CFB) mode, and IV is * used as the initialization vector. * * @memberOf GostCipher * @method decrypt * @instance * @param {CryptoOperationData} k 8x32 bits key * @param {CryptoOperationData} d 8 bits array with data * @param {CryptoOperationData} iv initial vector * @return {CryptoOperationData} result */ function decryptCFB(k, d, iv) // <editor-fold defaultstate="collapsed"> { var s = new Uint8Array(iv || this.iv), c = cloneArray(d), m = s.length, t = new Uint8Array(m), b = this.shiftBits >> 3, cb = c.length, r = cb % b, q = (cb - r) / b, key = this.keySchedule(k); for (var i = 0; i < q; i++) { for (var j = 0; j < m; j++) t[j] = s[j]; this.process(key, s); for (var j = 0; j < b; j++) { t[j] = c[i * b + j]; c[i * b + j] ^= s[j]; } for (var j = 0; j < m - b; j++) s[j] = t[b + j]; for (var j = 0; j < b; j++) s[m - b + j] = t[j]; k = this.keyMeshing(k, s, i, key); } if (r > 0) { this.process(key, s); for (var i = 0; i < r; i++) c[q * b + i] ^= s[i]; } return c.buffer; } // </editor-fold> /** * Algorithm name GOST 28147-OFB<br><br> * * encryptOFB/decryptOFB (IV, K, D) is D, encrypted with key K using GOST 28147/GOST R 34.13 * in "gammirovanie s obratnoj svyaziyu po vyhodu" (Output Feedback, OFB) mode, and IV is * used as the initialization vector. * * @memberOf GostCipher * @method encrypt * @instance * @param {CryptoOperationData} k 8x32 bits key * @param {CryptoOperationData} d 8 bits array with data * @param {CryptoOperationData} iv 8x8 optional bits initial vector * @return {CryptoOperationData} result */ /** * Algorithm name GOST 28147-OFB<br><br> * * encryptOFB/decryptOFB (IV, K, D) is D, encrypted with key K using GOST 28147/GOST R 34.13 * in "gammirovanie s obratnoj svyaziyu po vyhodu" (Output Feedback, OFB) mode, and IV is * used as the initialization vector. * * @memberOf GostCipher * @method decrypt * @instance * @param {CryptoOperationData} k 8x32 bits key * @param {CryptoOperationData} d 8 bits array with data * @param {CryptoOperationData} iv initial vector * @return {CryptoOperationData} result */ function processOFB(k, d, iv) // <editor-fold defaultstate="collapsed"> { var s = new Uint8Array(iv || this.iv), c = cloneArray(d), m = s.length, t = new Uint8Array(m), b = this.shiftBits >> 3, p = new Uint8Array(b), cb = c.length, r = cb % b, q = (cb - r) / b, key = this.keySchedule(k); for (var i = 0; i < q; i++) { for (var j = 0; j < m; j++) t[j] = s[j]; this.process(key, s); for (var j = 0; j < b; j++) p[j] = s[j]; for (var j = 0; j < b; j++) c[i * b + j] ^= s[j]; for (var j = 0; j < m - b; j++) s[j] = t[b + j]; for (var j = 0; j < b; j++) s[m - b + j] = p[j]; k = this.keyMeshing(k, s, i, key); } if (r > 0) { this.process(key, s); for (var i = 0; i < r; i++) c[q * b + i] ^= s[i]; } return c.buffer; } // </editor-fold> /** * Algorithm name GOST 28147-CTR<br><br> * * encryptCTR/decryptCTR (IV, K, D) is D, encrypted with key K using GOST 28147/GOST R 34.13 * in "gammirovanie" (Counter Mode-CTR) mode, and IV is used as the * initialization vector. * @memberOf GostCipher * @method encrypt * @instance * @param {CryptoOperationData} k 8x32 bits key * @param {CryptoOperationData} d 8 bits array with data * @param {CryptoOperationData} iv 8x8 optional bits initial vector * @return {CryptoOperationData} result */ /** * Algorithm name GOST 28147-CTR<br><br> * * encryptCTR/decryptCTR (IV, K, D) is D, encrypted with key K using GOST 28147/GOST R 34.13 * in "gammirovanie" (Counter Mode-CTR) mode, and IV is used as the * initialization vector. * @memberOf GostCipher * @method decrypt * @instance * @param {CryptoOperationData} k 8x32 bits key * @param {CryptoOperationData} d 8 bits array with data * @param {CryptoOperationData} iv initial vector * @return {CryptoOperationData} result */ function processCTR89(k, d, iv) // <editor-fold defaultstate="collapsed"> { var s = new Uint8Array(iv || this.iv), c = cloneArray(d), b = this.blockSize, t = new Int8Array(b), cb = c.length, r = cb % b, q = (cb - r) / b, key = this.keySchedule(k), syn = new Int32Array(s.buffer); this.process(key, s); for (var i = 0; i < q; i++) { syn[0] = (syn[0] + 0x1010101) & 0xffffffff; // syn[1] = signed(unsigned((syn[1] + 0x1010104) & 0xffffffff) % 0xffffffff); var tmp = unsigned(syn[1]) + 0x1010104; // Special thanks to Ilya Matveychikov syn[1] = signed(tmp < 0x100000000 ? tmp : tmp - 0xffffffff); for (var j = 0; j < b; j++) t[j] = s[j]; this.process(key, syn); for (var j = 0; j < b; j++) c[i * b + j] ^= s[j]; for (var j = 0; j < b; j++) s[j] = t[j]; k = this.keyMeshing(k, s, i, key); } if (r > 0) { syn[0] = (syn[0] + 0x1010101) & 0xffffffff; // syn[1] = signed(unsigned((syn[1] + 0x1010104) & 0xffffffff) % 0xffffffff); var tmp = unsigned(syn[1]) + 0x1010104; // Special thanks to Ilya Matveychikov syn[1] = signed(tmp < 0x100000000 ? tmp : tmp - 0xffffffff); this.process(key, syn); for (var i = 0; i < r; i++) c[q * b + i] ^= s[i]; } return c.buffer; } // </editor-fold> function processCTR15(k, d, iv) // <editor-fold defaultstate="collapsed"> { var c = cloneArray(d), n = this.blockSize, b = this.shiftBits >> 3, cb = c.length, r = cb % b, q = (cb - r) / b, s = new Uint8Array(n), t = new Int32Array(n), key = this.keySchedule(k); s.set(iv || this.iv); for (var i = 0; i < q; i++) { for (var j = 0; j < n; j++) t[j] = s[j]; this.process(key, s); for (var j = 0; j < b; j++) c[b * i + j] ^= s[j]; for (var j = 0; j < n; j++) s[j] = t[j]; for (var j = n - 1; i >= 0; --i) { if (s[j] > 0xfe) { s[j] -= 0xfe; } else { s[j]++; break; } } } if (r > 0) { this.process(key, s); for (var j = 0; j < r; j++) c[b * q + j] ^= s[j]; } return c.buffer; } // </editor-fold> /** * Algorithm name GOST 28147-CBC<br><br> * * encryptCBC (IV, K, D) is D, encrypted with key K using GOST 28147/GOST R 34.13 * in "Prostaya zamena s zatsepleniem" (Cipher-Block-Chaining, CBC) mode and IV is used as the initialization * vector. * * @memberOf GostCipher * @method encrypt * @instance * @param {CryptoOperationData} k 8x32 bits key * @param {CryptoOperationData} d 8 bits array with data * @param {CryptoOperationData} iv initial vector * @return {CryptoOperationData} result */ function encryptCBC(k, d, iv) // <editor-fold defaultstate="collapsed"> { var s = new Uint8Array(iv || this.iv), n = this.blockSize, m = s.length, c = this.pad(byteArray(d)), key = this.keySchedule(k); for (var i = 0, b = c.length / n; i < b; i++) { for (var j = 0; j < n; j++) s[j] ^= c[i * n + j]; this.process(key, s); for (var j = 0; j < n; j++) c[i * n + j] = s[j]; if (m !== n) { for (var j = 0; j < m - n; j++) s[j] = s[n + j]; for (var j = 0; j < n; j++) s[j + m - n] = c[i * n + j]; } k = this.keyMeshing(k, s, i, key); } return c.buffer; } // </editor-fold> /** * Algorithm name GOST 28147-CBC<br><br> * * decryptCBC (IV, K, D) is D, decrypted with key K using GOST 28147/GOST R 34.13 * in "Prostaya zamena s zatsepleniem" (Cipher-Block-Chaining, CBC) mode and IV is used as the initialization * vector. * * @memberOf GostCipher * @method decrypt * @instance * @param {CryptoOperationData} k 8x32 bits key * @param {CryptoOperationData} d 8 bits array with data * @param {CryptoOperationData} iv initial vector * @return {CryptoOperationData} result */ function decryptCBC(k, d, iv) // <editor-fold defaultstate="collapsed"> { var s = new Uint8Array(iv || this.iv), n = this.blockSize, m = s.length, c = cloneArray(d), next = new Uint8Array(n), key = this.keySchedule(k, 1); for (var i = 0, b = c.length / n; i < b; i++) { for (var j = 0; j < n; j++) next[j] = c[i * n + j]; this.process(key, c, i * n, 1); for (var j = 0; j < n; j++) c[i * n + j] ^= s[j]; if (m !== n) { for (var j = 0; j < m - n; j++) s[j] = s[n + j]; } for (var j = 0; j < n; j++) s[j + m - n] = next[j]; k = this.keyMeshing(k, s, i, key, 1); } return this.unpad(c).buffer; } // </editor-fold> /** * The generateKey method returns a new generated key. * * @memberOf GostCipher * @method generateKey * @instance * @return {CryptoOperationData} result */ function generateKey() // <editor-fold defaultstate="collapsed"> { // Simple generate 256 bit random seed var k = new Uint8Array(this.keySize); randomSeed(k); return k.buffer; } // </editor-fold> /** * makeIMIT (K, D) is the 32-bit result of the GOST 28147/GOST R 34.13 in * "imitovstavka" (MAC) mode, used with D as plaintext, K as key and IV * as initialization vector. Note that the standard specifies its use * in this mode only with an initialization vector of zero. * * @memberOf GostCipher * @method processMAC * @private * @instance * @param {Int32Array} key 8x32 bits key * @param {Int32Array} s 8x8 sum array * @param {Uint8Array} d 8 bits array with data * @return {Uint8Array} result */ function processMAC89(key, s, d) // <editor-fold defaultstate="collapsed"> { var c = zeroPad.call(this, byteArray(d)), n = this.blockSize, q = c.length / n, sBox = this.sBox, sum = new Int32Array(s.buffer); for (var i = 0; i < q; i++) { for (var j = 0; j < n; j++) s[j] ^= c[i * n + j]; for (var j = 0; j < 16; j++) // 1-16 steps round(sBox, sum, key[j]); } } // </editor-fold> function processKeyMAC15(s) // <editor-fold defaultstate="collapsed"> { var t = 0, n = s.length; for (var i = n - 1; i >= 0; --i) { var t1 = s[i] >>> 7; s[i] = (s[i] << 1) & 0xff | t; t = t1; } if (t !== 0) { if (n === 16) s[15] ^= 0x87; else s[7] ^= 0x1b; } } // </editor-fold> function processMAC15(key, s, d) // <editor-fold defaultstate="collapsed"> { var n = this.blockSize, sBox = this.sBox, c = byteArray(d), r = new Uint8Array(n); // R this.process(key, r); // K1 processKeyMAC15(r); if (d.byteLength % n !== 0) { c = bitPad.call(this, byteArray(d)); // K2 processKeyMAC15(r); } for (var i = 0, q = c.length / n; i < q; i++) { for (var j = 0; j < n; j++) s[j] ^= c[i * n + j]; if (i === q - 1) {// Last block for (var j = 0; j < n; j++) s[j] ^= r[j]; } this.process(key, s); } } // </editor-fold> /** * signMAC (K, D, IV) is the 32-bit result of the GOST 28147/GOST R 34.13 in * "imitovstavka" (MAC) mode, used with D as plaintext, K as key and IV * as initialization vector. Note that the standard specifies its use * in this mode only with an initialization vector of zero. * * @memberOf GostCipher * @method sign * @instance * @param {CryptoOperationData} k 8x32 bits key * @param {CryptoOperationData} d 8 bits array with data * @param {CryptoOperationData} iv initial vector * @return {CryptoOperationData} result */ function signMAC(k, d, iv) // <editor-fold defaultstate="collapsed"> { var key = this.keySchedule(k), s = new Uint8Array(iv || this.iv), m = Math.ceil(this.macLength >> 3) || this.blockSize >> 1; this.processMAC(key, s, d); var mac = new Uint8Array(m); // mac size mac.set(new Uint8Array(s.buffer, 0, m)); return mac.buffer; } // </editor-fold> /** * verifyMAC (K, M, D, IV) the 32-bit result verification of the GOST 28147/GOST R 34.13 in * "imitovstavka" (MAC) mode, used with D as plaintext, K as key and IV * as initialization vector. Note that the standard specifies its use * in this mode only with an initialization vector of zero. * * @memberOf GostCipher * @method verify * @instance * @param {CryptoOperationData} k 8x32 bits key * @param {CryptoOperationData} m 8 bits array with signature * @param {CryptoOperationData} d 8 bits array with data * @param {CryptoOperationData} iv 8x8 optional bits initial vector * @return {boolen} MAC verified = true */ function verifyMAC(k, m, d, iv) // <editor-fold defaultstate="collapsed"> { var mac = new Uint8Array(signMAC.call(this, k, d, iv)), test = byteArray(m); if (mac.length !== test.length) return false; for (var i = 0, n = mac.length; i < n; i++) if (mac[i] !== test[i]) return false; return true; } // </editor-fold> /** * Algorithm name GOST 28147-KW<br><br> * * This algorithm encrypts GOST 28147-89 CEK with a GOST 28147/GOST R 34.13 KEK. * Ref. rfc4357 6.1 GOST 28147-89 Key Wrap * Note: This algorithm MUST NOT be used with a KEK produced by VKO GOST * R 34.10-94, because such a KEK is constant for every sender-recipient * pair. Encrypting many different content encryption keys on the same * constant KEK may reveal that KEK. * * @memberOf GostCipher * @method wrapKey * @instance * @param {CryptoOperationData} kek Key encryption key * @param {CryptoOperationData} cek Content encryption key * @returns {CryptoOperationData} Encrypted cek */ function wrapKeyGOST(kek, cek) // <editor-fold defaultstate="collapsed"> { var n = this.blockSize, k = this.keySize, len = k + (n >> 1); // 1) For a unique symmetric KEK, generate 8 octets at random and call // the result UKM. For a KEK, produced by VKO GOST R 34.10-2001, use // the UKM that was used for key derivation. if (!this.ukm) throw new DataError('UKM must be defined'); var ukm = new Uint8Array(this.ukm); // 2) Compute a 4-byte checksum value, GOST 28147IMIT (UKM, KEK, CEK). // Call the result CEK_MAC. var mac = signMAC.call(this, kek, cek, ukm); // 3) Encrypt the CEK in ECB mode using the KEK. Call the ciphertext CEK_ENC. var enc = encryptECB.call(this, kek, cek); // 4) The wrapped content-encryption key is (UKM | CEK_ENC | CEK_MAC). var r = new Uint8Array(len); r.set(new Uint8Array(enc), 0); r.set(new Uint8Array(mac), k); return r.buffer; } // </editor-fold> /** * Algorithm name GOST 28147-KW<br><br> * * This algorithm decrypts GOST 28147-89 CEK with a GOST 28147 KEK. * Ref. rfc4357 6.2 GOST 28147-89 Key Unwrap * * @memberOf GostCipher * @method unwrapKey * @instance * @param {type} kek Key encryption key * @param {type} data Content encryption key * @return {CryptoOperationData} result */ function unwrapKeyGOST(kek, data) // <editor-fold defaultstate="collapsed"> { var n = this.blockSize, k = this.keySize, len = k + (n >> 1); // 1) If the wrapped content-encryption key is not 44 octets, then error. var d = buffer(data); if (d.byteLength !== len) throw new DataError('Wrapping key size must be ' + len + ' bytes'); // 2) Decompose the wrapped content-encryption key into UKM, CEK_ENC, and CEK_MAC. // UKM is the most significant (first) 8 octets. CEK_ENC is next 32 octets, // and CEK_MAC is the least significant (last) 4 octets. if (!this.ukm) throw new DataError('UKM must be defined'); var ukm = new Uint8Array(this.ukm), enc = new Uint8Array(d, 0, k), mac = new Uint8Array(d, k, n >> 1); // 3) Decrypt CEK_ENC in ECB mode using the KEK. Call the output CEK. var cek = decryptECB.call(this, kek, enc); // 4) Compute a 4-byte checksum value, GOST 28147IMIT (UKM, KEK, CEK), // compare the result with CEK_MAC. If they are not equal, then error. var check = verifyMAC.call(this, kek, mac, cek, ukm); if (!check) throw new DataError('Error verify MAC of wrapping key'); return cek; } // </editor-fold> /** * Algorithm name GOST 28147-CPKW<br><br> * * Given a random 64-bit UKM and a GOST 28147 key K, this algorithm * creates a new GOST 28147-89 key K(UKM). * Ref. rfc4357 6.3 CryptoPro KEK Diversification Algorithm * * @memberOf GostCipher * @method diversify * @instance * @private * @param {CryptoOperationData} kek Key encryption key * @param {CryptoOperationData} ukm Random generated value * @returns {CryptoOperationData} Diversified kek */ function diversifyKEK(kek, ukm) // <editor-fold defaultstate="collapsed"> { var n = this.blockSize; // 1) Let K[0] = K; var k = intArray(kek); // 2) UKM is split into components a[i,j]: // UKM = a[0]|..|a[7] (a[i] - byte, a[i,0]..a[i,7] - it’s bits) var a = []; for (var i = 0; i < n; i++) { a[i] = []; for (var j = 0; j < 8; j++) { a[i][j] = (ukm[i] >>> j) & 0x1; } } // 3) Let i be 0. // 4) K[1]..K[8] are calculated by repeating the following algorithm // eight times: for (var i = 0; i < n; i++) { // A) K[i] is split into components k[i,j]: // K[i] = k[i,0]|k[i,1]|..|k[i,7] (k[i,j] - 32-bit integer) // B) Vector S[i] is calculated: // S[i] = ((a[i,0]*k[i,0] + ... + a[i,7]*k[i,7]) mod 2^32) | // (((~a[i,0])*k[i,0] + ... + (~a[i,7])*k[i,7]) mod 2^32); var s = new Int32Array(2); for (var j = 0; j < 8; j++) { if (a[i][j]) s[0] = (s[0] + k[j]) & 0xffffffff; else s[1] = (s[1] + k[j]) & 0xffffffff; } // C) K[i+1] = encryptCFB (S[i], K[i], K[i]) var iv = new Uint8Array(s.buffer); k = new Int32Array(encryptCFB.call(this, k, k, iv)); // D) i = i + 1 } // 5) Let K(UKM) be K[8]. return k; } // </editor-fold> /** * Algorithm name GOST 28147-CPKW<br><br> * * This algorithm encrypts GOST 28147-89 CEK with a GOST 28147 KEK. * It can be used with any KEK (e.g., produced by VKO GOST R 34.10-94 or * VKO GOST R 34.10-2001) because a unique UKM is used to diversify the KEK. * Ref. rfc4357 6.3 CryptoPro Key Wrap * * @memberOf GostCipher * @method wrapKey * @instance * @param {CryptoOperationData} kek Key encryption key * @param {CryptoOperationData} cek Content encryption key * @returns {CryptoOperationData} Encrypted cek */ function wrapKeyCP(kek, cek) // <editor-fold defaultstate="collapsed"> { var n = this.blockSize, k = this.keySize, len = k + (n >> 1); // 1) For a unique symmetric KEK or a KEK produced by VKO GOST R // 34.10-94, generate 8 octets at random. Call the result UKM. For // a KEK, produced by VKO GOST R 34.10-2001, use the UKM that was // used for key derivation. if (!this.ukm) throw new DataError('UKM must be defined'); var ukm = new Uint8Array(this.ukm); // 2) Diversify KEK, using the CryptoPro KEK Diversification Algorithm, // described in Section 6.5. Call the result KEK(UKM). var dek = diversifyKEK.call(this, kek, ukm); // 3) Compute a 4-byte checksum value, GOST 28147IMIT (UKM, KEK(UKM), // CEK). Call the result CEK_MAC. var mac = signMAC.call(this, dek, cek, ukm); // 4) Encrypt CEK in ECB mode using KEK(UKM). Call the ciphertext // CEK_ENC. var enc = encryptECB.call(this, dek, cek); // 5) The wrapped content-encryption key is (UKM | CEK_ENC | CEK_MAC). var r = new Uint8Array(len); r.set(new Uint8Array(enc), 0); r.set(new Uint8Array(mac), k); return r.buffer; } // </editor-fold> /** * Algorithm name GOST 28147-CPKW<br><br> * * This algorithm encrypts GOST 28147-89 CEK with a GOST 28147 KEK. * Ref. rfc4357 6.4 CryptoPro Key Unwrap * * @memberOf GostCipher * @method unwrapKey * @instance * @param {CryptoOperationData} kek Key encryption key * @param {CryptoOperationData} data Encrypted content encryption keu * @return {CryptoOperationData} result Decrypted content encryption keu */ function unwrapKeyCP(kek, data) // <editor-fold defaultstate="collapsed"> { var n = this.blockSize