From db491cbb09ab3c6aa49074650961f553d9881752 Mon Sep 17 00:00:00 2001 From: mshwed Date: Thu, 28 Mar 2019 11:46:04 -0400 Subject: [PATCH 1/5] Added initial hashing for Streebog GOST R 34.11-94 --- src/core/config/Categories.json | 7 +- src/core/operations/Streebog.mjs | 54 + src/core/vendor/Streebog.mjs | 1318 ++++++++++++++ src/core/vendor/streebog/gostCipher.js | 2267 ++++++++++++++++++++++++ src/core/vendor/streebog/gostCoding.js | 1171 ++++++++++++ src/core/vendor/streebog/gostCrypto.js | 1657 +++++++++++++++++ src/core/vendor/streebog/gostDigest.js | 1269 +++++++++++++ src/core/vendor/streebog/gostRandom.js | 139 ++ 8 files changed, 7879 insertions(+), 3 deletions(-) create mode 100644 src/core/operations/Streebog.mjs create mode 100644 src/core/vendor/Streebog.mjs create mode 100644 src/core/vendor/streebog/gostCipher.js create mode 100644 src/core/vendor/streebog/gostCoding.js create mode 100644 src/core/vendor/streebog/gostCrypto.js create mode 100644 src/core/vendor/streebog/gostDigest.js create mode 100644 src/core/vendor/streebog/gostRandom.js diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json index 2fe8e8f7..bf1a6050 100755 --- a/src/core/config/Categories.json +++ b/src/core/config/Categories.json @@ -106,7 +106,8 @@ "Enigma", "Bombe", "Multiple Bombe", - "Typex" + "Typex", + "Streebog" ] }, { @@ -194,8 +195,8 @@ "Remove null bytes", "To Upper case", "To Lower case", - "To Case Insensitive Regex", - "From Case Insensitive Regex", + "To Case Insensitive Regex", + "From Case Insensitive Regex", "Add line numbers", "Remove line numbers", "To Table", diff --git a/src/core/operations/Streebog.mjs b/src/core/operations/Streebog.mjs new file mode 100644 index 00000000..0c46f4f7 --- /dev/null +++ b/src/core/operations/Streebog.mjs @@ -0,0 +1,54 @@ +/** + * @author mshwed [m@ttshwed.com] + * @copyright Crown Copyright 2019 + * @license Apache-2.0 + */ + +import Operation from "../Operation"; +import OperationError from "../errors/OperationError"; +import * as GostDigest from "../vendor/streebog/gostDigest"; +import * as GostCoding from "../vendor/streebog/gostCoding"; + +/** + * Streebog operation + */ +class Streebog extends Operation { + + /** + * Streebog constructor + */ + constructor() { + super(); + + this.name = "Streebog"; + this.module = "Crypto"; + this.description = "Streebog is a cryptographic hash function defined in the Russian national standard GOST R 34.11-2012 Information Technology \u2013 Cryptographic Information Security \u2013 Hash Function. It was created to replace an obsolete GOST hash function defined in the old standard GOST R 34.11-94, and as an asymmetric reply to SHA-3 competition by the US National Institute of Standards and Technology."; + this.infoURL = "https://en.wikipedia.org/wiki/Streebog"; + this.inputType = "string"; + this.outputType = "string"; + this.args = []; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + try { + const gostDigest = new GostDigest({name: 'GOST R 34.11', version: 1994}); + const gostCoding = new GostCoding(); + + const decode = gostCoding.Chars.decode(input, 'utf8'); + let hexEncode = gostCoding.Hex.encode(gostDigest.digest(decode)) + + return hexEncode.replace(/[^\-A-Fa-f0-9]/g, '').toLowerCase();; + } catch (err) { + console.log(err) + throw new OperationError("Test"); + } + } + +} + +export default Streebog; diff --git a/src/core/vendor/Streebog.mjs b/src/core/vendor/Streebog.mjs new file mode 100644 index 00000000..9b078b2d --- /dev/null +++ b/src/core/vendor/Streebog.mjs @@ -0,0 +1,1318 @@ +/*------------------------------------------------------------------------------------------------------------------------- + Created by Rudolf Nickolaev (https://github.com/rudonick/crypto/) + & 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. + * + * Converted to JavaScript from source https://www.streebog.net/ + * Copyright (c) 2013, Alexey Degtyarev. + * All rights reserved. + * + * 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. + * + */ + +(function(root, factory) { + /* + * Module imports and exports + * + */ // + if (typeof define === "function" && define.amd) { + define(["gostRandom", "gostCipher"], factory); + } else if (typeof exports === "object") { + module.exports = factory(require("gostRandom"), require("gostCipher")); + } else { + root.GostDigest = factory(root.GostRandom, root.GostCipher); + } + // +})(this, function(GostRandom, GostCipher) { + /* + * GOST R 34.11 + * Common methods + * + */ // + + var root = this; + var rootCrypto = root.crypto || root.msCrypto; + + var DataError = root.DataError || Error, + NotSupportedError = root.NotSupportedError || Error; + + // Copy len values from s[sOfs] to d[dOfs] + function arraycopy(s, sOfs, d, dOfs, len) { + for (var i = 0; i < len; i++) d[dOfs + i] = s[sOfs + i]; + } + + // Swap bytes in buffer + function swap(s) { + var src = new Uint8Array(s), + dst = new Uint8Array(src.length); + for (var i = 0, n = src.length; i < n; i++) dst[n - i - 1] = src[i]; + return dst.buffer; + } + + // Convert BASE64 string to Uint8Array + // for decompression of constants and precalc values + function b64decode(s) { + // s = s.replace(/[^A-Za-z0-9\+\/]/g, ''); + var n = s.length, + k = (n * 3 + 1) >> 2, + r = new Uint8Array(k); + + for (var m3, m4, u24 = 0, j = 0, i = 0; i < n; i++) { + m4 = i & 3; + var c = s.charCodeAt(i); + + c = + c > 64 && c < 91 + ? c - 65 + : c > 96 && c < 123 + ? c - 71 + : c > 47 && c < 58 + ? c + 4 + : c === 43 + ? 62 + : c === 47 + ? 63 + : 0; + + u24 |= c << (18 - 6 * m4); + if (m4 === 3 || n - i === 1) { + for (m3 = 0; m3 < 3 && j < k; m3++, j++) { + r[j] = (u24 >>> ((16 >>> m3) & 24)) & 255; + } + u24 = 0; + } + } + return r.buffer; + } + + // Random seed + function getSeed(length) { + GostRandom = GostRandom || root.GostRandom; + var randomSource = GostRandom + ? new (GostRandom || root.GostRandom)() + : rootCrypto; + if (randomSource.getRandomValues) { + var d = new Uint8Array(Math.ceil(length / 8)); + randomSource.getRandomValues(d); + return d; + } else throw new NotSupportedError("Random generator not found"); + } + + // Check buffer + function buffer(d) { + if (d instanceof ArrayBuffer) return d; + else if (d && d.buffer && d.buffer instanceof ArrayBuffer) + 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("ArrayBuffer or ArrayBufferView required"); + } // + + /** + * Algorithm name GOST R 34.11 or GOST R 34.11-12

+ * + * http://tools.ietf.org/html/rfc6986 + * + * The digest method returns digest data in according to GOST R 4311-2012.
+ * Size of digest also defines in algorithm name. + * + * + * @memberOf GostDigest + * @method digest + * @instance + * @param {(ArrayBuffer|TypedArray)} data Data + * @returns {ArrayBuffer} Digest of data + */ + var digest2012 = (function() // + { + // Constants + var buffer0 = new Int32Array(16); // [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + + var buffer512 = new Int32Array(16); // [512, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + buffer512[0] = 512; + + // Constant C + var C = (function(s) { + var h = new Int32Array(b64decode(s)), + r = new Array(12); + for (var i = 0; i < 12; i++) + r[i] = new Int32Array(h.buffer, i * 64, 16); + return r; + })( + "B0Wm8lllgN0jTXTMNnR2BRXTYKQIKkKiAWlnkpHgfEv8xIV1jbhOcRbQRS5DdmovH3xlwIEvy+vp2soe2lsIsbebsSFwBHnmVs3L1xui3VXKpwrbwmG1XFiZ1hJrF7WaMQG1Fg9e1WGYKyMKcur+89e1cA9GneNPGi+dqYq1o2+yCroK9ZYemTHbeoZD9LbCCdtiYDc6ycGxnjWQ5A/i03t7KbEUderyix+cUl9e8QY1hD1qKPw5Cscvzius3HT1LtHjhLy+DCLxN+iToepTNL4DUpMzE7fYddYD7YIs16k/NV5orRxynX08XDN+hY5I3eRxXaDhSPnSZhXos98f71f+bHz9WBdg9WPqqX6iVnoWGicjtwD/36P1OiVHF82/vf8PgNc1njVKEIYWHxwVf2MjqWwMQT+amUdHraxr6ktufWRGekBo+jVPkDZyxXG/tsa+wmYf8gq0t5oct6b6z8aO8Jq0mn8YbKRCUfnEZi3AOTB6O8Okb9nTOh2urk+uk9QUOk1WhojzSjyiTEUXNQQFSiiDaUcGNyyCLcWrkgnJk3oZMz5H08mHv+bHxp45VAkkv/6GrFHsxaruFg7H9B7nAr/UDX+k" + + "2ahRWTXCrDYvxKXRK43RaZAGm5LLK4n0msTbTTtEtIke3jaccfi3TkFBbgwCqucDp8mTTUJbH5vbWiODUURhcmAqH8uS3DgOVJwHppqKK3uxzrLbC0QKgIQJDeC3Vdk8JEKJJRs6fTreXxbs2JpMlJsiMRZUWo837ZxFmPvHtHTDtjsV0fqYNvRSdjswbB56SzNprwJn558DYTMbiuH/H9t4iv8c50GJ8/PkskjlKjhSbwWApt6+qxst84HNpMprXdhvwEpZot6Ybkd9Hc2678q5SOrvcR2KeWaEFCGAASBhB6vru2v62JT+WmPNxgIw+4nI79CezXsg1xvxSpK8SJkbstnVF/T6UijhiKqkHeeGzJEYne+AXZufITDUEiD4dx3fvDI8pM16sUkEsIAT0roxFvFn5443" + ); + + // Precalc Ax + var Ax = (function(s) { + return new Int32Array(b64decode(s)); + })( + "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" + ); //== + + // Variables + var sigma, N, h; + + // 64bit tools + function get8(x, i) { + return (x[i >> 2] >> ((i & 3) << 3)) & 0xff; + } + + // 512bit tools + function add512(x, y) { + var CF = 0, + w0, + w1; + for (var i = 0; i < 16; i++) { + w0 = (x[i] & 0xffff) + (y[i] & 0xffff) + (CF || 0); + w1 = (x[i] >>> 16) + (y[i] >>> 16) + (w0 >>> 16); + x[i] = (w0 & 0xffff) | (w1 << 16); + CF = w1 >>> 16; + } + } + + function get512(d) { + return new Int32Array(d.buffer, d.byteOffset, 16); + } + + function copy512(r, d) { + for (var i = 0; i < 16; i++) r[i] = d[i]; + } + + function new512() { + return new Int32Array(16); + } + + // Core private algorithms + function xor512(x, y) { + for (var i = 0; i < 16; i++) x[i] = x[i] ^ y[i]; + } + + var r = new512(); + function XLPS(x, y) { + copy512(r, x); + xor512(r, y); + for (var i = 0; i < 8; i++) { + var z0, + z1, + k = get8(r, i) << 1; + z0 = Ax[k]; + z1 = Ax[k + 1]; + for (var j = 1; j < 8; j++) { + k = (j << 9) + (get8(r, (j << 3) + i) << 1); + z0 = z0 ^ Ax[k]; + z1 = z1 ^ Ax[k + 1]; + } + x[i << 1] = z0; + x[(i << 1) + 1] = z1; + } + } + + var data = new512(), + Ki = new512(); + function g(h, N, m) { + var i; + + copy512(data, h); + XLPS(data, N); + + /* Starting E() */ + copy512(Ki, data); + XLPS(data, m); + + for (i = 0; i < 11; i++) { + XLPS(Ki, C[i]); + XLPS(data, Ki); + } + + XLPS(Ki, C[11]); + xor512(data, Ki); + /* E() done */ + + xor512(h, data); + xor512(h, m); + } + + // Stages + function stage2(d) { + var m = get512(d); + g(h, N, m); + + add512(N, buffer512); + add512(sigma, m); + } + + function stage3(d) { + var n = d.length; + if (n > 63) return; + + var b0 = new Int32Array(16); + b0[0] = n << 3; + + var b = new Uint8Array(64); + for (var i = 0; i < n; i++) b[i] = d[i]; + b[n] = 0x01; + + var m = get512(b), + m0 = get512(b0); + g(h, N, m); + + add512(N, m0); + add512(sigma, m); + + g(h, buffer0, N); + g(h, buffer0, sigma); + } + + return function(data) { + // Cleanup + sigma = new512(); + N = new512(); + + // Initial vector + h = new512(); + for (var i = 0; i < 16; i++) + if (this.bitLength === 256) h[i] = 0x01010101; + + // Make data + var d = new Uint8Array(buffer(data)); + + var n = d.length; + var r = n % 64, + q = (n - r) / 64; + + for (var i = 0; i < q; i++) + stage2.call(this, new Uint8Array(d.buffer, i * 64, 64)); + + stage3.call(this, new Uint8Array(d.buffer, q * 64, r)); + + var digest; + if (this.bitLength === 256) { + digest = new Int32Array(8); + for (var i = 0; i < 8; i++) digest[i] = h[8 + i]; + } else { + digest = new Int32Array(16); + for (var i = 0; i < 16; i++) digest[i] = h[i]; + } + // Swap hash for SignalCom + if (this.procreator === "SC" || this.procreator === "VN") + return swap(digest.buffer); + else return digest.buffer; + }; + })(); // + + /** + * Algorithm name GOST R 34.11-94

+ * + * http://tools.ietf.org/html/rfc5831 + * + * The digest method returns digest data in according to GOST R 34.11-94. + * @memberOf GostDigest + * @method digest + * @instance + * @param {(ArrayBuffer|TypedArray)} data Data + * @returns {ArrayBuffer} Digest of data + */ + var digest94 = (function() // + { + var C, H, M, Sum; + + // (i + 1 + 4(k - 1)) = 8i + k i = 0-3, k = 1-8 + function P(d) { + var K = new Uint8Array(32); + + for (var k = 0; k < 8; k++) { + K[4 * k] = d[k]; + K[1 + 4 * k] = d[8 + k]; + K[2 + 4 * k] = d[16 + k]; + K[3 + 4 * k] = d[24 + k]; + } + + return K; + } + + //A (x) = (x0 ^ x1) || x3 || x2 || x1 + function A(d) { + var a = new Uint8Array(8); + + for (var j = 0; j < 8; j++) { + a[j] = d[j] ^ d[j + 8]; + } + + arraycopy(d, 8, d, 0, 24); + arraycopy(a, 0, d, 24, 8); + + return d; + } + + // (in:) n16||..||n1 ==> (out:) n1^n2^n3^n4^n13^n16||n16||..||n2 + function fw(d) { + var wS = new Uint16Array(d.buffer, 0, 16); + var wS15 = wS[0] ^ wS[1] ^ wS[2] ^ wS[3] ^ wS[12] ^ wS[15]; + arraycopy(wS, 1, wS, 0, 15); + wS[15] = wS15; + } + + //Encrypt function, ECB mode + function encrypt(key, s, sOff, d, dOff) { + var t = new Uint8Array(8); + arraycopy(d, dOff, t, 0, 8); + var r = new Uint8Array(this.cipher.encrypt(key, t)); + arraycopy(r, 0, s, sOff, 8); + } + + // block processing + function process(d, dOff) { + var S = new Uint8Array(32), + U = new Uint8Array(32), + V = new Uint8Array(32), + W = new Uint8Array(32); + + arraycopy(d, dOff, M, 0, 32); + + //key step 1 + + // H = h3 || h2 || h1 || h0 + // S = s3 || s2 || s1 || s0 + arraycopy(H, 0, U, 0, 32); + arraycopy(M, 0, V, 0, 32); + for (var j = 0; j < 32; j++) { + W[j] = U[j] ^ V[j]; + } + // Encrypt GOST 28147-ECB + encrypt.call(this, P(W), S, 0, H, 0); // s0 = EK0 [h0] + + //keys step 2,3,4 + for (var i = 1; i < 4; i++) { + var tmpA = A(U); + for (var j = 0; j < 32; j++) { + U[j] = tmpA[j] ^ C[i][j]; + } + V = A(A(V)); + for (var j = 0; j < 32; j++) { + W[j] = U[j] ^ V[j]; + } + // Encrypt GOST 28147-ECB + encrypt.call(this, P(W), S, i * 8, H, i * 8); // si = EKi [hi] + } + + // x(M, H) = y61(H^y(M^y12(S))) + for (var n = 0; n < 12; n++) { + fw(S); + } + for (var n = 0; n < 32; n++) { + S[n] = S[n] ^ M[n]; + } + + fw(S); + + for (var n = 0; n < 32; n++) { + S[n] = H[n] ^ S[n]; + } + for (var n = 0; n < 61; n++) { + fw(S); + } + arraycopy(S, 0, H, 0, H.length); + } + + // 256 bitsblock modul -> (Sum + a mod (2^256)) + function summing(d) { + var carry = 0; + for (var i = 0; i < Sum.length; i++) { + var sum = (Sum[i] & 0xff) + (d[i] & 0xff) + carry; + + Sum[i] = sum; + + carry = sum >>> 8; + } + } + + // reset the chaining variables to the IV values. + var C2 = new Uint8Array([ + 0x00, + 0xff, + 0x00, + 0xff, + 0x00, + 0xff, + 0x00, + 0xff, + 0xff, + 0x00, + 0xff, + 0x00, + 0xff, + 0x00, + 0xff, + 0x00, + 0x00, + 0xff, + 0xff, + 0x00, + 0xff, + 0x00, + 0x00, + 0xff, + 0xff, + 0x00, + 0x00, + 0x00, + 0xff, + 0xff, + 0x00, + 0xff + ]); + + return function(data) { + // Reset buffers + H = new Uint8Array(32); + M = new Uint8Array(32); + Sum = new Uint8Array(32); + + // Reset IV value + C = new Array(4); + for (var i = 0; i < 4; i++) C[i] = new Uint8Array(32); + arraycopy(C2, 0, C[2], 0, C2.length); + + // Make data + var d = new Uint8Array(buffer(data)); + + var n = d.length; + var r = n % 32, + q = (n - r) / 32; + + // Proccess full blocks + for (var i = 0; i < q; i++) { + var b = new Uint8Array(d.buffer, i * 32, 32); + + summing.call(this, b); // calc sum M + process.call(this, b, 0); + } + + // load d the remadder with padding zero; + if (r > 0) { + var b = new Uint8Array(d.buffer, q * 32), + c = new Uint8Array(32); + arraycopy(b, 0, c, 0, r); + summing.call(this, c); // calc sum M + process.call(this, c, 0); + } + + // get length into L (byteCount * 8 = bitCount) in little endian. + var L = new Uint8Array(32), + n8 = n * 8, + k = 0; + while (n8 > 0) { + L[k++] = n8 & 0xff; + n8 = Math.floor(n8 / 256); + } + process.call(this, L, 0); + process.call(this, Sum, 0); + + var h = H.buffer; + + // Swap hash for SignalCom + if (this.procreator === "SC") h = swap(h); + + return h; + }; + })(); // + + /** + * Algorithm name SHA-1

+ * + * https://tools.ietf.org/html/rfc3174 + * + * The digest method returns digest data in according to SHA-1.
+ * + * @memberOf GostDigest + * @method digest + * @instance + * @param {(ArrayBuffer|TypedArray)} data Data + * @returns {ArrayBuffer} Digest of data + */ + var digestSHA1 = (function() // + { + // Create a buffer for each 80 word block. + var state, + block = new Uint32Array(80); + + function common(a, e, w, k, f) { + return (f + e + w + k + ((a << 5) | (a >>> 27))) >>> 0; + } + + function f1(a, b, c, d, e, w) { + return common(a, e, w, 0x5a827999, d ^ (b & (c ^ d))); + } + + function f2(a, b, c, d, e, w) { + return common(a, e, w, 0x6ed9eba1, b ^ c ^ d); + } + + function f3(a, b, c, d, e, w) { + return common(a, e, w, 0x8f1bbcdc, (b & c) | (d & (b | c))); + } + + function f4(a, b, c, d, e, w) { + return common(a, e, w, 0xca62c1d6, b ^ c ^ d); + } + + function cycle(state, block) { + var a = state[0], + b = state[1], + c = state[2], + d = state[3], + e = state[4]; + + // Partially unroll loops so we don't have to shift variables. + var fn = f1; + for (var i = 0; i < 80; i += 5) { + if (i === 20) { + fn = f2; + } else if (i === 40) { + fn = f3; + } else if (i === 60) { + fn = f4; + } + e = fn(a, b, c, d, e, block[i]); + b = ((b << 30) | (b >>> 2)) >>> 0; + d = fn(e, a, b, c, d, block[i + 1]); + a = ((a << 30) | (a >>> 2)) >>> 0; + c = fn(d, e, a, b, c, block[i + 2]); + e = ((e << 30) | (e >>> 2)) >>> 0; + b = fn(c, d, e, a, b, block[i + 3]); + d = ((d << 30) | (d >>> 2)) >>> 0; + a = fn(b, c, d, e, a, block[i + 4]); + c = ((c << 30) | (c >>> 2)) >>> 0; + } + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + } + + // Swap bytes for 32bits word + function swap32(b) { + return ( + ((b & 0xff) << 24) | + ((b & 0xff00) << 8) | + ((b >> 8) & 0xff00) | + ((b >> 24) & 0xff) + ); + } + + // input is a Uint8Array bitstream of the data + return function(data) { + var d = new Uint8Array(buffer(data)), + dlen = d.length; + + // Pad the input string length. + var len = dlen + 9; + if (len % 64) { + len += 64 - (len % 64); + } + + state = new Uint32Array(5); + state[0] = 0x67452301; + state[1] = 0xefcdab89; + state[2] = 0x98badcfe; + state[3] = 0x10325476; + state[4] = 0xc3d2e1f0; + + for (var ofs = 0; ofs < len; ofs += 64) { + // Copy input to block and write padding as needed + for (var i = 0; i < 64; i++) { + var b = 0, + o = ofs + i; + if (o < dlen) { + b = d[o]; + } else if (o === dlen) { + b = 0x80; + } else { + // Write original bit length as a 64bit big-endian integer to the end. + var x = len - o - 1; + if (x >= 0 && x < 4) { + b = ((dlen << 3) >>> (x * 8)) & 0xff; + } + } + + // Interpret the input bytes as big-endian per the spec + if (i % 4 === 0) { + block[i >> 2] = b << 24; + } else { + block[i >> 2] |= b << ((3 - (i % 4)) * 8); + } + } + + // Extend the block + for (var i = 16; i < 80; i++) { + var w = + block[i - 3] ^ + block[i - 8] ^ + block[i - 14] ^ + block[i - 16]; + block[i] = (w << 1) | (w >>> 31); + } + + cycle(state, block); + } + + // Swap the bytes around since they are big endian internally + for (var i = 0; i < 5; i++) state[i] = swap32(state[i]); + return state.buffer; + }; + })(); // + + /** + * Algorithm name GOST R 34.11-HMAC

+ * + * HMAC with the specified hash function. + * @memberOf GostDigest + * @method sign + * @instance + * @param {ArrayBuffer} key The key for HMAC. + * @param {Hash} data Data + */ + function signHMAC(key, data) { + // + // GOST R 34.11-94 - B=32b, L=32b + // GOST R 34.11-256 - B=64b, L=32b + // GOST R 34.11-512 - B=64b, L=64b + var b = this.digest === digest94 ? 32 : 64, + l = this.bitLength / 8, + k = buffer(key), + d = buffer(data), + k0; + if (k.byteLength === b) k0 = new Uint8Array(k); + else { + var k0 = new Uint8Array(b); + if (k.byteLength > b) { + k0.set(new Uint8Array(this.digest(k))); + } else { + k0.set(new Uint8Array(k)); + } + } + var s0 = new Uint8Array(b + d.byteLength), + s1 = new Uint8Array(b + l); + for (var i = 0; i < b; i++) { + s0[i] = k0[i] ^ 0x36; + s1[i] = k0[i] ^ 0x5c; + } + s0.set(new Uint8Array(d), b); + s1.set(new Uint8Array(this.digest(s0)), b); + return this.digest(s1); + } // + + /** + * Algorithm name GOST R 34.11-HMAC

+ * + * Verify HMAC based on GOST R 34.11 hash + * + * @memberOf GostDigest + * @method verify + * @instance + * @param {(ArrayBuffer|TypedArray)} key Key which used for HMAC generation + * @param {(ArrayBuffer|TypedArray)} signature generated HMAC + * @param {(ArrayBuffer|TypedArray)} data Data + * @returns {boolean} HMAC verified = true + */ + function verifyHMAC(key, signature, data) { + // + var hmac = new Uint8Array(this.sign(key, data)), + test = new Uint8Array(signature); + if (hmac.length !== test.length) return false; + for (var i = 0, n = hmac.length; i < n; i++) + if (hmac[i] !== test[i]) return false; + return true; + } // + + /** + * Algorithm name GOST R 34.11-KDF

+ * + * Simple generate key 256/512 bit random seed for derivation algorithms + * + * @memberOf GostDigest + * @method generateKey + * @instance + * @returns {ArrayBuffer} Generated key + */ + function generateKey() { + // + return getSeed(this.bitLength).buffer; + } // + + /** + * Algorithm name GOST R 34.11-PFXKDF

+ * + * Derive bits from password (PKCS12 mode) + * + * @memberOf GostDigest + * @method deriveBits + * @instance + * @param {ArrayBuffer} baseKey - password after UTF-8 decoding + * @param {number} length output bit-length + * @returns {ArrayBuffer} result + */ + function deriveBitsPFXKDF(baseKey, length) { + // + if (length % 8 > 0) throw new DataError("Length must multiple of 8"); + var u = this.bitLength / 8, + v = this.digest === digest94 ? 32 : 64, + n = length / 8, + r = this.iterations; + // 1. Construct a string, D (the "diversifier"), by concatenating v/8 + // copies of ID. + var ID = this.diversifier, + D = new Uint8Array(v); + for (var i = 0; i < v; i++) D[i] = ID; + // 2. Concatenate copies of the salt together to create a string S of + // length v(ceiling(s/v)) bits (the final copy of the salt may be + // truncated to create S). Note that if the salt is the empty + // string, then so is S. + var S0 = new Uint8Array(buffer(this.salt)), + s = S0.length, + slen = v * Math.ceil(s / v), + S = new Uint8Array(slen); + for (var i = 0; i < slen; i++) S[i] = S0[i % s]; + // 3. Concatenate copies of the password together to create a string P + // of length v(ceiling(p/v)) bits (the final copy of the password + // may be truncated to create P). Note that if the password is the + // empty string, then so is P. + var P0 = new Uint8Array(buffer(baseKey)), + p = P0.length, + plen = v * Math.ceil(p / v), + P = new Uint8Array(plen); + for (var i = 0; i < plen; i++) P[i] = P0[i % p]; + // 4. Set I=S||P to be the concatenation of S and P. + var I = new Uint8Array(slen + plen); + arraycopy(S, 0, I, 0, slen); + arraycopy(P, 0, I, slen, plen); + // 5. Set c=ceiling(n/u). + var c = Math.ceil(n / u); + // 6. For i=1, 2, ..., c, do the following: + var A = new Uint8Array(c * u); + for (var i = 0; i < c; i++) { + // A. Set A2=H^r(D||I). (i.e., the r-th hash of D||1, + // H(H(H(... H(D||I)))) + var H = new Uint8Array(v + slen + plen); + arraycopy(D, 0, H, 0, v); + arraycopy(I, 0, H, v, slen + plen); + for (var j = 0; j < r; j++) H = new Uint8Array(this.digest(H)); + arraycopy(H, 0, A, i * u, u); + // B. Concatenate copies of Ai to create a string B of length v + // bits (the final copy of Ai may be truncated to create B). + var B = new Uint8Array(v); + for (var j = 0; j < v; j++) B[j] = H[j % u]; + // C. Treating I as a concatenation I_0, I_1, ..., I_(k-1) of v-bit + // blocks, where k=ceiling(s/v)+ceiling(p/v), modify I by + // setting I_j=(I_j+B+1) mod 2^v for each j. + var k = (slen + plen) / v; + for (j = 0; j < k; j++) { + var cf = 1, + w; + for (var l = v - 1; l >= 0; --l) { + w = I[v * j + l] + B[l] + cf; + cf = w >>> 8; + I[v * j + l] = w & 0xff; + } + } + } + // 7. Concatenate A_1, A_2, ..., A_c together to form a pseudorandom + // bit string, A. + // 8. Use the first n bits of A as the output of this entire process. + var R = new Uint8Array(n); + arraycopy(A, 0, R, 0, n); + return R.buffer; + } // + + /** + * Algorithm name GOST R 34.11-KDF

+ * + * Derive bits for KEK deversification in 34.10-2012 algorithm + * KDF(KEK, UKM, label) = HMAC256 (KEK, 0x01|label|0x00|UKM|0x01|0x00) + * Default label = 0x26|0xBD|0xB8|0x78 + * + * @memberOf GostDigest + * @method deriveBits + * @instance + * @param {(ArrayBuffer|TypedArray)} baseKey base key for deriviation + * @param {number} length output bit-length + * @returns {ArrayBuffer} result + */ + function deriveBitsKDF(baseKey, length) { + // + if (length % 8 > 0) throw new DataError("Length must be multiple of 8"); + var rlen = length / 8, + label, + context = new Uint8Array(buffer(this.context)), + blen = this.bitLength / 8, + n = Math.ceil(rlen / blen); + if (this.label) label = new Uint8Array(buffer(this.label)); + else label = new Uint8Array([0x26, 0xbd, 0xb8, 0x78]); + var result = new Uint8Array(rlen); + for (var i = 0; i < n; i++) { + var data = new Uint8Array(label.length + context.length + 4); + data[0] = i + 1; + data.set(label, 1); + data[label.length + 1] = 0x00; + data.set(context, label.length + 2); + data[data.length - 2] = length >>> 8; + data[data.length - 1] = length & 0xff; + result.set( + new Uint8Array( + signHMAC.call(this, baseKey, data), + 0, + i < n - 1 ? blen : rlen - i * blen + ), + i * blen + ); + } + return result.buffer; + } // + + /** + * Algorithm name GOST R 34.11-PBKDF1

+ * + * Derive bits from password + * + * @memberOf GostDigest + * @method deriveBits + * @instance + * @param {ArrayBuffer} baseKey - password after UTF-8 decoding + * @param {number} length output bit-length + * @returns {ArrayBuffer} result + */ + function deriveBitsPBKDF1(baseKey, length) { + // + if (length < this.bitLength / 2 || length % 8 > 0) + throw new DataError( + "Length must be more than " + + this.bitLength / 2 + + " bits and multiple of 8" + ); + var hLen = this.bitLength / 8, + dkLen = length / 8, + c = this.iterations, + P = new Uint8Array(buffer(baseKey)), + S = new Uint8Array(buffer(this.salt)), + slen = S.length, + plen = P.length, + T = new Uint8Array(plen + slen), + DK = new Uint8Array(dkLen); + if (dkLen > hLen) + throw new DataError("Invalid parameters: Length value"); + arraycopy(P, 0, T, 0, plen); + arraycopy(S, 0, T, plen, slen); + for (var i = 0; i < c; i++) T = new Uint8Array(this.digest(T)); + arraycopy(T, 0, DK, 0, dkLen); + return DK.buffer; + } // + + /** + * Algorithm name GOST R 34.11-PBKDF2

+ * + * Derive bits from password + * + * @memberOf GostDigest + * @method deriveBits + * @instance + * @param {ArrayBuffer} baseKey - password after UTF-8 decoding + * @param {number} length output bit-length + * @returns {ArrayBuffer} result + */ + function deriveBitsPBKDF2(baseKey, length) { + // + var diversifier = this.diversifier || 1; // For PKCS12 MAC required 3*length + length = length * diversifier; + if (length < this.bitLength / 2 || length % 8 > 0) + throw new DataError( + "Length must be more than " + + this.bitLength / 2 + + " bits and multiple of 8" + ); + var hLen = this.bitLength / 8, + dkLen = length / 8, + c = this.iterations, + P = new Uint8Array(buffer(baseKey)), + S = new Uint8Array(buffer(this.salt)); + var slen = S.byteLength, + data = new Uint8Array(slen + 4); + arraycopy(S, 0, data, 0, slen); + + if (dkLen > (0xffffffff - 1) * 32) + throw new DataError("Invalid parameters: Length value"); + var n = Math.ceil(dkLen / hLen), + DK = new Uint8Array(dkLen); + for (var i = 1; i <= n; i++) { + data[slen] = (i >>> 24) & 0xff; + data[slen + 1] = (i >>> 16) & 0xff; + data[slen + 2] = (i >>> 8) & 0xff; + data[slen + 3] = i & 0xff; + + var U = new Uint8Array(signHMAC.call(this, P, data)), + Z = U; + for (var j = 1; j < c; j++) { + U = new Uint8Array(signHMAC.call(this, P, U)); + for (var k = 0; k < hLen; k++) Z[k] = U[k] ^ Z[k]; + } + var ofs = (i - 1) * hLen; + arraycopy(Z, 0, DK, ofs, Math.min(hLen, dkLen - ofs)); + } + if (diversifier > 1) { + var rLen = dkLen / diversifier, + R = new Uint8Array(rLen); + arraycopy(DK, dkLen - rLen, R, 0, rLen); + return R.buffer; + } else return DK.buffer; + } // + + /** + * Algorithm name GOST R 34.11-CPKDF

+ * + * Derive bits from password. CryptoPro algorithm + * + * @memberOf GostDigest + * @method deriveBits + * @instance + * @param {ArrayBuffer} baseKey - password after UTF-8 decoding + * @param {number} length output bit-length + * @returns {ArrayBuffer} result + */ + function deriveBitsCP(baseKey, length) { + if (length > this.bitLength || length % 8 > 0) + throw new DataError( + "Length can't be more than " + + this.bitLength + + " bits and multiple of 8" + ); + // GOST R 34.11-94 - B=32b, L=32b + // GOST R 34.11-256 - B=64b, L=32b + // GOST R 34.11-512 - B=64b, L=64b + var b = this.digest === digest94 ? 32 : 64, + l = this.bitLength / 8, + p = + baseKey && baseKey.byteLength > 0 + ? new Uint8Array(buffer(baseKey)) + : false, + plen = p ? p.length : 0, + iterations = this.iterations, + salt = new Uint8Array(buffer(this.salt)), + slen = salt.length, + d = new Uint8Array(slen + plen); + arraycopy(salt, 0, d, 0, slen); + if (p) arraycopy(p, 0, d, slen, plen); + + var h = new Uint8Array(this.digest(d)), + k = new Uint8Array(b), + s0 = new Uint8Array(b), + s1 = new Uint8Array(b); + var c = "DENEFH028.760246785.IUEFHWUIO.EF"; + for (var i = 0; i < c.length; i++) k[i] = c.charCodeAt(i); + + d = new Uint8Array(2 * (b + l)); + for (var j = 0; j < iterations; j++) { + for (var i = 0; i < b; i++) { + s0[i] = k[i] ^ 0x36; + s1[i] = k[i] ^ 0x5c; + k[i] = 0; + } + arraycopy(s0, 0, d, 0, b); + arraycopy(h, 0, d, b, l); + arraycopy(s1, 0, d, b + l, b); + arraycopy(h, 0, d, b + l + b, l); + arraycopy(new Uint8Array(this.digest(d)), 0, k, 0, l); + } + for (var i = 0; i < l; i++) { + s0[i] = k[i] ^ 0x36; + s1[i] = k[i] ^ 0x5c; + k[i] = 0; + } + d = new Uint8Array(2 * l + slen + plen); + arraycopy(s0, 0, d, 0, l); + arraycopy(salt, 0, d, l, slen); + arraycopy(s1, 0, d, l + slen, l); + if (p) arraycopy(p, 0, d, l + slen + l, plen); + h = this.digest(this.digest(d)); + if (length === this.bitLength) return h; + else { + var rlen = length / 8, + r = new Uint8Array(rlen); + arraycopy(h, 0, r, 0, rlen); + return r.buffer; + } + } + + /** + * Algorithm name GOST R 34.11-KDF or GOST R 34.11-PBKDF2 or other

+ * + * Derive key from derive bits subset + * + * @memberOf GostDigest + * @method deriveKey + * @instance + * @param {ArrayBuffer} baseKey + * @returns {ArrayBuffer} + */ + function deriveKey(baseKey) { + // + return this.deriveBits(baseKey, this.keySize * 8); + } // + + /** + * GOST R 34.11 Algorithm

+ * + * References: {@link http://tools.ietf.org/html/rfc6986} and {@link http://tools.ietf.org/html/rfc5831}

+ * + * Normalized algorithm identifier common parameters: + * + * + * + * Supported algorithms, modes and parameters: + * + * + * + * @class GostDigest + * @param {AlgorithmIdentifier} algorithm WebCryptoAPI algorithm identifier + */ + function GostDigest(algorithm) { + // + algorithm = algorithm || {}; + + this.name = + (algorithm.name || "GOST R 34.10") + + "-" + + ((algorithm.version || 2012) % 100) + + ((algorithm.version || 2012) > 1 + ? "-" + (algorithm.length || 256) + : "") + + ((algorithm.mode || "HASH") !== "HASH" + ? "-" + algorithm.mode + : "") + + (algorithm.procreator ? "/" + algorithm.procreator : "") + + (typeof algorithm.sBox === "string" ? "/" + algorithm.sBox : ""); + + // Algorithm procreator + this.procreator = algorithm.procreator; + + // Bit length + this.bitLength = algorithm.length || 256; + + switch (algorithm.version || 2012) { + case 1: // SHA-1 + this.digest = digestSHA1; + this.bitLength = 160; + break; + case 1994: + this.digest = digest94; + // Define chiper algorithm + this.sBox = ( + algorithm.sBox || + (algorithm.procreator === "SC" ? "D-SC" : "D-A") + ).toUpperCase(); + + if (!GostCipher) GostCipher = root.GostCipher; + if (!GostCipher) + throw new NotSupportedError("Object GostCipher not found"); + + this.cipher = new GostCipher({ + name: "GOST 28147", + block: "ECB", + sBox: this.sBox, + procreator: this.procreator + }); + + break; + case 2012: + this.digest = digest2012; + break; + default: + throw new NotSupportedError( + "Algorithm version " + algorithm.version + " not supported" + ); + } + + // Key size + this.keySize = + algorithm.keySize || + (algorithm.version <= 2 ? this.bitLength / 8 : 32); + + switch (algorithm.mode || "HASH") { + case "HASH": + break; + case "HMAC": + this.sign = signHMAC; + this.verify = verifyHMAC; + this.generateKey = generateKey; + break; + case "KDF": + this.deriveKey = deriveKey; + this.deriveBits = deriveBitsKDF; + this.label = algorithm.label; + this.context = algorithm.context; + break; + case "PBKDF2": + this.deriveKey = deriveKey; + this.deriveBits = deriveBitsPBKDF2; + this.generateKey = generateKey; + this.salt = algorithm.salt; + this.iterations = algorithm.iterations || 2000; + this.diversifier = algorithm.diversifier || 1; + break; + case "PFXKDF": + this.deriveKey = deriveKey; + this.deriveBits = deriveBitsPFXKDF; + this.generateKey = generateKey; + this.salt = algorithm.salt; + this.iterations = algorithm.iterations || 2000; + this.diversifier = algorithm.diversifier || 1; + break; + case "CPKDF": + this.deriveKey = deriveKey; + this.deriveBits = deriveBitsCP; + this.generateKey = generateKey; + this.salt = algorithm.salt; + this.iterations = algorithm.iterations || 2000; + break; + default: + throw new NotSupportedError( + "Algorithm mode " + algorithm.mode + " not supported" + ); + } + } // + + return GostDigest; +}); diff --git a/src/core/vendor/streebog/gostCipher.js b/src/core/vendor/streebog/gostCipher.js new file mode 100644 index 00000000..b3ec0116 --- /dev/null +++ b/src/core/vendor/streebog/gostCipher.js @@ -0,0 +1,2267 @@ +/** + * @file GOST 28147-89/GOST R 34.12-2015/GOST R 32.13-2015 Encryption Algorithm + * @version 1.76 + * @copyright 2014-2016, Rudolf Nickolaev. All rights reserved. + */ + +/* + * 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. + * + */ + +(function (root, factory) { + + /* + * Module imports and exports + * + */ // + module.exports = factory(require('./gostRandom')); + +// + +}(this, function (GostRandom) { + + /* + * Initial parameters and common algortithms of GOST 28147-89 + * + * http://tools.ietf.org/html/rfc5830 + * + */ // + + var root = this; + var rootCrypto = root.crypto || root.msCrypto; + var CryptoOperationData = root.ArrayBuffer; + var SyntaxError = root.SyntaxError || root.Error, + DataError = root.DataError || root.Error, + NotSupportedError = root.NotSupportedError || root.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 && 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); + } + + // + + /* + * Initial parameters and common algortithms of GOST R 34.12-15 + * Algorithm "Kuznechik" 128bit + * + */ // + + // 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); + } + + // + + /** + * Key schedule for GOST R 34.12-15 128bits + * + * @memberOf GostCipher + * @private + * @instance + * @method keySchedule + * @param {type} k + * @returns {Uint8Array} + */ + function keySchedule128(k) // + { + 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; + } // + + /** + * 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) // + { + 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)); + } + } // + + /** + * 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) // + { + 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; + + } // + + /** + * 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) // + { + 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; + } // + + /** + * 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) // + { + 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]); + } // + + /** + * 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) // + { + 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; + } // + + /** + * 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) // + { + 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; + } // + + /** + * Key schedule for RC2 + * + * https://tools.ietf.org/html/rfc2268 + * + * @memberOf GostCipher + * @private + * @instance + * @method keySchedule + * @param {Uint8Array} k + * @returns {Uint16Array} + */ + var keyScheduleRC2 = (function () // + { + // 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; + }; + } // + )(); + + /** + * 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 () // + { + 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); + }; + } // + )(); + + /** + * Algorithm name GOST 28147-ECB

+ * + * 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) // + { + 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; + } // + + /** + * Algorithm name GOST 28147-ECB

+ * + * 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) // + { + 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; + } // + + /** + * Algorithm name GOST 28147-CFB

+ * + * 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) // + { + 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; + } // + + /** + * Algorithm name GOST 28147-CFB

+ * + * 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) // + { + 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; + } // + + /** + * Algorithm name GOST 28147-OFB

+ * + * 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

+ * + * 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) // + { + 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; + } // + + /** + * Algorithm name GOST 28147-CTR

+ * + * 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

+ * + * 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) // + { + 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; + } // + + function processCTR15(k, d, iv) // + { + 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; + } // + + /** + * Algorithm name GOST 28147-CBC

+ * + * 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) // + { + 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; + } // + + /** + * Algorithm name GOST 28147-CBC

+ * + * 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) // + { + 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; + } // + + /** + * The generateKey method returns a new generated key. + * + * @memberOf GostCipher + * @method generateKey + * @instance + * @return {CryptoOperationData} result + */ + + function generateKey() // + { + // Simple generate 256 bit random seed + var k = new Uint8Array(this.keySize); + randomSeed(k); + return k.buffer; + } // + + + /** + * 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) // + { + 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]); + } + } // + + function processKeyMAC15(s) // + { + 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; + } + } // + + function processMAC15(key, s, d) // + { + 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); + } + } // + + /** + * 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) // + { + 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; + } // + + /** + * 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) // + { + 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; + } // + + /** + * Algorithm name GOST 28147-KW

+ * + * 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) // + { + 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; + } // + + /** + * Algorithm name GOST 28147-KW

+ * + * 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) // + { + 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; + } // + + /** + * Algorithm name GOST 28147-CPKW

+ * + * 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) // + { + 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; + } // + + /** + * Algorithm name GOST 28147-CPKW

+ * + * 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) // + { + 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; + } // + + /** + * Algorithm name GOST 28147-CPKW

+ * + * 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) // + { + 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) 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); + // 4) Decrypt CEK_ENC in ECB mode using KEK(UKM). Call the output CEK. + var cek = decryptECB.call(this, dek, enc); + // 5) Compute a 4-byte checksum value, GOST 28147IMIT (UKM, KEK(UKM), + // CEK), compare the result with CEK_MAC. If they are not equal, + // then it is an error. + var check = verifyMAC.call(this, dek, mac, cek, ukm); + if (!check) + throw new DataError('Error verify MAC of wrapping key'); + return cek; + } // + + /** + * SignalCom master key packing algorithm + * + * kek stored in 3 files - kek.opq, mk.db3, masks.db3 + * kek.opq - always 36 bytes length = 32 bytes encrypted kek + 4 bytes mac of decrypted kek + * mk.db3 - 6 bytes header (1 byte magic code 0x22 + 1 byte count of masks + 4 bytes mac of + * xor summarizing masks value) + attached masks + * masks.db3 - detached masks. + * Total length of attached + detached masks = 32 bits * count of masks + * Default value of count 8 = (7 attached + 1 detached). But really no reason for such + * separation - all masks xor summarizing - order is not matter. + * Content of file rand.opq can used as ukm. Don't forget change file content after using. + * + * For usb-token files has names: + * a001 - mk.db3, b001 - masks.db3, c001 - kek.opq, d001 - rand.opq + * For windows registry + * 00000001 - mk.db3, 00000002 - masks.db3, 00000003 - key.opq, 00000004 - rand.opq, + * 00000006 - keys\00000001.key, 0000000A - certificate + * + * @memberOf GostCipher + * @method packKey + * @instance + * @private + * @param {CryptoOperationData} unpacked - clear main key 32 bytes + * @param {CryptoOperationData} ukm - random vector for packing - 32 bytes * (count of masks - 1) + * @returns {CryptoOperationData} packed master key - concatination of mk.db3 + masks.db3 + */ + function packKeySC(unpacked, ukm) // + { + var m = this.blockSize >> 1, k = this.keySize; + var mcount = 8; + var key = new Uint8Array(buffer(unpacked)); + if (key.byteLength !== k) + throw new DataError('Wrong cleartext size ' + key.byteLength + ' bytes'); + // Check or generate UKM + ukm = ukm || this.ukm; + if (ukm) { + ukm = new Uint8Array(buffer(ukm)); + if (ukm.byteLength > 0 && ukm.byteLength % k === 0) + mcount = ukm.byteLength / k + 1; + else + throw new DataError('Wrong rand size ' + ukm.byteLength + ' bytes'); + } else + randomSeed(ukm = new Uint8Array((mcount - 1) * k)); + // Output array + var d = new Uint8Array(mcount * k + m + 2), b = d.buffer; + // Calculate MAC + var zero32 = new Uint8Array(k); + var mac = signMAC.call(this, key, zero32); + d[0] = 0x22; // Magic code + d[1] = mcount; // Count of masks + d.set(new Uint8Array(mac), 2); + d.set(ukm, k + m + 2); + for (var i = 1; i < mcount; i++) { + var mask = new Uint8Array(b, 2 + m + k * i); + for (var j = 0; j < k; j++) + key[j] ^= mask[j]; + } + d.set(key, m + 2); + return d.buffer; + } // + + /** + * Algorithm name GOST 28147-SCKW

+ * + * SignalCom master key unpacking algorithm + * + * @memberOf GostCipher + * @method unpackKey + * @instance + * @private + * @param {CryptoOperationData} packed - concatination of mk.db3 + masks.db3 + * @returns {CryptoOperationData} unpacked master key + */ + function unpackKeySC(packed) // + { + var m = this.blockSize >> 1, k = this.keySize; + var b = buffer(packed); + // Unpack master key + var magic = new Uint8Array(b, 0, 1)[0]; + if (magic !== 0x22) + throw new DataError('Invalid magic number'); + var mcount = new Uint8Array(b, 1, 1)[0]; + var mac = new Uint8Array(b, 2, m); // MAC for summarized mask + // Compute packKey xor summing for all masks + var key = new Uint8Array(k); + for (var i = 0; i < mcount; i++) { + var mask = new Uint8Array(b, 2 + m + k * i, k); + for (var j = 0; j < k; j++) + key[j] ^= mask[j]; + } + // Test MAC for packKey with default sBox on zero 32 bytes array + var zero32 = new Uint8Array(k); + var test = verifyMAC.call(this, key, mac, zero32); + if (!test) { + // Try to use different sBoxes + var names = ['E-A', 'E-B', 'E-C', 'E-D', 'E-SC']; + for (var i = 0, n = names.length; i < n; i++) { + this.sBox = sBoxes[names[i]]; + test = verifyMAC.call(this, key, mac, zero32); + if (test) + break; + } + } + if (!test) + throw new DataError('Invalid main key MAC'); + return key.buffer; + } // + + /** + * Algorithm name GOST 28147-SCKW

+ * + * SignalCom Key Wrapping algorithm + * + * @memberOf GostCipher + * @method wrapKey + * @instance + * @param {CryptoOperationData} kek - clear kek or concatination of mk.db3 + masks.db3 + * @param {CryptoOperationData} cek - key for wrapping + * @returns {CryptoOperationData} wrapped key - file kek.opq + */ + function wrapKeySC(kek, cek) // + { + var m = this.blockSize >> 1, n = this.keySize; + var k = buffer(kek); + var c = buffer(cek); + if (k.byteLength !== n) + k = unpackKeySC.call(this, k); + var enc = encryptECB.call(this, k, c); + var mac = signMAC.call(this, k, c); + var d = new Uint8Array(m + n); + d.set(new Uint8Array(enc), 0); + d.set(new Uint8Array(mac), n); + return d.buffer; + } // + + /** + * Algorithm name GOST 28147-SCKW

+ * + * SignalCom Key UnWrapping algorithm + * + * @memberOf GostCipher + * @method unwrapKey + * @instance + * @param {CryptoOperationData} kek - concatination of files mk.db3 + masks.db3 or clear kek + * @param {CryptoOperationData} cek - wrapping key - file kek.opq + * @return {CryptoOperationData} result + */ + function unwrapKeySC(kek, cek) // + { + var m = this.blockSize >> 1, n = this.keySize; + var k = buffer(kek); + var c = buffer(cek); + if (k.byteLength !== n) + k = unpackKeySC.call(this, k); + var enc = new Uint8Array(c, 0, n); // Encrypted kek + var mac = new Uint8Array(c, n, m); // MAC for clear kek + var d = decryptECB.call(this, k, enc); + if (!verifyMAC.call(this, k, mac, d)) + throw new DataError('Invalid key MAC'); + return d; + } // + + /** + * Algorithm name GOST 28147-SCKW

+ * + * SignalCom master key generation for wrapping + * + * @memberOf GostCipher + * @method generateKey + * @instance + * @return {CryptoOperationData} result + */ + function generateWrappingKeySC() // + { + return packKeySC.call(this, generateKey.call(this)); + } // + + function maskKey(mask, key, inverse, keySize) // + { + var k = keySize / 4, + m32 = new Int32Array(buffer(mask)), + k32 = new Int32Array(buffer(key)), + r32 = new Int32Array(k); + if (inverse) + for (var i = 0; i < k; i++) + r32[i] = (k32[i] + m32[i]) & 0xffffffff; + else + for (var i = 0; i < k; i++) + r32[i] = (k32[i] - m32[i]) & 0xffffffff; + return r32.buffer; + } // + + /** + * Algorithm name GOST 28147-MASK

+ * + * This algorithm wrap key mask + * + * @memberOf GostCipher + * @method wrapKey + * @instance + * @param {CryptoOperationData} mask The mask + * @param {CryptoOperationData} key The key + * @returns {CryptoOperationData} The masked key + */ + function wrapKeyMask(mask, key) // + { + return maskKey(mask, key, this.procreator === 'VN', this.keySize); + } // + + /** + * Algorithm name GOST 28147-CPKW

+ * + * This algorithm unwrap key mask + * + * @memberOf GostCipher + * @method unwrapKey + * @instance + * @param {CryptoOperationData} mask The mask + * @param {CryptoOperationData} key The masked key + * @return {CryptoOperationData} result The key + */ + function unwrapKeyMask(mask, key) // + { + return maskKey(mask, key, this.procreator !== 'VN', this.keySize); + } // + + /** + * Algorithm name GOST 28147-CPKM

+ * + * Key meshing in according to rfc4357 2.3.2. CryptoPro Key Meshing + * + * @memberOf GostCipher + * @method keyMeshing + * @instance + * @private + * @param {(Uint8Array|CryptoOperationData)} k 8x8 bit key + * @param {Uint8Array} s 8x8 bit sync (iv) + * @param {Integer} i block index + * @param {Int32Array} key 8x32 bit key schedule + * @param {boolean} e true - decrypt + * @returns CryptoOperationData next 8x8 bit key + */ + function keyMeshingCP(k, s, i, key, e) // + { + if ((i + 1) * this.blockSize % 1024 === 0) { // every 1024 octets + // K[i+1] = decryptECB (K[i], C); + k = decryptECB.call(this, k, C); + // IV0[i+1] = encryptECB (K[i+1],IVn[i]) + s.set(new Uint8Array(encryptECB.call(this, k, s))); + // restore key schedule + key.set(this.keySchedule(k, e)); + } + return k; + } // + + /** + * Null Key Meshing in according to rfc4357 2.3.1 + * + * @memberOf GostCipher + * @method keyMeshing + * @instance + * @private + * @param {(Uint8Array|CryptoOperationData)} k 8x8 bit key + */ + function noKeyMeshing(k) // + { + return k; + } // + + /** + * Algorithm name GOST 28147-NoPadding

+ * + * No padding. + * + * @memberOf GostCipher + * @method padding + * @instance + * @private + * @param {Uint8Array} d array with source data + * @returns {Uint8Array} result + */ + function noPad(d) // + { + return new Uint8Array(d); + } // + + /** + * Algorithm name GOST 28147-PKCS5Padding

+ * + * PKCS#5 padding: 8-x remaining bytes are filled with the value of + * 8-x. If there’s no incomplete block, one extra block filled with + * value 8 is added + * + * @memberOf GostCipher + * @method padding + * @instance + * @private + * @param {Uint8Array} d array with source data + * @returns {Uint8Array} result + */ + function pkcs5Pad(d) // + { + var n = d.byteLength, + nb = this.blockSize, + q = nb - n % nb, + m = Math.ceil((n + 1) / nb) * nb, + r = new Uint8Array(m); + r.set(d); + for (var i = n; i < m; i++) + r[i] = q; + return r; + } // + + function pkcs5Unpad(d) // + { + var m = d.byteLength, + nb = this.blockSize, + q = d[m - 1], + n = m - q; + if (q > nb) + throw DataError('Invalid padding'); + var r = new Uint8Array(n); + if (n > 0) + r.set(new Uint8Array(d.buffer, 0, n)); + return r; + } // + + + /** + * Algorithm name GOST 28147-ZeroPadding

+ * + * Zero padding: 8-x remaining bytes are filled with zero + * + * @memberOf GostCipher + * @method padding + * @instance + * @private + * @param {Uint8Array} d array with source data + * @returns {Uint8Array} result + */ + function zeroPad(d) // + { + var n = d.byteLength, + nb = this.blockSize, + m = Math.ceil(n / nb) * nb, + r = new Uint8Array(m); + r.set(d); + for (var i = n; i < m; i++) + r[i] = 0; + return r; + } // + + + /** + * Algorithm name GOST 28147-BitPadding

+ * + * Bit padding: P* = P || 1 || 000...0 If there’s no incomplete block, + * one extra block filled with 1 || 000...0 + * + * @memberOf GostCipher + * @method padding + * @instance + * @private + * @param {Uint8Array} d array with source data + * @returns {Uint8Array} result + */ + function bitPad(d) // + { + var n = d.byteLength, + nb = this.blockSize, + m = Math.ceil((n + 1) / nb) * nb, + r = new Uint8Array(m); + r.set(d); + r[n] = 1; + for (var i = n + 1; i < m; i++) + r[i] = 0; + return r; + } // + + function bitUnpad(d) // + { + var m = d.byteLength, + n = m; + while (n > 1 && d[n - 1] === 0) + n--; + if (d[n - 1] !== 1) + throw DataError('Invalid padding'); + n--; + var r = new Uint8Array(n); + if (n > 0) + r.set(new Uint8Array(d.buffer, 0, n)); + return r; + } // + + /** + * Algorithm name GOST 28147-RandomPadding

+ * + * Random padding: 8-x remaining bytes of the last block are set to + * random. + * + * @memberOf GostCipher + * @method padding + * @instance + * @private + * @param {Uint8Array} d array with source data + * @returns {Uint8Array} result + */ + function randomPad(d) // + { + var n = d.byteLength, + nb = this.blockSize, + q = nb - n % nb, + m = Math.ceil(n / nb) * nb, + r = new Uint8Array(m), e = new Uint8Array(r.buffer, n, q); + r.set(d); + randomSeed(e); + return r; + } // + + /** + * GOST 28147-89 Encryption Algorithm

+ * + * References {@link http://tools.ietf.org/html/rfc5830}

+ * + * When keys and initialization vectors are converted to/from byte arrays, + * little-endian byte order is assumed.

+ * + * Normalized algorithm identifier common parameters: + * + * + * + * Supported algorithms, modes and parameters: + * + * + * + * Supported paramters values: + * + * + * + * @class GostCipher + * @param {AlgorithmIndentifier} algorithm WebCryptoAPI algorithm identifier + */ + function GostCipher(algorithm) // + { + // Check little endian support + if (!littleEndian) + throw new NotSupportedError('Big endian platform not supported'); + algorithm = algorithm || {}; + this.keySize = 32; + this.blockLength = algorithm.length || 64; + this.blockSize = this.blockLength >> 3; + + this.name = (algorithm.name || (algorithm.version === 1 ? 'RC2' : + algorithm.version === 1989 ? 'GOST 28147' : 'GOST R 34.12')) + + (algorithm.version > 4 ? '-' + ((algorithm.version || 1989) % 100) : '') + '-' + + (this.blockLength === 64 ? '' : this.blockLength + '-') + + ((algorithm.mode === 'MAC') ? 'MAC-' + (algorithm.macLength || this.blockLength >> 1) : + (algorithm.mode === 'KW' || algorithm.keyWrapping) ? + ((algorithm.keyWrapping || 'NO') !== 'NO' ? algorithm.keyWrapping : '') + 'KW' : + (algorithm.block || 'ECB') + ((algorithm.block === 'CFB' || algorithm.block === 'OFB' || + (algorithm.block === 'CTR' && algorithm.version === 2015)) && + algorithm.shiftBits && algorithm.shiftBits !== this.blockLength ? '-' + algorithm.shiftBits : '') + + (algorithm.padding ? '-' + (algorithm.padding || (algorithm.block === 'CTR' || + algorithm.block === 'CFB' || algorithm.block === 'OFB' ? 'NO' : 'ZERO')) + 'PADDING' : '') + + ((algorithm.keyMeshing || 'NO') !== 'NO' ? '-CPKEYMESHING' : '')) + + (algorithm.procreator ? '/' + algorithm.procreator : '') + + (typeof algorithm.sBox === 'string' ? '/' + algorithm.sBox : ''); + + // Algorithm procreator + this.procreator = algorithm.procreator; + + switch (algorithm.version || 1989) { + case 1: + this.process = processRC2; + this.keySchedule = keyScheduleRC2; + this.blockLength = 64; + this.effectiveLength = algorithm.length || 32; + this.keySize = 8 * Math.ceil(this.effectiveLength / 8); // Max 128 + this.blockSize = this.blockLength >> 3; + break; + case 2015: + this.version = 2015; + if (this.blockLength === 64) { + this.process = process15; + this.keySchedule = keySchedule15; + } else if (this.blockLength === 128) { + this.process = process128; + this.keySchedule = keySchedule128; + } else + throw new DataError('Invalid block length'); + this.processMAC = processMAC15; + break; + case 1989: + this.version = 1989; + this.process = process89; + this.processMAC = processMAC89; + this.keySchedule = keySchedule89; + if (this.blockLength !== 64) + throw new DataError('Invalid block length'); + break; + default: + throw new NotSupportedError('Algorithm version ' + algorithm.version + ' not supported'); + } + + switch (algorithm.mode || (algorithm.keyWrapping && 'KW') || 'ES') { + + case 'ES': + switch (algorithm.block || 'ECB') { + case 'ECB': + this.encrypt = encryptECB; + this.decrypt = decryptECB; + break; + case 'CTR': + if (this.version === 1989) { + this.encrypt = processCTR89; + this.decrypt = processCTR89; + } else { + this.encrypt = processCTR15; + this.decrypt = processCTR15; + this.shiftBits = algorithm.shiftBits || this.blockLength; + } + break + case 'CBC': + this.encrypt = encryptCBC; + this.decrypt = decryptCBC; + break + case 'CFB': + this.encrypt = encryptCFB; + this.decrypt = decryptCFB; + this.shiftBits = algorithm.shiftBits || this.blockLength; + break; + case 'OFB': + this.encrypt = processOFB; + this.decrypt = processOFB; + this.shiftBits = algorithm.shiftBits || this.blockLength; + break; + default: + throw new NotSupportedError('Block mode ' + algorithm.block + ' not supported'); + } + switch (algorithm.keyMeshing) { + case 'CP': + this.keyMeshing = keyMeshingCP; + break; + default: + this.keyMeshing = noKeyMeshing; + } + if (this.encrypt === encryptECB || this.encrypt === encryptCBC) { + switch (algorithm.padding) { + case 'PKCS5P': + this.pad = pkcs5Pad; + this.unpad = pkcs5Unpad; + break; + case 'RANDOM': + this.pad = randomPad; + this.unpad = noPad; + break; + case 'BIT': + this.pad = bitPad; + this.unpad = bitUnpad; + break; + default: + this.pad = zeroPad; + this.unpad = noPad; + } + } else { + this.pad = noPad; + this.unpad = noPad; + } + this.generateKey = generateKey; + break; + case 'MAC': + this.sign = signMAC; + this.verify = verifyMAC; + this.generateKey = generateKey; + this.macLength = algorithm.macLength || (this.blockLength >> 1); + this.pad = noPad; + this.unpad = noPad; + this.keyMeshing = noKeyMeshing; + break; + case 'KW': + this.pad = noPad; + this.unpad = noPad; + this.keyMeshing = noKeyMeshing; + switch (algorithm.keyWrapping) { + case 'CP': + this.wrapKey = wrapKeyCP; + this.unwrapKey = unwrapKeyCP; + this.generateKey = generateKey; + this.shiftBits = algorithm.shiftBits || this.blockLength; + break; + case 'SC': + this.wrapKey = wrapKeySC; + this.unwrapKey = unwrapKeySC; + this.generateKey = generateWrappingKeySC; + break; + default: + this.wrapKey = wrapKeyGOST; + this.unwrapKey = unwrapKeyGOST; + this.generateKey = generateKey; + } + break; + case 'MASK': + this.wrapKey = wrapKeyMask; + this.unwrapKey = unwrapKeyMask; + this.generateKey = generateKey; + break; + default: + throw new NotSupportedError('Mode ' + algorithm.mode + ' not supported'); + } + + // Define sBox parameter + var sBox = algorithm.sBox, sBoxName; + if (!sBox) + sBox = this.version === 2015 ? sBoxes['E-Z'] : this.procreator === 'SC' ? sBoxes['E-SC'] : sBoxes['E-A']; + else if (typeof sBox === 'string') { + sBoxName = sBox.toUpperCase(); + sBox = sBoxes[sBoxName]; + if (!sBox) + throw new SyntaxError('Unknown sBox name: ' + algorithm.sBox); + } else if (!sBox.length || sBox.length !== sBoxes['E-Z'].length) + throw new SyntaxError('Length of sBox must be ' + sBoxes['E-Z'].length); + this.sBox = sBox; + // Initial vector + if (algorithm.iv) { + this.iv = new Uint8Array(algorithm.iv); + if (this.iv.byteLength !== this.blockSize && this.version === 1989) + throw new SyntaxError('Length of iv must be ' + this.blockLength + ' bits'); + else if (this.iv.byteLength !== this.blockSize >> 1 && this.encrypt === processCTR15) + throw new SyntaxError('Length of iv must be ' + this.blockLength >> 1 + ' bits'); + else if (this.iv.byteLength % this.blockSize !== 0 && this.encrypt !== processCTR15) + throw new SyntaxError('Length of iv must be a multiple of ' + this.blockLength + ' bits'); + } else + this.iv = this.blockLength === 128 ? defaultIV128 : defaultIV; + // User key material + if (algorithm.ukm) { + this.ukm = new Uint8Array(algorithm.ukm); + if (this.ukm.byteLength * 8 !== this.blockLength) + throw new SyntaxError('Length of ukm must be ' + this.blockLength + ' bits'); + } + } // + + return GostCipher; +})); + diff --git a/src/core/vendor/streebog/gostCoding.js b/src/core/vendor/streebog/gostCoding.js new file mode 100644 index 00000000..cc909c12 --- /dev/null +++ b/src/core/vendor/streebog/gostCoding.js @@ -0,0 +1,1171 @@ +/** + * @file Coding algorithms: Base64, Hex, Int16, Chars, BER and PEM + * @version 1.76 + * @copyright 2014-2016, Rudolf Nickolaev. All rights reserved. + */ + +/* + * 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. + * + */ + +(function (root, factory) { + + /* + * Module imports and exports + * + */ // + if (typeof exports === 'object') { + module.exports = factory(require('./gostCrypto')); + } + // + +}(this, function (gostCrypto) { + + /** + * The Coding interface provides string converting methods: Base64, Hex, + * Int16, Chars, BER and PEM + * @class GostCoding + * + */ // + var root = this; + var DataError = root.DataError || root.Error; + var CryptoOperationData = root.ArrayBuffer; + var Date = root.Date; + + function buffer(d) { + if (d instanceof CryptoOperationData) + return d; + else if (d && d.buffer && 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'); + } // + + function GostCoding() { + } + + /** + * BASE64 conversion + * + * @class GostCoding.Base64 + */ + var Base64 = {// + /** + * Base64.decode convert BASE64 string s to CryptoOperationData + * + * @memberOf GostCoding.Base64 + * @param {String} s BASE64 encoded string value + * @returns {CryptoOperationData} Binary decoded data + */ + decode: function (s) { + s = s.replace(/[^A-Za-z0-9\+\/]/g, ''); + var n = s.length, + k = n * 3 + 1 >> 2, r = new Uint8Array(k); + + for (var m3, m4, u24 = 0, j = 0, i = 0; i < n; i++) { + m4 = i & 3; + var c = s.charCodeAt(i); + + c = c > 64 && c < 91 ? + c - 65 : c > 96 && c < 123 ? + c - 71 : c > 47 && c < 58 ? + c + 4 : c === 43 ? + 62 : c === 47 ? + 63 : 0; + + u24 |= c << 18 - 6 * m4; + if (m4 === 3 || n - i === 1) { + for (m3 = 0; m3 < 3 && j < k; m3++, j++) { + r[j] = u24 >>> (16 >>> m3 & 24) & 255; + } + u24 = 0; + + } + } + return r.buffer; + }, + /** + * Base64.encode(data) convert CryptoOperationData data to BASE64 string + * + * @memberOf GostCoding.Base64 + * @param {CryptoOperationData} data Bynary data for encoding + * @returns {String} BASE64 encoded data + */ + encode: function (data) { + var slen = 8, d = new Uint8Array(buffer(data)); + var m3 = 2, s = ''; + for (var n = d.length, u24 = 0, i = 0; i < n; i++) { + m3 = i % 3; + if (i > 0 && (i * 4 / 3) % (12 * slen) === 0) + s += '\r\n'; + u24 |= d[i] << (16 >>> m3 & 24); + if (m3 === 2 || n - i === 1) { + for (var j = 18; j >= 0; j -= 6) { + var c = u24 >>> j & 63; + c = c < 26 ? c + 65 : c < 52 ? c + 71 : c < 62 ? c - 4 : + c === 62 ? 43 : c === 63 ? 47 : 65; + s += String.fromCharCode(c); + } + u24 = 0; + } + } + return s.substr(0, s.length - 2 + m3) + (m3 === 2 ? '' : m3 === 1 ? '=' : '=='); + } // + }; + + /** + * BASE64 conversion + * + * @memberOf GostCoding + * @insnance + * @type GostCoding.Base64 + */ + GostCoding.prototype.Base64 = Base64; + + /** + * Text string conversion
+ * Methods support charsets: ascii, win1251, utf8, utf16 (ucs2, unicode), utf32 (ucs4) + * + * @class GostCoding.Chars + */ + var Chars = (function () { // + + var _win1251_ = { + 0x402: 0x80, 0x403: 0x81, 0x201A: 0x82, 0x453: 0x83, 0x201E: 0x84, 0x2026: 0x85, 0x2020: 0x86, 0x2021: 0x87, + 0x20AC: 0x88, 0x2030: 0x89, 0x409: 0x8A, 0x2039: 0x8B, 0x40A: 0x8C, 0x40C: 0x8D, 0x40B: 0x8E, 0x40f: 0x8f, + 0x452: 0x90, 0x2018: 0x91, 0x2019: 0x92, 0x201C: 0x93, 0x201D: 0x94, 0x2022: 0x95, 0x2013: 0x96, 0x2014: 0x97, + 0x2122: 0x99, 0x459: 0x9A, 0x203A: 0x9B, 0x45A: 0x9C, 0x45C: 0x9D, 0x45B: 0x9E, 0x45f: 0x9f, + 0xA0: 0xA0, 0x40E: 0xA1, 0x45E: 0xA2, 0x408: 0xA3, 0xA4: 0xA4, 0x490: 0xA5, 0xA6: 0xA6, 0xA7: 0xA7, + 0x401: 0xA8, 0xA9: 0xA9, 0x404: 0xAA, 0xAB: 0xAB, 0xAC: 0xAC, 0xAD: 0xAD, 0xAE: 0xAE, 0x407: 0xAf, + 0xB0: 0xB0, 0xB1: 0xB1, 0x406: 0xB2, 0x456: 0xB3, 0x491: 0xB4, 0xB5: 0xB5, 0xB6: 0xB6, 0xB7: 0xB7, + 0x451: 0xB8, 0x2116: 0xB9, 0x454: 0xBA, 0xBB: 0xBB, 0x458: 0xBC, 0x405: 0xBD, 0x455: 0xBE, 0x457: 0xBf + }; + var _win1251back_ = {}; + for (var from in _win1251_) { + var to = _win1251_[from]; + _win1251back_[to] = from; + } + + return { + /** + * Chars.decode(s, charset) convert string s with defined charset to CryptoOperationData + * + * @memberOf GostCoding.Chars + * @param {string} s Javascript string + * @param {string} charset Charset, default 'win1251' + * @returns {CryptoOperationData} Decoded binary data + */ + decode: function (s, charset) { + charset = (charset || 'win1251').toLowerCase().replace('-', ''); + var r = []; + for (var i = 0, j = s.length; i < j; i++) { + var c = s.charCodeAt(i); + if (charset === 'utf8') { + if (c < 0x80) { + r.push(c); + } else if (c < 0x800) { + r.push(0xc0 + (c >>> 6)); + r.push(0x80 + (c & 63)); + } else if (c < 0x10000) { + r.push(0xe0 + (c >>> 12)); + r.push(0x80 + (c >>> 6 & 63)); + r.push(0x80 + (c & 63)); + } else if (c < 0x200000) { + r.push(0xf0 + (c >>> 18)); + r.push(0x80 + (c >>> 12 & 63)); + r.push(0x80 + (c >>> 6 & 63)); + r.push(0x80 + (c & 63)); + } else if (c < 0x4000000) { + r.push(0xf8 + (c >>> 24)); + r.push(0x80 + (c >>> 18 & 63)); + r.push(0x80 + (c >>> 12 & 63)); + r.push(0x80 + (c >>> 6 & 63)); + r.push(0x80 + (c & 63)); + } else { + r.push(0xfc + (c >>> 30)); + r.push(0x80 + (c >>> 24 & 63)); + r.push(0x80 + (c >>> 18 & 63)); + r.push(0x80 + (c >>> 12 & 63)); + r.push(0x80 + (c >>> 6 & 63)); + r.push(0x80 + (c & 63)); + } + } else if (charset === 'unicode' || charset === 'ucs2' || charset === 'utf16') { + if (c < 0xD800 || (c >= 0xE000 && c <= 0x10000)) { + r.push(c >>> 8); + r.push(c & 0xff); + } else if (c >= 0x10000 && c < 0x110000) { + c -= 0x10000; + var first = ((0xffc00 & c) >> 10) + 0xD800; + var second = (0x3ff & c) + 0xDC00; + r.push(first >>> 8); + r.push(first & 0xff); + r.push(second >>> 8); + r.push(second & 0xff); + } + } else if (charset === 'utf32' || charset === 'ucs4') { + r.push(c >>> 24 & 0xff); + r.push(c >>> 16 & 0xff); + r.push(c >>> 8 & 0xff); + r.push(c & 0xff); + } else if (charset === 'win1251') { + if (c >= 0x80) { + if (c >= 0x410 && c < 0x450) // А..Яа..я + c -= 0x350; + else + c = _win1251_[c] || 0; + } + r.push(c); + } else + r.push(c & 0xff); + } + return new Uint8Array(r).buffer; + }, + /** + * Chars.encode(data, charset) convert CryptoOperationData data to string with defined charset + * + * @memberOf GostCoding.Chars + * @param {CryptoOperationData} data Binary data + * @param {string} charset Charset, default win1251 + * @returns {string} Encoded javascript string + */ + encode: function (data, charset) { + charset = (charset || 'win1251').toLowerCase().replace('-', ''); + var r = [], d = new Uint8Array(buffer(data)); + for (var i = 0, n = d.length; i < n; i++) { + var c = d[i]; + if (charset === 'utf8') { + c = c >= 0xfc && c < 0xfe && i + 5 < n ? // six bytes + (c - 0xfc) * 1073741824 + (d[++i] - 0x80 << 24) + (d[++i] - 0x80 << 18) + (d[++i] - 0x80 << 12) + (d[++i] - 0x80 << 6) + d[++i] - 0x80 + : c >> 0xf8 && c < 0xfc && i + 4 < n ? // five bytes + (c - 0xf8 << 24) + (d[++i] - 0x80 << 18) + (d[++i] - 0x80 << 12) + (d[++i] - 0x80 << 6) + d[++i] - 0x80 + : c >> 0xf0 && c < 0xf8 && i + 3 < n ? // four bytes + (c - 0xf0 << 18) + (d[++i] - 0x80 << 12) + (d[++i] - 0x80 << 6) + d[++i] - 0x80 + : c >= 0xe0 && c < 0xf0 && i + 2 < n ? // three bytes + (c - 0xe0 << 12) + (d[++i] - 0x80 << 6) + d[++i] - 0x80 + : c >= 0xc0 && c < 0xe0 && i + 1 < n ? // two bytes + (c - 0xc0 << 6) + d[++i] - 0x80 + : c; // one byte + } else if (charset === 'unicode' || charset === 'ucs2' || charset === 'utf16') { + c = (c << 8) + d[++i]; + if (c >= 0xD800 && c < 0xE000) { + var first = (c - 0xD800) << 10; + c = d[++i]; + c = (c << 8) + d[++i]; + var second = c - 0xDC00; + c = first + second + 0x10000; + } + } else if (charset === 'utf32' || charset === 'ucs4') { + c = (c << 8) + d[++i]; + c = (c << 8) + d[++i]; + c = (c << 8) + d[++i]; + } else if (charset === 'win1251') { + if (c >= 0x80) { + if (c >= 0xC0 && c < 0x100) + c += 0x350; // А..Яа..я + else + c = _win1251back_[c] || 0; + } + } + r.push(String.fromCharCode(c)); + } + return r.join(''); + } + }; // + })(); + + /** + * Text string conversion + * + * @memberOf GostCoding + * @insnance + * @type GostCoding.Chars + */ + GostCoding.prototype.Chars = Chars; + + /** + * HEX conversion + * + * @class GostCoding.Hex + */ + var Hex = {// + /** + * Hex.decode(s, endean) convert HEX string s to CryptoOperationData in endean mode + * + * @memberOf GostCoding.Hex + * @param {string} s Hex encoded string + * @param {boolean} endean Little or Big Endean, default Little + * @returns {CryptoOperationData} Decoded binary data + */ + decode: function (s, endean) { + s = s.replace(/[^A-fa-f0-9]/g, ''); + var n = Math.ceil(s.length / 2), r = new Uint8Array(n); + s = (s.length % 2 > 0 ? '0' : '') + s; + if (endean && ((typeof endean !== 'string') || + (endean.toLowerCase().indexOf('little') < 0))) + for (var i = 0; i < n; i++) + r[i] = parseInt(s.substr((n - i - 1) * 2, 2), 16); + else + for (var i = 0; i < n; i++) + r[i] = parseInt(s.substr(i * 2, 2), 16); + return r.buffer; + }, + /** + * Hex.encode(data, endean) convert CryptoOperationData data to HEX string in endean mode + * + * @memberOf GostCoding.Hex + * @param {CryptoOperationData} data Binary data + * @param {boolean} endean Little/Big Endean, default Little + * @returns {string} Hex decoded string + */ + encode: function (data, endean) { + var s = [], d = new Uint8Array(buffer(data)), n = d.length; + if (endean && ((typeof endean !== 'string') || + (endean.toLowerCase().indexOf('little') < 0))) + for (var i = 0; i < n; i++) { + var j = n - i - 1; + s[j] = (j > 0 && j % 32 === 0 ? '\r\n' : '') + + ('00' + d[i].toString(16)).slice(-2); + } + else + for (var i = 0; i < n; i++) + s[i] = (i > 0 && i % 32 === 0 ? '\r\n' : '') + + ('00' + d[i].toString(16)).slice(-2); + return s.join(''); + } // + }; + + /** + * HEX conversion + * @memberOf GostCoding + * @insnance + * @type GostCoding.Hex + */ + GostCoding.prototype.Hex = Hex; + + /** + * String hex-encoded integer conversion + * + * @class GostCoding.Int16 + */ + var Int16 = {// + /** + * Int16.decode(s) convert hex big insteger s to CryptoOperationData + * + * @memberOf GostCoding.Int16 + * @param {string} s Int16 string + * @returns {CryptoOperationData} Decoded binary data + */ + decode: function (s) { + s = (s || '').replace(/[^\-A-fa-f0-9]/g, ''); + if (s.length === 0) + s = '0'; + // Signature + var neg = false; + if (s.charAt(0) === '-') { + neg = true; + s = s.substring(1); + } + // Align 2 chars + while (s.charAt(0) === '0' && s.length > 1) + s = s.substring(1); + s = (s.length % 2 > 0 ? '0' : '') + s; + // Padding for singanuture + // '800000' - 'ffffff' - for positive + // '800001' - 'ffffff' - for negative + if ((!neg && !/^[0-7]/.test(s)) || + (neg && !/^[0-7]|8[0]+$/.test(s))) + s = '00' + s; + // Convert hex + var n = s.length / 2, r = new Uint8Array(n), t = 0; + for (var i = n - 1; i >= 0; --i) { + var c = parseInt(s.substr(i * 2, 2), 16); + if (neg && (c + t > 0)) { + c = 256 - c - t; + t = 1; + } + r[i] = c; + } + return r.buffer; + }, + /** + * Int16.encode(data) convert CryptoOperationData data to big integer hex string + * + * @memberOf GostCoding.Int16 + * @param {CryptoOperationData} data Binary data + * @returns {string} Int16 encoded string + */ + encode: function (data) { + var d = new Uint8Array(buffer(data)), n = d.length; + if (d.length === 0) + return '0x00'; + var s = [], neg = d[0] > 0x7f, t = 0; + for (var i = n - 1; i >= 0; --i) { + var v = d[i]; + if (neg && (v + t > 0)) { + v = 256 - v - t; + t = 1; + } + s[i] = ('00' + v.toString(16)).slice(-2); + } + s = s.join(''); + while (s.charAt(0) === '0') + s = s.substring(1); + return (neg ? '-' : '') + '0x' + s; + } // + }; + + /** + * String hex-encoded integer conversion + * @memberOf GostCoding + * @insnance + * @type GostCoding.Int16 + */ + GostCoding.prototype.Int16 = Int16; + + /** + * BER, DER, CER conversion + * + * @class GostCoding.BER + */ + var BER = (function () { // + + // Predefenition block + function encodeBER(source, format, onlyContent) { + // Correct primitive type + var object = source.object; + if (object === undefined) + object = source; + + // Determinate tagClass + var tagClass = source.tagClass = source.tagClass || 0; // Universial default + + // Determinate tagNumber. Use only for Universal class + if (tagClass === 0) { + var tagNumber = source.tagNumber; + if (typeof tagNumber === 'undefined') { + if (typeof object === 'string') { + if (object === '') // NULL + tagNumber = 0x05; + else if (/^\-?0x[0-9a-fA-F]+$/.test(object)) // INTEGER + tagNumber = 0x02; + else if (/^(\d+\.)+\d+$/.test(object)) // OID + tagNumber = 0x06; + else if (/^[01]+$/.test(object)) // BIT STRING + tagNumber = 0x03; + else if (/^(true|false)$/.test(object)) // BOOLEAN + tagNumber = 0x01; + else if (/^[0-9a-fA-F]+$/.test(object)) // OCTET STRING + tagNumber = 0x04; + else + tagNumber = 0x13; // Printable string (later can be changed to UTF8String) + } else if (typeof object === 'number') { // INTEGER + tagNumber = 0x02; + } else if (typeof object === 'boolean') { // BOOLEAN + tagNumber = 0x01; + } else if (object instanceof Array) { // SEQUENCE + tagNumber = 0x10; + } else if (object instanceof Date) { // GeneralizedTime + tagNumber = 0x18; + } else if (object instanceof CryptoOperationData || (object && object.buffer instanceof CryptoOperationData)) { + tagNumber = 0x04; + } else + throw new DataError('Unrecognized type for ' + object); + } + } + + // Determinate constructed + var tagConstructed = source.tagConstructed; + if (typeof tagConstructed === 'undefined') + tagConstructed = source.tagConstructed = object instanceof Array; + + // Create content + var content; + if (object instanceof CryptoOperationData || (object && object.buffer instanceof CryptoOperationData)) { // Direct + content = new Uint8Array(buffer(object)); + if (tagNumber === 0x03) { // BITSTRING + // Set unused bits + var a = new Uint8Array(buffer(content)); + content = new Uint8Array(a.length + 1); + content[0] = 0; // No unused bits + content.set(a, 1); + } + } else if (tagConstructed) { // Sub items coding + if (object instanceof Array) { + var bytelen = 0, ba = [], offset = 0; + for (var i = 0, n = object.length; i < n; i++) { + ba[i] = encodeBER(object[i], format); + bytelen += ba[i].length; + } + if (tagNumber === 0x11) + ba.sort(function (a, b) { // Sort order for SET components + for (var i = 0, n = Math.min(a.length, b.length); i < n; i++) { + var r = a[i] - b[i]; + if (r !== 0) + return r; + } + return a.length - b.length; + }); + if (format === 'CER') { // final for CER 00 00 + ba[n] = new Uint8Array(2); + bytelen += 2; + } + content = new Uint8Array(bytelen); + for (var i = 0, n = ba.length; i < n; i++) { + content.set(ba[i], offset); + offset = offset + ba[i].length; + } + } else + throw new DataError('Constracted block can\'t be primitive'); + } else { + switch (tagNumber) { + // 0x00: // EOC + case 0x01: // BOOLEAN + content = new Uint8Array(1); + content[0] = object ? 0xff : 0; + break; + case 0x02: // INTEGER + case 0x0a: // ENUMIRATED + content = Int16.decode( + typeof object === 'number' ? object.toString(16) : object); + break; + case 0x03: // BIT STRING + if (typeof object === 'string') { + var unusedBits = 7 - (object.length + 7) % 8; + var n = Math.ceil(object.length / 8); + content = new Uint8Array(n + 1); + content[0] = unusedBits; + for (var i = 0; i < n; i++) { + var c = 0; + for (var j = 0; j < 8; j++) { + var k = i * 8 + j; + c = (c << 1) + (k < object.length ? (object.charAt(k) === '1' ? 1 : 0) : 0); + } + content[i + 1] = c; + } + } + break; + case 0x04: + content = Hex.decode( + typeof object === 'number' ? object.toString(16) : object); + break; + // case 0x05: // NULL + case 0x06: // OBJECT IDENTIFIER + var a = object.match(/\d+/g), r = []; + for (var i = 1; i < a.length; i++) { + var n = +a[i], r1 = []; + if (i === 1) + n = n + a[0] * 40; + do { + r1.push(n & 0x7F); + n = n >>> 7; + } while (n); + // reverse order + for (j = r1.length - 1; j >= 0; --j) + r.push(r1[j] + (j === 0 ? 0x00 : 0x80)); + } + content = new Uint8Array(r); + break; + // case 0x07: // ObjectDescriptor + // case 0x08: // EXTERNAL + // case 0x09: // REAL + // case 0x0A: // ENUMERATED + // case 0x0B: // EMBEDDED PDV + case 0x0C: // UTF8String + content = Chars.decode(object, 'utf8'); + break; + // case 0x10: // SEQUENCE + // case 0x11: // SET + case 0x12: // NumericString + case 0x16: // IA5String // ASCII + case 0x13: // PrintableString // ASCII subset + case 0x14: // TeletexString // aka T61String + case 0x15: // VideotexString + case 0x19: // GraphicString + case 0x1A: // VisibleString // ASCII subset + case 0x1B: // GeneralString + // Reflect on character encoding + for (var i = 0, n = object.length; i < n; i++) + if (object.charCodeAt(i) > 255) + tagNumber = 0x0C; + if (tagNumber === 0x0C) + content = Chars.decode(object, 'utf8'); + else + content = Chars.decode(object, 'ascii'); + break; + case 0x17: // UTCTime + case 0x18: // GeneralizedTime + var result = object.original; + if (!result) { + var date = new Date(object); + date.setMinutes(date.getMinutes() + date.getTimezoneOffset()); // to UTC + var ms = tagNumber === 0x18 ? date.getMilliseconds().toString() : ''; // Milliseconds, remove trailing zeros + while (ms.length > 0 && ms.charAt(ms.length - 1) === '0') + ms = ms.substring(0, ms.length - 1); + if (ms.length > 0) + ms = '.' + ms; + result = (tagNumber === 0x17 ? date.getYear().toString().slice(-2) : date.getFullYear().toString()) + + ('00' + (date.getMonth() + 1)).slice(-2) + + ('00' + date.getDate()).slice(-2) + + ('00' + date.getHours()).slice(-2) + + ('00' + date.getMinutes()).slice(-2) + + ('00' + date.getSeconds()).slice(-2) + ms + 'Z'; + } + content = Chars.decode(result, 'ascii'); + break; + case 0x1C: // UniversalString + content = Chars.decode(object, 'utf32'); + break; + case 0x1E: // BMPString + content = Chars.decode(object, 'utf16'); + break; + } + } + + if (!content) + content = new Uint8Array(0); + if (content instanceof CryptoOperationData) + content = new Uint8Array(content); + + if (!tagConstructed && format === 'CER') { + // Encoding CER-form for string types + var k; + switch (tagNumber) { + case 0x03: // BIT_STRING + k = 1; // ingnore unused bit for bit string + case 0x04: // OCTET_STRING + case 0x0C: // UTF8String + case 0x12: // NumericString + case 0x13: // PrintableString + case 0x14: // TeletexString + case 0x15: // VideotexString + case 0x16: // IA5String + case 0x19: // GraphicString + case 0x1A: // VisibleString + case 0x1B: // GeneralString + case 0x1C: // UniversalString + case 0x1E: // BMPString + k = k || 0; + // Split content on 1000 octet len parts + var size = 1000; + var bytelen = 0, ba = [], offset = 0; + for (var i = k, n = content.length; i < n; i += size - k) { + ba[i] = encodeBER({ + object: new Unit8Array(content.buffer, i, Math.min(size - k, n - i)), + tagNumber: tagNumber, + tagClass: 0, + tagConstructed: false + }, format); + bytelen += ba[i].length; + } + ba[n] = new Uint8Array(2); // final for CER 00 00 + bytelen += 2; + content = new Uint8Array(bytelen); + for (var i = 0, n = ba.length; i < n; i++) { + content.set(ba[i], offset); + offset = offset + ba[i].length; + } + } + } + + // Restore tagNumber for all classes + if (tagClass === 0) + source.tagNumber = tagNumber; + else + source.tagNumber = tagNumber = source.tagNumber || 0; + source.content = content; + + if (onlyContent) + return content; + + // Create header + // tagNumber + var ha = [], first = tagClass === 3 ? 0xC0 : tagClass === 2 ? 0x80 : + tagClass === 1 ? 0x40 : 0x00; + if (tagConstructed) + first |= 0x20; + if (tagNumber < 0x1F) { + first |= tagNumber & 0x1F; + ha.push(first); + } else { + first |= 0x1F; + ha.push(first); + var n = tagNumber, ha1 = []; + do { + ha1.push(n & 0x7F); + n = n >>> 7; + } while (n) + // reverse order + for (var j = ha1.length - 1; j >= 0; --j) + ha.push(ha1[j] + (j === 0 ? 0x00 : 0x80)); + } + // Length + if (tagConstructed && format === 'CER') { + ha.push(0x80); + } else { + var len = content.length; + if (len > 0x7F) { + var l2 = len, ha2 = []; + do { + ha2.push(l2 & 0xff); + l2 = l2 >>> 8; + } while (l2); + ha.push(ha2.length + 0x80); // reverse order + for (var j = ha2.length - 1; j >= 0; --j) + ha.push(ha2[j]); + } else { + // simple len + ha.push(len); + } + } + var header = source.header = new Uint8Array(ha); + + // Result - complete buffer + var block = new Uint8Array(header.length + content.length); + block.set(header, 0); + block.set(content, header.length); + return block; + } + + function decodeBER(source, offset) { + + // start pos + var pos = offset || 0, start = pos; + var tagNumber, tagClass, tagConstructed, + content, header, buffer, sub, len; + + if (source.object) { + // Ready from source + tagNumber = source.tagNumber; + tagClass = source.tagClass; + tagConstructed = source.tagConstructed; + content = source.content; + header = source.header; + buffer = source.object instanceof CryptoOperationData ? + new Uint8Array(source.object) : null; + sub = source.object instanceof Array ? source.object : null; + len = buffer && buffer.length || null; + } else { + // Decode header + var d = source; + + // Read tag + var buf = d[pos++]; + tagNumber = buf & 0x1f; + tagClass = buf >> 6; + tagConstructed = (buf & 0x20) !== 0; + if (tagNumber === 0x1f) { // long tag + tagNumber = 0; + do { + if (tagNumber > 0x1fffffffffff80) + throw new DataError('Convertor not supported tag number more then (2^53 - 1) at position ' + offset); + buf = d[pos++]; + tagNumber = (tagNumber << 7) + (buf & 0x7f); + } while (buf & 0x80); + } + + // Read len + buf = d[pos++]; + len = buf & 0x7f; + if (len !== buf) { + if (len > 6) // no reason to use Int10, as it would be a huge buffer anyways + throw new DataError('Length over 48 bits not supported at position ' + offset); + if (len === 0) + len = null; // undefined + else { + buf = 0; + for (var i = 0; i < len; ++i) + buf = (buf << 8) + d[pos++]; + len = buf; + } + } + + start = pos; + sub = null; + + if (tagConstructed) { + // must have valid content + sub = []; + if (len !== null) { + // definite length + var end = start + len; + while (pos < end) { + var s = decodeBER(d, pos); + sub.push(s); + pos += s.header.length + s.content.length; + } + if (pos !== end) + throw new DataError('Content size is not correct for container starting at offset ' + start); + } else { + // undefined length + try { + for (; ; ) { + var s = decodeBER(d, pos); + pos += s.header.length + s.content.length; + if (s.tagClass === 0x00 && s.tagNumber === 0x00) + break; + sub.push(s); + } + len = pos - start; + } catch (e) { + throw new DataError('Exception ' + e + ' while decoding undefined length content at offset ' + start); + } + } + } + + // Header and content + header = new Uint8Array(d.buffer, offset, start - offset); + content = new Uint8Array(d.buffer, start, len); + buffer = content; + } + + // Constructed types - check for string concationation + if (sub !== null && tagClass === 0) { + var k; + switch (tagNumber) { + case 0x03: // BIT_STRING + k = 1; // ingnore unused bit for bit string + case 0x04: // OCTET_STRING + case 0x0C: // UTF8String + case 0x12: // NumericString + case 0x13: // PrintableString + case 0x14: // TeletexString + case 0x15: // VideotexString + case 0x16: // IA5String + case 0x19: // GraphicString + case 0x1A: // VisibleString + case 0x1B: // GeneralString + case 0x1C: // UniversalString + case 0x1E: // BMPString + k = k || 0; + // Concatination + if (sub.length === 0) + throw new DataError('No constructed encoding content of string type at offset ' + start); + len = k; + for (var i = 0, n = sub.length; i < n; i++) { + var s = sub[i]; + if (s.tagClass !== tagClass || s.tagNumber !== tagNumber || s.tagConstructed) + throw new DataError('Invalid constructed encoding of string type at offset ' + start); + len += s.content.length - k; + } + buffer = new Uint8Array(len); + for (var i = 0, n = sub.length, j = k; i < n; i++) { + var s = sub[i]; + if (k > 0) + buffer.set(s.content.subarray(1), j); + else + buffer.set(s.content, j); + j += s.content.length - k; + } + tagConstructed = false; // follow not required + sub = null; + break; + } + } + // Primitive types + var object = ''; + if (sub === null) { + if (len === null) + throw new DataError('Invalid tag with undefined length at offset ' + start); + + if (tagClass === 0) { + switch (tagNumber) { + case 0x01: // BOOLEAN + object = buffer[0] !== 0; + break; + case 0x02: // INTEGER + case 0x0a: // ENUMIRATED + if (len > 6) { + object = Int16.encode(buffer); + } else { + var v = buffer[0]; + if (buffer[0] > 0x7f) + v = v - 256; + for (var i = 1; i < len; i++) + v = v * 256 + buffer[i]; + object = v; + } + break; + case 0x03: // BIT_STRING + if (len > 5) { // Content buffer + object = new Uint8Array(buffer.subarray(1)).buffer; + } else { // Max bit mask only for 32 bit + var unusedBit = buffer[0], + skip = unusedBit, s = []; + for (var i = len - 1; i >= 1; --i) { + var b = buffer[i]; + for (var j = skip; j < 8; ++j) + s.push((b >> j) & 1 ? '1' : '0'); + skip = 0; + } + object = s.reverse().join(''); + } + break; + case 0x04: // OCTET_STRING + object = new Uint8Array(buffer).buffer; + break; + // case 0x05: // NULL + case 0x06: // OBJECT_IDENTIFIER + var s = '', + n = 0, + bits = 0; + for (var i = 0; i < len; ++i) { + var v = buffer[i]; + n = (n << 7) + (v & 0x7F); + bits += 7; + if (!(v & 0x80)) { // finished + if (s === '') { + var m = n < 80 ? n < 40 ? 0 : 1 : 2; + s = m + "." + (n - m * 40); + } else + s += "." + n.toString(); + n = 0; + bits = 0; + } + } + if (bits > 0) + throw new DataError('Incompleted OID at offset ' + start); + object = s; + break; + //case 0x07: // ObjectDescriptor + //case 0x08: // EXTERNAL + //case 0x09: // REAL + //case 0x0A: // ENUMERATED + //case 0x0B: // EMBEDDED_PDV + case 0x10: // SEQUENCE + case 0x11: // SET + object = []; + break; + case 0x0C: // UTF8String + object = Chars.encode(buffer, 'utf8'); + break; + case 0x12: // NumericString + case 0x13: // PrintableString + case 0x14: // TeletexString + case 0x15: // VideotexString + case 0x16: // IA5String + case 0x19: // GraphicString + case 0x1A: // VisibleString + case 0x1B: // GeneralString + object = Chars.encode(buffer, 'ascii'); + break; + case 0x1C: // UniversalString + object = Chars.encode(buffer, 'utf32'); + break; + case 0x1E: // BMPString + object = Chars.encode(buffer, 'utf16'); + break; + case 0x17: // UTCTime + case 0x18: // GeneralizedTime + var shortYear = tagNumber === 0x17; + var s = Chars.encode(buffer, 'ascii'), + m = (shortYear ? + /^(\d\d)(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])([01]\d|2[0-3])(?:([0-5]\d)(?:([0-5]\d)(?:[.,](\d{1,3}))?)?)?(Z|[-+](?:[0]\d|1[0-2])([0-5]\d)?)?$/ : + /^(\d\d\d\d)(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])([01]\d|2[0-3])(?:([0-5]\d)(?:([0-5]\d)(?:[.,](\d{1,3}))?)?)?(Z|[-+](?:[0]\d|1[0-2])([0-5]\d)?)?$/).exec(s); + if (!m) + throw new DataError('Unrecognized time format "' + s + '" at offset ' + start); + if (shortYear) { + // Where YY is greater than or equal to 50, the year SHALL be interpreted as 19YY; and + // Where YY is less than 50, the year SHALL be interpreted as 20YY + m[1] = +m[1]; + m[1] += (m[1] < 50) ? 2000 : 1900; + } + var dt = new Date(m[1], +m[2] - 1, +m[3], +(m[4] || '0'), +(m[5] || '0'), +(m[6] || '0'), +(m[7] || '0')), + tz = dt.getTimezoneOffset(); + if (m[8] || tagNumber === 0x17) { + if (m[8].toUpperCase() !== 'Z' && m[9]) { + tz = tz + parseInt(m[9]); + } + dt.setMinutes(dt.getMinutes() - tz); + } + dt.original = s; + object = dt; + break; + } + } else // OCTET_STRING + object = new Uint8Array(buffer).buffer; + } else + object = sub; + + // result + return { + tagConstructed: tagConstructed, + tagClass: tagClass, + tagNumber: tagNumber, + header: header, + content: content, + object: object + }; + } + + return { + /** + * BER.decode(object, format) convert javascript object to ASN.1 format CryptoOperationData

+ * If object has members tagNumber, tagClass and tagConstructed + * it is clear define encoding rules. Else method use defaul rules: + * + * SEQUENCE or SET arrays recursively encoded for each item.
+ * OCTET STRING and BIT STRING can presents as array with one item. + * It means encapsulates encoding for child element.
+ * + * If CONTEXT or APPLICATION classes item presents as array with one + * item we use EXPLICIT encoding for element, else IMPLICIT encoding.
+ * + * @memberOf GostCoding.BER + * @param {Object} object Object to encoding + * @param {string} format Encoding rule: 'DER' or 'CER', default 'DER' + * @param {boolean} onlyContent Encode content only, without header + * @returns {CryptoOperationData} BER encoded data + */ + encode: function (object, format, onlyContent) { + return encodeBER(object, format, onlyContent).buffer; + }, + /** + * BER.encode(data) convert ASN.1 format CryptoOperationData data to javascript object

+ * + * Conversion rules to javascript object: + * + * @memberOf GostCoding.BER + * @param {(CryptoOperationData|GostCoding.BER)} data Binary data to decode + * @returns {Object} Javascript object with result of decoding + */ + decode: function (data) { + return decodeBER(data.object ? data : new Uint8Array(buffer(data)), 0); + } + }; //
+ })(); + + /** + * BER, DER, CER conversion + * @memberOf GostCoding + * @insnance + * @type GostCoding.BER + */ + GostCoding.prototype.BER = BER; + + /** + * PEM conversion + * @class GostCoding.PEM + */ + var PEM = {// + /** + * PEM.encode(data, name) encode CryptoOperationData to PEM format with name label + * + * @memberOf GostCoding.PEM + * @param {(Object|CryptoOperationData)} data Java script object or BER-encoded binary data + * @param {string} name Name of PEM object: 'certificate', 'private key' etc. + * @returns {string} Encoded object + */ + encode: function (data, name) { + return (name ? '-----BEGIN ' + name.toUpperCase() + '-----\r\n' : '') + + Base64.encode(data instanceof CryptoOperationData ? data : BER.encode(data)) + + (name ? '\r\n-----END ' + name.toUpperCase() + '-----' : ''); + }, + /** + * PEM.decode(s, name, deep) decode PEM format s labeled name to CryptoOperationData or javascript object in according to deep parameter + * + * @memberOf GostCoding.PEM + * @param {string} s PEM encoded string + * @param {string} name Name of PEM object: 'certificate', 'private key' etc. + * @param {boolean} deep If true method do BER-decoding, else only BASE64 decoding + * @param {integer} index Index of decoded value + * @returns {(Object|CryptoOperationData)} Decoded javascript object if deep=true, else CryptoOperationData for father BER decoding + */ + decode: function (s, name, deep, index) { + // Try clear base64 + var re1 = /([A-Za-z0-9\+\/\s\=]+)/g, + valid = re1.exec(s); + if (valid[1].length !== s.length) + valid = false; + if (!valid && name) { + // Try with the name + var re2 = new RegExp( + '-----\\s?BEGIN ' + name.toUpperCase() + + '-----([A-Za-z0-9\\+\\/\\s\\=]+)-----\\s?END ' + + name.toUpperCase() + '-----', 'g'); + valid = re2.exec(s); + } + if (!valid) { + // Try with some name + var re3 = new RegExp( + '-----\\s?BEGIN [A-Z0-9\\s]+' + + '-----([A-Za-z0-9\\+\\/\\s\\=]+)-----\\s?END ' + + '[A-Z0-9\\s]+-----', 'g'); + valid = re3.exec(s); + } + var r = valid && valid[1 + (index || 0)]; + if (!r) + throw new DataError('Not valid PEM format'); + var out = Base64.decode(r); + if (deep) + out = BER.decode(out); + return out; + } // + }; + + /** + * PEM conversion + * @memberOf GostCoding + * @insnance + * @type GostCoding.PEM + */ + GostCoding.prototype.PEM = PEM; + + if (gostCrypto) + /** + * Coding algorithms: Base64, Hex, Int16, Chars, BER and PEM + * + * @memberOf gostCrypto + * @type GostCoding + */ + gostCrypto.coding = new GostCoding(); + + return GostCoding; + +})); \ No newline at end of file diff --git a/src/core/vendor/streebog/gostCrypto.js b/src/core/vendor/streebog/gostCrypto.js new file mode 100644 index 00000000..fd6b19a2 --- /dev/null +++ b/src/core/vendor/streebog/gostCrypto.js @@ -0,0 +1,1657 @@ +/** + * @file Implementation Web Crypto interfaces for GOST algorithms + * @version 1.76 + * @copyright 2014-2016, Rudolf Nickolaev. All rights reserved. + */ + +/* + * 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. + * + */ + +(function (root, factory) { + + /* + * Module imports and exports + * + */ // + module.exports = factory(require('./gostRandom')); + + // + +}(this, function (GostRandom) { + + /* + * Algorithm normalization + * + */ // + + var root = this; + var rootCrypto = root.crypto || root.msCrypto; + + var SyntaxError = root.SyntaxError || root.Error, + DataError = root.DataError || root.Error, + NotSupportedError = root.NotSupportedError || root.Error, + OperationError = root.OperationError || root.Error, + InvalidStateError = root.InvalidAccessError || root.Error, + InvalidAccessError = root.InvalidAccessError || root.Error; + + // Normalize algorithm + function normalize(algorithm, method) { + if (typeof algorithm === 'string' || algorithm instanceof String) + algorithm = {name: algorithm}; + var name = algorithm.name; + if (!name) + throw new SyntaxError('Algorithm name not defined'); + // Extract algorithm modes from name + var modes = name.split('/'), modes = modes[0].split('-').concat(modes.slice(1)); + // Normalize the name with default modes + var na = {}; + name = modes[0].replace(/[\.\s]/g, ''); + modes = modes.slice(1); + if (name.indexOf('28147') >= 0) { + na = { + name: 'GOST 28147', + version: 1989, + mode: (algorithm.mode || (// ES, MAC, KW + (method === 'sign' || method === 'verify') ? 'MAC' : + (method === 'wrapKey' || method === 'unwrapKey') ? 'KW' : 'ES')).toUpperCase(), + length: algorithm.length || 64 + }; + } else if (name.indexOf('3412') >= 0) { + na = { + name: 'GOST R 34.12', + version: 2015, + mode: (algorithm.mode || (// ES, MAC, KW + (method === 'sign' || method === 'verify') ? 'MAC' : + (method === 'wrapKey' || method === 'unwrapKey') ? 'KW' : 'ES')).toUpperCase(), + length: algorithm.length || 64 // 128 + }; + } else if (name.indexOf('3411') >= 0) { + na = { + name: 'GOST R 34.11', + version: 2012, // 1994 + mode: (algorithm.mode || (// HASH, KDF, HMAC, PBKDF2, PFXKDF, CPKDF + (method === 'deriveKey' || method === 'deriveBits') ? 'KDF' : + (method === 'sign' || method === 'verify') ? 'HMAC' : 'HASH')).toUpperCase(), + length: algorithm.length || 256 // 512 + }; + } else if (name.indexOf('3410') >= 0) { + na = { + name: 'GOST R 34.10', + version: 2012, // 1994, 2001 + mode: (algorithm.mode || (// SIGN, DH, MASK + (method === 'deriveKey' || method === 'deriveBits') ? 'DH' : 'SIGN')).toUpperCase(), + length: algorithm.length || 256 // 512 + }; + } else if (name.indexOf('SHA') >= 0) { + na = { + name: 'SHA', + version: (algorithm.length || 160) === 160 ? 1 : 2, // 1, 2 + mode: (algorithm.mode || (// HASH, KDF, HMAC, PBKDF2, PFXKDF + (method === 'deriveKey' || method === 'deriveBits') ? 'KDF' : + (method === 'sign' || method === 'verify') ? 'HMAC' : 'HASH')).toUpperCase(), + length: algorithm.length || 160 + }; + } else if (name.indexOf('RC2') >= 0) { + na = { + name: 'RC2', + version: 1, + mode: (algorithm.mode || (// ES, MAC, KW + (method === 'sign' || method === 'verify') ? 'MAC' : + (method === 'wrapKey' || method === 'unwrapKey') ? 'KW' : 'ES')).toUpperCase(), + length: algorithm.length || 32 // 1 - 1024 + }; + } else if (name.indexOf('PBKDF2') >= 0) { + na = normalize(algorithm.hash, 'digest'); + na.mode = 'PBKDF2'; + } else if (name.indexOf('PFXKDF') >= 0) { + na = normalize(algorithm.hash, 'digest'); + na.mode = 'PFXKDF'; + } else if (name.indexOf('CPKDF') >= 0) { + na = normalize(algorithm.hash, 'digest'); + na.mode = 'CPKDF'; + } else if (name.indexOf('HMAC') >= 0) { + na = normalize(algorithm.hash, 'digest'); + na.mode = 'HMAC'; + } else + throw new NotSupportedError('Algorithm not supported'); + + // Compile modes + modes.forEach(function (mode) { + mode = mode.toUpperCase(); + if (/^[0-9]+$/.test(mode)) { + if ((['8', '16', '32'].indexOf(mode) >= 0) || (na.length === '128' && mode === '64')) { // Shift bits + if (na.mode === 'ES') + na.shiftBits = parseInt(mode); + else if (na.mode === 'MAC') + na.macLength = parseInt(mode); + else + throw new NotSupportedError('Algorithm ' + na.name + ' mode ' + mode + ' not supported'); + } else if (['89', '94', '01', '12', '15', '1989', '1994', '2001', '2012', '2015'].indexOf(mode) >= 0) { // GOST Year + var version = parseInt(mode); + version = version < 1900 ? (version < 80 ? 2000 + version : 1900 + version) : version; + na.version = version; + } else if (['1'].indexOf(mode) >= 0 && na.name === 'SHA') { // SHA-1 + na.version = 1; + na.length = 160; + } else if (['256', '384', '512'].indexOf(mode) >= 0 && na.name === 'SHA') { // SHA-2 + na.version = 2; + na.length = parseInt(mode); + } else if (['40', '128'].indexOf(mode) >= 0 && na.name === 'RC2') { // RC2 + na.version = 1; + na.length = parseInt(mode); // key size + } else if (['64', '128', '256', '512'].indexOf(mode) >= 0) // block size + na.length = parseInt(mode); + else if (['1000', '2000'].indexOf(mode) >= 0) // Iterations + na.iterations = parseInt(mode); + // Named Paramsets + } else if (['E-TEST', 'E-A', 'E-B', 'E-C', 'E-D', 'E-SC', 'E-Z', 'D-TEST', 'D-A', 'D-SC'].indexOf(mode) >= 0) { + na.sBox = mode; + } else if (['S-TEST', 'S-A', 'S-B', 'S-C', 'S-D', 'X-A', 'X-B', 'X-C'].indexOf(mode) >= 0) { + na.namedParam = mode; + } else if (['S-256-TEST', 'S-256-A', 'S-256-B', 'S-256-C', 'P-256', 'T-512-TEST', 'T-512-A', + 'T-512-B', 'X-256-A', 'X-256-B', 'T-256-TEST', 'T-256-A', 'T-256-B', 'S-256-B', 'T-256-C', 'S-256-C'].indexOf(mode) >= 0) { + na.namedCurve = mode; + } else if (['SC', 'CP', 'VN'].indexOf(mode) >= 0) { + na.procreator = mode; + + // Encription GOST 28147 or GOST R 34.12 + } else if (na.name === 'GOST 28147' || na.name === 'GOST R 34.12' || na.name === 'RC2') { + if (['ES', 'MAC', 'KW', 'MASK'].indexOf(mode) >= 0) { + na.mode = mode; + } else if (['ECB', 'CFB', 'OFB', 'CTR', 'CBC'].indexOf(mode) >= 0) { + na.mode = 'ES'; + na.block = mode; + } else if (['CPKW', 'NOKW', 'SCKW'].indexOf(mode) >= 0) { + na.mode = 'KW'; + na.keyWrapping = mode.replace('KW', ''); + } else if (['ZEROPADDING', 'PKCS5PADDING', 'NOPADDING', 'RANDOMPADDING', 'BITPADDING'].indexOf(mode) >= 0) { + na.padding = mode.replace('PADDING', ''); + } else if (['NOKM', 'CPKM'].indexOf(mode) >= 0) { + na.keyMeshing = mode.replace('KM', ''); + } else + throw new NotSupportedError('Algorithm ' + na.name + ' mode ' + mode + ' not supported'); + + // Digesting GOST 34.11 + } else if (na.name === 'GOST R 34.11' || na.name === 'SHA') { + if (['HASH', 'KDF', 'HMAC', 'PBKDF2', 'PFXKDF', 'CPKDF'].indexOf(mode) >= 0) + na.mode = mode; + else + throw new NotSupportedError('Algorithm ' + na.name + ' mode ' + mode + ' not supported'); + + // Signing GOST 34.10 + } else if (na.name === 'GOST R 34.10') { + var hash = mode.replace(/[\.\s]/g, ''); + if (hash.indexOf('GOST') >= 0 && hash.indexOf('3411') >= 0) + na.hash = mode; + else if (['SIGN', 'DH', 'MASK'].indexOf(mode)) + na.mode = mode; + else + throw new NotSupportedError('Algorithm ' + na.name + ' mode ' + mode + ' not supported'); + } + }); + + // Procreator + na.procreator = algorithm.procreator || na.procreator || 'CP'; + + // Key size + switch (na.name) { + case 'GOST R 34.10': + na.keySize = na.length / (na.version === 1994 ? 4 : 8); + break; + case 'GOST R 34.11': + na.keySize = 32; + break; + case 'GOST 28147': + case 'GOST R 34.12': + na.keySize = 32; + break; + case 'RC2': + na.keySize = Math.ceil(na.length / 8); + break; + case 'SHA': + na.keySize = na.length / 8; + break; + } + + // Encrypt additional modes + if (na.mode === 'ES') { + if (algorithm.block) + na.block = algorithm.block; // ECB, CFB, OFB, CTR, CBC + if (na.block) + na.block = na.block.toUpperCase(); + if (algorithm.padding) + na.padding = algorithm.padding; // NO, ZERO, PKCS5, RANDOM, BIT + if (na.padding) + na.padding = na.padding.toUpperCase(); + if (algorithm.shiftBits) + na.shiftBits = algorithm.shiftBits; // 8, 16, 32, 64 + if (algorithm.keyMeshing) + na.keyMeshing = algorithm.keyMeshing; // NO, CP + if (na.keyMeshing) + na.keyMeshing = na.keyMeshing.toUpperCase(); + // Default values + if (method !== 'importKey' && method !== 'generateKey') { + na.block = na.block || 'ECB'; + na.padding = na.padding || (na.block === 'CBC' || na.block === 'ECB' ? 'ZERO' : 'NO'); + if (na.block === 'CFB' || na.block === 'OFB') + na.shiftBits = na.shiftBits || na.length; + na.keyMeshing = na.keyMeshing || 'NO'; + } + } + if (na.mode === 'KW') { + if (algorithm.keyWrapping) + na.keyWrapping = algorithm.keyWrapping; // NO, CP, SC + if (na.keyWrapping) + na.keyWrapping = na.keyWrapping.toUpperCase(); + if (method !== 'importKey' && method !== 'generateKey') + na.keyWrapping = na.keyWrapping || 'NO'; + } + + // Paramsets + ['sBox', 'namedParam', 'namedCurve', 'curve', 'param', 'modulusLength'].forEach(function (name) { + algorithm[name] && (na[name] = algorithm[name]); + }); + // Default values + if (method !== 'importKey' && method !== 'generateKey') { + if (na.name === 'GOST 28147') { + na.sBox = na.sBox || (na.procreator === 'SC' ? 'E-SC' : 'E-A'); // 'E-A', 'E-B', 'E-C', 'E-D', 'E-SC' + } else if (na.name === 'GOST R 34.12' && na.length === 64) { + na.sBox = 'E-Z'; + } else if (na.name === 'GOST R 34.11' && na.version === 1994) { + na.sBox = na.sBox || (na.procreator === 'SC' ? 'D-SC' : 'D-A'); // 'D-SC' + } else if (na.name === 'GOST R 34.10' && na.version === 1994) { + na.namedParam = na.namedParam || (na.mode === 'DH' ? 'X-A' : 'S-A'); // 'S-B', 'S-C', 'S-D', 'X-B', 'X-C' + } else if (na.name === 'GOST R 34.10' && na.version === 2001) { + na.namedCurve = na.namedCurve || (na.length === 256 ? + na.procreator === 'SC' ? 'P-256' : (na.mode === 'DH' ? 'X-256-A' : 'S-256-A') : // 'S-256-B', 'S-256-C', 'X-256-B', 'T-256-A', 'T-256-B', 'T-256-C', 'P-256' + na.mode === 'T-512-A'); // 'T-512-B', 'T-512-C' + } else if (na.name === 'GOST R 34.10' && na.version === 2012) { + na.namedCurve = na.namedCurve || (na.length === 256 ? + na.procreator === 'SC' ? 'P-256' : (na.mode === 'DH' ? 'X-256-A' : 'S-256-A') : // 'S-256-B', 'S-256-C', 'X-256-B', 'T-256-A', 'T-256-B', 'T-256-C', 'P-256' + na.mode === 'T-512-A'); // 'T-512-B', 'T-512-C' + } + } + + // Vectors + switch (na.mode) { + case 'DH': + algorithm.ukm && (na.ukm = algorithm.ukm); + algorithm['public'] && (na['public'] = algorithm['public']); + break; + case 'SIGN': + case 'KW': + algorithm.ukm && (na.ukm = algorithm.ukm); + break; + case 'ES': + case 'MAC': + algorithm.iv && (na.iv = algorithm.iv); + break; + case 'KDF': + algorithm.label && (na.label = algorithm.label); + algorithm.contex && (na.context = algorithm.contex); + break; + case 'PBKDF2': + algorithm.salt && (na.salt = algorithm.salt); + algorithm.iterations && (na.iterations = algorithm.iterations); + algorithm.diversifier && (na.diversifier = algorithm.diversifier); + break; + case 'PFXKDF': + algorithm.salt && (na.salt = algorithm.salt); + algorithm.iterations && (na.iterations = algorithm.iterations); + algorithm.diversifier && (na.diversifier = algorithm.diversifier); + break; + case 'CPKDF': + algorithm.salt && (na.salt = algorithm.salt); + algorithm.iterations && (na.iterations = algorithm.iterations); + break; + } + + // Verification method and modes + if (method && ( + ((na.mode !== 'ES' && na.mode !== 'SIGN' && na.mode !== 'MAC' && + na.mode !== 'HMAC' && na.mode !== 'KW' && na.mode !== 'DH' + && na.mode !== 'MASK') && + (method === 'generateKey')) || + ((na.mode !== 'ES') && + (method === 'encrypt' || method === 'decrypt')) || + ((na.mode !== 'SIGN' && na.mode !== 'MAC' && na.mode !== 'HMAC') && + (method === 'sign' || method === 'verify')) || + ((na.mode !== 'HASH') && + (method === 'digest')) || + ((na.mode !== 'KW' && na.mode !== 'MASK') && + (method === 'wrapKey' || method === 'unwrapKey')) || + ((na.mode !== 'DH' && na.mode !== 'PBKDF2' && na.mode !== 'PFXKDF' && + na.mode !== 'CPKDF' && na.mode !== 'KDF') && + (method === 'deriveKey' || method === 'deriveBits')))) + throw new NotSupportedError('Algorithm mode ' + na.mode + ' not valid for method ' + method); + + // Normalize hash algorithm + algorithm.hash && (na.hash = algorithm.hash); + if (na.hash) { + if ((typeof na.hash === 'string' || na.hash instanceof String) + && na.procreator) + na.hash = na.hash + '/' + na.procreator; + na.hash = normalize(na.hash, 'digest'); + } + + // Algorithm object identirifer + algorithm.id && (na.id = algorithm.id); + + return na; + } + + // Check for possibility use native crypto.subtle + function checkNative(algorithm) { + if (!rootCrypto || !rootCrypto.subtle || !algorithm) + return false; + // Prepare name + var name = (typeof algorithm === 'string' || algorithm instanceof String) ? + name = algorithm : algorithm.name; + if (!name) + return false; + name = name.toUpperCase(); + // Digest algorithm for key derivation + if ((name.indexOf('KDF') >= 0 || name.indexOf('HMAC') >= 0) && algorithm.hash) + return checkNative(algorithm.hash); + // True if no supported names + return name.indexOf('GOST') === -1 && + name.indexOf('SHA-1') === -1 && + name.indexOf('RC2') === -1 && + name.indexOf('?DES') === -1; + } + // + + /* + * Key conversion methods + * + */ // + + // Check key parameter + function checkKey(key, method) { + if (!key.algorithm) + throw new SyntaxError('Key algorithm not defined'); + + if (!key.algorithm.name) + throw new SyntaxError('Key algorithm name not defined'); + + var name = key.algorithm.name, + gostCipher = name === 'GOST 28147' || name === 'GOST R 34.12' || name === 'RC2', + gostDigest = name === 'GOST R 34.11' || name === 'SHA', + gostSign = name === 'GOST R 34.10'; + + if (!gostCipher && !gostSign && !gostDigest) + throw new NotSupportedError('Key algorithm ' + name + ' is unsupproted'); + + if (!key.type) + throw new SyntaxError('Key type not defined'); + + if (((gostCipher || gostDigest) && key.type !== 'secret') || + (gostSign && !(key.type === 'public' || key.type === 'private'))) + throw new DataError('Key type ' + key.type + ' is not valid for algorithm ' + name); + + if (!key.usages || !key.usages.indexOf) + throw new SyntaxError('Key usages not defined'); + + for (var i = 0, n = key.usages.length; i < n; i++) { + var md = key.usages[i]; + if (((md === 'encrypt' || md === 'decrypt') && key.type !== 'secret') || + (md === 'sign' && key.type === 'public') || + (md === 'verify' && key.type === 'private')) + throw new InvalidStateError('Key type ' + key.type + ' is not valid for ' + md); + } + + if (method) + if (key.usages.indexOf(method) === -1) + throw new InvalidAccessError('Key usages is not contain method ' + method); + + if (!key.buffer) + throw new SyntaxError('Key buffer is not defined'); + + var size = key.buffer.byteLength * 8, keySize = 8 * key.algorithm.keySize; + if ((key.type === 'secret' && size !== (keySize || 256) && + (key.usages.indexOf('encrypt') >= 0 || key.usages.indexOf('decrypt') >= 0)) || + (key.type === 'private' && !(size === 256 || size === 512)) || + (key.type === 'public' && !(size === 512 || size === 1024))) + throw new SyntaxError('Key buffer has wrong size ' + size + ' bit'); + } + + // Extract key and enrich cipher algorithm + function extractKey(method, algorithm, key) { + checkKey(key, method); + if (algorithm) { + var params; + switch (algorithm.mode) { + case 'ES': + params = ['sBox', 'keyMeshing', 'padding', 'block']; + break; + case 'SIGN': + params = ['namedCurve', 'namedParam', 'sBox', 'curve', 'param', 'modulusLength']; + break; + case 'MAC': + params = ['sBox']; + break; + case 'KW': + params = ['keyWrapping', 'ukm']; + break; + case 'DH': + params = ['namedCurve', 'namedParam', 'sBox', 'ukm', 'curve', 'param', 'modulusLength']; + break; + case 'KDF': + params = ['context', 'label']; + break; + case 'PBKDF2': + params = ['sBox', 'iterations', 'salt']; + break; + case 'PFXKDF': + params = ['sBox', 'iterations', 'salt', 'diversifier']; + break; + case 'CPKDF': + params = ['sBox', 'salt']; + break; + } + if (params) + params.forEach(function (name) { + key.algorithm[name] && (algorithm[name] = key.algorithm[name]); + }); + } + return key.buffer; + } + + // Make key definition + function convertKey(algorithm, extractable, keyUsages, keyData, keyType) { + var key = { + type: keyType || (algorithm.name === 'GOST R 34.10' ? 'private' : 'secret'), + extractable: extractable || 'false', + algorithm: algorithm, + usages: keyUsages || [], + buffer: keyData + }; + checkKey(key); + return key; + } + + function convertKeyPair(publicAlgorithm, privateAlgorithm, extractable, keyUsages, publicBuffer, privateBuffer) { + + if (!keyUsages || !keyUsages.indexOf) + throw new SyntaxError('Key usages not defined'); + + var publicUsages = keyUsages.filter(function (value) { + return value !== 'sign'; + }); + var privateUsages = keyUsages.filter(function (value) { + return value !== 'verify'; + }); + + return { + publicKey: convertKey(publicAlgorithm, extractable, publicUsages, publicBuffer, 'public'), + privateKey: convertKey(privateAlgorithm, extractable, privateUsages, privateBuffer, 'private') + }; + } + + // Swap bytes in buffer + function swapBytes(src) { + if (src instanceof CryptoOperationData) + src = new Uint8Array(src); + var dst = new Uint8Array(src.length); + for (var i = 0, n = src.length; i < n; i++) + dst[n - i - 1] = src[i]; + return dst.buffer; + } + // + + /** + * Promise stub object (not fulfill specification, only for internal use) + * Class not defined if Promise class already defined in root context

+ * + * The Promise object is used for deferred and asynchronous computations. A Promise is in one of the three states: + * + * Another term describing the state is settled: the Promise is either fulfilled or rejected, but not pending.

+ * @class Promise + * @global + * @param {function} executor Function object with two arguments resolve and reject. + * The first argument fulfills the promise, the second argument rejects it. + * We can call these functions, once our operation is completed. + */ // + if (!root.Promise) { + + root.Promise = (function () { + + function mswrap(value) { + if (value && value.oncomplete === null && value.onerror === null) { + return new Promise(function (resolve, reject) { + value.oncomplete = function () { + resolve(value.result); + }; + value.onerror = function () { + reject(new OperationError(value.toString())); + }; + }); + } else + return value; + } + + function Promise(executor) { + + var state = 'pending', result, + resolveQueue = [], rejectQueue = []; + + function call(callback) { + try { + callback(); + } catch (e) { + } + } + + try { + executor(function (value) { + if (state === 'pending') { + state = 'fulfilled'; + result = value; + resolveQueue.forEach(call); + } + }, function (reason) { + if (state === 'pending') { + state = 'rejected'; + result = reason; + rejectQueue.forEach(call); + } + }); + } catch (error) { + if (state === 'pending') { + state = 'rejected'; + result = error; + rejectQueue.forEach(call); + } + } + /** + * The then() method returns a Promise. It takes two arguments, both are + * callback functions for the success and failure cases of the Promise. + * + * @method then + * @memberOf Promise + * @instance + * @param {function} onFulfilled A Function called when the Promise is fulfilled. This function has one argument, the fulfillment value. + * @param {function} onRejected A Function called when the Promise is rejected. This function has one argument, the rejection reason. + * @returns {Promise} + */ + this.then = function (onFulfilled, onRejected) { + + return new Promise(function (resolve, reject) { + + function asyncOnFulfilled() { + var value; + try { + value = onFulfilled ? onFulfilled(result) : result; + } catch (error) { + reject(error); + return; + } + value = mswrap(value); + if (value && value.then && value.then.call) { + value.then(resolve, reject); + } else { + resolve(value); + } + } + + function asyncOnRejected() { + var reason; + try { + reason = onRejected ? onRejected(result) : result; + } catch (error) { + reject(error); + return; + } + reason = mswrap(reason); + if (reason && reason.then && reason.then.call) { + reason.then(resolve, reject); + } else { + reject(reason); + } + } + + if (state === 'fulfilled') { + asyncOnFulfilled(); + } else if (state === 'rejected') { + asyncOnRejected(); + } else { + resolveQueue.push(asyncOnFulfilled); + rejectQueue.push(asyncOnRejected); + } + + }); + + }; + /** + * The catch() method returns a Promise and deals with rejected cases only. + * It behaves the same as calling Promise.prototype.then(undefined, onRejected). + * + * @method catch + * @memberOf Promise + * @instance + * @param {function} onRejected A Function called when the Promise is rejected. This function has one argument, the rejection reason. + * @returns {Promise} + */ + this['catch'] = function (onRejected) { + return this.then(undefined, onRejected); + }; + } + + /** + * The Promise.all(iterable) method returns a promise that resolves when all + * of the promises in the iterable argument have resolved.

+ * + * The result is passed as an array of values from all the promises. + * If something passed in the iterable array is not a promise, it's converted to + * one by Promise.resolve. If any of the passed in promises rejects, the + * all Promise immediately rejects with the value of the promise that rejected, + * discarding all the other promises whether or not they have resolved. + * + * @method all + * @memberOf Promise + * @static + * @param {KeyUsages} promises Array with promises. + * @returns {Promise} + */ + Promise.all = function (promises) { + return new Promise(function (resolve, reject) { + var result = [], count = 0; + function asyncResolve(k) { + count++; + return function (data) { + result[k] = data; + count--; + if (count === 0) + resolve(result); + }; + } + + function asyncReject(reason) { + if (count > 0) + reject(reason); + count = 0; + } + + for (var i = 0, n = promises.length; i < n; i++) { + var data = promises[i]; + if (data.then && data.then.call) + data.then(asyncResolve(i), asyncReject); + else + result[i] = data; + } + + if (count === 0) + resolve(result); + }); + }; + + return Promise; + })(); + } //
+ + /* + * Worker executor + * + */ // + + var baseUrl = '', nameSuffix = ''; + // Try to define from DOM model + if (typeof document !== 'undefined') { + (function () { + var regs = /^(.*)gostCrypto(.*)\.js$/i; + var list = document.querySelectorAll('script'); + for (var i = 0, n = list.length; i < n; i++) { + var value = list[i].getAttribute('src'); + var test = regs.exec(value); + if (test) { + baseUrl = test[1]; + nameSuffix = test[2]; + } + } + })(); + } + + // Local importScripts procedure for include dependens + function importScripts() { + for (var i = 0, n = arguments.length; i < n; i++) { + var name = arguments[i].split('.'), + src = baseUrl + name[0] + nameSuffix + '.' + name[1]; + var el = document.querySelector('script[src="' + src + '"]'); + if (!el) { + el = document.createElement('script'); + el.setAttribute('src', src); + document.head.appendChild(el); + } + } + } + + // Create Worker + var worker = false, tasks = [], sequence = 0; + // Worker will create only for first child process and + // Gost implementation libraries not yet loaded + if (!root.importScripts && !root.gostEngine) { + + try { + worker = new Worker(baseUrl + 'gostEngine' + nameSuffix + '.js'); + + // Result of opertion + worker.onmessage = function (event) { + // Find task + var id = event.data.id; + for (var i = 0, n = tasks.length; i < n; i++) + if (tasks[i].id === id) + break; + if (i < n) { + var task = tasks[i]; + tasks.splice(i, 1); + // Reject if error or resolve with result + if (event.data.error) + task.reject(new OperationError(event.data.error)); + else + task.resolve(event.data.result); + } + }; + + // Worker error - reject all waiting tasks + worker.onerror = function (event) { + for (var i = 0, n = tasks.length; i < n; i++) + tasks[i].reject(event.error); + tasks = []; + }; + + } catch (e) { + // Worker is't supported + worker = false; + } + } + + if (!root.importScripts) { + // This procedure emulate load dependents as in Worker + root.importScripts = importScripts; + + } + + if (!worker) { + // Import main module + // Reason: we are already in worker process or Worker interface is not + // yet supported + root.gostEngine //|| importScripts('gostEngine.js'); + } + + // Executor for any method + function execute(algorithm, method, args) { + return new Promise(function (resolve, reject) { + try { + if (worker) { + var id = ++sequence; + tasks.push({ + id: id, + resolve: resolve, + reject: reject + }); + worker.postMessage({ + id: id, algorithm: algorithm, + method: method, args: args + }); + } else { + if (root.gostEngine) + resolve(root.gostEngine.execute(algorithm, method, args)); + else + reject(new OperationError('Module gostEngine not found')); + } + } catch (error) { + reject(error); + } + }); + } + + // Self resolver + function call(callback) { + try { + callback(); + } catch (e) { + } + } + + // + + /* + * WebCrypto common class references + * + */ // + /** + * The Algorithm object is a dictionary object [WebIDL] which is used to + * specify an algorithm and any additional parameters required to fully + * specify the desired operation.
+ *
+     *  dictionary Algorithm {
+     *      DOMString name;
+     *  };
+     * 
+ * WebCrypto API reference {@link http://www.w3.org/TR/WebCryptoAPI/#algorithm-dictionary} + * @class Algorithm + * @param {DOMString} name The name of the registered algorithm to use. + */ + + /** + * AlgorithmIdentifier - Algorithm or DOMString name of algorithm
+ *
+     *  typedef (Algorithm or DOMString) AlgorithmIdentifier;
+     * 
+ * WebCrypto API reference {@link http://www.w3.org/TR/WebCryptoAPI/#algorithm-dictionary} + * @class AlgorithmIdentifier + */ + + /** + * The KeyAlgorithm interface represents information about the contents of a + * given Key object. + *
+     *  interface KeyAlgorithm {
+     *      readonly attribute DOMString name
+     *  };
+     * 
+ * WebCrypto API reference {@link http://www.w3.org/TR/WebCryptoAPI/#key-algorithm-interface} + * @class KeyAlgorithm + * @param {DOMString} name The name of the algorithm used to generate the Key + */ + + /** + * The type of a key. The recognized key type values are "public", "private" + * and "secret". Opaque keying material, including that used for symmetric + * algorithms, is represented by "secret", while keys used as part of asymmetric + * algorithms composed of public/private keypairs will be either "public" or "private". + *
+     *  typedef DOMString KeyType;
+     * 
+ * WebCrypto API reference {@link http://www.w3.org/TR/WebCryptoAPI/#key-interface} + * @class KeyType + */ + + /** + * Sequence of operation type that may be performed using a key. The recognized + * key usage values are "encrypt", "decrypt", "sign", "verify", "deriveKey", + * "deriveBits", "wrapKey" and "unwrapKey". + *
+     *  typedef DOMString[] KeyUsages;
+     * 
+ * WebCrypto API reference {@link http://www.w3.org/TR/WebCryptoAPI/#key-interface} + * @class KeyUsages + */ + + /** + * The Key object represents an opaque reference to keying material that is + * managed by the user agent.
+ * This specification provides a uniform interface for many different kinds of + * keying material managed by the user agent. This may include keys that have + * been generated by the user agent, derived from other keys by the user agent, + * imported to the user agent through user actions or using this API, + * pre-provisioned within software or hardware to which the user agent has + * access or made available to the user agent in other ways. The term key refers + * broadly to any keying material including actual keys for cryptographic + * operations and secret values obtained within key derivation or exchange operations.
+ * The Key object is not required to directly interface with the underlying key + * storage mechanism, and may instead simply be a reference for the user agent + * to understand how to obtain the keying material when needed, eg. when performing + * a cryptographic operation. + *
+     *  interface Key {
+     *      readonly attribute KeyType type;
+     *      readonly attribute boolean extractable;
+     *      readonly attribute KeyAlgorithm algorithm;
+     *      readonly attribute KeyUsages usages;
+     *  };     
+     * 
+ * WebCrypto API reference {@link http://www.w3.org/TR/WebCryptoAPI/#key-interface} + * @class Key + * @param {KeyType} type The type of a key. The recognized key type values are "public", "private" and "secret". + * @param {boolean} extractable Whether or not the raw keying material may be exported by the application. + * @param {KeyAlgorithm} algorithm The Algorithm used to generate the key. + * @param {KeyUsages} usages Key usage array: type of operation that may be performed using a key. + */ + + /** + * The KeyPair interface represents an asymmetric key pair that is comprised of both public and private keys. + *
+     *  interface KeyPair {
+     *      readonly attribute Key publicKey;
+     *      readonly attribute Key privateKey;
+     *  };     
+     * 
+ * WebCrypto API reference {@link http://www.w3.org/TR/WebCryptoAPI/#keypair} + * @class KeyPair + * @param {Key} privateKey Private key + * @param {Key} publicKey Public key + */ + + /** + * Specifies a serialization format for a key. The recognized key format values are: + * + *
+     *  typedef DOMString KeyFormat;
+     *  
+ * WebCrypto API reference {@link http://www.w3.org/TR/WebCryptoAPI/#key-interface} + * @class KeyFormat + */ + + /** + * Binary data + *
+     *  typedef (ArrayBuffer or ArrayBufferView) CryptoOperationData;
+     *  
+ * @class CryptoOperationData + */ + var CryptoOperationData = root.ArrayBuffer; + + /** + * DER-encoded ArrayBuffer or PEM-encoded DOMString constains ASN.1 object
+ *
+     *  typedef (ArrayBuffer or DOMString) FormatedData;
+     * 
+ * @class FormatedData + */ + //
+ + /** + * The gostCrypto provide general purpose cryptographic functionality for + * GOST standards including a cryptographically strong pseudo-random number + * generator seeded with truly random values. + * + * @namespace gostCrypto + */ + var gostCrypto = {}; + + /** + * The SubtleCrypto class provides low-level cryptographic primitives and algorithms. + * WebCrypto API reference {@link http://www.w3.org/TR/WebCryptoAPI/#subtlecrypto-interface} + * + * @class SubtleCrypto + */ // + function SubtleCrypto() { + } + + /** + * The encrypt method returns a new Promise object that will encrypt data + * using the specified algorithm identifier with the supplied Key. + * WebCrypto API reference {@link http://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-encrypt}

+ * + * Supported algorithm names: + * + * For more information see {@link GostCipher} + * + * @memberOf SubtleCrypto + * @method encrypt + * @instance + * @param {AlgorithmIdentifier} algorithm Algorithm identifier + * @param {Key} key Key object + * @param {CryptoOperationData} data Operation data + * @returns {Promise} Promise that resolves with {@link CryptoOperationData} + */ + SubtleCrypto.prototype.encrypt = function (algorithm, key, data) // + { + return new Promise(call).then(function () { + if (checkNative(algorithm)) + return rootCrypto.subtle.encrypt(algorithm, key, data); + + algorithm = normalize(algorithm, 'encrypt'); + return execute(algorithm, 'encrypt', + [extractKey('encrypt', algorithm, key), data]); + }); + }; // + + /** + * The decrypt method returns a new Promise object that will decrypt data + * using the specified algorithm identifier with the supplied Key. + * WebCrypto API reference {@link http://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-decrypt}

+ * + * Supported algorithm names: + * + * For additional modes see {@link GostCipher} + * + * @memberOf SubtleCrypto + * @method decrypt + * @instance + * @param {AlgorithmIdentifier} algorithm Algorithm identifier + * @param {Key} key Key object + * @param {CryptoOperationData} data Operation data + * @returns {Promise} Promise that resolves with {@link CryptoOperationData} + */ + SubtleCrypto.prototype.decrypt = function (algorithm, key, data) // + { + return new Promise(call).then(function () { + if (checkNative(algorithm)) + return rootCrypto.subtle.decrypt(algorithm, key, data); + + algorithm = normalize(algorithm, 'decrypt'); + return execute(algorithm, 'decrypt', + [extractKey('decrypt', algorithm, key), data]); + }); + }; // + + /** + * The sign method returns a new Promise object that will sign data using + * the specified algorithm identifier with the supplied Key. + * WebCrypto API reference {@link http://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-sign}

+ * + * Supported algorithm names: + * + * For additional modes see {@link GostSign}, {@link GostDigest} and {@link GostCipher} + * + * @memberOf SubtleCrypto + * @method sign + * @instance + * @param {AlgorithmIdentifier} algorithm Algorithm identifier + * @param {Key} key Key object + * @param {CryptoOperationData} data Operation data + * @returns {Promise} Promise that resolves with {@link CryptoOperationData} + */ + SubtleCrypto.prototype.sign = function (algorithm, key, data) // + { + return new Promise(call).then(function () { + if (checkNative(algorithm)) + return rootCrypto.subtle.sign(algorithm, key, data); + + algorithm = normalize(algorithm, 'sign'); + var value = execute(algorithm, 'sign', + [extractKey('sign', algorithm, key), data]).then(function (data) { + if (algorithm.procreator === 'SC' && algorithm.mode === 'SIGN') { + data = gostCrypto.asn1.GostSignature.encode(data); + } + return data; + }); + return value; + }); + }; // + + /** + * The verify method returns a new Promise object that will verify data + * using the specified algorithm identifier with the supplied Key. + * WebCrypto API reference {@link http://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-verify}

+ * + * Supported algorithm names: + * + * For additional modes see {@link GostSign}, {@link GostDigest} and {@link GostCipher} + * + * @memberOf SubtleCrypto + * @method verify + * @instance + * @param {AlgorithmIdentifier} algorithm Algorithm identifier + * @param {Key} key Key object + * @param {CryptoOperationData} signature Signature data + * @param {CryptoOperationData} data Operation data + * @returns {Promise} Promise that resolves with boolean value of verification result + */ + SubtleCrypto.prototype.verify = function (algorithm, key, signature, data) // + { + return new Promise(call).then(function () { + if (checkNative(algorithm)) + return rootCrypto.subtle.verify(algorithm, key, signature, data); + + algorithm = normalize(algorithm, 'verify'); + if (algorithm.procreator === 'SC' && algorithm.mode === 'SIGN') { + var obj = gostCrypto.asn1.GostSignature.decode(signature); + signature = {r: obj.r, s: obj.s}; + } + return execute(algorithm, 'verify', + [extractKey('verify', algorithm, key), signature, data]); + }); + }; // + + /** + * The digest method returns a new Promise object that will digest data + * using the specified algorithm identifier. + * WebCrypto API reference {@link http://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-digest}

+ * + * Supported algorithm names: + * + * For additional modes see {@link GostDigest} + * + * @memberOf SubtleCrypto + * @method digest + * @instance + * @param {AlgorithmIdentifier} algorithm Algorithm identifier + * @param {CryptoOperationData} data Operation data + * @returns {Promise} Promise that resolves with {@link CryptoOperationData} + */ + SubtleCrypto.prototype.digest = function (algorithm, data) // + { + return new Promise(call).then(function () { + if (checkNative(algorithm)) + return rootCrypto.subtle.digest(algorithm, data); + + algorithm = normalize(algorithm, 'digest'); + return execute(algorithm, 'digest', [data]); + }); + }; // + + /** + * The generateKey method returns a new Promise object that will key(s) using + * the specified algorithm identifier. Key can be used in according with + * KeyUsages sequence. The recognized key usage values are "encrypt", "decrypt", + * "sign", "verify", "deriveKey", "deriveBits", "wrapKey" and "unwrapKey". + * WebCrypto API reference {@link http://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-generateKey}

+ * + * Supported algorithm names: + * + * For additional modes see {@link GostSign}, {@link GostDigest} and {@link GostCipher}
+ * Note: Generation key for GOST R 34.10-94 not supported. + * + * @memberOf SubtleCrypto + * @method generateKey + * @instance + * @param {AlgorithmIdentifier} algorithm Key algorithm identifier + * @param {boolean} extractable Whether or not the raw keying material may be exported by the application + * @param {KeyUsages} keyUsages Key usage array: type of operation that may be performed using a key + * @returns {Promise} Promise that resolves with {@link Key} or {@link KeyPair} in according to key algorithm + */ + SubtleCrypto.prototype.generateKey = function (algorithm, extractable, keyUsages) // + { + return new Promise(call).then(function () { + if (checkNative(algorithm)) + return rootCrypto.subtle.generateKey(algorithm, extractable, keyUsages); + + var privateAlgorithm = algorithm.privateKey, + publicAlgorithm = algorithm.publicKey; + algorithm = normalize(algorithm, 'generateKey'); + if (privateAlgorithm) + privateAlgorithm = normalize(privateAlgorithm, 'generateKey'); + else + privateAlgorithm = algorithm; + if (publicAlgorithm) + publicAlgorithm = normalize(publicAlgorithm, 'generateKey'); + else + publicAlgorithm = algorithm; + return execute(algorithm, 'generateKey', []).then(function (data) { + if (data.publicKey && data.privateKey) + return convertKeyPair(publicAlgorithm, privateAlgorithm, extractable, keyUsages, data.publicKey, data.privateKey); + else + return convertKey(algorithm, extractable, keyUsages, data); + }); + }); + }; // + + /** + * The deriveKey method returns a new Promise object that will key(s) using + * the specified algorithm identifier. Key can be used in according with + * KeyUsage sequence. The recognized key usage values are "encrypt", "decrypt", + * "sign", "verify", "deriveKey", "deriveBits", "wrapKey" and "unwrapKey". + * WebCrypto API reference {@link http://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-deriveKey}

+ * + * Supported algorithm names: + * + * For additional modes see {@link GostSign} and {@link GostDigest} + * + * @memberOf SubtleCrypto + * @method deriveKey + * @instance + * @param {AlgorithmIdentifier} algorithm Algorithm identifier + * @param {Key} baseKey Derivation key object + * @param {AlgorithmIdentifier} derivedKeyType Derived key algorithm identifier + * @param {boolean} extractable Whether or not the raw keying material may be exported by the application + * @param {KeyUsages} keyUsages Key usage array: type of operation that may be performed using a key + * @returns {Promise} Promise that resolves with {@link Key} + */ + SubtleCrypto.prototype.deriveKey = function (algorithm, baseKey, + derivedKeyType, extractable, keyUsages) // + { + return new Promise(call).then(function () { + if (checkNative(algorithm)) + return rootCrypto.subtle.deriveKey(algorithm, baseKey, + derivedKeyType, extractable, keyUsages); + + algorithm = normalize(algorithm, 'deriveKey'); + derivedKeyType = normalize(derivedKeyType, 'generateKey'); + algorithm.keySize = derivedKeyType.keySize; + if (algorithm['public']) { + algorithm['public'].algorithm = normalize(algorithm['public'].algorithm); + algorithm['public'] = extractKey('deriveKey', algorithm, algorithm['public']); + } + return execute(algorithm, 'deriveKey', [extractKey('deriveKey', algorithm, baseKey)]).then(function (data) { + return convertKey(derivedKeyType, extractable, keyUsages, data); + }); + }); + }; // + + /** + * The deriveBits method returns length bits on baseKey using the + * specified algorithm identifier. + * WebCrypto API reference {@link http://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-deriveBits}

+ * + * Supported algorithm names: + * + * For additional modes see {@link GostSign} and {@link GostDigest} + * + * @memberOf SubtleCrypto + * @method deriveBits + * @instance + * @param {AlgorithmIdentifier} algorithm Algorithm identifier + * @param {Key} baseKey Derivation key object + * @param {number} length Length bits + * @returns {Promise} Promise that resolves with {@link CryptoOperationData} + */ + SubtleCrypto.prototype.deriveBits = function (algorithm, baseKey, length) // + { + return new Promise(call).then(function () { + if (checkNative(algorithm)) + return rootCrypto.subtle.deriveBits(algorithm, baseKey, length); + + algorithm = normalize(algorithm, 'deriveBits'); + if (algorithm['public']) + algorithm['public'] = extractKey('deriveBits', algorithm, algorithm['public']); + return execute(algorithm, 'deriveBits', [extractKey('deriveBits', algorithm, baseKey), length]); + }); + }; // + + /** + * The importKey method returns a new Promise object that will key(s) using + * the specified algorithm identifier. Key can be used in according with + * KeyUsage sequence. The recognized key usage values are "encrypt", "decrypt", + * "sign", "verify", "deriveKey", "deriveBits", "wrapKey" and "unwrapKey".

+ * Parameter keyData contains data in defined format. + * The suppored key format values are: + * + * WebCrypto API reference {@link http://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-importKey}

+ * + * Supported algorithm names: + * + * For additional modes see {@link GostSign}, {@link GostDigest} and {@link GostCipher}
+ * + * @memberOf SubtleCrypto + * @method importKey + * @instance + * @param {KeyFormat} format Key format Format specifies a serialization format for a key + * @param {CryptoOperationData} keyData + * @param {AlgorithmIdentifier} algorithm Key algorithm identifier + * @param {boolean} extractable Whether or not the raw keying material may be exported by the application + * @param {KeyUsages} keyUsages Key usage array: type of operation that may be performed using a key + * @returns {Promise} Promise that resolves with {@link Key} + */ + SubtleCrypto.prototype.importKey = function (format, keyData, algorithm, extractable, keyUsages) // + { + var type; + return new Promise(call).then(function () { + if (checkNative(algorithm)) + return rootCrypto.subtle.importKey(format, keyData, algorithm, extractable, keyUsages); + + if (format === 'raw') { + algorithm = normalize(algorithm, 'importKey'); + if (keyUsages && keyUsages.indexOf) { + var name = algorithm.name.toUpperCase().replace(/[\.\s]/g, ''); + if (name.indexOf('3410') >= 0 && keyUsages.indexOf('sign') >= 0) + type = 'private'; + else if (name.indexOf('3410') >= 0 && keyUsages.indexOf('verify') >= 0) + type = 'public'; + } + return keyData; + } else { + var key; + if (format === 'pkcs8') + key = gostCrypto.asn1.GostPrivateKeyInfo.decode(keyData).object; + else if (format === 'spki') + key = gostCrypto.asn1.GostSubjectPublicKeyInfo.decode(keyData).object; + else + throw new NotSupportedError('Key format not supported'); + + algorithm = normalize(key.algorithm, 'importKey'); + type = key.type; + if (extractable !== false) + extractable = extractable || key.extractable; + if (keyUsages) { + for (var i = 0; i < keyUsages.length; i++) { + if (key.usages.indexOf(keyUsages[i]) < 0) + throw DataError('Key usage not valid for this key'); + } + } else + keyUsages = key.usages; + var data = key.buffer, keySize = algorithm.keySize, dataLen = data.byteLength; + if (type === 'public' || keySize === dataLen) + return data; + else { + // Remove private key masks + if (dataLen % keySize > 0) + throw new DataError('Invalid key size'); + algorithm.mode = 'MASK'; + algorithm.procreator = 'VN'; + var chain = []; + for (var i = keySize; i < dataLen; i += keySize) { + chain.push((function (mask) { + return function (data) { + return execute(algorithm, 'unwrapKey', [mask, data]).then(function (data) { + var next = chain.pop(); + if (next) + return next(data); + else { + delete algorithm.mode; + return data; + } + }); + }; + })(new Uint8Array(data, i, keySize))); + } + return chain.pop()(new Uint8Array(data, 0, keySize)); + } + } + }).then(function (data) { + return convertKey(algorithm, extractable, keyUsages, data, type); + }); + }; // + + /** + * The exportKey method returns a new Promise object that will key data in + * defined format.

+ * The suppored key format values are: + * + * WebCrypto API reference {@link http://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-exportKey}

+ * + * Supported algorithm names: + * + * For additional modes see {@link GostSign}, {@link GostDigest} and {@link GostCipher}
+ * + * @memberOf SubtleCrypto + * @method exportKey + * @instance + * @param {KeyFormat} format Format specifies a serialization format for a key + * @param {Key} key Key object + * @returns {Promise} Promise that resolves with {@link CryptoOperationData} + */ + SubtleCrypto.prototype.exportKey = function (format, key) // + { + return new Promise(call).then(function () { + if (key && checkNative(key.algorithm)) + return rootCrypto.subtle.exportKey(format, key); + + if (!key.extractable) + throw new InvalidAccessError('Key not extractable'); + + var raw = extractKey(null, null, key); + if (format === 'raw') + return raw; + else if (format === 'pkcs8' && key.algorithm && key.algorithm.id) { + if (key.algorithm.procreator === 'VN') { + // Add masks for ViPNet + var algorithm = key.algorithm, mask; + algorithm.mode = 'MASK'; + return execute(algorithm, 'generateKey').then(function (data) { + mask = data; + return execute(algorithm, 'wrapKey', [mask, key.buffer]); + }).then(function (data) { + delete algorithm.mode; + var d = new Uint8Array(data.byteLength + mask.byteLength); + d.set(new Uint8Array(data, 0, data.byteLength)); + d.set(new Uint8Array(mask, 0, mask.byteLength), data.byteLength); + var buffer = d.buffer; + buffer.enclosed = true; + return gostCrypto.asn1.GostPrivateKeyInfo.encode({ + algorithm: algorithm, + buffer: buffer + }); + }); + } else + return gostCrypto.asn1.GostPrivateKeyInfo.encode(key); + } else if (format === 'spki' && key.algorithm && key.algorithm.id) + return gostCrypto.asn1.GostSubjectPublicKeyInfo.encode(key); + else + throw new NotSupportedError('Key format not supported'); + }); + }; // + + /** + * The wrapKey method returns a new Promise object that will wrapped key(s). + * WebCrypto API reference {@link http://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-wrapKey}

+ * + * Supported algorithm names: + * + * For additional modes see {@link GostCipher}
+ * + * @memberOf SubtleCrypto + * @method wrapKey + * @instance + * @param {KeyFormat} format Format specifies a serialization format for a key. Now suppored only 'raw' key format. + * @param {Key} key Key object + * @param {Key} wrappingKey Wrapping key object + * @param {AlgorithmIdentifier} wrapAlgorithm Algorithm identifier + * @returns {Promise} Promise that resolves with {@link CryptoOperationData} + */ + SubtleCrypto.prototype.wrapKey = function (format, key, wrappingKey, wrapAlgorithm) // + { + return new Promise(call).then(function () { + if (checkNative(wrapAlgorithm)) + return rootCrypto.subtle.wrapKey(format, key, wrappingKey, wrapAlgorithm); + + wrapAlgorithm = normalize(wrapAlgorithm, 'wrapKey'); + var keyData = extractKey(null, null, key); + if (wrapAlgorithm.procreator === 'SC' && key.type === 'private') + keyData = swapBytes(keyData); + return execute(wrapAlgorithm, 'wrapKey', + [extractKey('wrapKey', wrapAlgorithm, wrappingKey), keyData]).then(function (data) { + if (format === 'raw') + return data; + else + throw new NotSupportedError('Key format not supported'); + }); + }); + }; // + + /** + * The unwrapKey method returns a new Promise object that will unwrapped key(s). + * WebCrypto API reference {@link http://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-unwrapKey}

+ * + * Supported algorithm names: + * + * For additional modes see {@link GostCipher}
+ * + * @memberOf SubtleCrypto + * @method unwrapKey + * @instance + * @param {KeyFormat} format Format specifies a serialization format for a key. Now suppored only 'raw' key format. + * @param {CryptoOperationData} wrappedKey Wrapped key data + * @param {Key} unwrappingKey Unwrapping key object + * @param {AlgorithmIdentifier} unwrapAlgorithm Algorithm identifier + * @param {AlgorithmIdentifier} unwrappedKeyAlgorithm Key algorithm identifier + * @param {boolean} extractable Whether or not the raw keying material may be exported by the application + * @param {KeyUsages} keyUsages Key usage array: type of operation that may be performed using a key + * @returns {Promise} Promise that resolves with {@link Key} + */ + SubtleCrypto.prototype.unwrapKey = function (format, wrappedKey, unwrappingKey, + unwrapAlgorithm, unwrappedKeyAlgorithm, extractable, keyUsages) // + { + return new Promise(call).then(function () { + if (checkNative(unwrapAlgorithm)) + return rootCrypto.subtle.unwrapKey(format, wrappedKey, unwrappingKey, + unwrapAlgorithm, unwrappedKeyAlgorithm, extractable, keyUsages); + + unwrapAlgorithm = normalize(unwrapAlgorithm, 'unwrapKey'); + unwrappedKeyAlgorithm = normalize(unwrappedKeyAlgorithm, 'importKey'); + if (format !== 'raw') + throw new NotSupportedError('Key format not supported'); + + return execute(unwrapAlgorithm, 'unwrapKey', [extractKey('unwrapKey', unwrapAlgorithm, unwrappingKey), wrappedKey]).then(function (data) { + var type; + if (unwrappedKeyAlgorithm && unwrappedKeyAlgorithm.name) { + var name = unwrappedKeyAlgorithm.name.toUpperCase().replace(/[\.\s]/g, ''); + if (name.indexOf('3410') >= 0 && keyUsages.indexOf('sign') >= 0) + type = 'private'; + else if (name.indexOf('3410') >= 0 && keyUsages.indexOf('verify') >= 0) + type = 'public'; + } + if (unwrapAlgorithm.procreator === 'SC' && type === 'private') + data = swapBytes(data); + return convertKey(unwrappedKeyAlgorithm, extractable, keyUsages, data, type); + }); + }); + }; // + + /** + * The subtle attribute provides an instance of the SubtleCrypto + * interface which provides low-level cryptographic primitives and + * algorithms. + * + * @memberOf gostCrypto + * @type SubtleCrypto + */ + gostCrypto.subtle = new SubtleCrypto(); + + /** + * The getRandomValues method generates cryptographically random values. + * + * First try to use Web Crypto random genereator. Next make random + * bytes based on standart Math.random mixed with time and mouse pointer + * + * @memberOf gostCrypto + * @param {(CryptoOperationData)} array Destination buffer for random data + */ + gostCrypto.getRandomValues = function (array) // + { + // Execute randomizer + GostRandom = GostRandom || root.GostRandom; + var randomSource = GostRandom ? new GostRandom() : rootCrypto; + if (randomSource.getRandomValues) + randomSource.getRandomValues(array); + else + throw new NotSupportedError('Random generator not found'); + }; // + //
+ + return gostCrypto; +})); diff --git a/src/core/vendor/streebog/gostDigest.js b/src/core/vendor/streebog/gostDigest.js new file mode 100644 index 00000000..aa3ddb41 --- /dev/null +++ b/src/core/vendor/streebog/gostDigest.js @@ -0,0 +1,1269 @@ +/** + * @file GOST R 34.11-94 / GOST R 34.11-12 implementation + * @version 1.76 + * @copyright 2014-2016, Rudolf Nickolaev. All rights reserved. + */ + +/* + * 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. + * + * Converted to JavaScript from source https://www.streebog.net/ + * Copyright (c) 2013, Alexey Degtyarev. + * All rights reserved. + * + * 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. + * + */ + +(function (root, factory) { + + /* + * Module imports and exports + * + */ // + if (typeof exports === 'object') { + module.exports = factory(require('./gostRandom'), require('./gostCipher')); + } + // + +}(this, function (GostRandom, GostCipher) { + + /* + * GOST R 34.11 + * Common methods + * + */ // + + var root = this; + var rootCrypto = root.crypto || root.msCrypto; + + var DataError = root.DataError || Error, + NotSupportedError = root.NotSupportedError || Error; + + // Copy len values from s[sOfs] to d[dOfs] + function arraycopy(s, sOfs, d, dOfs, len) { + for (var i = 0; i < len; i++) + d[dOfs + i] = s[sOfs + i]; + } + + // Swap bytes in buffer + function swap(s) { + var src = new Uint8Array(s), + dst = new Uint8Array(src.length); + for (var i = 0, n = src.length; i < n; i++) + dst[n - i - 1] = src[i]; + return dst.buffer; + } + + // Convert BASE64 string to Uint8Array + // for decompression of constants and precalc values + function b64decode(s) { + // s = s.replace(/[^A-Za-z0-9\+\/]/g, ''); + var n = s.length, + k = n * 3 + 1 >> 2, r = new Uint8Array(k); + + for (var m3, m4, u24 = 0, j = 0, i = 0; i < n; i++) { + m4 = i & 3; + var c = s.charCodeAt(i); + + c = c > 64 && c < 91 ? + c - 65 : c > 96 && c < 123 ? + c - 71 : c > 47 && c < 58 ? + c + 4 : c === 43 ? + 62 : c === 47 ? + 63 : 0; + + u24 |= c << 18 - 6 * m4; + if (m4 === 3 || n - i === 1) { + for (m3 = 0; m3 < 3 && j < k; m3++, j++) { + r[j] = u24 >>> (16 >>> m3 & 24) & 255; + } + u24 = 0; + + } + } + return r.buffer; + } + + // Random seed + function getSeed(length) { + GostRandom = GostRandom || root.GostRandom; + var randomSource = GostRandom ? new (GostRandom || root.GostRandom) : rootCrypto; + if (randomSource.getRandomValues) { + var d = new Uint8Array(Math.ceil(length / 8)); + randomSource.getRandomValues(d); + return d; + } else + throw new NotSupportedError('Random generator not found'); + } + + // Check buffer + function buffer(d) { + if (d instanceof ArrayBuffer) + return d; + else if (d && d.buffer && d.buffer instanceof ArrayBuffer) + 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('ArrayBuffer or ArrayBufferView required'); + } // + + /** + * Algorithm name GOST R 34.11 or GOST R 34.11-12

+ * + * http://tools.ietf.org/html/rfc6986 + * + * The digest method returns digest data in according to GOST R 4311-2012.
+ * Size of digest also defines in algorithm name. + * + * + * @memberOf GostDigest + * @method digest + * @instance + * @param {(ArrayBuffer|TypedArray)} data Data + * @returns {ArrayBuffer} Digest of data + */ + var digest2012 = (function () // + { + // Constants + var buffer0 = new Int32Array(16); // [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + + var buffer512 = new Int32Array(16); // [512, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + buffer512[0] = 512; + + // Constant C + var C = (function (s) { + var h = new Int32Array(b64decode(s)), + r = new Array(12); + for (var i = 0; i < 12; i++) + r[i] = new Int32Array(h.buffer, i * 64, 16); + return r; + })( + 'B0Wm8lllgN0jTXTMNnR2BRXTYKQIKkKiAWlnkpHgfEv8xIV1jbhOcRbQRS5DdmovH3xlwIEvy+vp2soe2lsIsbebsSFwBHnmVs3L1xui3VXKpwrbwmG1XFiZ1hJrF7WaMQG1Fg9e1WGYKyMKcur+89e1cA9GneNPGi+dqYq1o2+yCroK9ZYemTHbeoZD9LbCCdtiYDc6ycGxnjWQ5A/i03t7KbEUderyix+cUl9e8QY1hD1qKPw5Cscvzius3HT1LtHjhLy+DCLxN+iToepTNL4DUpMzE7fYddYD7YIs16k/NV5orRxynX08XDN+hY5I3eRxXaDhSPnSZhXos98f71f+bHz9WBdg9WPqqX6iVnoWGicjtwD/36P1OiVHF82/vf8PgNc1njVKEIYWHxwVf2MjqWwMQT+amUdHraxr6ktufWRGekBo+jVPkDZyxXG/tsa+wmYf8gq0t5oct6b6z8aO8Jq0mn8YbKRCUfnEZi3AOTB6O8Okb9nTOh2urk+uk9QUOk1WhojzSjyiTEUXNQQFSiiDaUcGNyyCLcWrkgnJk3oZMz5H08mHv+bHxp45VAkkv/6GrFHsxaruFg7H9B7nAr/UDX+k' + + '2ahRWTXCrDYvxKXRK43RaZAGm5LLK4n0msTbTTtEtIke3jaccfi3TkFBbgwCqucDp8mTTUJbH5vbWiODUURhcmAqH8uS3DgOVJwHppqKK3uxzrLbC0QKgIQJDeC3Vdk8JEKJJRs6fTreXxbs2JpMlJsiMRZUWo837ZxFmPvHtHTDtjsV0fqYNvRSdjswbB56SzNprwJn558DYTMbiuH/H9t4iv8c50GJ8/PkskjlKjhSbwWApt6+qxst84HNpMprXdhvwEpZot6Ybkd9Hc2678q5SOrvcR2KeWaEFCGAASBhB6vru2v62JT+WmPNxgIw+4nI79CezXsg1xvxSpK8SJkbstnVF/T6UijhiKqkHeeGzJEYne+AXZufITDUEiD4dx3fvDI8pM16sUkEsIAT0roxFvFn5443'); + + // Precalc Ax + var Ax = (function (s) { + return new Int32Array(b64decode(s)); + })( + '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'); //== + + // Variables + var sigma, N, h; + + // 64bit tools + function get8(x, i) { + return (x[i >> 2] >> ((i & 3) << 3)) & 0xff; + } + + // 512bit tools + function add512(x, y) { + var CF = 0, w0, w1; + for (var i = 0; i < 16; i++) { + w0 = (x[i] & 0xffff) + (y[i] & 0xffff) + (CF || 0); + w1 = (x[i] >>> 16) + (y[i] >>> 16) + (w0 >>> 16); + x[i] = (w0 & 0xffff) | (w1 << 16); + CF = (w1 >>> 16); + } + } + + function get512(d) { + return new Int32Array(d.buffer, d.byteOffset, 16); + } + + + function copy512(r, d) { + for (var i = 0; i < 16; i++) + r[i] = d[i]; + } + + function new512() { + return new Int32Array(16); + } + + // Core private algorithms + function xor512(x, y) { + for (var i = 0; i < 16; i++) + x[i] = x[i] ^ y[i]; + } + + + var r = new512(); + function XLPS(x, y) { + copy512(r, x); + xor512(r, y); + for (var i = 0; i < 8; i++) { + var z0, z1, k = get8(r, i) << 1; + z0 = Ax[k]; + z1 = Ax[k + 1]; + for (var j = 1; j < 8; j++) { + k = (j << 9) + (get8(r, (j << 3) + i) << 1); + z0 = z0 ^ Ax[k]; + z1 = z1 ^ Ax[k + 1]; + } + x[i << 1] = z0; + x[(i << 1) + 1] = z1; + } + } + + var data = new512(), Ki = new512(); + function g(h, N, m) + { + var i; + + copy512(data, h); + XLPS(data, N); + + /* Starting E() */ + copy512(Ki, data); + XLPS(data, m); + + for (i = 0; i < 11; i++) { + XLPS(Ki, C[i]); + XLPS(data, Ki); + } + + XLPS(Ki, C[11]); + xor512(data, Ki); + /* E() done */ + + xor512(h, data); + xor512(h, m); + } + + // Stages + function stage2(d) { + var m = get512(d); + g(h, N, m); + + add512(N, buffer512); + add512(sigma, m); + } + + function stage3(d) { + var n = d.length; + if (n > 63) + return; + + var b0 = new Int32Array(16); + b0[0] = n << 3; + + var b = new Uint8Array(64); + for (var i = 0; i < n; i++) + b[i] = d[i]; + b[n] = 0x01; + + var m = get512(b), m0 = get512(b0); + g(h, N, m); + + add512(N, m0); + add512(sigma, m); + + g(h, buffer0, N); + g(h, buffer0, sigma); + } + + return function (data) { + + // Cleanup + sigma = new512(); + N = new512(); + + // Initial vector + h = new512(); + for (var i = 0; i < 16; i++) + if (this.bitLength === 256) + h[i] = 0x01010101; + + // Make data + var d = new Uint8Array(buffer(data)); + + var n = d.length; + var r = n % 64, q = (n - r) / 64; + + for (var i = 0; i < q; i++) + stage2.call(this, new Uint8Array(d.buffer, i * 64, 64)); + + stage3.call(this, new Uint8Array(d.buffer, q * 64, r)); + + var digest; + if (this.bitLength === 256) { + digest = new Int32Array(8); + for (var i = 0; i < 8; i++) + digest[i] = h[8 + i]; + } else { + digest = new Int32Array(16); + for (var i = 0; i < 16; i++) + digest[i] = h[i]; + } + // Swap hash for SignalCom + if (this.procreator === 'SC' || this.procreator === 'VN') + return swap(digest.buffer); + else + return digest.buffer; + }; + } // + )(); + + /** + * Algorithm name GOST R 34.11-94

+ * + * http://tools.ietf.org/html/rfc5831 + * + * The digest method returns digest data in according to GOST R 34.11-94. + * @memberOf GostDigest + * @method digest + * @instance + * @param {(ArrayBuffer|TypedArray)} data Data + * @returns {ArrayBuffer} Digest of data + */ + var digest94 = (function () // + { + var C, H, M, Sum; + + // (i + 1 + 4(k - 1)) = 8i + k i = 0-3, k = 1-8 + function P(d) { + var K = new Uint8Array(32); + + for (var k = 0; k < 8; k++) { + K[4 * k] = d[k]; + K[1 + 4 * k] = d[ 8 + k]; + K[2 + 4 * k] = d[16 + k]; + K[3 + 4 * k] = d[24 + k]; + } + + return K; + } + + //A (x) = (x0 ^ x1) || x3 || x2 || x1 + function A(d) + { + var a = new Uint8Array(8); + + for (var j = 0; j < 8; j++) + { + a[j] = (d[j] ^ d[j + 8]); + } + + arraycopy(d, 8, d, 0, 24); + arraycopy(a, 0, d, 24, 8); + + return d; + } + + // (in:) n16||..||n1 ==> (out:) n1^n2^n3^n4^n13^n16||n16||..||n2 + function fw(d) { + var wS = new Uint16Array(d.buffer, 0, 16); + var wS15 = wS[0] ^ wS[1] ^ wS[2] ^ wS[3] ^ wS[12] ^ wS[15]; + arraycopy(wS, 1, wS, 0, 15); + wS[15] = wS15; + } + + //Encrypt function, ECB mode + function encrypt(key, s, sOff, d, dOff) { + var t = new Uint8Array(8); + arraycopy(d, dOff, t, 0, 8); + var r = new Uint8Array(this.cipher.encrypt(key, t)); + arraycopy(r, 0, s, sOff, 8); + } + + // block processing + function process(d, dOff) { + var S = new Uint8Array(32), U = new Uint8Array(32), + V = new Uint8Array(32), W = new Uint8Array(32); + + arraycopy(d, dOff, M, 0, 32); + + //key step 1 + + // H = h3 || h2 || h1 || h0 + // S = s3 || s2 || s1 || s0 + arraycopy(H, 0, U, 0, 32); + arraycopy(M, 0, V, 0, 32); + for (var j = 0; j < 32; j++) + { + W[j] = (U[j] ^ V[j]); + } + // Encrypt GOST 28147-ECB + encrypt.call(this, P(W), S, 0, H, 0); // s0 = EK0 [h0] + + //keys step 2,3,4 + for (var i = 1; i < 4; i++) { + var tmpA = A(U); + for (var j = 0; j < 32; j++) { + U[j] = (tmpA[j] ^ C[i][j]); + } + V = A(A(V)); + for (var j = 0; j < 32; j++) { + W[j] = (U[j] ^ V[j]); + } + // Encrypt GOST 28147-ECB + encrypt.call(this, P(W), S, i * 8, H, i * 8); // si = EKi [hi] + } + + // x(M, H) = y61(H^y(M^y12(S))) + for (var n = 0; n < 12; n++) { + fw(S); + } + for (var n = 0; n < 32; n++) { + S[n] = (S[n] ^ M[n]); + } + + fw(S); + + for (var n = 0; n < 32; n++) { + S[n] = (H[n] ^ S[n]); + } + for (var n = 0; n < 61; n++) { + fw(S); + } + arraycopy(S, 0, H, 0, H.length); + } + + + // 256 bitsblock modul -> (Sum + a mod (2^256)) + function summing(d) + { + var carry = 0; + for (var i = 0; i < Sum.length; i++) + { + var sum = (Sum[i] & 0xff) + (d[i] & 0xff) + carry; + + Sum[i] = sum; + + carry = sum >>> 8; + } + } + + // reset the chaining variables to the IV values. + var C2 = new Uint8Array([ + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, + 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF + ]); + + return function (data) { + + // Reset buffers + H = new Uint8Array(32); + M = new Uint8Array(32); + Sum = new Uint8Array(32); + + // Reset IV value + C = new Array(4); + for (var i = 0; i < 4; i++) + C[i] = new Uint8Array(32); + arraycopy(C2, 0, C[2], 0, C2.length); + + // Make data + var d = new Uint8Array(buffer(data)); + + var n = d.length; + var r = n % 32, q = (n - r) / 32; + + // Proccess full blocks + for (var i = 0; i < q; i++) { + var b = new Uint8Array(d.buffer, i * 32, 32); + + summing.call(this, b); // calc sum M + process.call(this, b, 0); + } + + // load d the remadder with padding zero; + if (r > 0) { + var b = new Uint8Array(d.buffer, q * 32), + c = new Uint8Array(32); + arraycopy(b, 0, c, 0, r); + summing.call(this, c); // calc sum M + process.call(this, c, 0); + + } + + // get length into L (byteCount * 8 = bitCount) in little endian. + var L = new Uint8Array(32), n8 = n * 8, k = 0; + while (n8 > 0) { + L[k++] = n8 & 0xff; + n8 = Math.floor(n8 / 256); + } + process.call(this, L, 0); + process.call(this, Sum, 0); + + var h = H.buffer; + + // Swap hash for SignalCom + if (this.procreator === 'SC') + h = swap(h); + + return h; + }; + + } // + )(); + + /** + * Algorithm name SHA-1

+ * + * https://tools.ietf.org/html/rfc3174 + * + * The digest method returns digest data in according to SHA-1.
+ * + * @memberOf GostDigest + * @method digest + * @instance + * @param {(ArrayBuffer|TypedArray)} data Data + * @returns {ArrayBuffer} Digest of data + */ + var digestSHA1 = (function () // + { + + // Create a buffer for each 80 word block. + var state, block = new Uint32Array(80); + + function common(a, e, w, k, f) { + return (f + e + w + k + ((a << 5) | (a >>> 27))) >>> 0; + } + + function f1(a, b, c, d, e, w) { + return common(a, e, w, 0x5A827999, d ^ (b & (c ^ d))); + } + + function f2(a, b, c, d, e, w) { + return common(a, e, w, 0x6ED9EBA1, b ^ c ^ d); + } + + function f3(a, b, c, d, e, w) { + return common(a, e, w, 0x8F1BBCDC, (b & c) | (d & (b | c))); + } + + function f4(a, b, c, d, e, w) { + return common(a, e, w, 0xCA62C1D6, b ^ c ^ d); + } + + function cycle(state, block) { + var a = state[0], + b = state[1], + c = state[2], + d = state[3], + e = state[4]; + + // Partially unroll loops so we don't have to shift variables. + var fn = f1; + for (var i = 0; i < 80; i += 5) { + if (i === 20) { + fn = f2; + } + else if (i === 40) { + fn = f3; + } + else if (i === 60) { + fn = f4; + } + e = fn(a, b, c, d, e, block[i]); + b = ((b << 30) | (b >>> 2)) >>> 0; + d = fn(e, a, b, c, d, block[i + 1]); + a = ((a << 30) | (a >>> 2)) >>> 0; + c = fn(d, e, a, b, c, block[i + 2]); + e = ((e << 30) | (e >>> 2)) >>> 0; + b = fn(c, d, e, a, b, block[i + 3]); + d = ((d << 30) | (d >>> 2)) >>> 0; + a = fn(b, c, d, e, a, block[i + 4]); + c = ((c << 30) | (c >>> 2)) >>> 0; + } + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + } + + // Swap bytes for 32bits word + function swap32(b) { + return ((b & 0xff) << 24) + | ((b & 0xff00) << 8) + | ((b >> 8) & 0xff00) + | ((b >> 24) & 0xff); + } + + // input is a Uint8Array bitstream of the data + return function (data) { + var d = new Uint8Array(buffer(data)), dlen = d.length; + + // Pad the input string length. + var len = dlen + 9; + if (len % 64) { + len += 64 - (len % 64); + } + + state = new Uint32Array(5); + state[0] = 0x67452301; + state[1] = 0xefcdab89; + state[2] = 0x98badcfe; + state[3] = 0x10325476; + state[4] = 0xc3d2e1f0; + + for (var ofs = 0; ofs < len; ofs += 64) { + + // Copy input to block and write padding as needed + for (var i = 0; i < 64; i++) { + var b = 0, + o = ofs + i; + if (o < dlen) { + b = d[o]; + } + else if (o === dlen) { + b = 0x80; + } + else { + // Write original bit length as a 64bit big-endian integer to the end. + var x = len - o - 1; + if (x >= 0 && x < 4) { + b = (dlen << 3 >>> (x * 8)) & 0xff; + } + } + + // Interpret the input bytes as big-endian per the spec + if (i % 4 === 0) { + block[i >> 2] = b << 24; + } + else { + block[i >> 2] |= b << ((3 - (i % 4)) * 8); + } + } + + // Extend the block + for (var i = 16; i < 80; i++) { + var w = block[i - 3] ^ block[i - 8] ^ block[i - 14] ^ block[i - 16]; + block[i] = (w << 1) | (w >>> 31); + } + + cycle(state, block); + + } + + // Swap the bytes around since they are big endian internally + for (var i = 0; i < 5; i++) + state[i] = swap32(state[i]); + return state.buffer; + }; + + } // + )(); + + /** + * Algorithm name GOST R 34.11-HMAC

+ * + * HMAC with the specified hash function. + * @memberOf GostDigest + * @method sign + * @instance + * @param {ArrayBuffer} key The key for HMAC. + * @param {Hash} data Data + */ + function signHMAC(key, data) // + { + // GOST R 34.11-94 - B=32b, L=32b + // GOST R 34.11-256 - B=64b, L=32b + // GOST R 34.11-512 - B=64b, L=64b + var b = (this.digest === digest94) ? 32 : 64, + l = this.bitLength / 8, + k = buffer(key), + d = buffer(data), k0; + if (k.byteLength === b) + k0 = new Uint8Array(k); + else { + var k0 = new Uint8Array(b); + if (k.byteLength > b) { + k0.set(new Uint8Array(this.digest(k))); + } else { + k0.set(new Uint8Array(k)); + } + } + var s0 = new Uint8Array(b + d.byteLength), + s1 = new Uint8Array(b + l); + for (var i = 0; i < b; i++) { + s0[i] = k0[i] ^ 0x36; + s1[i] = k0[i] ^ 0x5C; + } + s0.set(new Uint8Array(d), b); + s1.set(new Uint8Array(this.digest(s0)), b); + return this.digest(s1); + } // + + /** + * Algorithm name GOST R 34.11-HMAC

+ * + * Verify HMAC based on GOST R 34.11 hash + * + * @memberOf GostDigest + * @method verify + * @instance + * @param {(ArrayBuffer|TypedArray)} key Key which used for HMAC generation + * @param {(ArrayBuffer|TypedArray)} signature generated HMAC + * @param {(ArrayBuffer|TypedArray)} data Data + * @returns {boolean} HMAC verified = true + */ + function verifyHMAC(key, signature, data) // + { + var hmac = new Uint8Array(this.sign(key, data)), + test = new Uint8Array(signature); + if (hmac.length !== test.length) + return false; + for (var i = 0, n = hmac.length; i < n; i++) + if (hmac[i] !== test[i]) + return false; + return true; + } // + + + /** + * Algorithm name GOST R 34.11-KDF

+ * + * Simple generate key 256/512 bit random seed for derivation algorithms + * + * @memberOf GostDigest + * @method generateKey + * @instance + * @returns {ArrayBuffer} Generated key + */ + function generateKey() // + { + return getSeed(this.bitLength).buffer; + } // + + /** + * Algorithm name GOST R 34.11-PFXKDF

+ * + * Derive bits from password (PKCS12 mode) + * + * @memberOf GostDigest + * @method deriveBits + * @instance + * @param {ArrayBuffer} baseKey - password after UTF-8 decoding + * @param {number} length output bit-length + * @returns {ArrayBuffer} result + */ + function deriveBitsPFXKDF(baseKey, length) // + { + if (length % 8 > 0) + throw new DataError('Length must multiple of 8'); + var u = this.bitLength / 8, v = (this.digest === digest94) ? 32 : 64, + n = length / 8, r = this.iterations; + // 1. Construct a string, D (the "diversifier"), by concatenating v/8 + // copies of ID. + var ID = this.diversifier, D = new Uint8Array(v); + for (var i = 0; i < v; i++) + D[i] = ID; + // 2. Concatenate copies of the salt together to create a string S of + // length v(ceiling(s/v)) bits (the final copy of the salt may be + // truncated to create S). Note that if the salt is the empty + // string, then so is S. + var S0 = new Uint8Array(buffer(this.salt)), s = S0.length, + slen = v * Math.ceil(s / v), S = new Uint8Array(slen); + for (var i = 0; i < slen; i++) + S[i] = S0[i % s]; + // 3. Concatenate copies of the password together to create a string P + // of length v(ceiling(p/v)) bits (the final copy of the password + // may be truncated to create P). Note that if the password is the + // empty string, then so is P. + var P0 = new Uint8Array(buffer(baseKey)), p = P0.length, + plen = v * Math.ceil(p / v), P = new Uint8Array(plen); + for (var i = 0; i < plen; i++) + P[i] = P0[i % p]; + // 4. Set I=S||P to be the concatenation of S and P. + var I = new Uint8Array(slen + plen); + arraycopy(S, 0, I, 0, slen); + arraycopy(P, 0, I, slen, plen); + // 5. Set c=ceiling(n/u). + var c = Math.ceil(n / u); + // 6. For i=1, 2, ..., c, do the following: + var A = new Uint8Array(c * u); + for (var i = 0; i < c; i++) { + // A. Set A2=H^r(D||I). (i.e., the r-th hash of D||1, + // H(H(H(... H(D||I)))) + var H = new Uint8Array(v + slen + plen); + arraycopy(D, 0, H, 0, v); + arraycopy(I, 0, H, v, slen + plen); + for (var j = 0; j < r; j++) + H = new Uint8Array(this.digest(H)); + arraycopy(H, 0, A, i * u, u); + // B. Concatenate copies of Ai to create a string B of length v + // bits (the final copy of Ai may be truncated to create B). + var B = new Uint8Array(v); + for (var j = 0; j < v; j++) + B[j] = H[j % u]; + // C. Treating I as a concatenation I_0, I_1, ..., I_(k-1) of v-bit + // blocks, where k=ceiling(s/v)+ceiling(p/v), modify I by + // setting I_j=(I_j+B+1) mod 2^v for each j. + var k = (slen + plen) / v; + for (j = 0; j < k; j++) { + var cf = 1, w; + for (var l = v - 1; l >= 0; --l) { + w = I[v * j + l] + B[l] + cf; + cf = w >>> 8; + I[v * j + l] = w & 0xff; + } + } + } + // 7. Concatenate A_1, A_2, ..., A_c together to form a pseudorandom + // bit string, A. + // 8. Use the first n bits of A as the output of this entire process. + var R = new Uint8Array(n); + arraycopy(A, 0, R, 0, n); + return R.buffer; + } // + + /** + * Algorithm name GOST R 34.11-KDF

+ * + * Derive bits for KEK deversification in 34.10-2012 algorithm + * KDF(KEK, UKM, label) = HMAC256 (KEK, 0x01|label|0x00|UKM|0x01|0x00) + * Default label = 0x26|0xBD|0xB8|0x78 + * + * @memberOf GostDigest + * @method deriveBits + * @instance + * @param {(ArrayBuffer|TypedArray)} baseKey base key for deriviation + * @param {number} length output bit-length + * @returns {ArrayBuffer} result + */ + function deriveBitsKDF(baseKey, length) // + { + if (length % 8 > 0) + throw new DataError('Length must be multiple of 8'); + var rlen = length / 8, label, context = new Uint8Array(buffer(this.context)), + blen = this.bitLength / 8, n = Math.ceil(rlen / blen); + if (this.label) + label = new Uint8Array(buffer(this.label)); + else + label = new Uint8Array([0x26, 0xBD, 0xB8, 0x78]); + var result = new Uint8Array(rlen); + for (var i = 0; i < n; i++) { + var data = new Uint8Array(label.length + context.length + 4); + data[0] = i + 1; + data.set(label, 1); + data[label.length + 1] = 0x00; + data.set(context, label.length + 2); + data[data.length - 2] = length >>> 8; + data[data.length - 1] = length & 0xff; + result.set(new Uint8Array(signHMAC.call(this, baseKey, data), 0, + i < n - 1 ? blen : rlen - i * blen), i * blen); + } + return result.buffer; + } // + + /** + * Algorithm name GOST R 34.11-PBKDF1

+ * + * Derive bits from password + * + * @memberOf GostDigest + * @method deriveBits + * @instance + * @param {ArrayBuffer} baseKey - password after UTF-8 decoding + * @param {number} length output bit-length + * @returns {ArrayBuffer} result + */ + function deriveBitsPBKDF1(baseKey, length) // + { + if (length < this.bitLength / 2 || length % 8 > 0) + throw new DataError('Length must be more than ' + this.bitLength / 2 + ' bits and multiple of 8'); + var hLen = this.bitLength / 8, dkLen = length / 8, + c = this.iterations, + P = new Uint8Array(buffer(baseKey)), + S = new Uint8Array(buffer(this.salt)), + slen = S.length, plen = P.length, + T = new Uint8Array(plen + slen), + DK = new Uint8Array(dkLen); + if (dkLen > hLen) + throw new DataError('Invalid parameters: Length value'); + arraycopy(P, 0, T, 0, plen); + arraycopy(S, 0, T, plen, slen); + for (var i = 0; i < c; i++) + T = new Uint8Array(this.digest(T)); + arraycopy(T, 0, DK, 0, dkLen); + return DK.buffer; + } // + + /** + * Algorithm name GOST R 34.11-PBKDF2

+ * + * Derive bits from password + * + * @memberOf GostDigest + * @method deriveBits + * @instance + * @param {ArrayBuffer} baseKey - password after UTF-8 decoding + * @param {number} length output bit-length + * @returns {ArrayBuffer} result + */ + function deriveBitsPBKDF2(baseKey, length) // + { + var diversifier = this.diversifier || 1; // For PKCS12 MAC required 3*length + length = length * diversifier; + if (length < this.bitLength / 2 || length % 8 > 0) + throw new DataError('Length must be more than ' + this.bitLength / 2 + ' bits and multiple of 8'); + var hLen = this.bitLength / 8, dkLen = length / 8, + c = this.iterations, + P = new Uint8Array(buffer(baseKey)), + S = new Uint8Array(buffer(this.salt)); + var slen = S.byteLength, + data = new Uint8Array(slen + 4); + arraycopy(S, 0, data, 0, slen); + + if (dkLen > (0xffffffff - 1) * 32) + throw new DataError('Invalid parameters: Length value'); + var n = Math.ceil(dkLen / hLen), + DK = new Uint8Array(dkLen); + for (var i = 1; i <= n; i++) { + data[slen] = i >>> 24 & 0xff; + data[slen + 1] = i >>> 16 & 0xff; + data[slen + 2] = i >>> 8 & 0xff; + data[slen + 3] = i & 0xff; + + var U = new Uint8Array(signHMAC.call(this, P, data)), Z = U; + for (var j = 1; j < c; j++) { + U = new Uint8Array(signHMAC.call(this, P, U)); + for (var k = 0; k < hLen; k++) + Z[k] = U[k] ^ Z[k]; + } + var ofs = (i - 1) * hLen; + arraycopy(Z, 0, DK, ofs, Math.min(hLen, dkLen - ofs)); + } + if (diversifier > 1) { + var rLen = dkLen / diversifier, R = new Uint8Array(rLen); + arraycopy(DK, dkLen - rLen, R, 0, rLen); + return R.buffer; + } else + return DK.buffer; + } // + + /** + * Algorithm name GOST R 34.11-CPKDF

+ * + * Derive bits from password. CryptoPro algorithm + * + * @memberOf GostDigest + * @method deriveBits + * @instance + * @param {ArrayBuffer} baseKey - password after UTF-8 decoding + * @param {number} length output bit-length + * @returns {ArrayBuffer} result + */ + function deriveBitsCP(baseKey, length) { + if (length > this.bitLength || length % 8 > 0) + throw new DataError('Length can\'t be more than ' + this.bitLength + ' bits and multiple of 8'); + // GOST R 34.11-94 - B=32b, L=32b + // GOST R 34.11-256 - B=64b, L=32b + // GOST R 34.11-512 - B=64b, L=64b + var b = (this.digest === digest94) ? 32 : 64, + l = this.bitLength / 8, + p = baseKey && baseKey.byteLength > 0 ? new Uint8Array(buffer(baseKey)) : false, + plen = p ? p.length : 0, + iterations = this.iterations, + salt = new Uint8Array(buffer(this.salt)), + slen = salt.length, + d = new Uint8Array(slen + plen); + arraycopy(salt, 0, d, 0, slen); + if (p) + arraycopy(p, 0, d, slen, plen); + + var h = new Uint8Array(this.digest(d)), + k = new Uint8Array(b), + s0 = new Uint8Array(b), + s1 = new Uint8Array(b); + var c = 'DENEFH028.760246785.IUEFHWUIO.EF'; + for (var i = 0; i < c.length; i++) + k[i] = c.charCodeAt(i); + + d = new Uint8Array(2 * (b + l)); + for (var j = 0; j < iterations; j++) { + for (var i = 0; i < b; i++) { + s0[i] = k[i] ^ 0x36; + s1[i] = k[i] ^ 0x5C; + k[i] = 0; + } + arraycopy(s0, 0, d, 0, b); + arraycopy(h, 0, d, b, l); + arraycopy(s1, 0, d, b + l, b); + arraycopy(h, 0, d, b + l + b, l); + arraycopy(new Uint8Array(this.digest(d)), 0, k, 0, l); + } + for (var i = 0; i < l; i++) { + s0[i] = k[i] ^ 0x36; + s1[i] = k[i] ^ 0x5C; + k[i] = 0; + } + d = new Uint8Array(2 * l + slen + plen); + arraycopy(s0, 0, d, 0, l); + arraycopy(salt, 0, d, l, slen); + arraycopy(s1, 0, d, l + slen, l); + if (p) + arraycopy(p, 0, d, l + slen + l, plen); + h = this.digest(this.digest(d)); + if (length === this.bitLength) + return h; + else { + var rlen = length / 8, r = new Uint8Array(rlen); + arraycopy(h, 0, r, 0, rlen); + return r.buffer; + } + } + + /** + * Algorithm name GOST R 34.11-KDF or GOST R 34.11-PBKDF2 or other

+ * + * Derive key from derive bits subset + * + * @memberOf GostDigest + * @method deriveKey + * @instance + * @param {ArrayBuffer} baseKey + * @returns {ArrayBuffer} + */ + function deriveKey(baseKey) // + { + return this.deriveBits(baseKey, this.keySize * 8); + } // + + /** + * GOST R 34.11 Algorithm

+ * + * References: {@link http://tools.ietf.org/html/rfc6986} and {@link http://tools.ietf.org/html/rfc5831}

+ * + * Normalized algorithm identifier common parameters: + * + * + * + * Supported algorithms, modes and parameters: + * + * + * + * @class GostDigest + * @param {AlgorithmIdentifier} algorithm WebCryptoAPI algorithm identifier + */ + function GostDigest(algorithm) // + { + + algorithm = algorithm || {}; + + this.name = (algorithm.name || 'GOST R 34.10') + '-' + ((algorithm.version || 2012) % 100) + + ((algorithm.version || 2012) > 1 ? '-' + (algorithm.length || 256) : '') + + (((algorithm.mode || 'HASH') !== 'HASH') ? '-' + algorithm.mode : '') + + (algorithm.procreator ? '/' + algorithm.procreator : '') + + (typeof algorithm.sBox === 'string' ? '/' + algorithm.sBox : ''); + + // Algorithm procreator + this.procreator = algorithm.procreator; + + // Bit length + this.bitLength = algorithm.length || 256; + + switch (algorithm.version || 2012) { + case 1: // SHA-1 + this.digest = digestSHA1; + this.bitLength = 160; + break; + case 1994: + this.digest = digest94; + // Define chiper algorithm + this.sBox = (algorithm.sBox || (algorithm.procreator === 'SC' ? 'D-SC' : 'D-A')).toUpperCase(); + + if (!GostCipher) + GostCipher = root.GostCipher; + if (!GostCipher) + throw new NotSupportedError('Object GostCipher not found'); + + this.cipher = new GostCipher({ + name: 'GOST 28147', + block: 'ECB', + sBox: this.sBox, + procreator: this.procreator + }); + + break; + case 2012: + this.digest = digest2012; + break; + default: + throw new NotSupportedError('Algorithm version ' + algorithm.version + ' not supported'); + } + + // Key size + this.keySize = algorithm.keySize || (algorithm.version <= 2 ? this.bitLength / 8 : 32); + + switch (algorithm.mode || 'HASH') { + case 'HASH': + break; + case 'HMAC': + this.sign = signHMAC; + this.verify = verifyHMAC; + this.generateKey = generateKey; + break; + case 'KDF': + this.deriveKey = deriveKey; + this.deriveBits = deriveBitsKDF; + this.label = algorithm.label; + this.context = algorithm.context; + break; + case 'PBKDF2': + this.deriveKey = deriveKey; + this.deriveBits = deriveBitsPBKDF2; + this.generateKey = generateKey; + this.salt = algorithm.salt; + this.iterations = algorithm.iterations || 2000; + this.diversifier = algorithm.diversifier || 1; + break; + case 'PFXKDF': + this.deriveKey = deriveKey; + this.deriveBits = deriveBitsPFXKDF; + this.generateKey = generateKey; + this.salt = algorithm.salt; + this.iterations = algorithm.iterations || 2000; + this.diversifier = algorithm.diversifier || 1; + break; + case 'CPKDF': + this.deriveKey = deriveKey; + this.deriveBits = deriveBitsCP; + this.generateKey = generateKey; + this.salt = algorithm.salt; + this.iterations = algorithm.iterations || 2000; + break; + default: + throw new NotSupportedError('Algorithm mode ' + algorithm.mode + ' not supported'); + } + } // + + return GostDigest; + +})); \ No newline at end of file diff --git a/src/core/vendor/streebog/gostRandom.js b/src/core/vendor/streebog/gostRandom.js new file mode 100644 index 00000000..5282cf0d --- /dev/null +++ b/src/core/vendor/streebog/gostRandom.js @@ -0,0 +1,139 @@ +/** + * @file Implementation Web Crypto random generatore for GOST algorithms + * @version 1.76 + * @copyright 2014-2016, Rudolf Nickolaev. All rights reserved. + */ + +/* + * 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. + * + */ + +(function (root, factory) { + + /* + * Module imports and exports + * + */ // + if (typeof exports === 'object') { + module.exports = factory(); + } + // + +}(this, function () { + + /** + * The gostCrypto provide general purpose cryptographic functionality for + * GOST standards including a cryptographically strong pseudo-random number + * generator seeded with truly random values. + * + * @Class GostRandom + * + */ // + + var root = this; + var rootCrypto = root.crypto || root.msCrypto; + + var TypeMismatchError = root.TypeMismatchError || Error; + var QuotaExceededError = root.QuotaExceededError || Error; + + // Initialize mouse and time counters for random generator + var randomRing = { + seed: new Uint8Array(1024), + getIndex: 0, + setIndex: 0, + set: function (x) { + if (this.setIndex >= 1024) + this.setIndex = 0; + this.seed[this.setIndex++] = x; + }, + get: function () { + if (this.getIndex >= 1024) + this.getIndex = 0; + return this.seed[this.getIndex++]; + } + }; + + if (typeof document !== 'undefiend') { + try { + // Mouse move event to fill random array + document.addEventListener('mousemove', function (e) { + randomRing.set((new Date().getTime() & 255) ^ + ((e.clientX || e.pageX) & 255) ^ + ((e.clientY || e.pageY) & 255)); + }, false); + } catch (e) { + } + + try { + // Keypress event to fill random array + document.addEventListener('keydown', function (e) { + randomRing.set((new Date().getTime() & 255) ^ + (e.keyCode & 255)); + }, false); + } catch (e) { + } + } // + + function GostRandom() { + } + + /** + * The getRandomValues method generates cryptographically random values.

+ * + * Random generator based on JavaScript Web Crypto random genereator + * (if it is possible) or Math.random mixed with time and parameters of + * mouse and keyboard events + * + * @memberOf GostRandom + * @param {(ArrayBuffer|ArrayBufferView)} array Destination buffer for random data + */ + GostRandom.prototype.getRandomValues = function (array) // + { + + if (!array.byteLength) + throw new TypeMismatchError('Array is not of an integer type (Int8Array, Uint8Array, Int16Array, Uint16Array, Int32Array, or Uint32Array)'); + + if (array.byteLength > 65536) + throw new QuotaExceededError('Byte length of array can\'t be greate then 65536'); + + var u8 = new Uint8Array(array.buffer, array.byteOffset, array.byteLength); + if (rootCrypto && rootCrypto.getRandomValues) { + // Native window cryptographic interface + rootCrypto.getRandomValues(u8); + } else { + // Standard Javascript method + for (var i = 0, n = u8.length; i < n; i++) + u8[i] = Math.floor(256 * Math.random()) & 255; + } + + // Mix bio randomizator + for (var i = 0, n = u8.length; i < n; i++) + u8[i] = u8[i] ^ randomRing.get(); + return array; + }; // + + return GostRandom; + +})); From 37389a62c1b0239d131030b0812ae84158fd908c Mon Sep 17 00:00:00 2001 From: mshwed Date: Mon, 1 Apr 2019 23:14:40 -0400 Subject: [PATCH 2/5] Added support for hashing version 1994 and 2012. Added S-Box selection for 1994 version. Added length selection --- src/core/operations/Streebog.mjs | 58 ++++++++++++++++++++++---- src/core/vendor/streebog/gostCipher.js | 8 ++-- src/core/vendor/streebog/gostCoding.js | 12 +++--- src/core/vendor/streebog/gostCrypto.js | 9 ++-- src/core/vendor/streebog/gostDigest.js | 12 +++--- src/core/vendor/streebog/gostRandom.js | 12 +++--- 6 files changed, 78 insertions(+), 33 deletions(-) diff --git a/src/core/operations/Streebog.mjs b/src/core/operations/Streebog.mjs index 0c46f4f7..f24f2e06 100644 --- a/src/core/operations/Streebog.mjs +++ b/src/core/operations/Streebog.mjs @@ -26,7 +26,36 @@ class Streebog extends Operation { this.infoURL = "https://en.wikipedia.org/wiki/Streebog"; this.inputType = "string"; this.outputType = "string"; - this.args = []; + this.args = [ + { + "name": "Version", + "type": "option", + "value": ["2012", "1994"] + }, + // Paramset sBox for GOST 28147-89. Used only if version = 1994 + { + "name": "S-Box", + "type": "option", + "value": [ + "D-A", + "D-SC", + "E-TEST", + "E-A", + "E-B", + "E-C", + "E-D", + "E-SC", + "E-Z", + "D-TEST" + ] + }, + // 512 bits digest, valid only for algorithm "Streebog" + { + "name": "Length", + "type": "option", + "value": ["256", "512"] + } + ]; } /** @@ -36,16 +65,29 @@ class Streebog extends Operation { */ run(input, args) { try { - const gostDigest = new GostDigest({name: 'GOST R 34.11', version: 1994}); + const version = parseInt(args[0], 10); + let sBox = args[1]; + let length = parseInt(args[2], 10); + + // 1994 old-style 256 bits digest based on GOST 28147-89 + if (version === 1994) { + length = 256; + } + + if (version === 2012) { + sBox = ""; + } + + const gostDigest = new GostDigest({name: "GOST R 34.11", version, sBox, length }); const gostCoding = new GostCoding(); - const decode = gostCoding.Chars.decode(input, 'utf8'); - let hexEncode = gostCoding.Hex.encode(gostDigest.digest(decode)) - - return hexEncode.replace(/[^\-A-Fa-f0-9]/g, '').toLowerCase();; + + const decode = gostCoding.Chars.decode(input); + const hexEncode = gostCoding.Hex.encode(gostDigest.digest(decode)); + + return hexEncode.replace(/[^\-A-Fa-f0-9]/g, "").toLowerCase(); } catch (err) { - console.log(err) - throw new OperationError("Test"); + throw new OperationError(`Invalid Input, Details ${err.message}`); } } diff --git a/src/core/vendor/streebog/gostCipher.js b/src/core/vendor/streebog/gostCipher.js index b3ec0116..bf6b31b5 100644 --- a/src/core/vendor/streebog/gostCipher.js +++ b/src/core/vendor/streebog/gostCipher.js @@ -1,7 +1,9 @@ /** - * @file GOST 28147-89/GOST R 34.12-2015/GOST R 32.13-2015 Encryption Algorithm - * @version 1.76 - * @copyright 2014-2016, Rudolf Nickolaev. All rights reserved. + * 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] */ /* diff --git a/src/core/vendor/streebog/gostCoding.js b/src/core/vendor/streebog/gostCoding.js index cc909c12..c9514a79 100644 --- a/src/core/vendor/streebog/gostCoding.js +++ b/src/core/vendor/streebog/gostCoding.js @@ -1,7 +1,9 @@ /** - * @file Coding algorithms: Base64, Hex, Int16, Chars, BER and PEM - * @version 1.76 - * @copyright 2014-2016, Rudolf Nickolaev. All rights reserved. + * Coding algorithms: Base64, Hex, Int16, Chars, BER and PEM + * version 1.76 + * 2014-2016, Rudolf Nickolaev. All rights reserved. + * + * Exported for CyberChef by mshwed [m@ttshwed.com] */ /* @@ -36,9 +38,7 @@ * Module imports and exports * */ // - if (typeof exports === 'object') { - module.exports = factory(require('./gostCrypto')); - } + module.exports = factory(require('./gostCrypto')); // }(this, function (gostCrypto) { diff --git a/src/core/vendor/streebog/gostCrypto.js b/src/core/vendor/streebog/gostCrypto.js index fd6b19a2..f3e23895 100644 --- a/src/core/vendor/streebog/gostCrypto.js +++ b/src/core/vendor/streebog/gostCrypto.js @@ -1,7 +1,9 @@ /** - * @file Implementation Web Crypto interfaces for GOST algorithms - * @version 1.76 - * @copyright 2014-2016, Rudolf Nickolaev. All rights reserved. + * Implementation Web Crypto interfaces for GOST algorithms + * 1.76 + * 2014-2016, Rudolf Nickolaev. All rights reserved. + * + * Exported for CyberChef by mshwed [m@ttshwed.com] */ /* @@ -37,7 +39,6 @@ * */ // module.exports = factory(require('./gostRandom')); - // }(this, function (GostRandom) { diff --git a/src/core/vendor/streebog/gostDigest.js b/src/core/vendor/streebog/gostDigest.js index aa3ddb41..e6f5db33 100644 --- a/src/core/vendor/streebog/gostDigest.js +++ b/src/core/vendor/streebog/gostDigest.js @@ -1,7 +1,9 @@ /** - * @file GOST R 34.11-94 / GOST R 34.11-12 implementation - * @version 1.76 - * @copyright 2014-2016, Rudolf Nickolaev. All rights reserved. + * GOST R 34.11-94 / GOST R 34.11-12 implementation + * 1.76 + * 2014-2016, Rudolf Nickolaev. All rights reserved. + * + * Exported for CyberChef by mshwed [m@ttshwed.com] */ /* @@ -40,9 +42,7 @@ * Module imports and exports * */ // - if (typeof exports === 'object') { - module.exports = factory(require('./gostRandom'), require('./gostCipher')); - } + module.exports = factory(require('./gostRandom'), require('./gostCipher')); // }(this, function (GostRandom, GostCipher) { diff --git a/src/core/vendor/streebog/gostRandom.js b/src/core/vendor/streebog/gostRandom.js index 5282cf0d..93e0c845 100644 --- a/src/core/vendor/streebog/gostRandom.js +++ b/src/core/vendor/streebog/gostRandom.js @@ -1,7 +1,9 @@ /** - * @file Implementation Web Crypto random generatore for GOST algorithms - * @version 1.76 - * @copyright 2014-2016, Rudolf Nickolaev. All rights reserved. + * Implementation Web Crypto random generatore for GOST algorithms + * 1.76 + * 2014-2016, Rudolf Nickolaev. All rights reserved. + * + * Exported for CyberChef by mshwed [m@ttshwed.com] */ /* @@ -36,9 +38,7 @@ * Module imports and exports * */ // - if (typeof exports === 'object') { - module.exports = factory(); - } + module.exports = factory(); // }(this, function () { From 4496d7762b84d393b08b3d184bbcdded9a500c1b Mon Sep 17 00:00:00 2001 From: mshwed Date: Tue, 2 Apr 2019 09:41:49 -0400 Subject: [PATCH 3/5] Converted js files to mjs. Added test cases for hashing --- src/core/operations/Streebog.mjs | 5 +- src/core/vendor/Streebog.mjs | 1318 ------------- src/core/vendor/streebog/gostCipher.js | 2269 ----------------------- src/core/vendor/streebog/gostCipher.mjs | 2259 ++++++++++++++++++++++ src/core/vendor/streebog/gostCoding.js | 1171 ------------ src/core/vendor/streebog/gostCoding.mjs | 1160 ++++++++++++ src/core/vendor/streebog/gostCrypto.js | 1658 ----------------- src/core/vendor/streebog/gostCrypto.mjs | 1653 +++++++++++++++++ src/core/vendor/streebog/gostDigest.js | 1269 ------------- src/core/vendor/streebog/gostDigest.mjs | 1260 +++++++++++++ src/core/vendor/streebog/gostEngine.mjs | 451 +++++ src/core/vendor/streebog/gostRandom.js | 139 -- src/core/vendor/streebog/gostRandom.mjs | 128 ++ src/core/vendor/streebog/gostSign.mjs | 2023 ++++++++++++++++++++ tests/operations/tests/Hash.mjs | 78 + 15 files changed, 9014 insertions(+), 7827 deletions(-) delete mode 100644 src/core/vendor/Streebog.mjs delete mode 100644 src/core/vendor/streebog/gostCipher.js create mode 100644 src/core/vendor/streebog/gostCipher.mjs delete mode 100644 src/core/vendor/streebog/gostCoding.js create mode 100644 src/core/vendor/streebog/gostCoding.mjs delete mode 100644 src/core/vendor/streebog/gostCrypto.js create mode 100644 src/core/vendor/streebog/gostCrypto.mjs delete mode 100644 src/core/vendor/streebog/gostDigest.js create mode 100644 src/core/vendor/streebog/gostDigest.mjs create mode 100755 src/core/vendor/streebog/gostEngine.mjs delete mode 100644 src/core/vendor/streebog/gostRandom.js create mode 100644 src/core/vendor/streebog/gostRandom.mjs create mode 100755 src/core/vendor/streebog/gostSign.mjs diff --git a/src/core/operations/Streebog.mjs b/src/core/operations/Streebog.mjs index f24f2e06..7f054fb4 100644 --- a/src/core/operations/Streebog.mjs +++ b/src/core/operations/Streebog.mjs @@ -6,8 +6,8 @@ import Operation from "../Operation"; import OperationError from "../errors/OperationError"; -import * as GostDigest from "../vendor/streebog/gostDigest"; -import * as GostCoding from "../vendor/streebog/gostCoding"; +import GostCoding from "../vendor/streebog/gostCoding"; +import GostDigest from "../vendor/streebog/gostDigest"; /** * Streebog operation @@ -81,7 +81,6 @@ class Streebog extends Operation { const gostDigest = new GostDigest({name: "GOST R 34.11", version, sBox, length }); const gostCoding = new GostCoding(); - const decode = gostCoding.Chars.decode(input); const hexEncode = gostCoding.Hex.encode(gostDigest.digest(decode)); diff --git a/src/core/vendor/Streebog.mjs b/src/core/vendor/Streebog.mjs deleted file mode 100644 index 9b078b2d..00000000 --- a/src/core/vendor/Streebog.mjs +++ /dev/null @@ -1,1318 +0,0 @@ -/*------------------------------------------------------------------------------------------------------------------------- - Created by Rudolf Nickolaev (https://github.com/rudonick/crypto/) - & 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. - * - * Converted to JavaScript from source https://www.streebog.net/ - * Copyright (c) 2013, Alexey Degtyarev. - * All rights reserved. - * - * 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. - * - */ - -(function(root, factory) { - /* - * Module imports and exports - * - */ // - if (typeof define === "function" && define.amd) { - define(["gostRandom", "gostCipher"], factory); - } else if (typeof exports === "object") { - module.exports = factory(require("gostRandom"), require("gostCipher")); - } else { - root.GostDigest = factory(root.GostRandom, root.GostCipher); - } - // -})(this, function(GostRandom, GostCipher) { - /* - * GOST R 34.11 - * Common methods - * - */ // - - var root = this; - var rootCrypto = root.crypto || root.msCrypto; - - var DataError = root.DataError || Error, - NotSupportedError = root.NotSupportedError || Error; - - // Copy len values from s[sOfs] to d[dOfs] - function arraycopy(s, sOfs, d, dOfs, len) { - for (var i = 0; i < len; i++) d[dOfs + i] = s[sOfs + i]; - } - - // Swap bytes in buffer - function swap(s) { - var src = new Uint8Array(s), - dst = new Uint8Array(src.length); - for (var i = 0, n = src.length; i < n; i++) dst[n - i - 1] = src[i]; - return dst.buffer; - } - - // Convert BASE64 string to Uint8Array - // for decompression of constants and precalc values - function b64decode(s) { - // s = s.replace(/[^A-Za-z0-9\+\/]/g, ''); - var n = s.length, - k = (n * 3 + 1) >> 2, - r = new Uint8Array(k); - - for (var m3, m4, u24 = 0, j = 0, i = 0; i < n; i++) { - m4 = i & 3; - var c = s.charCodeAt(i); - - c = - c > 64 && c < 91 - ? c - 65 - : c > 96 && c < 123 - ? c - 71 - : c > 47 && c < 58 - ? c + 4 - : c === 43 - ? 62 - : c === 47 - ? 63 - : 0; - - u24 |= c << (18 - 6 * m4); - if (m4 === 3 || n - i === 1) { - for (m3 = 0; m3 < 3 && j < k; m3++, j++) { - r[j] = (u24 >>> ((16 >>> m3) & 24)) & 255; - } - u24 = 0; - } - } - return r.buffer; - } - - // Random seed - function getSeed(length) { - GostRandom = GostRandom || root.GostRandom; - var randomSource = GostRandom - ? new (GostRandom || root.GostRandom)() - : rootCrypto; - if (randomSource.getRandomValues) { - var d = new Uint8Array(Math.ceil(length / 8)); - randomSource.getRandomValues(d); - return d; - } else throw new NotSupportedError("Random generator not found"); - } - - // Check buffer - function buffer(d) { - if (d instanceof ArrayBuffer) return d; - else if (d && d.buffer && d.buffer instanceof ArrayBuffer) - 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("ArrayBuffer or ArrayBufferView required"); - } // - - /** - * Algorithm name GOST R 34.11 or GOST R 34.11-12

- * - * http://tools.ietf.org/html/rfc6986 - * - * The digest method returns digest data in according to GOST R 4311-2012.
- * Size of digest also defines in algorithm name. - *
    - *
  • GOST R 34.11-256-12 - 256 bits digest
  • - *
  • GOST R 34.11-512-12 - 512 bits digest
  • - *
- * - * @memberOf GostDigest - * @method digest - * @instance - * @param {(ArrayBuffer|TypedArray)} data Data - * @returns {ArrayBuffer} Digest of data - */ - var digest2012 = (function() // - { - // Constants - var buffer0 = new Int32Array(16); // [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; - - var buffer512 = new Int32Array(16); // [512, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; - buffer512[0] = 512; - - // Constant C - var C = (function(s) { - var h = new Int32Array(b64decode(s)), - r = new Array(12); - for (var i = 0; i < 12; i++) - r[i] = new Int32Array(h.buffer, i * 64, 16); - return r; - })( - "B0Wm8lllgN0jTXTMNnR2BRXTYKQIKkKiAWlnkpHgfEv8xIV1jbhOcRbQRS5DdmovH3xlwIEvy+vp2soe2lsIsbebsSFwBHnmVs3L1xui3VXKpwrbwmG1XFiZ1hJrF7WaMQG1Fg9e1WGYKyMKcur+89e1cA9GneNPGi+dqYq1o2+yCroK9ZYemTHbeoZD9LbCCdtiYDc6ycGxnjWQ5A/i03t7KbEUderyix+cUl9e8QY1hD1qKPw5Cscvzius3HT1LtHjhLy+DCLxN+iToepTNL4DUpMzE7fYddYD7YIs16k/NV5orRxynX08XDN+hY5I3eRxXaDhSPnSZhXos98f71f+bHz9WBdg9WPqqX6iVnoWGicjtwD/36P1OiVHF82/vf8PgNc1njVKEIYWHxwVf2MjqWwMQT+amUdHraxr6ktufWRGekBo+jVPkDZyxXG/tsa+wmYf8gq0t5oct6b6z8aO8Jq0mn8YbKRCUfnEZi3AOTB6O8Okb9nTOh2urk+uk9QUOk1WhojzSjyiTEUXNQQFSiiDaUcGNyyCLcWrkgnJk3oZMz5H08mHv+bHxp45VAkkv/6GrFHsxaruFg7H9B7nAr/UDX+k" + - "2ahRWTXCrDYvxKXRK43RaZAGm5LLK4n0msTbTTtEtIke3jaccfi3TkFBbgwCqucDp8mTTUJbH5vbWiODUURhcmAqH8uS3DgOVJwHppqKK3uxzrLbC0QKgIQJDeC3Vdk8JEKJJRs6fTreXxbs2JpMlJsiMRZUWo837ZxFmPvHtHTDtjsV0fqYNvRSdjswbB56SzNprwJn558DYTMbiuH/H9t4iv8c50GJ8/PkskjlKjhSbwWApt6+qxst84HNpMprXdhvwEpZot6Ybkd9Hc2678q5SOrvcR2KeWaEFCGAASBhB6vru2v62JT+WmPNxgIw+4nI79CezXsg1xvxSpK8SJkbstnVF/T6UijhiKqkHeeGzJEYne+AXZufITDUEiD4dx3fvDI8pM16sUkEsIAT0roxFvFn5443" - ); - - // Precalc Ax - var Ax = (function(s) { - return new Int32Array(b64decode(s)); - })( - "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" - ); //== - - // Variables - var sigma, N, h; - - // 64bit tools - function get8(x, i) { - return (x[i >> 2] >> ((i & 3) << 3)) & 0xff; - } - - // 512bit tools - function add512(x, y) { - var CF = 0, - w0, - w1; - for (var i = 0; i < 16; i++) { - w0 = (x[i] & 0xffff) + (y[i] & 0xffff) + (CF || 0); - w1 = (x[i] >>> 16) + (y[i] >>> 16) + (w0 >>> 16); - x[i] = (w0 & 0xffff) | (w1 << 16); - CF = w1 >>> 16; - } - } - - function get512(d) { - return new Int32Array(d.buffer, d.byteOffset, 16); - } - - function copy512(r, d) { - for (var i = 0; i < 16; i++) r[i] = d[i]; - } - - function new512() { - return new Int32Array(16); - } - - // Core private algorithms - function xor512(x, y) { - for (var i = 0; i < 16; i++) x[i] = x[i] ^ y[i]; - } - - var r = new512(); - function XLPS(x, y) { - copy512(r, x); - xor512(r, y); - for (var i = 0; i < 8; i++) { - var z0, - z1, - k = get8(r, i) << 1; - z0 = Ax[k]; - z1 = Ax[k + 1]; - for (var j = 1; j < 8; j++) { - k = (j << 9) + (get8(r, (j << 3) + i) << 1); - z0 = z0 ^ Ax[k]; - z1 = z1 ^ Ax[k + 1]; - } - x[i << 1] = z0; - x[(i << 1) + 1] = z1; - } - } - - var data = new512(), - Ki = new512(); - function g(h, N, m) { - var i; - - copy512(data, h); - XLPS(data, N); - - /* Starting E() */ - copy512(Ki, data); - XLPS(data, m); - - for (i = 0; i < 11; i++) { - XLPS(Ki, C[i]); - XLPS(data, Ki); - } - - XLPS(Ki, C[11]); - xor512(data, Ki); - /* E() done */ - - xor512(h, data); - xor512(h, m); - } - - // Stages - function stage2(d) { - var m = get512(d); - g(h, N, m); - - add512(N, buffer512); - add512(sigma, m); - } - - function stage3(d) { - var n = d.length; - if (n > 63) return; - - var b0 = new Int32Array(16); - b0[0] = n << 3; - - var b = new Uint8Array(64); - for (var i = 0; i < n; i++) b[i] = d[i]; - b[n] = 0x01; - - var m = get512(b), - m0 = get512(b0); - g(h, N, m); - - add512(N, m0); - add512(sigma, m); - - g(h, buffer0, N); - g(h, buffer0, sigma); - } - - return function(data) { - // Cleanup - sigma = new512(); - N = new512(); - - // Initial vector - h = new512(); - for (var i = 0; i < 16; i++) - if (this.bitLength === 256) h[i] = 0x01010101; - - // Make data - var d = new Uint8Array(buffer(data)); - - var n = d.length; - var r = n % 64, - q = (n - r) / 64; - - for (var i = 0; i < q; i++) - stage2.call(this, new Uint8Array(d.buffer, i * 64, 64)); - - stage3.call(this, new Uint8Array(d.buffer, q * 64, r)); - - var digest; - if (this.bitLength === 256) { - digest = new Int32Array(8); - for (var i = 0; i < 8; i++) digest[i] = h[8 + i]; - } else { - digest = new Int32Array(16); - for (var i = 0; i < 16; i++) digest[i] = h[i]; - } - // Swap hash for SignalCom - if (this.procreator === "SC" || this.procreator === "VN") - return swap(digest.buffer); - else return digest.buffer; - }; - })(); // - - /** - * Algorithm name GOST R 34.11-94

- * - * http://tools.ietf.org/html/rfc5831 - * - * The digest method returns digest data in according to GOST R 34.11-94. - * @memberOf GostDigest - * @method digest - * @instance - * @param {(ArrayBuffer|TypedArray)} data Data - * @returns {ArrayBuffer} Digest of data - */ - var digest94 = (function() // - { - var C, H, M, Sum; - - // (i + 1 + 4(k - 1)) = 8i + k i = 0-3, k = 1-8 - function P(d) { - var K = new Uint8Array(32); - - for (var k = 0; k < 8; k++) { - K[4 * k] = d[k]; - K[1 + 4 * k] = d[8 + k]; - K[2 + 4 * k] = d[16 + k]; - K[3 + 4 * k] = d[24 + k]; - } - - return K; - } - - //A (x) = (x0 ^ x1) || x3 || x2 || x1 - function A(d) { - var a = new Uint8Array(8); - - for (var j = 0; j < 8; j++) { - a[j] = d[j] ^ d[j + 8]; - } - - arraycopy(d, 8, d, 0, 24); - arraycopy(a, 0, d, 24, 8); - - return d; - } - - // (in:) n16||..||n1 ==> (out:) n1^n2^n3^n4^n13^n16||n16||..||n2 - function fw(d) { - var wS = new Uint16Array(d.buffer, 0, 16); - var wS15 = wS[0] ^ wS[1] ^ wS[2] ^ wS[3] ^ wS[12] ^ wS[15]; - arraycopy(wS, 1, wS, 0, 15); - wS[15] = wS15; - } - - //Encrypt function, ECB mode - function encrypt(key, s, sOff, d, dOff) { - var t = new Uint8Array(8); - arraycopy(d, dOff, t, 0, 8); - var r = new Uint8Array(this.cipher.encrypt(key, t)); - arraycopy(r, 0, s, sOff, 8); - } - - // block processing - function process(d, dOff) { - var S = new Uint8Array(32), - U = new Uint8Array(32), - V = new Uint8Array(32), - W = new Uint8Array(32); - - arraycopy(d, dOff, M, 0, 32); - - //key step 1 - - // H = h3 || h2 || h1 || h0 - // S = s3 || s2 || s1 || s0 - arraycopy(H, 0, U, 0, 32); - arraycopy(M, 0, V, 0, 32); - for (var j = 0; j < 32; j++) { - W[j] = U[j] ^ V[j]; - } - // Encrypt GOST 28147-ECB - encrypt.call(this, P(W), S, 0, H, 0); // s0 = EK0 [h0] - - //keys step 2,3,4 - for (var i = 1; i < 4; i++) { - var tmpA = A(U); - for (var j = 0; j < 32; j++) { - U[j] = tmpA[j] ^ C[i][j]; - } - V = A(A(V)); - for (var j = 0; j < 32; j++) { - W[j] = U[j] ^ V[j]; - } - // Encrypt GOST 28147-ECB - encrypt.call(this, P(W), S, i * 8, H, i * 8); // si = EKi [hi] - } - - // x(M, H) = y61(H^y(M^y12(S))) - for (var n = 0; n < 12; n++) { - fw(S); - } - for (var n = 0; n < 32; n++) { - S[n] = S[n] ^ M[n]; - } - - fw(S); - - for (var n = 0; n < 32; n++) { - S[n] = H[n] ^ S[n]; - } - for (var n = 0; n < 61; n++) { - fw(S); - } - arraycopy(S, 0, H, 0, H.length); - } - - // 256 bitsblock modul -> (Sum + a mod (2^256)) - function summing(d) { - var carry = 0; - for (var i = 0; i < Sum.length; i++) { - var sum = (Sum[i] & 0xff) + (d[i] & 0xff) + carry; - - Sum[i] = sum; - - carry = sum >>> 8; - } - } - - // reset the chaining variables to the IV values. - var C2 = new Uint8Array([ - 0x00, - 0xff, - 0x00, - 0xff, - 0x00, - 0xff, - 0x00, - 0xff, - 0xff, - 0x00, - 0xff, - 0x00, - 0xff, - 0x00, - 0xff, - 0x00, - 0x00, - 0xff, - 0xff, - 0x00, - 0xff, - 0x00, - 0x00, - 0xff, - 0xff, - 0x00, - 0x00, - 0x00, - 0xff, - 0xff, - 0x00, - 0xff - ]); - - return function(data) { - // Reset buffers - H = new Uint8Array(32); - M = new Uint8Array(32); - Sum = new Uint8Array(32); - - // Reset IV value - C = new Array(4); - for (var i = 0; i < 4; i++) C[i] = new Uint8Array(32); - arraycopy(C2, 0, C[2], 0, C2.length); - - // Make data - var d = new Uint8Array(buffer(data)); - - var n = d.length; - var r = n % 32, - q = (n - r) / 32; - - // Proccess full blocks - for (var i = 0; i < q; i++) { - var b = new Uint8Array(d.buffer, i * 32, 32); - - summing.call(this, b); // calc sum M - process.call(this, b, 0); - } - - // load d the remadder with padding zero; - if (r > 0) { - var b = new Uint8Array(d.buffer, q * 32), - c = new Uint8Array(32); - arraycopy(b, 0, c, 0, r); - summing.call(this, c); // calc sum M - process.call(this, c, 0); - } - - // get length into L (byteCount * 8 = bitCount) in little endian. - var L = new Uint8Array(32), - n8 = n * 8, - k = 0; - while (n8 > 0) { - L[k++] = n8 & 0xff; - n8 = Math.floor(n8 / 256); - } - process.call(this, L, 0); - process.call(this, Sum, 0); - - var h = H.buffer; - - // Swap hash for SignalCom - if (this.procreator === "SC") h = swap(h); - - return h; - }; - })(); // - - /** - * Algorithm name SHA-1

- * - * https://tools.ietf.org/html/rfc3174 - * - * The digest method returns digest data in according to SHA-1.
- * - * @memberOf GostDigest - * @method digest - * @instance - * @param {(ArrayBuffer|TypedArray)} data Data - * @returns {ArrayBuffer} Digest of data - */ - var digestSHA1 = (function() // - { - // Create a buffer for each 80 word block. - var state, - block = new Uint32Array(80); - - function common(a, e, w, k, f) { - return (f + e + w + k + ((a << 5) | (a >>> 27))) >>> 0; - } - - function f1(a, b, c, d, e, w) { - return common(a, e, w, 0x5a827999, d ^ (b & (c ^ d))); - } - - function f2(a, b, c, d, e, w) { - return common(a, e, w, 0x6ed9eba1, b ^ c ^ d); - } - - function f3(a, b, c, d, e, w) { - return common(a, e, w, 0x8f1bbcdc, (b & c) | (d & (b | c))); - } - - function f4(a, b, c, d, e, w) { - return common(a, e, w, 0xca62c1d6, b ^ c ^ d); - } - - function cycle(state, block) { - var a = state[0], - b = state[1], - c = state[2], - d = state[3], - e = state[4]; - - // Partially unroll loops so we don't have to shift variables. - var fn = f1; - for (var i = 0; i < 80; i += 5) { - if (i === 20) { - fn = f2; - } else if (i === 40) { - fn = f3; - } else if (i === 60) { - fn = f4; - } - e = fn(a, b, c, d, e, block[i]); - b = ((b << 30) | (b >>> 2)) >>> 0; - d = fn(e, a, b, c, d, block[i + 1]); - a = ((a << 30) | (a >>> 2)) >>> 0; - c = fn(d, e, a, b, c, block[i + 2]); - e = ((e << 30) | (e >>> 2)) >>> 0; - b = fn(c, d, e, a, b, block[i + 3]); - d = ((d << 30) | (d >>> 2)) >>> 0; - a = fn(b, c, d, e, a, block[i + 4]); - c = ((c << 30) | (c >>> 2)) >>> 0; - } - state[0] += a; - state[1] += b; - state[2] += c; - state[3] += d; - state[4] += e; - } - - // Swap bytes for 32bits word - function swap32(b) { - return ( - ((b & 0xff) << 24) | - ((b & 0xff00) << 8) | - ((b >> 8) & 0xff00) | - ((b >> 24) & 0xff) - ); - } - - // input is a Uint8Array bitstream of the data - return function(data) { - var d = new Uint8Array(buffer(data)), - dlen = d.length; - - // Pad the input string length. - var len = dlen + 9; - if (len % 64) { - len += 64 - (len % 64); - } - - state = new Uint32Array(5); - state[0] = 0x67452301; - state[1] = 0xefcdab89; - state[2] = 0x98badcfe; - state[3] = 0x10325476; - state[4] = 0xc3d2e1f0; - - for (var ofs = 0; ofs < len; ofs += 64) { - // Copy input to block and write padding as needed - for (var i = 0; i < 64; i++) { - var b = 0, - o = ofs + i; - if (o < dlen) { - b = d[o]; - } else if (o === dlen) { - b = 0x80; - } else { - // Write original bit length as a 64bit big-endian integer to the end. - var x = len - o - 1; - if (x >= 0 && x < 4) { - b = ((dlen << 3) >>> (x * 8)) & 0xff; - } - } - - // Interpret the input bytes as big-endian per the spec - if (i % 4 === 0) { - block[i >> 2] = b << 24; - } else { - block[i >> 2] |= b << ((3 - (i % 4)) * 8); - } - } - - // Extend the block - for (var i = 16; i < 80; i++) { - var w = - block[i - 3] ^ - block[i - 8] ^ - block[i - 14] ^ - block[i - 16]; - block[i] = (w << 1) | (w >>> 31); - } - - cycle(state, block); - } - - // Swap the bytes around since they are big endian internally - for (var i = 0; i < 5; i++) state[i] = swap32(state[i]); - return state.buffer; - }; - })(); // - - /** - * Algorithm name GOST R 34.11-HMAC

- * - * HMAC with the specified hash function. - * @memberOf GostDigest - * @method sign - * @instance - * @param {ArrayBuffer} key The key for HMAC. - * @param {Hash} data Data - */ - function signHMAC(key, data) { - // - // GOST R 34.11-94 - B=32b, L=32b - // GOST R 34.11-256 - B=64b, L=32b - // GOST R 34.11-512 - B=64b, L=64b - var b = this.digest === digest94 ? 32 : 64, - l = this.bitLength / 8, - k = buffer(key), - d = buffer(data), - k0; - if (k.byteLength === b) k0 = new Uint8Array(k); - else { - var k0 = new Uint8Array(b); - if (k.byteLength > b) { - k0.set(new Uint8Array(this.digest(k))); - } else { - k0.set(new Uint8Array(k)); - } - } - var s0 = new Uint8Array(b + d.byteLength), - s1 = new Uint8Array(b + l); - for (var i = 0; i < b; i++) { - s0[i] = k0[i] ^ 0x36; - s1[i] = k0[i] ^ 0x5c; - } - s0.set(new Uint8Array(d), b); - s1.set(new Uint8Array(this.digest(s0)), b); - return this.digest(s1); - } // - - /** - * Algorithm name GOST R 34.11-HMAC

- * - * Verify HMAC based on GOST R 34.11 hash - * - * @memberOf GostDigest - * @method verify - * @instance - * @param {(ArrayBuffer|TypedArray)} key Key which used for HMAC generation - * @param {(ArrayBuffer|TypedArray)} signature generated HMAC - * @param {(ArrayBuffer|TypedArray)} data Data - * @returns {boolean} HMAC verified = true - */ - function verifyHMAC(key, signature, data) { - // - var hmac = new Uint8Array(this.sign(key, data)), - test = new Uint8Array(signature); - if (hmac.length !== test.length) return false; - for (var i = 0, n = hmac.length; i < n; i++) - if (hmac[i] !== test[i]) return false; - return true; - } // - - /** - * Algorithm name GOST R 34.11-KDF

- * - * Simple generate key 256/512 bit random seed for derivation algorithms - * - * @memberOf GostDigest - * @method generateKey - * @instance - * @returns {ArrayBuffer} Generated key - */ - function generateKey() { - // - return getSeed(this.bitLength).buffer; - } // - - /** - * Algorithm name GOST R 34.11-PFXKDF

- * - * Derive bits from password (PKCS12 mode) - *
    - *
  • algorithm.salt - random value, salt
  • - *
  • algorithm.iterations - number of iterations
  • - *
- * @memberOf GostDigest - * @method deriveBits - * @instance - * @param {ArrayBuffer} baseKey - password after UTF-8 decoding - * @param {number} length output bit-length - * @returns {ArrayBuffer} result - */ - function deriveBitsPFXKDF(baseKey, length) { - // - if (length % 8 > 0) throw new DataError("Length must multiple of 8"); - var u = this.bitLength / 8, - v = this.digest === digest94 ? 32 : 64, - n = length / 8, - r = this.iterations; - // 1. Construct a string, D (the "diversifier"), by concatenating v/8 - // copies of ID. - var ID = this.diversifier, - D = new Uint8Array(v); - for (var i = 0; i < v; i++) D[i] = ID; - // 2. Concatenate copies of the salt together to create a string S of - // length v(ceiling(s/v)) bits (the final copy of the salt may be - // truncated to create S). Note that if the salt is the empty - // string, then so is S. - var S0 = new Uint8Array(buffer(this.salt)), - s = S0.length, - slen = v * Math.ceil(s / v), - S = new Uint8Array(slen); - for (var i = 0; i < slen; i++) S[i] = S0[i % s]; - // 3. Concatenate copies of the password together to create a string P - // of length v(ceiling(p/v)) bits (the final copy of the password - // may be truncated to create P). Note that if the password is the - // empty string, then so is P. - var P0 = new Uint8Array(buffer(baseKey)), - p = P0.length, - plen = v * Math.ceil(p / v), - P = new Uint8Array(plen); - for (var i = 0; i < plen; i++) P[i] = P0[i % p]; - // 4. Set I=S||P to be the concatenation of S and P. - var I = new Uint8Array(slen + plen); - arraycopy(S, 0, I, 0, slen); - arraycopy(P, 0, I, slen, plen); - // 5. Set c=ceiling(n/u). - var c = Math.ceil(n / u); - // 6. For i=1, 2, ..., c, do the following: - var A = new Uint8Array(c * u); - for (var i = 0; i < c; i++) { - // A. Set A2=H^r(D||I). (i.e., the r-th hash of D||1, - // H(H(H(... H(D||I)))) - var H = new Uint8Array(v + slen + plen); - arraycopy(D, 0, H, 0, v); - arraycopy(I, 0, H, v, slen + plen); - for (var j = 0; j < r; j++) H = new Uint8Array(this.digest(H)); - arraycopy(H, 0, A, i * u, u); - // B. Concatenate copies of Ai to create a string B of length v - // bits (the final copy of Ai may be truncated to create B). - var B = new Uint8Array(v); - for (var j = 0; j < v; j++) B[j] = H[j % u]; - // C. Treating I as a concatenation I_0, I_1, ..., I_(k-1) of v-bit - // blocks, where k=ceiling(s/v)+ceiling(p/v), modify I by - // setting I_j=(I_j+B+1) mod 2^v for each j. - var k = (slen + plen) / v; - for (j = 0; j < k; j++) { - var cf = 1, - w; - for (var l = v - 1; l >= 0; --l) { - w = I[v * j + l] + B[l] + cf; - cf = w >>> 8; - I[v * j + l] = w & 0xff; - } - } - } - // 7. Concatenate A_1, A_2, ..., A_c together to form a pseudorandom - // bit string, A. - // 8. Use the first n bits of A as the output of this entire process. - var R = new Uint8Array(n); - arraycopy(A, 0, R, 0, n); - return R.buffer; - } // - - /** - * Algorithm name GOST R 34.11-KDF

- * - * Derive bits for KEK deversification in 34.10-2012 algorithm - * KDF(KEK, UKM, label) = HMAC256 (KEK, 0x01|label|0x00|UKM|0x01|0x00) - * Default label = 0x26|0xBD|0xB8|0x78 - * - * @memberOf GostDigest - * @method deriveBits - * @instance - * @param {(ArrayBuffer|TypedArray)} baseKey base key for deriviation - * @param {number} length output bit-length - * @returns {ArrayBuffer} result - */ - function deriveBitsKDF(baseKey, length) { - // - if (length % 8 > 0) throw new DataError("Length must be multiple of 8"); - var rlen = length / 8, - label, - context = new Uint8Array(buffer(this.context)), - blen = this.bitLength / 8, - n = Math.ceil(rlen / blen); - if (this.label) label = new Uint8Array(buffer(this.label)); - else label = new Uint8Array([0x26, 0xbd, 0xb8, 0x78]); - var result = new Uint8Array(rlen); - for (var i = 0; i < n; i++) { - var data = new Uint8Array(label.length + context.length + 4); - data[0] = i + 1; - data.set(label, 1); - data[label.length + 1] = 0x00; - data.set(context, label.length + 2); - data[data.length - 2] = length >>> 8; - data[data.length - 1] = length & 0xff; - result.set( - new Uint8Array( - signHMAC.call(this, baseKey, data), - 0, - i < n - 1 ? blen : rlen - i * blen - ), - i * blen - ); - } - return result.buffer; - } // - - /** - * Algorithm name GOST R 34.11-PBKDF1

- * - * Derive bits from password - *
    - *
  • algorithm.salt - random value, salt
  • - *
  • algorithm.iterations - number of iterations
  • - *
- * @memberOf GostDigest - * @method deriveBits - * @instance - * @param {ArrayBuffer} baseKey - password after UTF-8 decoding - * @param {number} length output bit-length - * @returns {ArrayBuffer} result - */ - function deriveBitsPBKDF1(baseKey, length) { - // - if (length < this.bitLength / 2 || length % 8 > 0) - throw new DataError( - "Length must be more than " + - this.bitLength / 2 + - " bits and multiple of 8" - ); - var hLen = this.bitLength / 8, - dkLen = length / 8, - c = this.iterations, - P = new Uint8Array(buffer(baseKey)), - S = new Uint8Array(buffer(this.salt)), - slen = S.length, - plen = P.length, - T = new Uint8Array(plen + slen), - DK = new Uint8Array(dkLen); - if (dkLen > hLen) - throw new DataError("Invalid parameters: Length value"); - arraycopy(P, 0, T, 0, plen); - arraycopy(S, 0, T, plen, slen); - for (var i = 0; i < c; i++) T = new Uint8Array(this.digest(T)); - arraycopy(T, 0, DK, 0, dkLen); - return DK.buffer; - } // - - /** - * Algorithm name GOST R 34.11-PBKDF2

- * - * Derive bits from password - *
    - *
  • algorithm.salt - random value, salt
  • - *
  • algorithm.iterations - number of iterations
  • - *
- * @memberOf GostDigest - * @method deriveBits - * @instance - * @param {ArrayBuffer} baseKey - password after UTF-8 decoding - * @param {number} length output bit-length - * @returns {ArrayBuffer} result - */ - function deriveBitsPBKDF2(baseKey, length) { - // - var diversifier = this.diversifier || 1; // For PKCS12 MAC required 3*length - length = length * diversifier; - if (length < this.bitLength / 2 || length % 8 > 0) - throw new DataError( - "Length must be more than " + - this.bitLength / 2 + - " bits and multiple of 8" - ); - var hLen = this.bitLength / 8, - dkLen = length / 8, - c = this.iterations, - P = new Uint8Array(buffer(baseKey)), - S = new Uint8Array(buffer(this.salt)); - var slen = S.byteLength, - data = new Uint8Array(slen + 4); - arraycopy(S, 0, data, 0, slen); - - if (dkLen > (0xffffffff - 1) * 32) - throw new DataError("Invalid parameters: Length value"); - var n = Math.ceil(dkLen / hLen), - DK = new Uint8Array(dkLen); - for (var i = 1; i <= n; i++) { - data[slen] = (i >>> 24) & 0xff; - data[slen + 1] = (i >>> 16) & 0xff; - data[slen + 2] = (i >>> 8) & 0xff; - data[slen + 3] = i & 0xff; - - var U = new Uint8Array(signHMAC.call(this, P, data)), - Z = U; - for (var j = 1; j < c; j++) { - U = new Uint8Array(signHMAC.call(this, P, U)); - for (var k = 0; k < hLen; k++) Z[k] = U[k] ^ Z[k]; - } - var ofs = (i - 1) * hLen; - arraycopy(Z, 0, DK, ofs, Math.min(hLen, dkLen - ofs)); - } - if (diversifier > 1) { - var rLen = dkLen / diversifier, - R = new Uint8Array(rLen); - arraycopy(DK, dkLen - rLen, R, 0, rLen); - return R.buffer; - } else return DK.buffer; - } // - - /** - * Algorithm name GOST R 34.11-CPKDF

- * - * Derive bits from password. CryptoPro algorithm - *
    - *
  • algorithm.salt - random value, salt
  • - *
  • algorithm.iterations - number of iterations
  • - *
- * @memberOf GostDigest - * @method deriveBits - * @instance - * @param {ArrayBuffer} baseKey - password after UTF-8 decoding - * @param {number} length output bit-length - * @returns {ArrayBuffer} result - */ - function deriveBitsCP(baseKey, length) { - if (length > this.bitLength || length % 8 > 0) - throw new DataError( - "Length can't be more than " + - this.bitLength + - " bits and multiple of 8" - ); - // GOST R 34.11-94 - B=32b, L=32b - // GOST R 34.11-256 - B=64b, L=32b - // GOST R 34.11-512 - B=64b, L=64b - var b = this.digest === digest94 ? 32 : 64, - l = this.bitLength / 8, - p = - baseKey && baseKey.byteLength > 0 - ? new Uint8Array(buffer(baseKey)) - : false, - plen = p ? p.length : 0, - iterations = this.iterations, - salt = new Uint8Array(buffer(this.salt)), - slen = salt.length, - d = new Uint8Array(slen + plen); - arraycopy(salt, 0, d, 0, slen); - if (p) arraycopy(p, 0, d, slen, plen); - - var h = new Uint8Array(this.digest(d)), - k = new Uint8Array(b), - s0 = new Uint8Array(b), - s1 = new Uint8Array(b); - var c = "DENEFH028.760246785.IUEFHWUIO.EF"; - for (var i = 0; i < c.length; i++) k[i] = c.charCodeAt(i); - - d = new Uint8Array(2 * (b + l)); - for (var j = 0; j < iterations; j++) { - for (var i = 0; i < b; i++) { - s0[i] = k[i] ^ 0x36; - s1[i] = k[i] ^ 0x5c; - k[i] = 0; - } - arraycopy(s0, 0, d, 0, b); - arraycopy(h, 0, d, b, l); - arraycopy(s1, 0, d, b + l, b); - arraycopy(h, 0, d, b + l + b, l); - arraycopy(new Uint8Array(this.digest(d)), 0, k, 0, l); - } - for (var i = 0; i < l; i++) { - s0[i] = k[i] ^ 0x36; - s1[i] = k[i] ^ 0x5c; - k[i] = 0; - } - d = new Uint8Array(2 * l + slen + plen); - arraycopy(s0, 0, d, 0, l); - arraycopy(salt, 0, d, l, slen); - arraycopy(s1, 0, d, l + slen, l); - if (p) arraycopy(p, 0, d, l + slen + l, plen); - h = this.digest(this.digest(d)); - if (length === this.bitLength) return h; - else { - var rlen = length / 8, - r = new Uint8Array(rlen); - arraycopy(h, 0, r, 0, rlen); - return r.buffer; - } - } - - /** - * Algorithm name GOST R 34.11-KDF or GOST R 34.11-PBKDF2 or other

- * - * Derive key from derive bits subset - * - * @memberOf GostDigest - * @method deriveKey - * @instance - * @param {ArrayBuffer} baseKey - * @returns {ArrayBuffer} - */ - function deriveKey(baseKey) { - // - return this.deriveBits(baseKey, this.keySize * 8); - } // - - /** - * GOST R 34.11 Algorithm

- * - * References: {@link http://tools.ietf.org/html/rfc6986} and {@link http://tools.ietf.org/html/rfc5831}

- * - * Normalized algorithm identifier common parameters: - * - *
    - *
  • name Algorithm name 'GOST R 34.11'
  • - *
  • version Algorithm version - *
      - *
    • 1994 old-style 256 bits digest based on GOST 28147-89
    • - *
    • 2012 256 ro 512 bits digest algorithm "Streebog" GOST R 34.11-2012 (default)
    • - *
    - *
  • - *
  • length Digest length - *
      - *
    • 256 256 bits digest
    • - *
    • 512 512 bits digest, valid only for algorithm "Streebog"
    • - *
    - *
  • - *
  • mode Algorithm mode - *
      - *
    • HASH simple digest mode (default)
    • - *
    • HMAC HMAC algorithm based on GOST R 34.11
    • - *
    • KDF Derive bits for KEK deversification
    • - *
    • PBKDF2 Password based key dirivation algorithms PBKDF2 (based on HMAC)
    • - *
    • PFXKDF Password based PFX key dirivation algorithms
    • - *
    • CPKDF CpyptoPro Password based key dirivation algorithms
    • - *
    - *
  • - *
  • sBox Paramset sBox for GOST 28147-89. Used only if version = 1994
  • - *
- * - * Supported algorithms, modes and parameters: - * - *
    - *
  • Digest HASH mode (default)
  • - *
  • Sign/Verify HMAC modes parameters depends on version and length - *
      - *
    • version: 1994 HMAC parameters (B = 32, L = 32)
    • - *
    • version: 2012, length: 256 HMAC parameters (B = 64, L = 32)
    • - *
    • version: 2012, length: 512 HMAC parameters (B = 64, L = 64)
    • - *
    - *
  • - *
  • DeriveBits/DeriveKey KDF mode - *
      - *
    • context {@link CryptoOperationData} Context of the key derivation
    • - *
    • label {@link CryptoOperationData} Label that identifies the purpose for the derived keying material
    • - *
    - *
  • - *
  • DeriveBits/DeriveKey PBKDF2 mode - *
      - *
    • salt {@link CryptoOperationData} Random salt as input for HMAC algorithm
    • - *
    • iterations Iteration count. GOST recomended value 1000 (default) or 2000
    • - *
    • diversifier Deversifier, ID=1 - key material for performing encryption or decryption, ID=3 - integrity key for MACing
    • - *
    - *
  • - *
  • DeriveBits/DeriveKey PFXKDF mode - *
      - *
    • salt {@link CryptoOperationData} Random salt as input for HMAC algorithm
    • - *
    • iterations Iteration count. GOST recomended value 1000 (default) or 2000
    • - *
    • diversifier Deversifier, ID=1 - key material for performing encryption or decryption, - * ID=2 - IV (Initial Value) for encryption or decryption, ID=3 - integrity key for MACing
    • - *
    - *
  • - *
  • DeriveBits/DeriveKey CPKDF mode - *
      - *
    • salt {@link CryptoOperationData} Random salt as input for HMAC algorithm
    • - *
    • iterations Iteration count. GOST recomended value 1000 (default) or 2000
    • - *
    - *
  • - *
- * - * @class GostDigest - * @param {AlgorithmIdentifier} algorithm WebCryptoAPI algorithm identifier - */ - function GostDigest(algorithm) { - // - algorithm = algorithm || {}; - - this.name = - (algorithm.name || "GOST R 34.10") + - "-" + - ((algorithm.version || 2012) % 100) + - ((algorithm.version || 2012) > 1 - ? "-" + (algorithm.length || 256) - : "") + - ((algorithm.mode || "HASH") !== "HASH" - ? "-" + algorithm.mode - : "") + - (algorithm.procreator ? "/" + algorithm.procreator : "") + - (typeof algorithm.sBox === "string" ? "/" + algorithm.sBox : ""); - - // Algorithm procreator - this.procreator = algorithm.procreator; - - // Bit length - this.bitLength = algorithm.length || 256; - - switch (algorithm.version || 2012) { - case 1: // SHA-1 - this.digest = digestSHA1; - this.bitLength = 160; - break; - case 1994: - this.digest = digest94; - // Define chiper algorithm - this.sBox = ( - algorithm.sBox || - (algorithm.procreator === "SC" ? "D-SC" : "D-A") - ).toUpperCase(); - - if (!GostCipher) GostCipher = root.GostCipher; - if (!GostCipher) - throw new NotSupportedError("Object GostCipher not found"); - - this.cipher = new GostCipher({ - name: "GOST 28147", - block: "ECB", - sBox: this.sBox, - procreator: this.procreator - }); - - break; - case 2012: - this.digest = digest2012; - break; - default: - throw new NotSupportedError( - "Algorithm version " + algorithm.version + " not supported" - ); - } - - // Key size - this.keySize = - algorithm.keySize || - (algorithm.version <= 2 ? this.bitLength / 8 : 32); - - switch (algorithm.mode || "HASH") { - case "HASH": - break; - case "HMAC": - this.sign = signHMAC; - this.verify = verifyHMAC; - this.generateKey = generateKey; - break; - case "KDF": - this.deriveKey = deriveKey; - this.deriveBits = deriveBitsKDF; - this.label = algorithm.label; - this.context = algorithm.context; - break; - case "PBKDF2": - this.deriveKey = deriveKey; - this.deriveBits = deriveBitsPBKDF2; - this.generateKey = generateKey; - this.salt = algorithm.salt; - this.iterations = algorithm.iterations || 2000; - this.diversifier = algorithm.diversifier || 1; - break; - case "PFXKDF": - this.deriveKey = deriveKey; - this.deriveBits = deriveBitsPFXKDF; - this.generateKey = generateKey; - this.salt = algorithm.salt; - this.iterations = algorithm.iterations || 2000; - this.diversifier = algorithm.diversifier || 1; - break; - case "CPKDF": - this.deriveKey = deriveKey; - this.deriveBits = deriveBitsCP; - this.generateKey = generateKey; - this.salt = algorithm.salt; - this.iterations = algorithm.iterations || 2000; - break; - default: - throw new NotSupportedError( - "Algorithm mode " + algorithm.mode + " not supported" - ); - } - } // - - return GostDigest; -}); diff --git a/src/core/vendor/streebog/gostCipher.js b/src/core/vendor/streebog/gostCipher.js deleted file mode 100644 index bf6b31b5..00000000 --- a/src/core/vendor/streebog/gostCipher.js +++ /dev/null @@ -1,2269 +0,0 @@ -/** - * 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. - * - */ - -(function (root, factory) { - - /* - * Module imports and exports - * - */ // - module.exports = factory(require('./gostRandom')); - -// - -}(this, function (GostRandom) { - - /* - * Initial parameters and common algortithms of GOST 28147-89 - * - * http://tools.ietf.org/html/rfc5830 - * - */ // - - var root = this; - var rootCrypto = root.crypto || root.msCrypto; - var CryptoOperationData = root.ArrayBuffer; - var SyntaxError = root.SyntaxError || root.Error, - DataError = root.DataError || root.Error, - NotSupportedError = root.NotSupportedError || root.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 && 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); - } - - // - - /* - * Initial parameters and common algortithms of GOST R 34.12-15 - * Algorithm "Kuznechik" 128bit - * - */ // - - // 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); - } - - // - - /** - * Key schedule for GOST R 34.12-15 128bits - * - * @memberOf GostCipher - * @private - * @instance - * @method keySchedule - * @param {type} k - * @returns {Uint8Array} - */ - function keySchedule128(k) // - { - 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; - } // - - /** - * 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) // - { - 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)); - } - } // - - /** - * 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) // - { - 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; - - } // - - /** - * 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) // - { - 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; - } // - - /** - * 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) // - { - 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]); - } // - - /** - * 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) // - { - 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; - } // - - /** - * 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) // - { - 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; - } // - - /** - * Key schedule for RC2 - * - * https://tools.ietf.org/html/rfc2268 - * - * @memberOf GostCipher - * @private - * @instance - * @method keySchedule - * @param {Uint8Array} k - * @returns {Uint16Array} - */ - var keyScheduleRC2 = (function () // - { - // 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; - }; - } // - )(); - - /** - * 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 () // - { - 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); - }; - } // - )(); - - /** - * Algorithm name GOST 28147-ECB

- * - * 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) // - { - 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; - } // - - /** - * Algorithm name GOST 28147-ECB

- * - * 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) // - { - 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; - } // - - /** - * Algorithm name GOST 28147-CFB

- * - * 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) // - { - 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; - } // - - /** - * Algorithm name GOST 28147-CFB

- * - * 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) // - { - 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; - } // - - /** - * Algorithm name GOST 28147-OFB

- * - * 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

- * - * 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) // - { - 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; - } // - - /** - * Algorithm name GOST 28147-CTR

- * - * 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

- * - * 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) // - { - 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; - } // - - function processCTR15(k, d, iv) // - { - 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; - } // - - /** - * Algorithm name GOST 28147-CBC

- * - * 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) // - { - 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; - } // - - /** - * Algorithm name GOST 28147-CBC

- * - * 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) // - { - 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; - } // - - /** - * The generateKey method returns a new generated key. - * - * @memberOf GostCipher - * @method generateKey - * @instance - * @return {CryptoOperationData} result - */ - - function generateKey() // - { - // Simple generate 256 bit random seed - var k = new Uint8Array(this.keySize); - randomSeed(k); - return k.buffer; - } // - - - /** - * 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) // - { - 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]); - } - } // - - function processKeyMAC15(s) // - { - 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; - } - } // - - function processMAC15(key, s, d) // - { - 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); - } - } // - - /** - * 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) // - { - 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; - } // - - /** - * 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) // - { - 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; - } // - - /** - * Algorithm name GOST 28147-KW

- * - * 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) // - { - 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; - } // - - /** - * Algorithm name GOST 28147-KW

- * - * 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) // - { - 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; - } // - - /** - * Algorithm name GOST 28147-CPKW

- * - * 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) // - { - 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; - } // - - /** - * Algorithm name GOST 28147-CPKW

- * - * 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) // - { - 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; - } // - - /** - * Algorithm name GOST 28147-CPKW

- * - * 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) // - { - 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) 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); - // 4) Decrypt CEK_ENC in ECB mode using KEK(UKM). Call the output CEK. - var cek = decryptECB.call(this, dek, enc); - // 5) Compute a 4-byte checksum value, GOST 28147IMIT (UKM, KEK(UKM), - // CEK), compare the result with CEK_MAC. If they are not equal, - // then it is an error. - var check = verifyMAC.call(this, dek, mac, cek, ukm); - if (!check) - throw new DataError('Error verify MAC of wrapping key'); - return cek; - } // - - /** - * SignalCom master key packing algorithm - * - * kek stored in 3 files - kek.opq, mk.db3, masks.db3 - * kek.opq - always 36 bytes length = 32 bytes encrypted kek + 4 bytes mac of decrypted kek - * mk.db3 - 6 bytes header (1 byte magic code 0x22 + 1 byte count of masks + 4 bytes mac of - * xor summarizing masks value) + attached masks - * masks.db3 - detached masks. - * Total length of attached + detached masks = 32 bits * count of masks - * Default value of count 8 = (7 attached + 1 detached). But really no reason for such - * separation - all masks xor summarizing - order is not matter. - * Content of file rand.opq can used as ukm. Don't forget change file content after using. - * - * For usb-token files has names: - * a001 - mk.db3, b001 - masks.db3, c001 - kek.opq, d001 - rand.opq - * For windows registry - * 00000001 - mk.db3, 00000002 - masks.db3, 00000003 - key.opq, 00000004 - rand.opq, - * 00000006 - keys\00000001.key, 0000000A - certificate - * - * @memberOf GostCipher - * @method packKey - * @instance - * @private - * @param {CryptoOperationData} unpacked - clear main key 32 bytes - * @param {CryptoOperationData} ukm - random vector for packing - 32 bytes * (count of masks - 1) - * @returns {CryptoOperationData} packed master key - concatination of mk.db3 + masks.db3 - */ - function packKeySC(unpacked, ukm) // - { - var m = this.blockSize >> 1, k = this.keySize; - var mcount = 8; - var key = new Uint8Array(buffer(unpacked)); - if (key.byteLength !== k) - throw new DataError('Wrong cleartext size ' + key.byteLength + ' bytes'); - // Check or generate UKM - ukm = ukm || this.ukm; - if (ukm) { - ukm = new Uint8Array(buffer(ukm)); - if (ukm.byteLength > 0 && ukm.byteLength % k === 0) - mcount = ukm.byteLength / k + 1; - else - throw new DataError('Wrong rand size ' + ukm.byteLength + ' bytes'); - } else - randomSeed(ukm = new Uint8Array((mcount - 1) * k)); - // Output array - var d = new Uint8Array(mcount * k + m + 2), b = d.buffer; - // Calculate MAC - var zero32 = new Uint8Array(k); - var mac = signMAC.call(this, key, zero32); - d[0] = 0x22; // Magic code - d[1] = mcount; // Count of masks - d.set(new Uint8Array(mac), 2); - d.set(ukm, k + m + 2); - for (var i = 1; i < mcount; i++) { - var mask = new Uint8Array(b, 2 + m + k * i); - for (var j = 0; j < k; j++) - key[j] ^= mask[j]; - } - d.set(key, m + 2); - return d.buffer; - } // - - /** - * Algorithm name GOST 28147-SCKW

- * - * SignalCom master key unpacking algorithm - * - * @memberOf GostCipher - * @method unpackKey - * @instance - * @private - * @param {CryptoOperationData} packed - concatination of mk.db3 + masks.db3 - * @returns {CryptoOperationData} unpacked master key - */ - function unpackKeySC(packed) // - { - var m = this.blockSize >> 1, k = this.keySize; - var b = buffer(packed); - // Unpack master key - var magic = new Uint8Array(b, 0, 1)[0]; - if (magic !== 0x22) - throw new DataError('Invalid magic number'); - var mcount = new Uint8Array(b, 1, 1)[0]; - var mac = new Uint8Array(b, 2, m); // MAC for summarized mask - // Compute packKey xor summing for all masks - var key = new Uint8Array(k); - for (var i = 0; i < mcount; i++) { - var mask = new Uint8Array(b, 2 + m + k * i, k); - for (var j = 0; j < k; j++) - key[j] ^= mask[j]; - } - // Test MAC for packKey with default sBox on zero 32 bytes array - var zero32 = new Uint8Array(k); - var test = verifyMAC.call(this, key, mac, zero32); - if (!test) { - // Try to use different sBoxes - var names = ['E-A', 'E-B', 'E-C', 'E-D', 'E-SC']; - for (var i = 0, n = names.length; i < n; i++) { - this.sBox = sBoxes[names[i]]; - test = verifyMAC.call(this, key, mac, zero32); - if (test) - break; - } - } - if (!test) - throw new DataError('Invalid main key MAC'); - return key.buffer; - } // - - /** - * Algorithm name GOST 28147-SCKW

- * - * SignalCom Key Wrapping algorithm - * - * @memberOf GostCipher - * @method wrapKey - * @instance - * @param {CryptoOperationData} kek - clear kek or concatination of mk.db3 + masks.db3 - * @param {CryptoOperationData} cek - key for wrapping - * @returns {CryptoOperationData} wrapped key - file kek.opq - */ - function wrapKeySC(kek, cek) // - { - var m = this.blockSize >> 1, n = this.keySize; - var k = buffer(kek); - var c = buffer(cek); - if (k.byteLength !== n) - k = unpackKeySC.call(this, k); - var enc = encryptECB.call(this, k, c); - var mac = signMAC.call(this, k, c); - var d = new Uint8Array(m + n); - d.set(new Uint8Array(enc), 0); - d.set(new Uint8Array(mac), n); - return d.buffer; - } // - - /** - * Algorithm name GOST 28147-SCKW

- * - * SignalCom Key UnWrapping algorithm - * - * @memberOf GostCipher - * @method unwrapKey - * @instance - * @param {CryptoOperationData} kek - concatination of files mk.db3 + masks.db3 or clear kek - * @param {CryptoOperationData} cek - wrapping key - file kek.opq - * @return {CryptoOperationData} result - */ - function unwrapKeySC(kek, cek) // - { - var m = this.blockSize >> 1, n = this.keySize; - var k = buffer(kek); - var c = buffer(cek); - if (k.byteLength !== n) - k = unpackKeySC.call(this, k); - var enc = new Uint8Array(c, 0, n); // Encrypted kek - var mac = new Uint8Array(c, n, m); // MAC for clear kek - var d = decryptECB.call(this, k, enc); - if (!verifyMAC.call(this, k, mac, d)) - throw new DataError('Invalid key MAC'); - return d; - } // - - /** - * Algorithm name GOST 28147-SCKW

- * - * SignalCom master key generation for wrapping - * - * @memberOf GostCipher - * @method generateKey - * @instance - * @return {CryptoOperationData} result - */ - function generateWrappingKeySC() // - { - return packKeySC.call(this, generateKey.call(this)); - } // - - function maskKey(mask, key, inverse, keySize) // - { - var k = keySize / 4, - m32 = new Int32Array(buffer(mask)), - k32 = new Int32Array(buffer(key)), - r32 = new Int32Array(k); - if (inverse) - for (var i = 0; i < k; i++) - r32[i] = (k32[i] + m32[i]) & 0xffffffff; - else - for (var i = 0; i < k; i++) - r32[i] = (k32[i] - m32[i]) & 0xffffffff; - return r32.buffer; - } // - - /** - * Algorithm name GOST 28147-MASK

- * - * This algorithm wrap key mask - * - * @memberOf GostCipher - * @method wrapKey - * @instance - * @param {CryptoOperationData} mask The mask - * @param {CryptoOperationData} key The key - * @returns {CryptoOperationData} The masked key - */ - function wrapKeyMask(mask, key) // - { - return maskKey(mask, key, this.procreator === 'VN', this.keySize); - } // - - /** - * Algorithm name GOST 28147-CPKW

- * - * This algorithm unwrap key mask - * - * @memberOf GostCipher - * @method unwrapKey - * @instance - * @param {CryptoOperationData} mask The mask - * @param {CryptoOperationData} key The masked key - * @return {CryptoOperationData} result The key - */ - function unwrapKeyMask(mask, key) // - { - return maskKey(mask, key, this.procreator !== 'VN', this.keySize); - } // - - /** - * Algorithm name GOST 28147-CPKM

- * - * Key meshing in according to rfc4357 2.3.2. CryptoPro Key Meshing - * - * @memberOf GostCipher - * @method keyMeshing - * @instance - * @private - * @param {(Uint8Array|CryptoOperationData)} k 8x8 bit key - * @param {Uint8Array} s 8x8 bit sync (iv) - * @param {Integer} i block index - * @param {Int32Array} key 8x32 bit key schedule - * @param {boolean} e true - decrypt - * @returns CryptoOperationData next 8x8 bit key - */ - function keyMeshingCP(k, s, i, key, e) // - { - if ((i + 1) * this.blockSize % 1024 === 0) { // every 1024 octets - // K[i+1] = decryptECB (K[i], C); - k = decryptECB.call(this, k, C); - // IV0[i+1] = encryptECB (K[i+1],IVn[i]) - s.set(new Uint8Array(encryptECB.call(this, k, s))); - // restore key schedule - key.set(this.keySchedule(k, e)); - } - return k; - } // - - /** - * Null Key Meshing in according to rfc4357 2.3.1 - * - * @memberOf GostCipher - * @method keyMeshing - * @instance - * @private - * @param {(Uint8Array|CryptoOperationData)} k 8x8 bit key - */ - function noKeyMeshing(k) // - { - return k; - } // - - /** - * Algorithm name GOST 28147-NoPadding

- * - * No padding. - * - * @memberOf GostCipher - * @method padding - * @instance - * @private - * @param {Uint8Array} d array with source data - * @returns {Uint8Array} result - */ - function noPad(d) // - { - return new Uint8Array(d); - } // - - /** - * Algorithm name GOST 28147-PKCS5Padding

- * - * PKCS#5 padding: 8-x remaining bytes are filled with the value of - * 8-x. If there’s no incomplete block, one extra block filled with - * value 8 is added - * - * @memberOf GostCipher - * @method padding - * @instance - * @private - * @param {Uint8Array} d array with source data - * @returns {Uint8Array} result - */ - function pkcs5Pad(d) // - { - var n = d.byteLength, - nb = this.blockSize, - q = nb - n % nb, - m = Math.ceil((n + 1) / nb) * nb, - r = new Uint8Array(m); - r.set(d); - for (var i = n; i < m; i++) - r[i] = q; - return r; - } // - - function pkcs5Unpad(d) // - { - var m = d.byteLength, - nb = this.blockSize, - q = d[m - 1], - n = m - q; - if (q > nb) - throw DataError('Invalid padding'); - var r = new Uint8Array(n); - if (n > 0) - r.set(new Uint8Array(d.buffer, 0, n)); - return r; - } // - - - /** - * Algorithm name GOST 28147-ZeroPadding

- * - * Zero padding: 8-x remaining bytes are filled with zero - * - * @memberOf GostCipher - * @method padding - * @instance - * @private - * @param {Uint8Array} d array with source data - * @returns {Uint8Array} result - */ - function zeroPad(d) // - { - var n = d.byteLength, - nb = this.blockSize, - m = Math.ceil(n / nb) * nb, - r = new Uint8Array(m); - r.set(d); - for (var i = n; i < m; i++) - r[i] = 0; - return r; - } // - - - /** - * Algorithm name GOST 28147-BitPadding

- * - * Bit padding: P* = P || 1 || 000...0 If there’s no incomplete block, - * one extra block filled with 1 || 000...0 - * - * @memberOf GostCipher - * @method padding - * @instance - * @private - * @param {Uint8Array} d array with source data - * @returns {Uint8Array} result - */ - function bitPad(d) // - { - var n = d.byteLength, - nb = this.blockSize, - m = Math.ceil((n + 1) / nb) * nb, - r = new Uint8Array(m); - r.set(d); - r[n] = 1; - for (var i = n + 1; i < m; i++) - r[i] = 0; - return r; - } // - - function bitUnpad(d) // - { - var m = d.byteLength, - n = m; - while (n > 1 && d[n - 1] === 0) - n--; - if (d[n - 1] !== 1) - throw DataError('Invalid padding'); - n--; - var r = new Uint8Array(n); - if (n > 0) - r.set(new Uint8Array(d.buffer, 0, n)); - return r; - } // - - /** - * Algorithm name GOST 28147-RandomPadding

- * - * Random padding: 8-x remaining bytes of the last block are set to - * random. - * - * @memberOf GostCipher - * @method padding - * @instance - * @private - * @param {Uint8Array} d array with source data - * @returns {Uint8Array} result - */ - function randomPad(d) // - { - var n = d.byteLength, - nb = this.blockSize, - q = nb - n % nb, - m = Math.ceil(n / nb) * nb, - r = new Uint8Array(m), e = new Uint8Array(r.buffer, n, q); - r.set(d); - randomSeed(e); - return r; - } // - - /** - * GOST 28147-89 Encryption Algorithm

- * - * References {@link http://tools.ietf.org/html/rfc5830}

- * - * When keys and initialization vectors are converted to/from byte arrays, - * little-endian byte order is assumed.

- * - * Normalized algorithm identifier common parameters: - * - *
    - *
  • name Algorithm name 'GOST 28147' or 'GOST R 34.12'
  • - *
  • version Algorithm version, number - *
      - *
    • 1989 Current version of standard
    • - *
    • 2015 New draft version of standard
    • - *
    - *
  • - *
  • length Block length - *
      - *
    • 64 64 bits length (default)
    • - *
    • 128 128 bits length (only for version 2015)
    • - *
    - *
  • - *
  • mode Algorithm mode, string - *
      - *
    • ES Encryption mode (default)
    • - *
    • MAC "imitovstavka" (MAC) mode
    • - *
    • KW Key wrapping mode
    • - *
    - *
  • - *
  • sBox Paramset sBox for GOST 28147-89, string. Used only if version = 1989
  • - *
- * - * Supported algorithms, modes and parameters: - * - *
    - *
  • Encript/Decrypt mode (ES) - *
      - *
    • block Block mode, string. Default ECB
    • - *
    • keyMeshing Key meshing mode, string. Default NO
    • - *
    • padding Padding mode, string. Default NO for CFB and CTR modes, or ZERO for others
    • - *
    • iv {@link CryptoOperationData} Initial vector with length of block. Default - zero block
    • - *
    - *
  • - *
  • Sign/Verify mode (MAC) - *
      - *
    • macLength Length of mac in bits (default - 32 bits)
    • - *
    • iv {@link CryptoOperationData} Initial vector with length of block. Default - zero block
    • - *
    - *
  • - *
  • Wrap/Unwrap key mode (KW) - *
      - *
    • keyWrapping Mode of keywrapping, string. Default NO - standard GOST key wrapping
    • - *
    • ukm {@link CryptoOperationData} User key material. Default - random generated value
    • - *
    - *
  • - *
- * - * Supported paramters values: - * - *
    - *
  • Block modes (parameter 'block') - *
      - *
    • ECB "prostaya zamena" (ECB) mode (default)
    • - *
    • CFB "gammirovanie s obratnoj svyaziyu po shifrotekstu" (CFB) mode
    • - *
    • OFB "gammirovanie s obratnoj svyaziyu po vyhodu" (OFB) mode
    • - *
    • CTR "gammirovanie" (counter) mode
    • - *
    • CBC Cipher-Block-Chaining (CBC) mode
    • - *
    - *
  • - *
  • Key meshing modes (parameter 'keyMeshing') - *
      - *
    • NO No key wrapping (default)
    • - *
    • CP CryptoPor Key key meshing
    • - *
    - *
  • - *
  • Padding modes (parameter 'padding') - *
      - *
    • NO No padding only for CFB, OFB and CTR modes
    • - *
    • PKCS5 PKCS#5 padding mode
    • - *
    • ZERO Zero bits padding mode
    • - *
    • RANDOM Random bits padding mode
    • - *
    • BIT One bit padding mode
    • - *
    - *
  • - *
  • Wrapping key modes (parameter 'keyWrapping') - *
      - *
    • NO Ref. rfc4357 6.1 GOST 28147-89 Key wrapping
    • - *
    • CP CryptoPro Key wrapping mode
    • - *
    • SC SignalCom Key wrapping mode
    • - *
    - *
  • - *
- * - * @class GostCipher - * @param {AlgorithmIndentifier} algorithm WebCryptoAPI algorithm identifier - */ - function GostCipher(algorithm) // - { - // Check little endian support - if (!littleEndian) - throw new NotSupportedError('Big endian platform not supported'); - algorithm = algorithm || {}; - this.keySize = 32; - this.blockLength = algorithm.length || 64; - this.blockSize = this.blockLength >> 3; - - this.name = (algorithm.name || (algorithm.version === 1 ? 'RC2' : - algorithm.version === 1989 ? 'GOST 28147' : 'GOST R 34.12')) + - (algorithm.version > 4 ? '-' + ((algorithm.version || 1989) % 100) : '') + '-' + - (this.blockLength === 64 ? '' : this.blockLength + '-') + - ((algorithm.mode === 'MAC') ? 'MAC-' + (algorithm.macLength || this.blockLength >> 1) : - (algorithm.mode === 'KW' || algorithm.keyWrapping) ? - ((algorithm.keyWrapping || 'NO') !== 'NO' ? algorithm.keyWrapping : '') + 'KW' : - (algorithm.block || 'ECB') + ((algorithm.block === 'CFB' || algorithm.block === 'OFB' || - (algorithm.block === 'CTR' && algorithm.version === 2015)) && - algorithm.shiftBits && algorithm.shiftBits !== this.blockLength ? '-' + algorithm.shiftBits : '') + - (algorithm.padding ? '-' + (algorithm.padding || (algorithm.block === 'CTR' || - algorithm.block === 'CFB' || algorithm.block === 'OFB' ? 'NO' : 'ZERO')) + 'PADDING' : '') + - ((algorithm.keyMeshing || 'NO') !== 'NO' ? '-CPKEYMESHING' : '')) + - (algorithm.procreator ? '/' + algorithm.procreator : '') + - (typeof algorithm.sBox === 'string' ? '/' + algorithm.sBox : ''); - - // Algorithm procreator - this.procreator = algorithm.procreator; - - switch (algorithm.version || 1989) { - case 1: - this.process = processRC2; - this.keySchedule = keyScheduleRC2; - this.blockLength = 64; - this.effectiveLength = algorithm.length || 32; - this.keySize = 8 * Math.ceil(this.effectiveLength / 8); // Max 128 - this.blockSize = this.blockLength >> 3; - break; - case 2015: - this.version = 2015; - if (this.blockLength === 64) { - this.process = process15; - this.keySchedule = keySchedule15; - } else if (this.blockLength === 128) { - this.process = process128; - this.keySchedule = keySchedule128; - } else - throw new DataError('Invalid block length'); - this.processMAC = processMAC15; - break; - case 1989: - this.version = 1989; - this.process = process89; - this.processMAC = processMAC89; - this.keySchedule = keySchedule89; - if (this.blockLength !== 64) - throw new DataError('Invalid block length'); - break; - default: - throw new NotSupportedError('Algorithm version ' + algorithm.version + ' not supported'); - } - - switch (algorithm.mode || (algorithm.keyWrapping && 'KW') || 'ES') { - - case 'ES': - switch (algorithm.block || 'ECB') { - case 'ECB': - this.encrypt = encryptECB; - this.decrypt = decryptECB; - break; - case 'CTR': - if (this.version === 1989) { - this.encrypt = processCTR89; - this.decrypt = processCTR89; - } else { - this.encrypt = processCTR15; - this.decrypt = processCTR15; - this.shiftBits = algorithm.shiftBits || this.blockLength; - } - break - case 'CBC': - this.encrypt = encryptCBC; - this.decrypt = decryptCBC; - break - case 'CFB': - this.encrypt = encryptCFB; - this.decrypt = decryptCFB; - this.shiftBits = algorithm.shiftBits || this.blockLength; - break; - case 'OFB': - this.encrypt = processOFB; - this.decrypt = processOFB; - this.shiftBits = algorithm.shiftBits || this.blockLength; - break; - default: - throw new NotSupportedError('Block mode ' + algorithm.block + ' not supported'); - } - switch (algorithm.keyMeshing) { - case 'CP': - this.keyMeshing = keyMeshingCP; - break; - default: - this.keyMeshing = noKeyMeshing; - } - if (this.encrypt === encryptECB || this.encrypt === encryptCBC) { - switch (algorithm.padding) { - case 'PKCS5P': - this.pad = pkcs5Pad; - this.unpad = pkcs5Unpad; - break; - case 'RANDOM': - this.pad = randomPad; - this.unpad = noPad; - break; - case 'BIT': - this.pad = bitPad; - this.unpad = bitUnpad; - break; - default: - this.pad = zeroPad; - this.unpad = noPad; - } - } else { - this.pad = noPad; - this.unpad = noPad; - } - this.generateKey = generateKey; - break; - case 'MAC': - this.sign = signMAC; - this.verify = verifyMAC; - this.generateKey = generateKey; - this.macLength = algorithm.macLength || (this.blockLength >> 1); - this.pad = noPad; - this.unpad = noPad; - this.keyMeshing = noKeyMeshing; - break; - case 'KW': - this.pad = noPad; - this.unpad = noPad; - this.keyMeshing = noKeyMeshing; - switch (algorithm.keyWrapping) { - case 'CP': - this.wrapKey = wrapKeyCP; - this.unwrapKey = unwrapKeyCP; - this.generateKey = generateKey; - this.shiftBits = algorithm.shiftBits || this.blockLength; - break; - case 'SC': - this.wrapKey = wrapKeySC; - this.unwrapKey = unwrapKeySC; - this.generateKey = generateWrappingKeySC; - break; - default: - this.wrapKey = wrapKeyGOST; - this.unwrapKey = unwrapKeyGOST; - this.generateKey = generateKey; - } - break; - case 'MASK': - this.wrapKey = wrapKeyMask; - this.unwrapKey = unwrapKeyMask; - this.generateKey = generateKey; - break; - default: - throw new NotSupportedError('Mode ' + algorithm.mode + ' not supported'); - } - - // Define sBox parameter - var sBox = algorithm.sBox, sBoxName; - if (!sBox) - sBox = this.version === 2015 ? sBoxes['E-Z'] : this.procreator === 'SC' ? sBoxes['E-SC'] : sBoxes['E-A']; - else if (typeof sBox === 'string') { - sBoxName = sBox.toUpperCase(); - sBox = sBoxes[sBoxName]; - if (!sBox) - throw new SyntaxError('Unknown sBox name: ' + algorithm.sBox); - } else if (!sBox.length || sBox.length !== sBoxes['E-Z'].length) - throw new SyntaxError('Length of sBox must be ' + sBoxes['E-Z'].length); - this.sBox = sBox; - // Initial vector - if (algorithm.iv) { - this.iv = new Uint8Array(algorithm.iv); - if (this.iv.byteLength !== this.blockSize && this.version === 1989) - throw new SyntaxError('Length of iv must be ' + this.blockLength + ' bits'); - else if (this.iv.byteLength !== this.blockSize >> 1 && this.encrypt === processCTR15) - throw new SyntaxError('Length of iv must be ' + this.blockLength >> 1 + ' bits'); - else if (this.iv.byteLength % this.blockSize !== 0 && this.encrypt !== processCTR15) - throw new SyntaxError('Length of iv must be a multiple of ' + this.blockLength + ' bits'); - } else - this.iv = this.blockLength === 128 ? defaultIV128 : defaultIV; - // User key material - if (algorithm.ukm) { - this.ukm = new Uint8Array(algorithm.ukm); - if (this.ukm.byteLength * 8 !== this.blockLength) - throw new SyntaxError('Length of ukm must be ' + this.blockLength + ' bits'); - } - } // - - return GostCipher; -})); - diff --git a/src/core/vendor/streebog/gostCipher.mjs b/src/core/vendor/streebog/gostCipher.mjs new file mode 100644 index 00000000..d70d6532 --- /dev/null +++ b/src/core/vendor/streebog/gostCipher.mjs @@ -0,0 +1,2259 @@ +/** + * 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'; + +import crypto from 'crypto' + +/* +* Initial parameters and common algortithms of GOST 28147-89 +* +* http://tools.ietf.org/html/rfc5830 +* +*/ // + +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 && 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); +} + +// + +/* + * Initial parameters and common algortithms of GOST R 34.12-15 + * Algorithm "Kuznechik" 128bit + * + */ // + +// 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); +} + +// + +/** + * Key schedule for GOST R 34.12-15 128bits + * + * @memberOf GostCipher + * @private + * @instance + * @method keySchedule + * @param {type} k + * @returns {Uint8Array} + */ +function keySchedule128(k) // +{ + 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; +} // + +/** + * 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) // +{ + 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)); + } +} // + +/** + * 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) // +{ + 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; + +} // + +/** + * 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) // +{ + 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; +} // + +/** + * 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) // +{ + 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]); +} // + +/** + * 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) // +{ + 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; +} // + +/** + * 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) // +{ + 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; +} // + +/** + * Key schedule for RC2 + * + * https://tools.ietf.org/html/rfc2268 + * + * @memberOf GostCipher + * @private + * @instance + * @method keySchedule + * @param {Uint8Array} k + * @returns {Uint16Array} + */ +var keyScheduleRC2 = (function () // +{ + // 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; + }; +} // +)(); + +/** + * 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 () // +{ + 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); + }; +} // +)(); + +/** + * Algorithm name GOST 28147-ECB

+ * + * 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) // +{ + 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; +} // + +/** + * Algorithm name GOST 28147-ECB

+ * + * 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) // +{ + 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; +} // + +/** + * Algorithm name GOST 28147-CFB

+ * + * 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) // +{ + 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; +} // + +/** + * Algorithm name GOST 28147-CFB

+ * + * 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) // +{ + 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; +} // + +/** + * Algorithm name GOST 28147-OFB

+ * + * 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

+ * + * 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) // +{ + 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; +} // + +/** + * Algorithm name GOST 28147-CTR

+ * + * 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

+ * + * 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) // +{ + 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; +} // + +function processCTR15(k, d, iv) // +{ + 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; +} // + +/** + * Algorithm name GOST 28147-CBC

+ * + * 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) // +{ + 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; +} // + +/** + * Algorithm name GOST 28147-CBC

+ * + * 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) // +{ + 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; +} // + +/** + * The generateKey method returns a new generated key. + * + * @memberOf GostCipher + * @method generateKey + * @instance + * @return {CryptoOperationData} result + */ + +function generateKey() // +{ + // Simple generate 256 bit random seed + var k = new Uint8Array(this.keySize); + randomSeed(k); + return k.buffer; +} // + + +/** + * 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) // +{ + 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]); + } +} // + +function processKeyMAC15(s) // +{ + 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; + } +} // + +function processMAC15(key, s, d) // +{ + 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); + } +} // + +/** + * 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) // +{ + 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; +} // + +/** + * 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) // +{ + 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; +} // + +/** + * Algorithm name GOST 28147-KW

+ * + * 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) // +{ + 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; +} // + +/** + * Algorithm name GOST 28147-KW

+ * + * 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) // +{ + 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; +} // + +/** + * Algorithm name GOST 28147-CPKW

+ * + * 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) // +{ + 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; +} // + +/** + * Algorithm name GOST 28147-CPKW

+ * + * 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) // +{ + 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; +} // + +/** + * Algorithm name GOST 28147-CPKW

+ * + * 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) // +{ + 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) 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); + // 4) Decrypt CEK_ENC in ECB mode using KEK(UKM). Call the output CEK. + var cek = decryptECB.call(this, dek, enc); + // 5) Compute a 4-byte checksum value, GOST 28147IMIT (UKM, KEK(UKM), + // CEK), compare the result with CEK_MAC. If they are not equal, + // then it is an error. + var check = verifyMAC.call(this, dek, mac, cek, ukm); + if (!check) + throw new DataError('Error verify MAC of wrapping key'); + return cek; +} // + +/** + * SignalCom master key packing algorithm + * + * kek stored in 3 files - kek.opq, mk.db3, masks.db3 + * kek.opq - always 36 bytes length = 32 bytes encrypted kek + 4 bytes mac of decrypted kek + * mk.db3 - 6 bytes header (1 byte magic code 0x22 + 1 byte count of masks + 4 bytes mac of + * xor summarizing masks value) + attached masks + * masks.db3 - detached masks. + * Total length of attached + detached masks = 32 bits * count of masks + * Default value of count 8 = (7 attached + 1 detached). But really no reason for such + * separation - all masks xor summarizing - order is not matter. + * Content of file rand.opq can used as ukm. Don't forget change file content after using. + * + * For usb-token files has names: + * a001 - mk.db3, b001 - masks.db3, c001 - kek.opq, d001 - rand.opq + * For windows registry + * 00000001 - mk.db3, 00000002 - masks.db3, 00000003 - key.opq, 00000004 - rand.opq, + * 00000006 - keys\00000001.key, 0000000A - certificate + * + * @memberOf GostCipher + * @method packKey + * @instance + * @private + * @param {CryptoOperationData} unpacked - clear main key 32 bytes + * @param {CryptoOperationData} ukm - random vector for packing - 32 bytes * (count of masks - 1) + * @returns {CryptoOperationData} packed master key - concatination of mk.db3 + masks.db3 + */ +function packKeySC(unpacked, ukm) // +{ + var m = this.blockSize >> 1, k = this.keySize; + var mcount = 8; + var key = new Uint8Array(buffer(unpacked)); + if (key.byteLength !== k) + throw new DataError('Wrong cleartext size ' + key.byteLength + ' bytes'); + // Check or generate UKM + ukm = ukm || this.ukm; + if (ukm) { + ukm = new Uint8Array(buffer(ukm)); + if (ukm.byteLength > 0 && ukm.byteLength % k === 0) + mcount = ukm.byteLength / k + 1; + else + throw new DataError('Wrong rand size ' + ukm.byteLength + ' bytes'); + } else + randomSeed(ukm = new Uint8Array((mcount - 1) * k)); + // Output array + var d = new Uint8Array(mcount * k + m + 2), b = d.buffer; + // Calculate MAC + var zero32 = new Uint8Array(k); + var mac = signMAC.call(this, key, zero32); + d[0] = 0x22; // Magic code + d[1] = mcount; // Count of masks + d.set(new Uint8Array(mac), 2); + d.set(ukm, k + m + 2); + for (var i = 1; i < mcount; i++) { + var mask = new Uint8Array(b, 2 + m + k * i); + for (var j = 0; j < k; j++) + key[j] ^= mask[j]; + } + d.set(key, m + 2); + return d.buffer; +} // + +/** + * Algorithm name GOST 28147-SCKW

+ * + * SignalCom master key unpacking algorithm + * + * @memberOf GostCipher + * @method unpackKey + * @instance + * @private + * @param {CryptoOperationData} packed - concatination of mk.db3 + masks.db3 + * @returns {CryptoOperationData} unpacked master key + */ +function unpackKeySC(packed) // +{ + var m = this.blockSize >> 1, k = this.keySize; + var b = buffer(packed); + // Unpack master key + var magic = new Uint8Array(b, 0, 1)[0]; + if (magic !== 0x22) + throw new DataError('Invalid magic number'); + var mcount = new Uint8Array(b, 1, 1)[0]; + var mac = new Uint8Array(b, 2, m); // MAC for summarized mask + // Compute packKey xor summing for all masks + var key = new Uint8Array(k); + for (var i = 0; i < mcount; i++) { + var mask = new Uint8Array(b, 2 + m + k * i, k); + for (var j = 0; j < k; j++) + key[j] ^= mask[j]; + } + // Test MAC for packKey with default sBox on zero 32 bytes array + var zero32 = new Uint8Array(k); + var test = verifyMAC.call(this, key, mac, zero32); + if (!test) { + // Try to use different sBoxes + var names = ['E-A', 'E-B', 'E-C', 'E-D', 'E-SC']; + for (var i = 0, n = names.length; i < n; i++) { + this.sBox = sBoxes[names[i]]; + test = verifyMAC.call(this, key, mac, zero32); + if (test) + break; + } + } + if (!test) + throw new DataError('Invalid main key MAC'); + return key.buffer; +} // + +/** + * Algorithm name GOST 28147-SCKW

+ * + * SignalCom Key Wrapping algorithm + * + * @memberOf GostCipher + * @method wrapKey + * @instance + * @param {CryptoOperationData} kek - clear kek or concatination of mk.db3 + masks.db3 + * @param {CryptoOperationData} cek - key for wrapping + * @returns {CryptoOperationData} wrapped key - file kek.opq + */ +function wrapKeySC(kek, cek) // +{ + var m = this.blockSize >> 1, n = this.keySize; + var k = buffer(kek); + var c = buffer(cek); + if (k.byteLength !== n) + k = unpackKeySC.call(this, k); + var enc = encryptECB.call(this, k, c); + var mac = signMAC.call(this, k, c); + var d = new Uint8Array(m + n); + d.set(new Uint8Array(enc), 0); + d.set(new Uint8Array(mac), n); + return d.buffer; +} // + +/** + * Algorithm name GOST 28147-SCKW

+ * + * SignalCom Key UnWrapping algorithm + * + * @memberOf GostCipher + * @method unwrapKey + * @instance + * @param {CryptoOperationData} kek - concatination of files mk.db3 + masks.db3 or clear kek + * @param {CryptoOperationData} cek - wrapping key - file kek.opq + * @return {CryptoOperationData} result + */ +function unwrapKeySC(kek, cek) // +{ + var m = this.blockSize >> 1, n = this.keySize; + var k = buffer(kek); + var c = buffer(cek); + if (k.byteLength !== n) + k = unpackKeySC.call(this, k); + var enc = new Uint8Array(c, 0, n); // Encrypted kek + var mac = new Uint8Array(c, n, m); // MAC for clear kek + var d = decryptECB.call(this, k, enc); + if (!verifyMAC.call(this, k, mac, d)) + throw new DataError('Invalid key MAC'); + return d; +} // + +/** + * Algorithm name GOST 28147-SCKW

+ * + * SignalCom master key generation for wrapping + * + * @memberOf GostCipher + * @method generateKey + * @instance + * @return {CryptoOperationData} result + */ +function generateWrappingKeySC() // +{ + return packKeySC.call(this, generateKey.call(this)); +} // + +function maskKey(mask, key, inverse, keySize) // +{ + var k = keySize / 4, + m32 = new Int32Array(buffer(mask)), + k32 = new Int32Array(buffer(key)), + r32 = new Int32Array(k); + if (inverse) + for (var i = 0; i < k; i++) + r32[i] = (k32[i] + m32[i]) & 0xffffffff; + else + for (var i = 0; i < k; i++) + r32[i] = (k32[i] - m32[i]) & 0xffffffff; + return r32.buffer; +} // + +/** + * Algorithm name GOST 28147-MASK

+ * + * This algorithm wrap key mask + * + * @memberOf GostCipher + * @method wrapKey + * @instance + * @param {CryptoOperationData} mask The mask + * @param {CryptoOperationData} key The key + * @returns {CryptoOperationData} The masked key + */ +function wrapKeyMask(mask, key) // +{ + return maskKey(mask, key, this.procreator === 'VN', this.keySize); +} // + +/** + * Algorithm name GOST 28147-CPKW

+ * + * This algorithm unwrap key mask + * + * @memberOf GostCipher + * @method unwrapKey + * @instance + * @param {CryptoOperationData} mask The mask + * @param {CryptoOperationData} key The masked key + * @return {CryptoOperationData} result The key + */ +function unwrapKeyMask(mask, key) // +{ + return maskKey(mask, key, this.procreator !== 'VN', this.keySize); +} // + +/** + * Algorithm name GOST 28147-CPKM

+ * + * Key meshing in according to rfc4357 2.3.2. CryptoPro Key Meshing + * + * @memberOf GostCipher + * @method keyMeshing + * @instance + * @private + * @param {(Uint8Array|CryptoOperationData)} k 8x8 bit key + * @param {Uint8Array} s 8x8 bit sync (iv) + * @param {Integer} i block index + * @param {Int32Array} key 8x32 bit key schedule + * @param {boolean} e true - decrypt + * @returns CryptoOperationData next 8x8 bit key + */ +function keyMeshingCP(k, s, i, key, e) // +{ + if ((i + 1) * this.blockSize % 1024 === 0) { // every 1024 octets + // K[i+1] = decryptECB (K[i], C); + k = decryptECB.call(this, k, C); + // IV0[i+1] = encryptECB (K[i+1],IVn[i]) + s.set(new Uint8Array(encryptECB.call(this, k, s))); + // restore key schedule + key.set(this.keySchedule(k, e)); + } + return k; +} // + +/** + * Null Key Meshing in according to rfc4357 2.3.1 + * + * @memberOf GostCipher + * @method keyMeshing + * @instance + * @private + * @param {(Uint8Array|CryptoOperationData)} k 8x8 bit key + */ +function noKeyMeshing(k) // +{ + return k; +} // + +/** + * Algorithm name GOST 28147-NoPadding

+ * + * No padding. + * + * @memberOf GostCipher + * @method padding + * @instance + * @private + * @param {Uint8Array} d array with source data + * @returns {Uint8Array} result + */ +function noPad(d) // +{ + return new Uint8Array(d); +} // + +/** + * Algorithm name GOST 28147-PKCS5Padding

+ * + * PKCS#5 padding: 8-x remaining bytes are filled with the value of + * 8-x. If there’s no incomplete block, one extra block filled with + * value 8 is added + * + * @memberOf GostCipher + * @method padding + * @instance + * @private + * @param {Uint8Array} d array with source data + * @returns {Uint8Array} result + */ +function pkcs5Pad(d) // +{ + var n = d.byteLength, + nb = this.blockSize, + q = nb - n % nb, + m = Math.ceil((n + 1) / nb) * nb, + r = new Uint8Array(m); + r.set(d); + for (var i = n; i < m; i++) + r[i] = q; + return r; +} // + +function pkcs5Unpad(d) // +{ + var m = d.byteLength, + nb = this.blockSize, + q = d[m - 1], + n = m - q; + if (q > nb) + throw DataError('Invalid padding'); + var r = new Uint8Array(n); + if (n > 0) + r.set(new Uint8Array(d.buffer, 0, n)); + return r; +} // + + +/** + * Algorithm name GOST 28147-ZeroPadding

+ * + * Zero padding: 8-x remaining bytes are filled with zero + * + * @memberOf GostCipher + * @method padding + * @instance + * @private + * @param {Uint8Array} d array with source data + * @returns {Uint8Array} result + */ +function zeroPad(d) // +{ + var n = d.byteLength, + nb = this.blockSize, + m = Math.ceil(n / nb) * nb, + r = new Uint8Array(m); + r.set(d); + for (var i = n; i < m; i++) + r[i] = 0; + return r; +} // + + +/** + * Algorithm name GOST 28147-BitPadding

+ * + * Bit padding: P* = P || 1 || 000...0 If there’s no incomplete block, + * one extra block filled with 1 || 000...0 + * + * @memberOf GostCipher + * @method padding + * @instance + * @private + * @param {Uint8Array} d array with source data + * @returns {Uint8Array} result + */ +function bitPad(d) // +{ + var n = d.byteLength, + nb = this.blockSize, + m = Math.ceil((n + 1) / nb) * nb, + r = new Uint8Array(m); + r.set(d); + r[n] = 1; + for (var i = n + 1; i < m; i++) + r[i] = 0; + return r; +} // + +function bitUnpad(d) // +{ + var m = d.byteLength, + n = m; + while (n > 1 && d[n - 1] === 0) + n--; + if (d[n - 1] !== 1) + throw DataError('Invalid padding'); + n--; + var r = new Uint8Array(n); + if (n > 0) + r.set(new Uint8Array(d.buffer, 0, n)); + return r; +} // + +/** + * Algorithm name GOST 28147-RandomPadding

+ * + * Random padding: 8-x remaining bytes of the last block are set to + * random. + * + * @memberOf GostCipher + * @method padding + * @instance + * @private + * @param {Uint8Array} d array with source data + * @returns {Uint8Array} result + */ +function randomPad(d) // +{ + var n = d.byteLength, + nb = this.blockSize, + q = nb - n % nb, + m = Math.ceil(n / nb) * nb, + r = new Uint8Array(m), e = new Uint8Array(r.buffer, n, q); + r.set(d); + randomSeed(e); + return r; +} // + +/** + * GOST 28147-89 Encryption Algorithm

+ * + * References {@link http://tools.ietf.org/html/rfc5830}

+ * + * When keys and initialization vectors are converted to/from byte arrays, + * little-endian byte order is assumed.

+ * + * Normalized algorithm identifier common parameters: + * + *
    + *
  • name Algorithm name 'GOST 28147' or 'GOST R 34.12'
  • + *
  • version Algorithm version, number + *
      + *
    • 1989 Current version of standard
    • + *
    • 2015 New draft version of standard
    • + *
    + *
  • + *
  • length Block length + *
      + *
    • 64 64 bits length (default)
    • + *
    • 128 128 bits length (only for version 2015)
    • + *
    + *
  • + *
  • mode Algorithm mode, string + *
      + *
    • ES Encryption mode (default)
    • + *
    • MAC "imitovstavka" (MAC) mode
    • + *
    • KW Key wrapping mode
    • + *
    + *
  • + *
  • sBox Paramset sBox for GOST 28147-89, string. Used only if version = 1989
  • + *
+ * + * Supported algorithms, modes and parameters: + * + *
    + *
  • Encript/Decrypt mode (ES) + *
      + *
    • block Block mode, string. Default ECB
    • + *
    • keyMeshing Key meshing mode, string. Default NO
    • + *
    • padding Padding mode, string. Default NO for CFB and CTR modes, or ZERO for others
    • + *
    • iv {@link CryptoOperationData} Initial vector with length of block. Default - zero block
    • + *
    + *
  • + *
  • Sign/Verify mode (MAC) + *
      + *
    • macLength Length of mac in bits (default - 32 bits)
    • + *
    • iv {@link CryptoOperationData} Initial vector with length of block. Default - zero block
    • + *
    + *
  • + *
  • Wrap/Unwrap key mode (KW) + *
      + *
    • keyWrapping Mode of keywrapping, string. Default NO - standard GOST key wrapping
    • + *
    • ukm {@link CryptoOperationData} User key material. Default - random generated value
    • + *
    + *
  • + *
+ * + * Supported paramters values: + * + *
    + *
  • Block modes (parameter 'block') + *
      + *
    • ECB "prostaya zamena" (ECB) mode (default)
    • + *
    • CFB "gammirovanie s obratnoj svyaziyu po shifrotekstu" (CFB) mode
    • + *
    • OFB "gammirovanie s obratnoj svyaziyu po vyhodu" (OFB) mode
    • + *
    • CTR "gammirovanie" (counter) mode
    • + *
    • CBC Cipher-Block-Chaining (CBC) mode
    • + *
    + *
  • + *
  • Key meshing modes (parameter 'keyMeshing') + *
      + *
    • NO No key wrapping (default)
    • + *
    • CP CryptoPor Key key meshing
    • + *
    + *
  • + *
  • Padding modes (parameter 'padding') + *
      + *
    • NO No padding only for CFB, OFB and CTR modes
    • + *
    • PKCS5 PKCS#5 padding mode
    • + *
    • ZERO Zero bits padding mode
    • + *
    • RANDOM Random bits padding mode
    • + *
    • BIT One bit padding mode
    • + *
    + *
  • + *
  • Wrapping key modes (parameter 'keyWrapping') + *
      + *
    • NO Ref. rfc4357 6.1 GOST 28147-89 Key wrapping
    • + *
    • CP CryptoPro Key wrapping mode
    • + *
    • SC SignalCom Key wrapping mode
    • + *
    + *
  • + *
+ * + * @class GostCipher + * @param {AlgorithmIndentifier} algorithm WebCryptoAPI algorithm identifier + */ +function GostCipher(algorithm) // +{ + // Check little endian support + if (!littleEndian) + throw new NotSupportedError('Big endian platform not supported'); + algorithm = algorithm || {}; + this.keySize = 32; + this.blockLength = algorithm.length || 64; + this.blockSize = this.blockLength >> 3; + + this.name = (algorithm.name || (algorithm.version === 1 ? 'RC2' : + algorithm.version === 1989 ? 'GOST 28147' : 'GOST R 34.12')) + + (algorithm.version > 4 ? '-' + ((algorithm.version || 1989) % 100) : '') + '-' + + (this.blockLength === 64 ? '' : this.blockLength + '-') + + ((algorithm.mode === 'MAC') ? 'MAC-' + (algorithm.macLength || this.blockLength >> 1) : + (algorithm.mode === 'KW' || algorithm.keyWrapping) ? + ((algorithm.keyWrapping || 'NO') !== 'NO' ? algorithm.keyWrapping : '') + 'KW' : + (algorithm.block || 'ECB') + ((algorithm.block === 'CFB' || algorithm.block === 'OFB' || + (algorithm.block === 'CTR' && algorithm.version === 2015)) && + algorithm.shiftBits && algorithm.shiftBits !== this.blockLength ? '-' + algorithm.shiftBits : '') + + (algorithm.padding ? '-' + (algorithm.padding || (algorithm.block === 'CTR' || + algorithm.block === 'CFB' || algorithm.block === 'OFB' ? 'NO' : 'ZERO')) + 'PADDING' : '') + + ((algorithm.keyMeshing || 'NO') !== 'NO' ? '-CPKEYMESHING' : '')) + + (algorithm.procreator ? '/' + algorithm.procreator : '') + + (typeof algorithm.sBox === 'string' ? '/' + algorithm.sBox : ''); + + // Algorithm procreator + this.procreator = algorithm.procreator; + + switch (algorithm.version || 1989) { + case 1: + this.process = processRC2; + this.keySchedule = keyScheduleRC2; + this.blockLength = 64; + this.effectiveLength = algorithm.length || 32; + this.keySize = 8 * Math.ceil(this.effectiveLength / 8); // Max 128 + this.blockSize = this.blockLength >> 3; + break; + case 2015: + this.version = 2015; + if (this.blockLength === 64) { + this.process = process15; + this.keySchedule = keySchedule15; + } else if (this.blockLength === 128) { + this.process = process128; + this.keySchedule = keySchedule128; + } else + throw new DataError('Invalid block length'); + this.processMAC = processMAC15; + break; + case 1989: + this.version = 1989; + this.process = process89; + this.processMAC = processMAC89; + this.keySchedule = keySchedule89; + if (this.blockLength !== 64) + throw new DataError('Invalid block length'); + break; + default: + throw new NotSupportedError('Algorithm version ' + algorithm.version + ' not supported'); + } + + switch (algorithm.mode || (algorithm.keyWrapping && 'KW') || 'ES') { + + case 'ES': + switch (algorithm.block || 'ECB') { + case 'ECB': + this.encrypt = encryptECB; + this.decrypt = decryptECB; + break; + case 'CTR': + if (this.version === 1989) { + this.encrypt = processCTR89; + this.decrypt = processCTR89; + } else { + this.encrypt = processCTR15; + this.decrypt = processCTR15; + this.shiftBits = algorithm.shiftBits || this.blockLength; + } + break + case 'CBC': + this.encrypt = encryptCBC; + this.decrypt = decryptCBC; + break + case 'CFB': + this.encrypt = encryptCFB; + this.decrypt = decryptCFB; + this.shiftBits = algorithm.shiftBits || this.blockLength; + break; + case 'OFB': + this.encrypt = processOFB; + this.decrypt = processOFB; + this.shiftBits = algorithm.shiftBits || this.blockLength; + break; + default: + throw new NotSupportedError('Block mode ' + algorithm.block + ' not supported'); + } + switch (algorithm.keyMeshing) { + case 'CP': + this.keyMeshing = keyMeshingCP; + break; + default: + this.keyMeshing = noKeyMeshing; + } + if (this.encrypt === encryptECB || this.encrypt === encryptCBC) { + switch (algorithm.padding) { + case 'PKCS5P': + this.pad = pkcs5Pad; + this.unpad = pkcs5Unpad; + break; + case 'RANDOM': + this.pad = randomPad; + this.unpad = noPad; + break; + case 'BIT': + this.pad = bitPad; + this.unpad = bitUnpad; + break; + default: + this.pad = zeroPad; + this.unpad = noPad; + } + } else { + this.pad = noPad; + this.unpad = noPad; + } + this.generateKey = generateKey; + break; + case 'MAC': + this.sign = signMAC; + this.verify = verifyMAC; + this.generateKey = generateKey; + this.macLength = algorithm.macLength || (this.blockLength >> 1); + this.pad = noPad; + this.unpad = noPad; + this.keyMeshing = noKeyMeshing; + break; + case 'KW': + this.pad = noPad; + this.unpad = noPad; + this.keyMeshing = noKeyMeshing; + switch (algorithm.keyWrapping) { + case 'CP': + this.wrapKey = wrapKeyCP; + this.unwrapKey = unwrapKeyCP; + this.generateKey = generateKey; + this.shiftBits = algorithm.shiftBits || this.blockLength; + break; + case 'SC': + this.wrapKey = wrapKeySC; + this.unwrapKey = unwrapKeySC; + this.generateKey = generateWrappingKeySC; + break; + default: + this.wrapKey = wrapKeyGOST; + this.unwrapKey = unwrapKeyGOST; + this.generateKey = generateKey; + } + break; + case 'MASK': + this.wrapKey = wrapKeyMask; + this.unwrapKey = unwrapKeyMask; + this.generateKey = generateKey; + break; + default: + throw new NotSupportedError('Mode ' + algorithm.mode + ' not supported'); + } + + // Define sBox parameter + var sBox = algorithm.sBox, sBoxName; + if (!sBox) + sBox = this.version === 2015 ? sBoxes['E-Z'] : this.procreator === 'SC' ? sBoxes['E-SC'] : sBoxes['E-A']; + else if (typeof sBox === 'string') { + sBoxName = sBox.toUpperCase(); + sBox = sBoxes[sBoxName]; + if (!sBox) + throw new SyntaxError('Unknown sBox name: ' + algorithm.sBox); + } else if (!sBox.length || sBox.length !== sBoxes['E-Z'].length) + throw new SyntaxError('Length of sBox must be ' + sBoxes['E-Z'].length); + this.sBox = sBox; + // Initial vector + if (algorithm.iv) { + this.iv = new Uint8Array(algorithm.iv); + if (this.iv.byteLength !== this.blockSize && this.version === 1989) + throw new SyntaxError('Length of iv must be ' + this.blockLength + ' bits'); + else if (this.iv.byteLength !== this.blockSize >> 1 && this.encrypt === processCTR15) + throw new SyntaxError('Length of iv must be ' + this.blockLength >> 1 + ' bits'); + else if (this.iv.byteLength % this.blockSize !== 0 && this.encrypt !== processCTR15) + throw new SyntaxError('Length of iv must be a multiple of ' + this.blockLength + ' bits'); + } else + this.iv = this.blockLength === 128 ? defaultIV128 : defaultIV; + // User key material + if (algorithm.ukm) { + this.ukm = new Uint8Array(algorithm.ukm); + if (this.ukm.byteLength * 8 !== this.blockLength) + throw new SyntaxError('Length of ukm must be ' + this.blockLength + ' bits'); + } +} // + +export default GostCipher; diff --git a/src/core/vendor/streebog/gostCoding.js b/src/core/vendor/streebog/gostCoding.js deleted file mode 100644 index c9514a79..00000000 --- a/src/core/vendor/streebog/gostCoding.js +++ /dev/null @@ -1,1171 +0,0 @@ -/** - * Coding algorithms: Base64, Hex, Int16, Chars, BER and PEM - * version 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. - * - */ - -(function (root, factory) { - - /* - * Module imports and exports - * - */ // - module.exports = factory(require('./gostCrypto')); - // - -}(this, function (gostCrypto) { - - /** - * The Coding interface provides string converting methods: Base64, Hex, - * Int16, Chars, BER and PEM - * @class GostCoding - * - */ // - var root = this; - var DataError = root.DataError || root.Error; - var CryptoOperationData = root.ArrayBuffer; - var Date = root.Date; - - function buffer(d) { - if (d instanceof CryptoOperationData) - return d; - else if (d && d.buffer && 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'); - } // - - function GostCoding() { - } - - /** - * BASE64 conversion - * - * @class GostCoding.Base64 - */ - var Base64 = {// - /** - * Base64.decode convert BASE64 string s to CryptoOperationData - * - * @memberOf GostCoding.Base64 - * @param {String} s BASE64 encoded string value - * @returns {CryptoOperationData} Binary decoded data - */ - decode: function (s) { - s = s.replace(/[^A-Za-z0-9\+\/]/g, ''); - var n = s.length, - k = n * 3 + 1 >> 2, r = new Uint8Array(k); - - for (var m3, m4, u24 = 0, j = 0, i = 0; i < n; i++) { - m4 = i & 3; - var c = s.charCodeAt(i); - - c = c > 64 && c < 91 ? - c - 65 : c > 96 && c < 123 ? - c - 71 : c > 47 && c < 58 ? - c + 4 : c === 43 ? - 62 : c === 47 ? - 63 : 0; - - u24 |= c << 18 - 6 * m4; - if (m4 === 3 || n - i === 1) { - for (m3 = 0; m3 < 3 && j < k; m3++, j++) { - r[j] = u24 >>> (16 >>> m3 & 24) & 255; - } - u24 = 0; - - } - } - return r.buffer; - }, - /** - * Base64.encode(data) convert CryptoOperationData data to BASE64 string - * - * @memberOf GostCoding.Base64 - * @param {CryptoOperationData} data Bynary data for encoding - * @returns {String} BASE64 encoded data - */ - encode: function (data) { - var slen = 8, d = new Uint8Array(buffer(data)); - var m3 = 2, s = ''; - for (var n = d.length, u24 = 0, i = 0; i < n; i++) { - m3 = i % 3; - if (i > 0 && (i * 4 / 3) % (12 * slen) === 0) - s += '\r\n'; - u24 |= d[i] << (16 >>> m3 & 24); - if (m3 === 2 || n - i === 1) { - for (var j = 18; j >= 0; j -= 6) { - var c = u24 >>> j & 63; - c = c < 26 ? c + 65 : c < 52 ? c + 71 : c < 62 ? c - 4 : - c === 62 ? 43 : c === 63 ? 47 : 65; - s += String.fromCharCode(c); - } - u24 = 0; - } - } - return s.substr(0, s.length - 2 + m3) + (m3 === 2 ? '' : m3 === 1 ? '=' : '=='); - } // - }; - - /** - * BASE64 conversion - * - * @memberOf GostCoding - * @insnance - * @type GostCoding.Base64 - */ - GostCoding.prototype.Base64 = Base64; - - /** - * Text string conversion
- * Methods support charsets: ascii, win1251, utf8, utf16 (ucs2, unicode), utf32 (ucs4) - * - * @class GostCoding.Chars - */ - var Chars = (function () { // - - var _win1251_ = { - 0x402: 0x80, 0x403: 0x81, 0x201A: 0x82, 0x453: 0x83, 0x201E: 0x84, 0x2026: 0x85, 0x2020: 0x86, 0x2021: 0x87, - 0x20AC: 0x88, 0x2030: 0x89, 0x409: 0x8A, 0x2039: 0x8B, 0x40A: 0x8C, 0x40C: 0x8D, 0x40B: 0x8E, 0x40f: 0x8f, - 0x452: 0x90, 0x2018: 0x91, 0x2019: 0x92, 0x201C: 0x93, 0x201D: 0x94, 0x2022: 0x95, 0x2013: 0x96, 0x2014: 0x97, - 0x2122: 0x99, 0x459: 0x9A, 0x203A: 0x9B, 0x45A: 0x9C, 0x45C: 0x9D, 0x45B: 0x9E, 0x45f: 0x9f, - 0xA0: 0xA0, 0x40E: 0xA1, 0x45E: 0xA2, 0x408: 0xA3, 0xA4: 0xA4, 0x490: 0xA5, 0xA6: 0xA6, 0xA7: 0xA7, - 0x401: 0xA8, 0xA9: 0xA9, 0x404: 0xAA, 0xAB: 0xAB, 0xAC: 0xAC, 0xAD: 0xAD, 0xAE: 0xAE, 0x407: 0xAf, - 0xB0: 0xB0, 0xB1: 0xB1, 0x406: 0xB2, 0x456: 0xB3, 0x491: 0xB4, 0xB5: 0xB5, 0xB6: 0xB6, 0xB7: 0xB7, - 0x451: 0xB8, 0x2116: 0xB9, 0x454: 0xBA, 0xBB: 0xBB, 0x458: 0xBC, 0x405: 0xBD, 0x455: 0xBE, 0x457: 0xBf - }; - var _win1251back_ = {}; - for (var from in _win1251_) { - var to = _win1251_[from]; - _win1251back_[to] = from; - } - - return { - /** - * Chars.decode(s, charset) convert string s with defined charset to CryptoOperationData - * - * @memberOf GostCoding.Chars - * @param {string} s Javascript string - * @param {string} charset Charset, default 'win1251' - * @returns {CryptoOperationData} Decoded binary data - */ - decode: function (s, charset) { - charset = (charset || 'win1251').toLowerCase().replace('-', ''); - var r = []; - for (var i = 0, j = s.length; i < j; i++) { - var c = s.charCodeAt(i); - if (charset === 'utf8') { - if (c < 0x80) { - r.push(c); - } else if (c < 0x800) { - r.push(0xc0 + (c >>> 6)); - r.push(0x80 + (c & 63)); - } else if (c < 0x10000) { - r.push(0xe0 + (c >>> 12)); - r.push(0x80 + (c >>> 6 & 63)); - r.push(0x80 + (c & 63)); - } else if (c < 0x200000) { - r.push(0xf0 + (c >>> 18)); - r.push(0x80 + (c >>> 12 & 63)); - r.push(0x80 + (c >>> 6 & 63)); - r.push(0x80 + (c & 63)); - } else if (c < 0x4000000) { - r.push(0xf8 + (c >>> 24)); - r.push(0x80 + (c >>> 18 & 63)); - r.push(0x80 + (c >>> 12 & 63)); - r.push(0x80 + (c >>> 6 & 63)); - r.push(0x80 + (c & 63)); - } else { - r.push(0xfc + (c >>> 30)); - r.push(0x80 + (c >>> 24 & 63)); - r.push(0x80 + (c >>> 18 & 63)); - r.push(0x80 + (c >>> 12 & 63)); - r.push(0x80 + (c >>> 6 & 63)); - r.push(0x80 + (c & 63)); - } - } else if (charset === 'unicode' || charset === 'ucs2' || charset === 'utf16') { - if (c < 0xD800 || (c >= 0xE000 && c <= 0x10000)) { - r.push(c >>> 8); - r.push(c & 0xff); - } else if (c >= 0x10000 && c < 0x110000) { - c -= 0x10000; - var first = ((0xffc00 & c) >> 10) + 0xD800; - var second = (0x3ff & c) + 0xDC00; - r.push(first >>> 8); - r.push(first & 0xff); - r.push(second >>> 8); - r.push(second & 0xff); - } - } else if (charset === 'utf32' || charset === 'ucs4') { - r.push(c >>> 24 & 0xff); - r.push(c >>> 16 & 0xff); - r.push(c >>> 8 & 0xff); - r.push(c & 0xff); - } else if (charset === 'win1251') { - if (c >= 0x80) { - if (c >= 0x410 && c < 0x450) // А..Яа..я - c -= 0x350; - else - c = _win1251_[c] || 0; - } - r.push(c); - } else - r.push(c & 0xff); - } - return new Uint8Array(r).buffer; - }, - /** - * Chars.encode(data, charset) convert CryptoOperationData data to string with defined charset - * - * @memberOf GostCoding.Chars - * @param {CryptoOperationData} data Binary data - * @param {string} charset Charset, default win1251 - * @returns {string} Encoded javascript string - */ - encode: function (data, charset) { - charset = (charset || 'win1251').toLowerCase().replace('-', ''); - var r = [], d = new Uint8Array(buffer(data)); - for (var i = 0, n = d.length; i < n; i++) { - var c = d[i]; - if (charset === 'utf8') { - c = c >= 0xfc && c < 0xfe && i + 5 < n ? // six bytes - (c - 0xfc) * 1073741824 + (d[++i] - 0x80 << 24) + (d[++i] - 0x80 << 18) + (d[++i] - 0x80 << 12) + (d[++i] - 0x80 << 6) + d[++i] - 0x80 - : c >> 0xf8 && c < 0xfc && i + 4 < n ? // five bytes - (c - 0xf8 << 24) + (d[++i] - 0x80 << 18) + (d[++i] - 0x80 << 12) + (d[++i] - 0x80 << 6) + d[++i] - 0x80 - : c >> 0xf0 && c < 0xf8 && i + 3 < n ? // four bytes - (c - 0xf0 << 18) + (d[++i] - 0x80 << 12) + (d[++i] - 0x80 << 6) + d[++i] - 0x80 - : c >= 0xe0 && c < 0xf0 && i + 2 < n ? // three bytes - (c - 0xe0 << 12) + (d[++i] - 0x80 << 6) + d[++i] - 0x80 - : c >= 0xc0 && c < 0xe0 && i + 1 < n ? // two bytes - (c - 0xc0 << 6) + d[++i] - 0x80 - : c; // one byte - } else if (charset === 'unicode' || charset === 'ucs2' || charset === 'utf16') { - c = (c << 8) + d[++i]; - if (c >= 0xD800 && c < 0xE000) { - var first = (c - 0xD800) << 10; - c = d[++i]; - c = (c << 8) + d[++i]; - var second = c - 0xDC00; - c = first + second + 0x10000; - } - } else if (charset === 'utf32' || charset === 'ucs4') { - c = (c << 8) + d[++i]; - c = (c << 8) + d[++i]; - c = (c << 8) + d[++i]; - } else if (charset === 'win1251') { - if (c >= 0x80) { - if (c >= 0xC0 && c < 0x100) - c += 0x350; // А..Яа..я - else - c = _win1251back_[c] || 0; - } - } - r.push(String.fromCharCode(c)); - } - return r.join(''); - } - }; // - })(); - - /** - * Text string conversion - * - * @memberOf GostCoding - * @insnance - * @type GostCoding.Chars - */ - GostCoding.prototype.Chars = Chars; - - /** - * HEX conversion - * - * @class GostCoding.Hex - */ - var Hex = {// - /** - * Hex.decode(s, endean) convert HEX string s to CryptoOperationData in endean mode - * - * @memberOf GostCoding.Hex - * @param {string} s Hex encoded string - * @param {boolean} endean Little or Big Endean, default Little - * @returns {CryptoOperationData} Decoded binary data - */ - decode: function (s, endean) { - s = s.replace(/[^A-fa-f0-9]/g, ''); - var n = Math.ceil(s.length / 2), r = new Uint8Array(n); - s = (s.length % 2 > 0 ? '0' : '') + s; - if (endean && ((typeof endean !== 'string') || - (endean.toLowerCase().indexOf('little') < 0))) - for (var i = 0; i < n; i++) - r[i] = parseInt(s.substr((n - i - 1) * 2, 2), 16); - else - for (var i = 0; i < n; i++) - r[i] = parseInt(s.substr(i * 2, 2), 16); - return r.buffer; - }, - /** - * Hex.encode(data, endean) convert CryptoOperationData data to HEX string in endean mode - * - * @memberOf GostCoding.Hex - * @param {CryptoOperationData} data Binary data - * @param {boolean} endean Little/Big Endean, default Little - * @returns {string} Hex decoded string - */ - encode: function (data, endean) { - var s = [], d = new Uint8Array(buffer(data)), n = d.length; - if (endean && ((typeof endean !== 'string') || - (endean.toLowerCase().indexOf('little') < 0))) - for (var i = 0; i < n; i++) { - var j = n - i - 1; - s[j] = (j > 0 && j % 32 === 0 ? '\r\n' : '') + - ('00' + d[i].toString(16)).slice(-2); - } - else - for (var i = 0; i < n; i++) - s[i] = (i > 0 && i % 32 === 0 ? '\r\n' : '') + - ('00' + d[i].toString(16)).slice(-2); - return s.join(''); - } // - }; - - /** - * HEX conversion - * @memberOf GostCoding - * @insnance - * @type GostCoding.Hex - */ - GostCoding.prototype.Hex = Hex; - - /** - * String hex-encoded integer conversion - * - * @class GostCoding.Int16 - */ - var Int16 = {// - /** - * Int16.decode(s) convert hex big insteger s to CryptoOperationData - * - * @memberOf GostCoding.Int16 - * @param {string} s Int16 string - * @returns {CryptoOperationData} Decoded binary data - */ - decode: function (s) { - s = (s || '').replace(/[^\-A-fa-f0-9]/g, ''); - if (s.length === 0) - s = '0'; - // Signature - var neg = false; - if (s.charAt(0) === '-') { - neg = true; - s = s.substring(1); - } - // Align 2 chars - while (s.charAt(0) === '0' && s.length > 1) - s = s.substring(1); - s = (s.length % 2 > 0 ? '0' : '') + s; - // Padding for singanuture - // '800000' - 'ffffff' - for positive - // '800001' - 'ffffff' - for negative - if ((!neg && !/^[0-7]/.test(s)) || - (neg && !/^[0-7]|8[0]+$/.test(s))) - s = '00' + s; - // Convert hex - var n = s.length / 2, r = new Uint8Array(n), t = 0; - for (var i = n - 1; i >= 0; --i) { - var c = parseInt(s.substr(i * 2, 2), 16); - if (neg && (c + t > 0)) { - c = 256 - c - t; - t = 1; - } - r[i] = c; - } - return r.buffer; - }, - /** - * Int16.encode(data) convert CryptoOperationData data to big integer hex string - * - * @memberOf GostCoding.Int16 - * @param {CryptoOperationData} data Binary data - * @returns {string} Int16 encoded string - */ - encode: function (data) { - var d = new Uint8Array(buffer(data)), n = d.length; - if (d.length === 0) - return '0x00'; - var s = [], neg = d[0] > 0x7f, t = 0; - for (var i = n - 1; i >= 0; --i) { - var v = d[i]; - if (neg && (v + t > 0)) { - v = 256 - v - t; - t = 1; - } - s[i] = ('00' + v.toString(16)).slice(-2); - } - s = s.join(''); - while (s.charAt(0) === '0') - s = s.substring(1); - return (neg ? '-' : '') + '0x' + s; - } // - }; - - /** - * String hex-encoded integer conversion - * @memberOf GostCoding - * @insnance - * @type GostCoding.Int16 - */ - GostCoding.prototype.Int16 = Int16; - - /** - * BER, DER, CER conversion - * - * @class GostCoding.BER - */ - var BER = (function () { // - - // Predefenition block - function encodeBER(source, format, onlyContent) { - // Correct primitive type - var object = source.object; - if (object === undefined) - object = source; - - // Determinate tagClass - var tagClass = source.tagClass = source.tagClass || 0; // Universial default - - // Determinate tagNumber. Use only for Universal class - if (tagClass === 0) { - var tagNumber = source.tagNumber; - if (typeof tagNumber === 'undefined') { - if (typeof object === 'string') { - if (object === '') // NULL - tagNumber = 0x05; - else if (/^\-?0x[0-9a-fA-F]+$/.test(object)) // INTEGER - tagNumber = 0x02; - else if (/^(\d+\.)+\d+$/.test(object)) // OID - tagNumber = 0x06; - else if (/^[01]+$/.test(object)) // BIT STRING - tagNumber = 0x03; - else if (/^(true|false)$/.test(object)) // BOOLEAN - tagNumber = 0x01; - else if (/^[0-9a-fA-F]+$/.test(object)) // OCTET STRING - tagNumber = 0x04; - else - tagNumber = 0x13; // Printable string (later can be changed to UTF8String) - } else if (typeof object === 'number') { // INTEGER - tagNumber = 0x02; - } else if (typeof object === 'boolean') { // BOOLEAN - tagNumber = 0x01; - } else if (object instanceof Array) { // SEQUENCE - tagNumber = 0x10; - } else if (object instanceof Date) { // GeneralizedTime - tagNumber = 0x18; - } else if (object instanceof CryptoOperationData || (object && object.buffer instanceof CryptoOperationData)) { - tagNumber = 0x04; - } else - throw new DataError('Unrecognized type for ' + object); - } - } - - // Determinate constructed - var tagConstructed = source.tagConstructed; - if (typeof tagConstructed === 'undefined') - tagConstructed = source.tagConstructed = object instanceof Array; - - // Create content - var content; - if (object instanceof CryptoOperationData || (object && object.buffer instanceof CryptoOperationData)) { // Direct - content = new Uint8Array(buffer(object)); - if (tagNumber === 0x03) { // BITSTRING - // Set unused bits - var a = new Uint8Array(buffer(content)); - content = new Uint8Array(a.length + 1); - content[0] = 0; // No unused bits - content.set(a, 1); - } - } else if (tagConstructed) { // Sub items coding - if (object instanceof Array) { - var bytelen = 0, ba = [], offset = 0; - for (var i = 0, n = object.length; i < n; i++) { - ba[i] = encodeBER(object[i], format); - bytelen += ba[i].length; - } - if (tagNumber === 0x11) - ba.sort(function (a, b) { // Sort order for SET components - for (var i = 0, n = Math.min(a.length, b.length); i < n; i++) { - var r = a[i] - b[i]; - if (r !== 0) - return r; - } - return a.length - b.length; - }); - if (format === 'CER') { // final for CER 00 00 - ba[n] = new Uint8Array(2); - bytelen += 2; - } - content = new Uint8Array(bytelen); - for (var i = 0, n = ba.length; i < n; i++) { - content.set(ba[i], offset); - offset = offset + ba[i].length; - } - } else - throw new DataError('Constracted block can\'t be primitive'); - } else { - switch (tagNumber) { - // 0x00: // EOC - case 0x01: // BOOLEAN - content = new Uint8Array(1); - content[0] = object ? 0xff : 0; - break; - case 0x02: // INTEGER - case 0x0a: // ENUMIRATED - content = Int16.decode( - typeof object === 'number' ? object.toString(16) : object); - break; - case 0x03: // BIT STRING - if (typeof object === 'string') { - var unusedBits = 7 - (object.length + 7) % 8; - var n = Math.ceil(object.length / 8); - content = new Uint8Array(n + 1); - content[0] = unusedBits; - for (var i = 0; i < n; i++) { - var c = 0; - for (var j = 0; j < 8; j++) { - var k = i * 8 + j; - c = (c << 1) + (k < object.length ? (object.charAt(k) === '1' ? 1 : 0) : 0); - } - content[i + 1] = c; - } - } - break; - case 0x04: - content = Hex.decode( - typeof object === 'number' ? object.toString(16) : object); - break; - // case 0x05: // NULL - case 0x06: // OBJECT IDENTIFIER - var a = object.match(/\d+/g), r = []; - for (var i = 1; i < a.length; i++) { - var n = +a[i], r1 = []; - if (i === 1) - n = n + a[0] * 40; - do { - r1.push(n & 0x7F); - n = n >>> 7; - } while (n); - // reverse order - for (j = r1.length - 1; j >= 0; --j) - r.push(r1[j] + (j === 0 ? 0x00 : 0x80)); - } - content = new Uint8Array(r); - break; - // case 0x07: // ObjectDescriptor - // case 0x08: // EXTERNAL - // case 0x09: // REAL - // case 0x0A: // ENUMERATED - // case 0x0B: // EMBEDDED PDV - case 0x0C: // UTF8String - content = Chars.decode(object, 'utf8'); - break; - // case 0x10: // SEQUENCE - // case 0x11: // SET - case 0x12: // NumericString - case 0x16: // IA5String // ASCII - case 0x13: // PrintableString // ASCII subset - case 0x14: // TeletexString // aka T61String - case 0x15: // VideotexString - case 0x19: // GraphicString - case 0x1A: // VisibleString // ASCII subset - case 0x1B: // GeneralString - // Reflect on character encoding - for (var i = 0, n = object.length; i < n; i++) - if (object.charCodeAt(i) > 255) - tagNumber = 0x0C; - if (tagNumber === 0x0C) - content = Chars.decode(object, 'utf8'); - else - content = Chars.decode(object, 'ascii'); - break; - case 0x17: // UTCTime - case 0x18: // GeneralizedTime - var result = object.original; - if (!result) { - var date = new Date(object); - date.setMinutes(date.getMinutes() + date.getTimezoneOffset()); // to UTC - var ms = tagNumber === 0x18 ? date.getMilliseconds().toString() : ''; // Milliseconds, remove trailing zeros - while (ms.length > 0 && ms.charAt(ms.length - 1) === '0') - ms = ms.substring(0, ms.length - 1); - if (ms.length > 0) - ms = '.' + ms; - result = (tagNumber === 0x17 ? date.getYear().toString().slice(-2) : date.getFullYear().toString()) + - ('00' + (date.getMonth() + 1)).slice(-2) + - ('00' + date.getDate()).slice(-2) + - ('00' + date.getHours()).slice(-2) + - ('00' + date.getMinutes()).slice(-2) + - ('00' + date.getSeconds()).slice(-2) + ms + 'Z'; - } - content = Chars.decode(result, 'ascii'); - break; - case 0x1C: // UniversalString - content = Chars.decode(object, 'utf32'); - break; - case 0x1E: // BMPString - content = Chars.decode(object, 'utf16'); - break; - } - } - - if (!content) - content = new Uint8Array(0); - if (content instanceof CryptoOperationData) - content = new Uint8Array(content); - - if (!tagConstructed && format === 'CER') { - // Encoding CER-form for string types - var k; - switch (tagNumber) { - case 0x03: // BIT_STRING - k = 1; // ingnore unused bit for bit string - case 0x04: // OCTET_STRING - case 0x0C: // UTF8String - case 0x12: // NumericString - case 0x13: // PrintableString - case 0x14: // TeletexString - case 0x15: // VideotexString - case 0x16: // IA5String - case 0x19: // GraphicString - case 0x1A: // VisibleString - case 0x1B: // GeneralString - case 0x1C: // UniversalString - case 0x1E: // BMPString - k = k || 0; - // Split content on 1000 octet len parts - var size = 1000; - var bytelen = 0, ba = [], offset = 0; - for (var i = k, n = content.length; i < n; i += size - k) { - ba[i] = encodeBER({ - object: new Unit8Array(content.buffer, i, Math.min(size - k, n - i)), - tagNumber: tagNumber, - tagClass: 0, - tagConstructed: false - }, format); - bytelen += ba[i].length; - } - ba[n] = new Uint8Array(2); // final for CER 00 00 - bytelen += 2; - content = new Uint8Array(bytelen); - for (var i = 0, n = ba.length; i < n; i++) { - content.set(ba[i], offset); - offset = offset + ba[i].length; - } - } - } - - // Restore tagNumber for all classes - if (tagClass === 0) - source.tagNumber = tagNumber; - else - source.tagNumber = tagNumber = source.tagNumber || 0; - source.content = content; - - if (onlyContent) - return content; - - // Create header - // tagNumber - var ha = [], first = tagClass === 3 ? 0xC0 : tagClass === 2 ? 0x80 : - tagClass === 1 ? 0x40 : 0x00; - if (tagConstructed) - first |= 0x20; - if (tagNumber < 0x1F) { - first |= tagNumber & 0x1F; - ha.push(first); - } else { - first |= 0x1F; - ha.push(first); - var n = tagNumber, ha1 = []; - do { - ha1.push(n & 0x7F); - n = n >>> 7; - } while (n) - // reverse order - for (var j = ha1.length - 1; j >= 0; --j) - ha.push(ha1[j] + (j === 0 ? 0x00 : 0x80)); - } - // Length - if (tagConstructed && format === 'CER') { - ha.push(0x80); - } else { - var len = content.length; - if (len > 0x7F) { - var l2 = len, ha2 = []; - do { - ha2.push(l2 & 0xff); - l2 = l2 >>> 8; - } while (l2); - ha.push(ha2.length + 0x80); // reverse order - for (var j = ha2.length - 1; j >= 0; --j) - ha.push(ha2[j]); - } else { - // simple len - ha.push(len); - } - } - var header = source.header = new Uint8Array(ha); - - // Result - complete buffer - var block = new Uint8Array(header.length + content.length); - block.set(header, 0); - block.set(content, header.length); - return block; - } - - function decodeBER(source, offset) { - - // start pos - var pos = offset || 0, start = pos; - var tagNumber, tagClass, tagConstructed, - content, header, buffer, sub, len; - - if (source.object) { - // Ready from source - tagNumber = source.tagNumber; - tagClass = source.tagClass; - tagConstructed = source.tagConstructed; - content = source.content; - header = source.header; - buffer = source.object instanceof CryptoOperationData ? - new Uint8Array(source.object) : null; - sub = source.object instanceof Array ? source.object : null; - len = buffer && buffer.length || null; - } else { - // Decode header - var d = source; - - // Read tag - var buf = d[pos++]; - tagNumber = buf & 0x1f; - tagClass = buf >> 6; - tagConstructed = (buf & 0x20) !== 0; - if (tagNumber === 0x1f) { // long tag - tagNumber = 0; - do { - if (tagNumber > 0x1fffffffffff80) - throw new DataError('Convertor not supported tag number more then (2^53 - 1) at position ' + offset); - buf = d[pos++]; - tagNumber = (tagNumber << 7) + (buf & 0x7f); - } while (buf & 0x80); - } - - // Read len - buf = d[pos++]; - len = buf & 0x7f; - if (len !== buf) { - if (len > 6) // no reason to use Int10, as it would be a huge buffer anyways - throw new DataError('Length over 48 bits not supported at position ' + offset); - if (len === 0) - len = null; // undefined - else { - buf = 0; - for (var i = 0; i < len; ++i) - buf = (buf << 8) + d[pos++]; - len = buf; - } - } - - start = pos; - sub = null; - - if (tagConstructed) { - // must have valid content - sub = []; - if (len !== null) { - // definite length - var end = start + len; - while (pos < end) { - var s = decodeBER(d, pos); - sub.push(s); - pos += s.header.length + s.content.length; - } - if (pos !== end) - throw new DataError('Content size is not correct for container starting at offset ' + start); - } else { - // undefined length - try { - for (; ; ) { - var s = decodeBER(d, pos); - pos += s.header.length + s.content.length; - if (s.tagClass === 0x00 && s.tagNumber === 0x00) - break; - sub.push(s); - } - len = pos - start; - } catch (e) { - throw new DataError('Exception ' + e + ' while decoding undefined length content at offset ' + start); - } - } - } - - // Header and content - header = new Uint8Array(d.buffer, offset, start - offset); - content = new Uint8Array(d.buffer, start, len); - buffer = content; - } - - // Constructed types - check for string concationation - if (sub !== null && tagClass === 0) { - var k; - switch (tagNumber) { - case 0x03: // BIT_STRING - k = 1; // ingnore unused bit for bit string - case 0x04: // OCTET_STRING - case 0x0C: // UTF8String - case 0x12: // NumericString - case 0x13: // PrintableString - case 0x14: // TeletexString - case 0x15: // VideotexString - case 0x16: // IA5String - case 0x19: // GraphicString - case 0x1A: // VisibleString - case 0x1B: // GeneralString - case 0x1C: // UniversalString - case 0x1E: // BMPString - k = k || 0; - // Concatination - if (sub.length === 0) - throw new DataError('No constructed encoding content of string type at offset ' + start); - len = k; - for (var i = 0, n = sub.length; i < n; i++) { - var s = sub[i]; - if (s.tagClass !== tagClass || s.tagNumber !== tagNumber || s.tagConstructed) - throw new DataError('Invalid constructed encoding of string type at offset ' + start); - len += s.content.length - k; - } - buffer = new Uint8Array(len); - for (var i = 0, n = sub.length, j = k; i < n; i++) { - var s = sub[i]; - if (k > 0) - buffer.set(s.content.subarray(1), j); - else - buffer.set(s.content, j); - j += s.content.length - k; - } - tagConstructed = false; // follow not required - sub = null; - break; - } - } - // Primitive types - var object = ''; - if (sub === null) { - if (len === null) - throw new DataError('Invalid tag with undefined length at offset ' + start); - - if (tagClass === 0) { - switch (tagNumber) { - case 0x01: // BOOLEAN - object = buffer[0] !== 0; - break; - case 0x02: // INTEGER - case 0x0a: // ENUMIRATED - if (len > 6) { - object = Int16.encode(buffer); - } else { - var v = buffer[0]; - if (buffer[0] > 0x7f) - v = v - 256; - for (var i = 1; i < len; i++) - v = v * 256 + buffer[i]; - object = v; - } - break; - case 0x03: // BIT_STRING - if (len > 5) { // Content buffer - object = new Uint8Array(buffer.subarray(1)).buffer; - } else { // Max bit mask only for 32 bit - var unusedBit = buffer[0], - skip = unusedBit, s = []; - for (var i = len - 1; i >= 1; --i) { - var b = buffer[i]; - for (var j = skip; j < 8; ++j) - s.push((b >> j) & 1 ? '1' : '0'); - skip = 0; - } - object = s.reverse().join(''); - } - break; - case 0x04: // OCTET_STRING - object = new Uint8Array(buffer).buffer; - break; - // case 0x05: // NULL - case 0x06: // OBJECT_IDENTIFIER - var s = '', - n = 0, - bits = 0; - for (var i = 0; i < len; ++i) { - var v = buffer[i]; - n = (n << 7) + (v & 0x7F); - bits += 7; - if (!(v & 0x80)) { // finished - if (s === '') { - var m = n < 80 ? n < 40 ? 0 : 1 : 2; - s = m + "." + (n - m * 40); - } else - s += "." + n.toString(); - n = 0; - bits = 0; - } - } - if (bits > 0) - throw new DataError('Incompleted OID at offset ' + start); - object = s; - break; - //case 0x07: // ObjectDescriptor - //case 0x08: // EXTERNAL - //case 0x09: // REAL - //case 0x0A: // ENUMERATED - //case 0x0B: // EMBEDDED_PDV - case 0x10: // SEQUENCE - case 0x11: // SET - object = []; - break; - case 0x0C: // UTF8String - object = Chars.encode(buffer, 'utf8'); - break; - case 0x12: // NumericString - case 0x13: // PrintableString - case 0x14: // TeletexString - case 0x15: // VideotexString - case 0x16: // IA5String - case 0x19: // GraphicString - case 0x1A: // VisibleString - case 0x1B: // GeneralString - object = Chars.encode(buffer, 'ascii'); - break; - case 0x1C: // UniversalString - object = Chars.encode(buffer, 'utf32'); - break; - case 0x1E: // BMPString - object = Chars.encode(buffer, 'utf16'); - break; - case 0x17: // UTCTime - case 0x18: // GeneralizedTime - var shortYear = tagNumber === 0x17; - var s = Chars.encode(buffer, 'ascii'), - m = (shortYear ? - /^(\d\d)(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])([01]\d|2[0-3])(?:([0-5]\d)(?:([0-5]\d)(?:[.,](\d{1,3}))?)?)?(Z|[-+](?:[0]\d|1[0-2])([0-5]\d)?)?$/ : - /^(\d\d\d\d)(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])([01]\d|2[0-3])(?:([0-5]\d)(?:([0-5]\d)(?:[.,](\d{1,3}))?)?)?(Z|[-+](?:[0]\d|1[0-2])([0-5]\d)?)?$/).exec(s); - if (!m) - throw new DataError('Unrecognized time format "' + s + '" at offset ' + start); - if (shortYear) { - // Where YY is greater than or equal to 50, the year SHALL be interpreted as 19YY; and - // Where YY is less than 50, the year SHALL be interpreted as 20YY - m[1] = +m[1]; - m[1] += (m[1] < 50) ? 2000 : 1900; - } - var dt = new Date(m[1], +m[2] - 1, +m[3], +(m[4] || '0'), +(m[5] || '0'), +(m[6] || '0'), +(m[7] || '0')), - tz = dt.getTimezoneOffset(); - if (m[8] || tagNumber === 0x17) { - if (m[8].toUpperCase() !== 'Z' && m[9]) { - tz = tz + parseInt(m[9]); - } - dt.setMinutes(dt.getMinutes() - tz); - } - dt.original = s; - object = dt; - break; - } - } else // OCTET_STRING - object = new Uint8Array(buffer).buffer; - } else - object = sub; - - // result - return { - tagConstructed: tagConstructed, - tagClass: tagClass, - tagNumber: tagNumber, - header: header, - content: content, - object: object - }; - } - - return { - /** - * BER.decode(object, format) convert javascript object to ASN.1 format CryptoOperationData

- * If object has members tagNumber, tagClass and tagConstructed - * it is clear define encoding rules. Else method use defaul rules: - *
    - *
  • Empty string or null - NULL
  • - *
  • String starts with '0x' and has 0-9 and a-f characters - INTEGER
  • - *
  • String like d.d.d.d (d - set of digits) - OBJECT IDENTIFIER
  • - *
  • String with characters 0 and 1 - BIT STRING
  • - *
  • Strings 'true' or 'false' - BOOLEAN
  • - *
  • String has only 0-9 and a-f characters - OCTET STRING
  • - *
  • String has only characters with code 0-255 - PrintableString
  • - *
  • Other strings - UTF8String
  • - *
  • Number - INTEGER
  • - *
  • Date - GeneralizedTime
  • - *
  • Boolean - SEQUENCE
  • - *
  • CryptoOperationData - OCTET STRING
  • - *
- * SEQUENCE or SET arrays recursively encoded for each item.
- * OCTET STRING and BIT STRING can presents as array with one item. - * It means encapsulates encoding for child element.
- * - * If CONTEXT or APPLICATION classes item presents as array with one - * item we use EXPLICIT encoding for element, else IMPLICIT encoding.
- * - * @memberOf GostCoding.BER - * @param {Object} object Object to encoding - * @param {string} format Encoding rule: 'DER' or 'CER', default 'DER' - * @param {boolean} onlyContent Encode content only, without header - * @returns {CryptoOperationData} BER encoded data - */ - encode: function (object, format, onlyContent) { - return encodeBER(object, format, onlyContent).buffer; - }, - /** - * BER.encode(data) convert ASN.1 format CryptoOperationData data to javascript object

- * - * Conversion rules to javascript object: - *
    - *
  • BOOLEAN - Boolean object
  • - *
  • INTEGER, ENUMIRATED - Integer object if len <= 6 (48 bits) else Int16 encoded string
  • - *
  • BIT STRING - Integer object if len <= 5 (w/o unsedBit octet - 32 bits) else String like '10111100' or Array with one item in case of incapsulates encoding
  • - *
  • OCTET STRING - Hex encoded string or Array with one item in case of incapsulates encoding
  • - *
  • OBJECT IDENTIFIER - String with object identifier
  • - *
  • SEQUENCE, SET - Array of encoded items
  • - *
  • UTF8String, NumericString, PrintableString, TeletexString, VideotexString, - * IA5String, GraphicString, VisibleString, GeneralString, UniversalString, - * BMPString - encoded String
  • - *
  • UTCTime, GeneralizedTime - Date
  • - *
- * @memberOf GostCoding.BER - * @param {(CryptoOperationData|GostCoding.BER)} data Binary data to decode - * @returns {Object} Javascript object with result of decoding - */ - decode: function (data) { - return decodeBER(data.object ? data : new Uint8Array(buffer(data)), 0); - } - }; //
- })(); - - /** - * BER, DER, CER conversion - * @memberOf GostCoding - * @insnance - * @type GostCoding.BER - */ - GostCoding.prototype.BER = BER; - - /** - * PEM conversion - * @class GostCoding.PEM - */ - var PEM = {// - /** - * PEM.encode(data, name) encode CryptoOperationData to PEM format with name label - * - * @memberOf GostCoding.PEM - * @param {(Object|CryptoOperationData)} data Java script object or BER-encoded binary data - * @param {string} name Name of PEM object: 'certificate', 'private key' etc. - * @returns {string} Encoded object - */ - encode: function (data, name) { - return (name ? '-----BEGIN ' + name.toUpperCase() + '-----\r\n' : '') + - Base64.encode(data instanceof CryptoOperationData ? data : BER.encode(data)) + - (name ? '\r\n-----END ' + name.toUpperCase() + '-----' : ''); - }, - /** - * PEM.decode(s, name, deep) decode PEM format s labeled name to CryptoOperationData or javascript object in according to deep parameter - * - * @memberOf GostCoding.PEM - * @param {string} s PEM encoded string - * @param {string} name Name of PEM object: 'certificate', 'private key' etc. - * @param {boolean} deep If true method do BER-decoding, else only BASE64 decoding - * @param {integer} index Index of decoded value - * @returns {(Object|CryptoOperationData)} Decoded javascript object if deep=true, else CryptoOperationData for father BER decoding - */ - decode: function (s, name, deep, index) { - // Try clear base64 - var re1 = /([A-Za-z0-9\+\/\s\=]+)/g, - valid = re1.exec(s); - if (valid[1].length !== s.length) - valid = false; - if (!valid && name) { - // Try with the name - var re2 = new RegExp( - '-----\\s?BEGIN ' + name.toUpperCase() + - '-----([A-Za-z0-9\\+\\/\\s\\=]+)-----\\s?END ' + - name.toUpperCase() + '-----', 'g'); - valid = re2.exec(s); - } - if (!valid) { - // Try with some name - var re3 = new RegExp( - '-----\\s?BEGIN [A-Z0-9\\s]+' + - '-----([A-Za-z0-9\\+\\/\\s\\=]+)-----\\s?END ' + - '[A-Z0-9\\s]+-----', 'g'); - valid = re3.exec(s); - } - var r = valid && valid[1 + (index || 0)]; - if (!r) - throw new DataError('Not valid PEM format'); - var out = Base64.decode(r); - if (deep) - out = BER.decode(out); - return out; - } // - }; - - /** - * PEM conversion - * @memberOf GostCoding - * @insnance - * @type GostCoding.PEM - */ - GostCoding.prototype.PEM = PEM; - - if (gostCrypto) - /** - * Coding algorithms: Base64, Hex, Int16, Chars, BER and PEM - * - * @memberOf gostCrypto - * @type GostCoding - */ - gostCrypto.coding = new GostCoding(); - - return GostCoding; - -})); \ No newline at end of file diff --git a/src/core/vendor/streebog/gostCoding.mjs b/src/core/vendor/streebog/gostCoding.mjs new file mode 100644 index 00000000..c9659d52 --- /dev/null +++ b/src/core/vendor/streebog/gostCoding.mjs @@ -0,0 +1,1160 @@ +/** + * Coding algorithms: Base64, Hex, Int16, Chars, BER and PEM + * version 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 gostCrypto from './gostCrypto'; + +/** + * The Coding interface provides string converting methods: Base64, Hex, + * Int16, Chars, BER and PEM + * @class GostCoding + * + */ // +var root = {}; +var DataError = Error; +var CryptoOperationData = ArrayBuffer; +var Date = Date; + +function buffer(d) { + if (d instanceof CryptoOperationData) + return d; + else if (d && d.buffer && 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'); +} // + +function GostCoding() { +} + +/** + * BASE64 conversion + * + * @class GostCoding.Base64 + */ +var Base64 = {// + /** + * Base64.decode convert BASE64 string s to CryptoOperationData + * + * @memberOf GostCoding.Base64 + * @param {String} s BASE64 encoded string value + * @returns {CryptoOperationData} Binary decoded data + */ + decode: function (s) { + s = s.replace(/[^A-Za-z0-9\+\/]/g, ''); + var n = s.length, + k = n * 3 + 1 >> 2, r = new Uint8Array(k); + + for (var m3, m4, u24 = 0, j = 0, i = 0; i < n; i++) { + m4 = i & 3; + var c = s.charCodeAt(i); + + c = c > 64 && c < 91 ? + c - 65 : c > 96 && c < 123 ? + c - 71 : c > 47 && c < 58 ? + c + 4 : c === 43 ? + 62 : c === 47 ? + 63 : 0; + + u24 |= c << 18 - 6 * m4; + if (m4 === 3 || n - i === 1) { + for (m3 = 0; m3 < 3 && j < k; m3++, j++) { + r[j] = u24 >>> (16 >>> m3 & 24) & 255; + } + u24 = 0; + + } + } + return r.buffer; + }, + /** + * Base64.encode(data) convert CryptoOperationData data to BASE64 string + * + * @memberOf GostCoding.Base64 + * @param {CryptoOperationData} data Bynary data for encoding + * @returns {String} BASE64 encoded data + */ + encode: function (data) { + var slen = 8, d = new Uint8Array(buffer(data)); + var m3 = 2, s = ''; + for (var n = d.length, u24 = 0, i = 0; i < n; i++) { + m3 = i % 3; + if (i > 0 && (i * 4 / 3) % (12 * slen) === 0) + s += '\r\n'; + u24 |= d[i] << (16 >>> m3 & 24); + if (m3 === 2 || n - i === 1) { + for (var j = 18; j >= 0; j -= 6) { + var c = u24 >>> j & 63; + c = c < 26 ? c + 65 : c < 52 ? c + 71 : c < 62 ? c - 4 : + c === 62 ? 43 : c === 63 ? 47 : 65; + s += String.fromCharCode(c); + } + u24 = 0; + } + } + return s.substr(0, s.length - 2 + m3) + (m3 === 2 ? '' : m3 === 1 ? '=' : '=='); + } // +}; + +/** + * BASE64 conversion + * + * @memberOf GostCoding + * @insnance + * @type GostCoding.Base64 + */ +GostCoding.prototype.Base64 = Base64; + +/** + * Text string conversion
+ * Methods support charsets: ascii, win1251, utf8, utf16 (ucs2, unicode), utf32 (ucs4) + * + * @class GostCoding.Chars + */ +var Chars = (function () { // + + var _win1251_ = { + 0x402: 0x80, 0x403: 0x81, 0x201A: 0x82, 0x453: 0x83, 0x201E: 0x84, 0x2026: 0x85, 0x2020: 0x86, 0x2021: 0x87, + 0x20AC: 0x88, 0x2030: 0x89, 0x409: 0x8A, 0x2039: 0x8B, 0x40A: 0x8C, 0x40C: 0x8D, 0x40B: 0x8E, 0x40f: 0x8f, + 0x452: 0x90, 0x2018: 0x91, 0x2019: 0x92, 0x201C: 0x93, 0x201D: 0x94, 0x2022: 0x95, 0x2013: 0x96, 0x2014: 0x97, + 0x2122: 0x99, 0x459: 0x9A, 0x203A: 0x9B, 0x45A: 0x9C, 0x45C: 0x9D, 0x45B: 0x9E, 0x45f: 0x9f, + 0xA0: 0xA0, 0x40E: 0xA1, 0x45E: 0xA2, 0x408: 0xA3, 0xA4: 0xA4, 0x490: 0xA5, 0xA6: 0xA6, 0xA7: 0xA7, + 0x401: 0xA8, 0xA9: 0xA9, 0x404: 0xAA, 0xAB: 0xAB, 0xAC: 0xAC, 0xAD: 0xAD, 0xAE: 0xAE, 0x407: 0xAf, + 0xB0: 0xB0, 0xB1: 0xB1, 0x406: 0xB2, 0x456: 0xB3, 0x491: 0xB4, 0xB5: 0xB5, 0xB6: 0xB6, 0xB7: 0xB7, + 0x451: 0xB8, 0x2116: 0xB9, 0x454: 0xBA, 0xBB: 0xBB, 0x458: 0xBC, 0x405: 0xBD, 0x455: 0xBE, 0x457: 0xBf + }; + var _win1251back_ = {}; + for (var from in _win1251_) { + var to = _win1251_[from]; + _win1251back_[to] = from; + } + + return { + /** + * Chars.decode(s, charset) convert string s with defined charset to CryptoOperationData + * + * @memberOf GostCoding.Chars + * @param {string} s Javascript string + * @param {string} charset Charset, default 'win1251' + * @returns {CryptoOperationData} Decoded binary data + */ + decode: function (s, charset) { + charset = (charset || 'win1251').toLowerCase().replace('-', ''); + var r = []; + for (var i = 0, j = s.length; i < j; i++) { + var c = s.charCodeAt(i); + if (charset === 'utf8') { + if (c < 0x80) { + r.push(c); + } else if (c < 0x800) { + r.push(0xc0 + (c >>> 6)); + r.push(0x80 + (c & 63)); + } else if (c < 0x10000) { + r.push(0xe0 + (c >>> 12)); + r.push(0x80 + (c >>> 6 & 63)); + r.push(0x80 + (c & 63)); + } else if (c < 0x200000) { + r.push(0xf0 + (c >>> 18)); + r.push(0x80 + (c >>> 12 & 63)); + r.push(0x80 + (c >>> 6 & 63)); + r.push(0x80 + (c & 63)); + } else if (c < 0x4000000) { + r.push(0xf8 + (c >>> 24)); + r.push(0x80 + (c >>> 18 & 63)); + r.push(0x80 + (c >>> 12 & 63)); + r.push(0x80 + (c >>> 6 & 63)); + r.push(0x80 + (c & 63)); + } else { + r.push(0xfc + (c >>> 30)); + r.push(0x80 + (c >>> 24 & 63)); + r.push(0x80 + (c >>> 18 & 63)); + r.push(0x80 + (c >>> 12 & 63)); + r.push(0x80 + (c >>> 6 & 63)); + r.push(0x80 + (c & 63)); + } + } else if (charset === 'unicode' || charset === 'ucs2' || charset === 'utf16') { + if (c < 0xD800 || (c >= 0xE000 && c <= 0x10000)) { + r.push(c >>> 8); + r.push(c & 0xff); + } else if (c >= 0x10000 && c < 0x110000) { + c -= 0x10000; + var first = ((0xffc00 & c) >> 10) + 0xD800; + var second = (0x3ff & c) + 0xDC00; + r.push(first >>> 8); + r.push(first & 0xff); + r.push(second >>> 8); + r.push(second & 0xff); + } + } else if (charset === 'utf32' || charset === 'ucs4') { + r.push(c >>> 24 & 0xff); + r.push(c >>> 16 & 0xff); + r.push(c >>> 8 & 0xff); + r.push(c & 0xff); + } else if (charset === 'win1251') { + if (c >= 0x80) { + if (c >= 0x410 && c < 0x450) // А..Яа..я + c -= 0x350; + else + c = _win1251_[c] || 0; + } + r.push(c); + } else + r.push(c & 0xff); + } + return new Uint8Array(r).buffer; + }, + /** + * Chars.encode(data, charset) convert CryptoOperationData data to string with defined charset + * + * @memberOf GostCoding.Chars + * @param {CryptoOperationData} data Binary data + * @param {string} charset Charset, default win1251 + * @returns {string} Encoded javascript string + */ + encode: function (data, charset) { + charset = (charset || 'win1251').toLowerCase().replace('-', ''); + var r = [], d = new Uint8Array(buffer(data)); + for (var i = 0, n = d.length; i < n; i++) { + var c = d[i]; + if (charset === 'utf8') { + c = c >= 0xfc && c < 0xfe && i + 5 < n ? // six bytes + (c - 0xfc) * 1073741824 + (d[++i] - 0x80 << 24) + (d[++i] - 0x80 << 18) + (d[++i] - 0x80 << 12) + (d[++i] - 0x80 << 6) + d[++i] - 0x80 + : c >> 0xf8 && c < 0xfc && i + 4 < n ? // five bytes + (c - 0xf8 << 24) + (d[++i] - 0x80 << 18) + (d[++i] - 0x80 << 12) + (d[++i] - 0x80 << 6) + d[++i] - 0x80 + : c >> 0xf0 && c < 0xf8 && i + 3 < n ? // four bytes + (c - 0xf0 << 18) + (d[++i] - 0x80 << 12) + (d[++i] - 0x80 << 6) + d[++i] - 0x80 + : c >= 0xe0 && c < 0xf0 && i + 2 < n ? // three bytes + (c - 0xe0 << 12) + (d[++i] - 0x80 << 6) + d[++i] - 0x80 + : c >= 0xc0 && c < 0xe0 && i + 1 < n ? // two bytes + (c - 0xc0 << 6) + d[++i] - 0x80 + : c; // one byte + } else if (charset === 'unicode' || charset === 'ucs2' || charset === 'utf16') { + c = (c << 8) + d[++i]; + if (c >= 0xD800 && c < 0xE000) { + var first = (c - 0xD800) << 10; + c = d[++i]; + c = (c << 8) + d[++i]; + var second = c - 0xDC00; + c = first + second + 0x10000; + } + } else if (charset === 'utf32' || charset === 'ucs4') { + c = (c << 8) + d[++i]; + c = (c << 8) + d[++i]; + c = (c << 8) + d[++i]; + } else if (charset === 'win1251') { + if (c >= 0x80) { + if (c >= 0xC0 && c < 0x100) + c += 0x350; // А..Яа..я + else + c = _win1251back_[c] || 0; + } + } + r.push(String.fromCharCode(c)); + } + return r.join(''); + } + }; // +})(); + +/** + * Text string conversion + * + * @memberOf GostCoding + * @insnance + * @type GostCoding.Chars + */ +GostCoding.prototype.Chars = Chars; + +/** + * HEX conversion + * + * @class GostCoding.Hex + */ +var Hex = {// + /** + * Hex.decode(s, endean) convert HEX string s to CryptoOperationData in endean mode + * + * @memberOf GostCoding.Hex + * @param {string} s Hex encoded string + * @param {boolean} endean Little or Big Endean, default Little + * @returns {CryptoOperationData} Decoded binary data + */ + decode: function (s, endean) { + s = s.replace(/[^A-fa-f0-9]/g, ''); + var n = Math.ceil(s.length / 2), r = new Uint8Array(n); + s = (s.length % 2 > 0 ? '0' : '') + s; + if (endean && ((typeof endean !== 'string') || + (endean.toLowerCase().indexOf('little') < 0))) + for (var i = 0; i < n; i++) + r[i] = parseInt(s.substr((n - i - 1) * 2, 2), 16); + else + for (var i = 0; i < n; i++) + r[i] = parseInt(s.substr(i * 2, 2), 16); + return r.buffer; + }, + /** + * Hex.encode(data, endean) convert CryptoOperationData data to HEX string in endean mode + * + * @memberOf GostCoding.Hex + * @param {CryptoOperationData} data Binary data + * @param {boolean} endean Little/Big Endean, default Little + * @returns {string} Hex decoded string + */ + encode: function (data, endean) { + var s = [], d = new Uint8Array(buffer(data)), n = d.length; + if (endean && ((typeof endean !== 'string') || + (endean.toLowerCase().indexOf('little') < 0))) + for (var i = 0; i < n; i++) { + var j = n - i - 1; + s[j] = (j > 0 && j % 32 === 0 ? '\r\n' : '') + + ('00' + d[i].toString(16)).slice(-2); + } + else + for (var i = 0; i < n; i++) + s[i] = (i > 0 && i % 32 === 0 ? '\r\n' : '') + + ('00' + d[i].toString(16)).slice(-2); + return s.join(''); + } // +}; + +/** + * HEX conversion + * @memberOf GostCoding + * @insnance + * @type GostCoding.Hex + */ +GostCoding.prototype.Hex = Hex; + +/** + * String hex-encoded integer conversion + * + * @class GostCoding.Int16 + */ +var Int16 = {// + /** + * Int16.decode(s) convert hex big insteger s to CryptoOperationData + * + * @memberOf GostCoding.Int16 + * @param {string} s Int16 string + * @returns {CryptoOperationData} Decoded binary data + */ + decode: function (s) { + s = (s || '').replace(/[^\-A-fa-f0-9]/g, ''); + if (s.length === 0) + s = '0'; + // Signature + var neg = false; + if (s.charAt(0) === '-') { + neg = true; + s = s.substring(1); + } + // Align 2 chars + while (s.charAt(0) === '0' && s.length > 1) + s = s.substring(1); + s = (s.length % 2 > 0 ? '0' : '') + s; + // Padding for singanuture + // '800000' - 'ffffff' - for positive + // '800001' - 'ffffff' - for negative + if ((!neg && !/^[0-7]/.test(s)) || + (neg && !/^[0-7]|8[0]+$/.test(s))) + s = '00' + s; + // Convert hex + var n = s.length / 2, r = new Uint8Array(n), t = 0; + for (var i = n - 1; i >= 0; --i) { + var c = parseInt(s.substr(i * 2, 2), 16); + if (neg && (c + t > 0)) { + c = 256 - c - t; + t = 1; + } + r[i] = c; + } + return r.buffer; + }, + /** + * Int16.encode(data) convert CryptoOperationData data to big integer hex string + * + * @memberOf GostCoding.Int16 + * @param {CryptoOperationData} data Binary data + * @returns {string} Int16 encoded string + */ + encode: function (data) { + var d = new Uint8Array(buffer(data)), n = d.length; + if (d.length === 0) + return '0x00'; + var s = [], neg = d[0] > 0x7f, t = 0; + for (var i = n - 1; i >= 0; --i) { + var v = d[i]; + if (neg && (v + t > 0)) { + v = 256 - v - t; + t = 1; + } + s[i] = ('00' + v.toString(16)).slice(-2); + } + s = s.join(''); + while (s.charAt(0) === '0') + s = s.substring(1); + return (neg ? '-' : '') + '0x' + s; + } // +}; + +/** + * String hex-encoded integer conversion + * @memberOf GostCoding + * @insnance + * @type GostCoding.Int16 + */ +GostCoding.prototype.Int16 = Int16; + +/** + * BER, DER, CER conversion + * + * @class GostCoding.BER + */ +var BER = (function () { // + + // Predefenition block + function encodeBER(source, format, onlyContent) { + // Correct primitive type + var object = source.object; + if (object === undefined) + object = source; + + // Determinate tagClass + var tagClass = source.tagClass = source.tagClass || 0; // Universial default + + // Determinate tagNumber. Use only for Universal class + if (tagClass === 0) { + var tagNumber = source.tagNumber; + if (typeof tagNumber === 'undefined') { + if (typeof object === 'string') { + if (object === '') // NULL + tagNumber = 0x05; + else if (/^\-?0x[0-9a-fA-F]+$/.test(object)) // INTEGER + tagNumber = 0x02; + else if (/^(\d+\.)+\d+$/.test(object)) // OID + tagNumber = 0x06; + else if (/^[01]+$/.test(object)) // BIT STRING + tagNumber = 0x03; + else if (/^(true|false)$/.test(object)) // BOOLEAN + tagNumber = 0x01; + else if (/^[0-9a-fA-F]+$/.test(object)) // OCTET STRING + tagNumber = 0x04; + else + tagNumber = 0x13; // Printable string (later can be changed to UTF8String) + } else if (typeof object === 'number') { // INTEGER + tagNumber = 0x02; + } else if (typeof object === 'boolean') { // BOOLEAN + tagNumber = 0x01; + } else if (object instanceof Array) { // SEQUENCE + tagNumber = 0x10; + } else if (object instanceof Date) { // GeneralizedTime + tagNumber = 0x18; + } else if (object instanceof CryptoOperationData || (object && object.buffer instanceof CryptoOperationData)) { + tagNumber = 0x04; + } else + throw new DataError('Unrecognized type for ' + object); + } + } + + // Determinate constructed + var tagConstructed = source.tagConstructed; + if (typeof tagConstructed === 'undefined') + tagConstructed = source.tagConstructed = object instanceof Array; + + // Create content + var content; + if (object instanceof CryptoOperationData || (object && object.buffer instanceof CryptoOperationData)) { // Direct + content = new Uint8Array(buffer(object)); + if (tagNumber === 0x03) { // BITSTRING + // Set unused bits + var a = new Uint8Array(buffer(content)); + content = new Uint8Array(a.length + 1); + content[0] = 0; // No unused bits + content.set(a, 1); + } + } else if (tagConstructed) { // Sub items coding + if (object instanceof Array) { + var bytelen = 0, ba = [], offset = 0; + for (var i = 0, n = object.length; i < n; i++) { + ba[i] = encodeBER(object[i], format); + bytelen += ba[i].length; + } + if (tagNumber === 0x11) + ba.sort(function (a, b) { // Sort order for SET components + for (var i = 0, n = Math.min(a.length, b.length); i < n; i++) { + var r = a[i] - b[i]; + if (r !== 0) + return r; + } + return a.length - b.length; + }); + if (format === 'CER') { // final for CER 00 00 + ba[n] = new Uint8Array(2); + bytelen += 2; + } + content = new Uint8Array(bytelen); + for (var i = 0, n = ba.length; i < n; i++) { + content.set(ba[i], offset); + offset = offset + ba[i].length; + } + } else + throw new DataError('Constracted block can\'t be primitive'); + } else { + switch (tagNumber) { + // 0x00: // EOC + case 0x01: // BOOLEAN + content = new Uint8Array(1); + content[0] = object ? 0xff : 0; + break; + case 0x02: // INTEGER + case 0x0a: // ENUMIRATED + content = Int16.decode( + typeof object === 'number' ? object.toString(16) : object); + break; + case 0x03: // BIT STRING + if (typeof object === 'string') { + var unusedBits = 7 - (object.length + 7) % 8; + var n = Math.ceil(object.length / 8); + content = new Uint8Array(n + 1); + content[0] = unusedBits; + for (var i = 0; i < n; i++) { + var c = 0; + for (var j = 0; j < 8; j++) { + var k = i * 8 + j; + c = (c << 1) + (k < object.length ? (object.charAt(k) === '1' ? 1 : 0) : 0); + } + content[i + 1] = c; + } + } + break; + case 0x04: + content = Hex.decode( + typeof object === 'number' ? object.toString(16) : object); + break; + // case 0x05: // NULL + case 0x06: // OBJECT IDENTIFIER + var a = object.match(/\d+/g), r = []; + for (var i = 1; i < a.length; i++) { + var n = +a[i], r1 = []; + if (i === 1) + n = n + a[0] * 40; + do { + r1.push(n & 0x7F); + n = n >>> 7; + } while (n); + // reverse order + for (j = r1.length - 1; j >= 0; --j) + r.push(r1[j] + (j === 0 ? 0x00 : 0x80)); + } + content = new Uint8Array(r); + break; + // case 0x07: // ObjectDescriptor + // case 0x08: // EXTERNAL + // case 0x09: // REAL + // case 0x0A: // ENUMERATED + // case 0x0B: // EMBEDDED PDV + case 0x0C: // UTF8String + content = Chars.decode(object, 'utf8'); + break; + // case 0x10: // SEQUENCE + // case 0x11: // SET + case 0x12: // NumericString + case 0x16: // IA5String // ASCII + case 0x13: // PrintableString // ASCII subset + case 0x14: // TeletexString // aka T61String + case 0x15: // VideotexString + case 0x19: // GraphicString + case 0x1A: // VisibleString // ASCII subset + case 0x1B: // GeneralString + // Reflect on character encoding + for (var i = 0, n = object.length; i < n; i++) + if (object.charCodeAt(i) > 255) + tagNumber = 0x0C; + if (tagNumber === 0x0C) + content = Chars.decode(object, 'utf8'); + else + content = Chars.decode(object, 'ascii'); + break; + case 0x17: // UTCTime + case 0x18: // GeneralizedTime + var result = object.original; + if (!result) { + var date = new Date(object); + date.setMinutes(date.getMinutes() + date.getTimezoneOffset()); // to UTC + var ms = tagNumber === 0x18 ? date.getMilliseconds().toString() : ''; // Milliseconds, remove trailing zeros + while (ms.length > 0 && ms.charAt(ms.length - 1) === '0') + ms = ms.substring(0, ms.length - 1); + if (ms.length > 0) + ms = '.' + ms; + result = (tagNumber === 0x17 ? date.getYear().toString().slice(-2) : date.getFullYear().toString()) + + ('00' + (date.getMonth() + 1)).slice(-2) + + ('00' + date.getDate()).slice(-2) + + ('00' + date.getHours()).slice(-2) + + ('00' + date.getMinutes()).slice(-2) + + ('00' + date.getSeconds()).slice(-2) + ms + 'Z'; + } + content = Chars.decode(result, 'ascii'); + break; + case 0x1C: // UniversalString + content = Chars.decode(object, 'utf32'); + break; + case 0x1E: // BMPString + content = Chars.decode(object, 'utf16'); + break; + } + } + + if (!content) + content = new Uint8Array(0); + if (content instanceof CryptoOperationData) + content = new Uint8Array(content); + + if (!tagConstructed && format === 'CER') { + // Encoding CER-form for string types + var k; + switch (tagNumber) { + case 0x03: // BIT_STRING + k = 1; // ingnore unused bit for bit string + case 0x04: // OCTET_STRING + case 0x0C: // UTF8String + case 0x12: // NumericString + case 0x13: // PrintableString + case 0x14: // TeletexString + case 0x15: // VideotexString + case 0x16: // IA5String + case 0x19: // GraphicString + case 0x1A: // VisibleString + case 0x1B: // GeneralString + case 0x1C: // UniversalString + case 0x1E: // BMPString + k = k || 0; + // Split content on 1000 octet len parts + var size = 1000; + var bytelen = 0, ba = [], offset = 0; + for (var i = k, n = content.length; i < n; i += size - k) { + ba[i] = encodeBER({ + object: new Unit8Array(content.buffer, i, Math.min(size - k, n - i)), + tagNumber: tagNumber, + tagClass: 0, + tagConstructed: false + }, format); + bytelen += ba[i].length; + } + ba[n] = new Uint8Array(2); // final for CER 00 00 + bytelen += 2; + content = new Uint8Array(bytelen); + for (var i = 0, n = ba.length; i < n; i++) { + content.set(ba[i], offset); + offset = offset + ba[i].length; + } + } + } + + // Restore tagNumber for all classes + if (tagClass === 0) + source.tagNumber = tagNumber; + else + source.tagNumber = tagNumber = source.tagNumber || 0; + source.content = content; + + if (onlyContent) + return content; + + // Create header + // tagNumber + var ha = [], first = tagClass === 3 ? 0xC0 : tagClass === 2 ? 0x80 : + tagClass === 1 ? 0x40 : 0x00; + if (tagConstructed) + first |= 0x20; + if (tagNumber < 0x1F) { + first |= tagNumber & 0x1F; + ha.push(first); + } else { + first |= 0x1F; + ha.push(first); + var n = tagNumber, ha1 = []; + do { + ha1.push(n & 0x7F); + n = n >>> 7; + } while (n) + // reverse order + for (var j = ha1.length - 1; j >= 0; --j) + ha.push(ha1[j] + (j === 0 ? 0x00 : 0x80)); + } + // Length + if (tagConstructed && format === 'CER') { + ha.push(0x80); + } else { + var len = content.length; + if (len > 0x7F) { + var l2 = len, ha2 = []; + do { + ha2.push(l2 & 0xff); + l2 = l2 >>> 8; + } while (l2); + ha.push(ha2.length + 0x80); // reverse order + for (var j = ha2.length - 1; j >= 0; --j) + ha.push(ha2[j]); + } else { + // simple len + ha.push(len); + } + } + var header = source.header = new Uint8Array(ha); + + // Result - complete buffer + var block = new Uint8Array(header.length + content.length); + block.set(header, 0); + block.set(content, header.length); + return block; + } + + function decodeBER(source, offset) { + + // start pos + var pos = offset || 0, start = pos; + var tagNumber, tagClass, tagConstructed, + content, header, buffer, sub, len; + + if (source.object) { + // Ready from source + tagNumber = source.tagNumber; + tagClass = source.tagClass; + tagConstructed = source.tagConstructed; + content = source.content; + header = source.header; + buffer = source.object instanceof CryptoOperationData ? + new Uint8Array(source.object) : null; + sub = source.object instanceof Array ? source.object : null; + len = buffer && buffer.length || null; + } else { + // Decode header + var d = source; + + // Read tag + var buf = d[pos++]; + tagNumber = buf & 0x1f; + tagClass = buf >> 6; + tagConstructed = (buf & 0x20) !== 0; + if (tagNumber === 0x1f) { // long tag + tagNumber = 0; + do { + if (tagNumber > 0x1fffffffffff80) + throw new DataError('Convertor not supported tag number more then (2^53 - 1) at position ' + offset); + buf = d[pos++]; + tagNumber = (tagNumber << 7) + (buf & 0x7f); + } while (buf & 0x80); + } + + // Read len + buf = d[pos++]; + len = buf & 0x7f; + if (len !== buf) { + if (len > 6) // no reason to use Int10, as it would be a huge buffer anyways + throw new DataError('Length over 48 bits not supported at position ' + offset); + if (len === 0) + len = null; // undefined + else { + buf = 0; + for (var i = 0; i < len; ++i) + buf = (buf << 8) + d[pos++]; + len = buf; + } + } + + start = pos; + sub = null; + + if (tagConstructed) { + // must have valid content + sub = []; + if (len !== null) { + // definite length + var end = start + len; + while (pos < end) { + var s = decodeBER(d, pos); + sub.push(s); + pos += s.header.length + s.content.length; + } + if (pos !== end) + throw new DataError('Content size is not correct for container starting at offset ' + start); + } else { + // undefined length + try { + for (; ; ) { + var s = decodeBER(d, pos); + pos += s.header.length + s.content.length; + if (s.tagClass === 0x00 && s.tagNumber === 0x00) + break; + sub.push(s); + } + len = pos - start; + } catch (e) { + throw new DataError('Exception ' + e + ' while decoding undefined length content at offset ' + start); + } + } + } + + // Header and content + header = new Uint8Array(d.buffer, offset, start - offset); + content = new Uint8Array(d.buffer, start, len); + buffer = content; + } + + // Constructed types - check for string concationation + if (sub !== null && tagClass === 0) { + var k; + switch (tagNumber) { + case 0x03: // BIT_STRING + k = 1; // ingnore unused bit for bit string + case 0x04: // OCTET_STRING + case 0x0C: // UTF8String + case 0x12: // NumericString + case 0x13: // PrintableString + case 0x14: // TeletexString + case 0x15: // VideotexString + case 0x16: // IA5String + case 0x19: // GraphicString + case 0x1A: // VisibleString + case 0x1B: // GeneralString + case 0x1C: // UniversalString + case 0x1E: // BMPString + k = k || 0; + // Concatination + if (sub.length === 0) + throw new DataError('No constructed encoding content of string type at offset ' + start); + len = k; + for (var i = 0, n = sub.length; i < n; i++) { + var s = sub[i]; + if (s.tagClass !== tagClass || s.tagNumber !== tagNumber || s.tagConstructed) + throw new DataError('Invalid constructed encoding of string type at offset ' + start); + len += s.content.length - k; + } + buffer = new Uint8Array(len); + for (var i = 0, n = sub.length, j = k; i < n; i++) { + var s = sub[i]; + if (k > 0) + buffer.set(s.content.subarray(1), j); + else + buffer.set(s.content, j); + j += s.content.length - k; + } + tagConstructed = false; // follow not required + sub = null; + break; + } + } + // Primitive types + var object = ''; + if (sub === null) { + if (len === null) + throw new DataError('Invalid tag with undefined length at offset ' + start); + + if (tagClass === 0) { + switch (tagNumber) { + case 0x01: // BOOLEAN + object = buffer[0] !== 0; + break; + case 0x02: // INTEGER + case 0x0a: // ENUMIRATED + if (len > 6) { + object = Int16.encode(buffer); + } else { + var v = buffer[0]; + if (buffer[0] > 0x7f) + v = v - 256; + for (var i = 1; i < len; i++) + v = v * 256 + buffer[i]; + object = v; + } + break; + case 0x03: // BIT_STRING + if (len > 5) { // Content buffer + object = new Uint8Array(buffer.subarray(1)).buffer; + } else { // Max bit mask only for 32 bit + var unusedBit = buffer[0], + skip = unusedBit, s = []; + for (var i = len - 1; i >= 1; --i) { + var b = buffer[i]; + for (var j = skip; j < 8; ++j) + s.push((b >> j) & 1 ? '1' : '0'); + skip = 0; + } + object = s.reverse().join(''); + } + break; + case 0x04: // OCTET_STRING + object = new Uint8Array(buffer).buffer; + break; + // case 0x05: // NULL + case 0x06: // OBJECT_IDENTIFIER + var s = '', + n = 0, + bits = 0; + for (var i = 0; i < len; ++i) { + var v = buffer[i]; + n = (n << 7) + (v & 0x7F); + bits += 7; + if (!(v & 0x80)) { // finished + if (s === '') { + var m = n < 80 ? n < 40 ? 0 : 1 : 2; + s = m + "." + (n - m * 40); + } else + s += "." + n.toString(); + n = 0; + bits = 0; + } + } + if (bits > 0) + throw new DataError('Incompleted OID at offset ' + start); + object = s; + break; + //case 0x07: // ObjectDescriptor + //case 0x08: // EXTERNAL + //case 0x09: // REAL + //case 0x0A: // ENUMERATED + //case 0x0B: // EMBEDDED_PDV + case 0x10: // SEQUENCE + case 0x11: // SET + object = []; + break; + case 0x0C: // UTF8String + object = Chars.encode(buffer, 'utf8'); + break; + case 0x12: // NumericString + case 0x13: // PrintableString + case 0x14: // TeletexString + case 0x15: // VideotexString + case 0x16: // IA5String + case 0x19: // GraphicString + case 0x1A: // VisibleString + case 0x1B: // GeneralString + object = Chars.encode(buffer, 'ascii'); + break; + case 0x1C: // UniversalString + object = Chars.encode(buffer, 'utf32'); + break; + case 0x1E: // BMPString + object = Chars.encode(buffer, 'utf16'); + break; + case 0x17: // UTCTime + case 0x18: // GeneralizedTime + var shortYear = tagNumber === 0x17; + var s = Chars.encode(buffer, 'ascii'), + m = (shortYear ? + /^(\d\d)(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])([01]\d|2[0-3])(?:([0-5]\d)(?:([0-5]\d)(?:[.,](\d{1,3}))?)?)?(Z|[-+](?:[0]\d|1[0-2])([0-5]\d)?)?$/ : + /^(\d\d\d\d)(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])([01]\d|2[0-3])(?:([0-5]\d)(?:([0-5]\d)(?:[.,](\d{1,3}))?)?)?(Z|[-+](?:[0]\d|1[0-2])([0-5]\d)?)?$/).exec(s); + if (!m) + throw new DataError('Unrecognized time format "' + s + '" at offset ' + start); + if (shortYear) { + // Where YY is greater than or equal to 50, the year SHALL be interpreted as 19YY; and + // Where YY is less than 50, the year SHALL be interpreted as 20YY + m[1] = +m[1]; + m[1] += (m[1] < 50) ? 2000 : 1900; + } + var dt = new Date(m[1], +m[2] - 1, +m[3], +(m[4] || '0'), +(m[5] || '0'), +(m[6] || '0'), +(m[7] || '0')), + tz = dt.getTimezoneOffset(); + if (m[8] || tagNumber === 0x17) { + if (m[8].toUpperCase() !== 'Z' && m[9]) { + tz = tz + parseInt(m[9]); + } + dt.setMinutes(dt.getMinutes() - tz); + } + dt.original = s; + object = dt; + break; + } + } else // OCTET_STRING + object = new Uint8Array(buffer).buffer; + } else + object = sub; + + // result + return { + tagConstructed: tagConstructed, + tagClass: tagClass, + tagNumber: tagNumber, + header: header, + content: content, + object: object + }; + } + + return { + /** + * BER.decode(object, format) convert javascript object to ASN.1 format CryptoOperationData

+ * If object has members tagNumber, tagClass and tagConstructed + * it is clear define encoding rules. Else method use defaul rules: + *
    + *
  • Empty string or null - NULL
  • + *
  • String starts with '0x' and has 0-9 and a-f characters - INTEGER
  • + *
  • String like d.d.d.d (d - set of digits) - OBJECT IDENTIFIER
  • + *
  • String with characters 0 and 1 - BIT STRING
  • + *
  • Strings 'true' or 'false' - BOOLEAN
  • + *
  • String has only 0-9 and a-f characters - OCTET STRING
  • + *
  • String has only characters with code 0-255 - PrintableString
  • + *
  • Other strings - UTF8String
  • + *
  • Number - INTEGER
  • + *
  • Date - GeneralizedTime
  • + *
  • Boolean - SEQUENCE
  • + *
  • CryptoOperationData - OCTET STRING
  • + *
+ * SEQUENCE or SET arrays recursively encoded for each item.
+ * OCTET STRING and BIT STRING can presents as array with one item. + * It means encapsulates encoding for child element.
+ * + * If CONTEXT or APPLICATION classes item presents as array with one + * item we use EXPLICIT encoding for element, else IMPLICIT encoding.
+ * + * @memberOf GostCoding.BER + * @param {Object} object Object to encoding + * @param {string} format Encoding rule: 'DER' or 'CER', default 'DER' + * @param {boolean} onlyContent Encode content only, without header + * @returns {CryptoOperationData} BER encoded data + */ + encode: function (object, format, onlyContent) { + return encodeBER(object, format, onlyContent).buffer; + }, + /** + * BER.encode(data) convert ASN.1 format CryptoOperationData data to javascript object

+ * + * Conversion rules to javascript object: + *
    + *
  • BOOLEAN - Boolean object
  • + *
  • INTEGER, ENUMIRATED - Integer object if len <= 6 (48 bits) else Int16 encoded string
  • + *
  • BIT STRING - Integer object if len <= 5 (w/o unsedBit octet - 32 bits) else String like '10111100' or Array with one item in case of incapsulates encoding
  • + *
  • OCTET STRING - Hex encoded string or Array with one item in case of incapsulates encoding
  • + *
  • OBJECT IDENTIFIER - String with object identifier
  • + *
  • SEQUENCE, SET - Array of encoded items
  • + *
  • UTF8String, NumericString, PrintableString, TeletexString, VideotexString, + * IA5String, GraphicString, VisibleString, GeneralString, UniversalString, + * BMPString - encoded String
  • + *
  • UTCTime, GeneralizedTime - Date
  • + *
+ * @memberOf GostCoding.BER + * @param {(CryptoOperationData|GostCoding.BER)} data Binary data to decode + * @returns {Object} Javascript object with result of decoding + */ + decode: function (data) { + return decodeBER(data.object ? data : new Uint8Array(buffer(data)), 0); + } + }; //
+})(); + +/** + * BER, DER, CER conversion + * @memberOf GostCoding + * @insnance + * @type GostCoding.BER + */ +GostCoding.prototype.BER = BER; + +/** + * PEM conversion + * @class GostCoding.PEM + */ +var PEM = {// + /** + * PEM.encode(data, name) encode CryptoOperationData to PEM format with name label + * + * @memberOf GostCoding.PEM + * @param {(Object|CryptoOperationData)} data Java script object or BER-encoded binary data + * @param {string} name Name of PEM object: 'certificate', 'private key' etc. + * @returns {string} Encoded object + */ + encode: function (data, name) { + return (name ? '-----BEGIN ' + name.toUpperCase() + '-----\r\n' : '') + + Base64.encode(data instanceof CryptoOperationData ? data : BER.encode(data)) + + (name ? '\r\n-----END ' + name.toUpperCase() + '-----' : ''); + }, + /** + * PEM.decode(s, name, deep) decode PEM format s labeled name to CryptoOperationData or javascript object in according to deep parameter + * + * @memberOf GostCoding.PEM + * @param {string} s PEM encoded string + * @param {string} name Name of PEM object: 'certificate', 'private key' etc. + * @param {boolean} deep If true method do BER-decoding, else only BASE64 decoding + * @param {integer} index Index of decoded value + * @returns {(Object|CryptoOperationData)} Decoded javascript object if deep=true, else CryptoOperationData for father BER decoding + */ + decode: function (s, name, deep, index) { + // Try clear base64 + var re1 = /([A-Za-z0-9\+\/\s\=]+)/g, + valid = re1.exec(s); + if (valid[1].length !== s.length) + valid = false; + if (!valid && name) { + // Try with the name + var re2 = new RegExp( + '-----\\s?BEGIN ' + name.toUpperCase() + + '-----([A-Za-z0-9\\+\\/\\s\\=]+)-----\\s?END ' + + name.toUpperCase() + '-----', 'g'); + valid = re2.exec(s); + } + if (!valid) { + // Try with some name + var re3 = new RegExp( + '-----\\s?BEGIN [A-Z0-9\\s]+' + + '-----([A-Za-z0-9\\+\\/\\s\\=]+)-----\\s?END ' + + '[A-Z0-9\\s]+-----', 'g'); + valid = re3.exec(s); + } + var r = valid && valid[1 + (index || 0)]; + if (!r) + throw new DataError('Not valid PEM format'); + var out = Base64.decode(r); + if (deep) + out = BER.decode(out); + return out; + } // +}; + +/** + * PEM conversion + * @memberOf GostCoding + * @insnance + * @type GostCoding.PEM + */ +GostCoding.prototype.PEM = PEM; + +if (gostCrypto) + /** + * Coding algorithms: Base64, Hex, Int16, Chars, BER and PEM + * + * @memberOf gostCrypto + * @type GostCoding + */ + gostCrypto.coding = new GostCoding(); + +export default GostCoding; \ No newline at end of file diff --git a/src/core/vendor/streebog/gostCrypto.js b/src/core/vendor/streebog/gostCrypto.js deleted file mode 100644 index f3e23895..00000000 --- a/src/core/vendor/streebog/gostCrypto.js +++ /dev/null @@ -1,1658 +0,0 @@ -/** - * Implementation Web Crypto interfaces for GOST algorithms - * 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. - * - */ - -(function (root, factory) { - - /* - * Module imports and exports - * - */ // - module.exports = factory(require('./gostRandom')); - // - -}(this, function (GostRandom) { - - /* - * Algorithm normalization - * - */ // - - var root = this; - var rootCrypto = root.crypto || root.msCrypto; - - var SyntaxError = root.SyntaxError || root.Error, - DataError = root.DataError || root.Error, - NotSupportedError = root.NotSupportedError || root.Error, - OperationError = root.OperationError || root.Error, - InvalidStateError = root.InvalidAccessError || root.Error, - InvalidAccessError = root.InvalidAccessError || root.Error; - - // Normalize algorithm - function normalize(algorithm, method) { - if (typeof algorithm === 'string' || algorithm instanceof String) - algorithm = {name: algorithm}; - var name = algorithm.name; - if (!name) - throw new SyntaxError('Algorithm name not defined'); - // Extract algorithm modes from name - var modes = name.split('/'), modes = modes[0].split('-').concat(modes.slice(1)); - // Normalize the name with default modes - var na = {}; - name = modes[0].replace(/[\.\s]/g, ''); - modes = modes.slice(1); - if (name.indexOf('28147') >= 0) { - na = { - name: 'GOST 28147', - version: 1989, - mode: (algorithm.mode || (// ES, MAC, KW - (method === 'sign' || method === 'verify') ? 'MAC' : - (method === 'wrapKey' || method === 'unwrapKey') ? 'KW' : 'ES')).toUpperCase(), - length: algorithm.length || 64 - }; - } else if (name.indexOf('3412') >= 0) { - na = { - name: 'GOST R 34.12', - version: 2015, - mode: (algorithm.mode || (// ES, MAC, KW - (method === 'sign' || method === 'verify') ? 'MAC' : - (method === 'wrapKey' || method === 'unwrapKey') ? 'KW' : 'ES')).toUpperCase(), - length: algorithm.length || 64 // 128 - }; - } else if (name.indexOf('3411') >= 0) { - na = { - name: 'GOST R 34.11', - version: 2012, // 1994 - mode: (algorithm.mode || (// HASH, KDF, HMAC, PBKDF2, PFXKDF, CPKDF - (method === 'deriveKey' || method === 'deriveBits') ? 'KDF' : - (method === 'sign' || method === 'verify') ? 'HMAC' : 'HASH')).toUpperCase(), - length: algorithm.length || 256 // 512 - }; - } else if (name.indexOf('3410') >= 0) { - na = { - name: 'GOST R 34.10', - version: 2012, // 1994, 2001 - mode: (algorithm.mode || (// SIGN, DH, MASK - (method === 'deriveKey' || method === 'deriveBits') ? 'DH' : 'SIGN')).toUpperCase(), - length: algorithm.length || 256 // 512 - }; - } else if (name.indexOf('SHA') >= 0) { - na = { - name: 'SHA', - version: (algorithm.length || 160) === 160 ? 1 : 2, // 1, 2 - mode: (algorithm.mode || (// HASH, KDF, HMAC, PBKDF2, PFXKDF - (method === 'deriveKey' || method === 'deriveBits') ? 'KDF' : - (method === 'sign' || method === 'verify') ? 'HMAC' : 'HASH')).toUpperCase(), - length: algorithm.length || 160 - }; - } else if (name.indexOf('RC2') >= 0) { - na = { - name: 'RC2', - version: 1, - mode: (algorithm.mode || (// ES, MAC, KW - (method === 'sign' || method === 'verify') ? 'MAC' : - (method === 'wrapKey' || method === 'unwrapKey') ? 'KW' : 'ES')).toUpperCase(), - length: algorithm.length || 32 // 1 - 1024 - }; - } else if (name.indexOf('PBKDF2') >= 0) { - na = normalize(algorithm.hash, 'digest'); - na.mode = 'PBKDF2'; - } else if (name.indexOf('PFXKDF') >= 0) { - na = normalize(algorithm.hash, 'digest'); - na.mode = 'PFXKDF'; - } else if (name.indexOf('CPKDF') >= 0) { - na = normalize(algorithm.hash, 'digest'); - na.mode = 'CPKDF'; - } else if (name.indexOf('HMAC') >= 0) { - na = normalize(algorithm.hash, 'digest'); - na.mode = 'HMAC'; - } else - throw new NotSupportedError('Algorithm not supported'); - - // Compile modes - modes.forEach(function (mode) { - mode = mode.toUpperCase(); - if (/^[0-9]+$/.test(mode)) { - if ((['8', '16', '32'].indexOf(mode) >= 0) || (na.length === '128' && mode === '64')) { // Shift bits - if (na.mode === 'ES') - na.shiftBits = parseInt(mode); - else if (na.mode === 'MAC') - na.macLength = parseInt(mode); - else - throw new NotSupportedError('Algorithm ' + na.name + ' mode ' + mode + ' not supported'); - } else if (['89', '94', '01', '12', '15', '1989', '1994', '2001', '2012', '2015'].indexOf(mode) >= 0) { // GOST Year - var version = parseInt(mode); - version = version < 1900 ? (version < 80 ? 2000 + version : 1900 + version) : version; - na.version = version; - } else if (['1'].indexOf(mode) >= 0 && na.name === 'SHA') { // SHA-1 - na.version = 1; - na.length = 160; - } else if (['256', '384', '512'].indexOf(mode) >= 0 && na.name === 'SHA') { // SHA-2 - na.version = 2; - na.length = parseInt(mode); - } else if (['40', '128'].indexOf(mode) >= 0 && na.name === 'RC2') { // RC2 - na.version = 1; - na.length = parseInt(mode); // key size - } else if (['64', '128', '256', '512'].indexOf(mode) >= 0) // block size - na.length = parseInt(mode); - else if (['1000', '2000'].indexOf(mode) >= 0) // Iterations - na.iterations = parseInt(mode); - // Named Paramsets - } else if (['E-TEST', 'E-A', 'E-B', 'E-C', 'E-D', 'E-SC', 'E-Z', 'D-TEST', 'D-A', 'D-SC'].indexOf(mode) >= 0) { - na.sBox = mode; - } else if (['S-TEST', 'S-A', 'S-B', 'S-C', 'S-D', 'X-A', 'X-B', 'X-C'].indexOf(mode) >= 0) { - na.namedParam = mode; - } else if (['S-256-TEST', 'S-256-A', 'S-256-B', 'S-256-C', 'P-256', 'T-512-TEST', 'T-512-A', - 'T-512-B', 'X-256-A', 'X-256-B', 'T-256-TEST', 'T-256-A', 'T-256-B', 'S-256-B', 'T-256-C', 'S-256-C'].indexOf(mode) >= 0) { - na.namedCurve = mode; - } else if (['SC', 'CP', 'VN'].indexOf(mode) >= 0) { - na.procreator = mode; - - // Encription GOST 28147 or GOST R 34.12 - } else if (na.name === 'GOST 28147' || na.name === 'GOST R 34.12' || na.name === 'RC2') { - if (['ES', 'MAC', 'KW', 'MASK'].indexOf(mode) >= 0) { - na.mode = mode; - } else if (['ECB', 'CFB', 'OFB', 'CTR', 'CBC'].indexOf(mode) >= 0) { - na.mode = 'ES'; - na.block = mode; - } else if (['CPKW', 'NOKW', 'SCKW'].indexOf(mode) >= 0) { - na.mode = 'KW'; - na.keyWrapping = mode.replace('KW', ''); - } else if (['ZEROPADDING', 'PKCS5PADDING', 'NOPADDING', 'RANDOMPADDING', 'BITPADDING'].indexOf(mode) >= 0) { - na.padding = mode.replace('PADDING', ''); - } else if (['NOKM', 'CPKM'].indexOf(mode) >= 0) { - na.keyMeshing = mode.replace('KM', ''); - } else - throw new NotSupportedError('Algorithm ' + na.name + ' mode ' + mode + ' not supported'); - - // Digesting GOST 34.11 - } else if (na.name === 'GOST R 34.11' || na.name === 'SHA') { - if (['HASH', 'KDF', 'HMAC', 'PBKDF2', 'PFXKDF', 'CPKDF'].indexOf(mode) >= 0) - na.mode = mode; - else - throw new NotSupportedError('Algorithm ' + na.name + ' mode ' + mode + ' not supported'); - - // Signing GOST 34.10 - } else if (na.name === 'GOST R 34.10') { - var hash = mode.replace(/[\.\s]/g, ''); - if (hash.indexOf('GOST') >= 0 && hash.indexOf('3411') >= 0) - na.hash = mode; - else if (['SIGN', 'DH', 'MASK'].indexOf(mode)) - na.mode = mode; - else - throw new NotSupportedError('Algorithm ' + na.name + ' mode ' + mode + ' not supported'); - } - }); - - // Procreator - na.procreator = algorithm.procreator || na.procreator || 'CP'; - - // Key size - switch (na.name) { - case 'GOST R 34.10': - na.keySize = na.length / (na.version === 1994 ? 4 : 8); - break; - case 'GOST R 34.11': - na.keySize = 32; - break; - case 'GOST 28147': - case 'GOST R 34.12': - na.keySize = 32; - break; - case 'RC2': - na.keySize = Math.ceil(na.length / 8); - break; - case 'SHA': - na.keySize = na.length / 8; - break; - } - - // Encrypt additional modes - if (na.mode === 'ES') { - if (algorithm.block) - na.block = algorithm.block; // ECB, CFB, OFB, CTR, CBC - if (na.block) - na.block = na.block.toUpperCase(); - if (algorithm.padding) - na.padding = algorithm.padding; // NO, ZERO, PKCS5, RANDOM, BIT - if (na.padding) - na.padding = na.padding.toUpperCase(); - if (algorithm.shiftBits) - na.shiftBits = algorithm.shiftBits; // 8, 16, 32, 64 - if (algorithm.keyMeshing) - na.keyMeshing = algorithm.keyMeshing; // NO, CP - if (na.keyMeshing) - na.keyMeshing = na.keyMeshing.toUpperCase(); - // Default values - if (method !== 'importKey' && method !== 'generateKey') { - na.block = na.block || 'ECB'; - na.padding = na.padding || (na.block === 'CBC' || na.block === 'ECB' ? 'ZERO' : 'NO'); - if (na.block === 'CFB' || na.block === 'OFB') - na.shiftBits = na.shiftBits || na.length; - na.keyMeshing = na.keyMeshing || 'NO'; - } - } - if (na.mode === 'KW') { - if (algorithm.keyWrapping) - na.keyWrapping = algorithm.keyWrapping; // NO, CP, SC - if (na.keyWrapping) - na.keyWrapping = na.keyWrapping.toUpperCase(); - if (method !== 'importKey' && method !== 'generateKey') - na.keyWrapping = na.keyWrapping || 'NO'; - } - - // Paramsets - ['sBox', 'namedParam', 'namedCurve', 'curve', 'param', 'modulusLength'].forEach(function (name) { - algorithm[name] && (na[name] = algorithm[name]); - }); - // Default values - if (method !== 'importKey' && method !== 'generateKey') { - if (na.name === 'GOST 28147') { - na.sBox = na.sBox || (na.procreator === 'SC' ? 'E-SC' : 'E-A'); // 'E-A', 'E-B', 'E-C', 'E-D', 'E-SC' - } else if (na.name === 'GOST R 34.12' && na.length === 64) { - na.sBox = 'E-Z'; - } else if (na.name === 'GOST R 34.11' && na.version === 1994) { - na.sBox = na.sBox || (na.procreator === 'SC' ? 'D-SC' : 'D-A'); // 'D-SC' - } else if (na.name === 'GOST R 34.10' && na.version === 1994) { - na.namedParam = na.namedParam || (na.mode === 'DH' ? 'X-A' : 'S-A'); // 'S-B', 'S-C', 'S-D', 'X-B', 'X-C' - } else if (na.name === 'GOST R 34.10' && na.version === 2001) { - na.namedCurve = na.namedCurve || (na.length === 256 ? - na.procreator === 'SC' ? 'P-256' : (na.mode === 'DH' ? 'X-256-A' : 'S-256-A') : // 'S-256-B', 'S-256-C', 'X-256-B', 'T-256-A', 'T-256-B', 'T-256-C', 'P-256' - na.mode === 'T-512-A'); // 'T-512-B', 'T-512-C' - } else if (na.name === 'GOST R 34.10' && na.version === 2012) { - na.namedCurve = na.namedCurve || (na.length === 256 ? - na.procreator === 'SC' ? 'P-256' : (na.mode === 'DH' ? 'X-256-A' : 'S-256-A') : // 'S-256-B', 'S-256-C', 'X-256-B', 'T-256-A', 'T-256-B', 'T-256-C', 'P-256' - na.mode === 'T-512-A'); // 'T-512-B', 'T-512-C' - } - } - - // Vectors - switch (na.mode) { - case 'DH': - algorithm.ukm && (na.ukm = algorithm.ukm); - algorithm['public'] && (na['public'] = algorithm['public']); - break; - case 'SIGN': - case 'KW': - algorithm.ukm && (na.ukm = algorithm.ukm); - break; - case 'ES': - case 'MAC': - algorithm.iv && (na.iv = algorithm.iv); - break; - case 'KDF': - algorithm.label && (na.label = algorithm.label); - algorithm.contex && (na.context = algorithm.contex); - break; - case 'PBKDF2': - algorithm.salt && (na.salt = algorithm.salt); - algorithm.iterations && (na.iterations = algorithm.iterations); - algorithm.diversifier && (na.diversifier = algorithm.diversifier); - break; - case 'PFXKDF': - algorithm.salt && (na.salt = algorithm.salt); - algorithm.iterations && (na.iterations = algorithm.iterations); - algorithm.diversifier && (na.diversifier = algorithm.diversifier); - break; - case 'CPKDF': - algorithm.salt && (na.salt = algorithm.salt); - algorithm.iterations && (na.iterations = algorithm.iterations); - break; - } - - // Verification method and modes - if (method && ( - ((na.mode !== 'ES' && na.mode !== 'SIGN' && na.mode !== 'MAC' && - na.mode !== 'HMAC' && na.mode !== 'KW' && na.mode !== 'DH' - && na.mode !== 'MASK') && - (method === 'generateKey')) || - ((na.mode !== 'ES') && - (method === 'encrypt' || method === 'decrypt')) || - ((na.mode !== 'SIGN' && na.mode !== 'MAC' && na.mode !== 'HMAC') && - (method === 'sign' || method === 'verify')) || - ((na.mode !== 'HASH') && - (method === 'digest')) || - ((na.mode !== 'KW' && na.mode !== 'MASK') && - (method === 'wrapKey' || method === 'unwrapKey')) || - ((na.mode !== 'DH' && na.mode !== 'PBKDF2' && na.mode !== 'PFXKDF' && - na.mode !== 'CPKDF' && na.mode !== 'KDF') && - (method === 'deriveKey' || method === 'deriveBits')))) - throw new NotSupportedError('Algorithm mode ' + na.mode + ' not valid for method ' + method); - - // Normalize hash algorithm - algorithm.hash && (na.hash = algorithm.hash); - if (na.hash) { - if ((typeof na.hash === 'string' || na.hash instanceof String) - && na.procreator) - na.hash = na.hash + '/' + na.procreator; - na.hash = normalize(na.hash, 'digest'); - } - - // Algorithm object identirifer - algorithm.id && (na.id = algorithm.id); - - return na; - } - - // Check for possibility use native crypto.subtle - function checkNative(algorithm) { - if (!rootCrypto || !rootCrypto.subtle || !algorithm) - return false; - // Prepare name - var name = (typeof algorithm === 'string' || algorithm instanceof String) ? - name = algorithm : algorithm.name; - if (!name) - return false; - name = name.toUpperCase(); - // Digest algorithm for key derivation - if ((name.indexOf('KDF') >= 0 || name.indexOf('HMAC') >= 0) && algorithm.hash) - return checkNative(algorithm.hash); - // True if no supported names - return name.indexOf('GOST') === -1 && - name.indexOf('SHA-1') === -1 && - name.indexOf('RC2') === -1 && - name.indexOf('?DES') === -1; - } - // - - /* - * Key conversion methods - * - */ // - - // Check key parameter - function checkKey(key, method) { - if (!key.algorithm) - throw new SyntaxError('Key algorithm not defined'); - - if (!key.algorithm.name) - throw new SyntaxError('Key algorithm name not defined'); - - var name = key.algorithm.name, - gostCipher = name === 'GOST 28147' || name === 'GOST R 34.12' || name === 'RC2', - gostDigest = name === 'GOST R 34.11' || name === 'SHA', - gostSign = name === 'GOST R 34.10'; - - if (!gostCipher && !gostSign && !gostDigest) - throw new NotSupportedError('Key algorithm ' + name + ' is unsupproted'); - - if (!key.type) - throw new SyntaxError('Key type not defined'); - - if (((gostCipher || gostDigest) && key.type !== 'secret') || - (gostSign && !(key.type === 'public' || key.type === 'private'))) - throw new DataError('Key type ' + key.type + ' is not valid for algorithm ' + name); - - if (!key.usages || !key.usages.indexOf) - throw new SyntaxError('Key usages not defined'); - - for (var i = 0, n = key.usages.length; i < n; i++) { - var md = key.usages[i]; - if (((md === 'encrypt' || md === 'decrypt') && key.type !== 'secret') || - (md === 'sign' && key.type === 'public') || - (md === 'verify' && key.type === 'private')) - throw new InvalidStateError('Key type ' + key.type + ' is not valid for ' + md); - } - - if (method) - if (key.usages.indexOf(method) === -1) - throw new InvalidAccessError('Key usages is not contain method ' + method); - - if (!key.buffer) - throw new SyntaxError('Key buffer is not defined'); - - var size = key.buffer.byteLength * 8, keySize = 8 * key.algorithm.keySize; - if ((key.type === 'secret' && size !== (keySize || 256) && - (key.usages.indexOf('encrypt') >= 0 || key.usages.indexOf('decrypt') >= 0)) || - (key.type === 'private' && !(size === 256 || size === 512)) || - (key.type === 'public' && !(size === 512 || size === 1024))) - throw new SyntaxError('Key buffer has wrong size ' + size + ' bit'); - } - - // Extract key and enrich cipher algorithm - function extractKey(method, algorithm, key) { - checkKey(key, method); - if (algorithm) { - var params; - switch (algorithm.mode) { - case 'ES': - params = ['sBox', 'keyMeshing', 'padding', 'block']; - break; - case 'SIGN': - params = ['namedCurve', 'namedParam', 'sBox', 'curve', 'param', 'modulusLength']; - break; - case 'MAC': - params = ['sBox']; - break; - case 'KW': - params = ['keyWrapping', 'ukm']; - break; - case 'DH': - params = ['namedCurve', 'namedParam', 'sBox', 'ukm', 'curve', 'param', 'modulusLength']; - break; - case 'KDF': - params = ['context', 'label']; - break; - case 'PBKDF2': - params = ['sBox', 'iterations', 'salt']; - break; - case 'PFXKDF': - params = ['sBox', 'iterations', 'salt', 'diversifier']; - break; - case 'CPKDF': - params = ['sBox', 'salt']; - break; - } - if (params) - params.forEach(function (name) { - key.algorithm[name] && (algorithm[name] = key.algorithm[name]); - }); - } - return key.buffer; - } - - // Make key definition - function convertKey(algorithm, extractable, keyUsages, keyData, keyType) { - var key = { - type: keyType || (algorithm.name === 'GOST R 34.10' ? 'private' : 'secret'), - extractable: extractable || 'false', - algorithm: algorithm, - usages: keyUsages || [], - buffer: keyData - }; - checkKey(key); - return key; - } - - function convertKeyPair(publicAlgorithm, privateAlgorithm, extractable, keyUsages, publicBuffer, privateBuffer) { - - if (!keyUsages || !keyUsages.indexOf) - throw new SyntaxError('Key usages not defined'); - - var publicUsages = keyUsages.filter(function (value) { - return value !== 'sign'; - }); - var privateUsages = keyUsages.filter(function (value) { - return value !== 'verify'; - }); - - return { - publicKey: convertKey(publicAlgorithm, extractable, publicUsages, publicBuffer, 'public'), - privateKey: convertKey(privateAlgorithm, extractable, privateUsages, privateBuffer, 'private') - }; - } - - // Swap bytes in buffer - function swapBytes(src) { - if (src instanceof CryptoOperationData) - src = new Uint8Array(src); - var dst = new Uint8Array(src.length); - for (var i = 0, n = src.length; i < n; i++) - dst[n - i - 1] = src[i]; - return dst.buffer; - } - // - - /** - * Promise stub object (not fulfill specification, only for internal use) - * Class not defined if Promise class already defined in root context

- * - * The Promise object is used for deferred and asynchronous computations. A Promise is in one of the three states: - *
    - *
  • pending: initial state, not fulfilled or rejected.
  • - *
  • fulfilled: successful operation
  • - *
  • rejected: failed operation.
  • - *
- * Another term describing the state is settled: the Promise is either fulfilled or rejected, but not pending.

- * @class Promise - * @global - * @param {function} executor Function object with two arguments resolve and reject. - * The first argument fulfills the promise, the second argument rejects it. - * We can call these functions, once our operation is completed. - */ // - if (!root.Promise) { - - root.Promise = (function () { - - function mswrap(value) { - if (value && value.oncomplete === null && value.onerror === null) { - return new Promise(function (resolve, reject) { - value.oncomplete = function () { - resolve(value.result); - }; - value.onerror = function () { - reject(new OperationError(value.toString())); - }; - }); - } else - return value; - } - - function Promise(executor) { - - var state = 'pending', result, - resolveQueue = [], rejectQueue = []; - - function call(callback) { - try { - callback(); - } catch (e) { - } - } - - try { - executor(function (value) { - if (state === 'pending') { - state = 'fulfilled'; - result = value; - resolveQueue.forEach(call); - } - }, function (reason) { - if (state === 'pending') { - state = 'rejected'; - result = reason; - rejectQueue.forEach(call); - } - }); - } catch (error) { - if (state === 'pending') { - state = 'rejected'; - result = error; - rejectQueue.forEach(call); - } - } - /** - * The then() method returns a Promise. It takes two arguments, both are - * callback functions for the success and failure cases of the Promise. - * - * @method then - * @memberOf Promise - * @instance - * @param {function} onFulfilled A Function called when the Promise is fulfilled. This function has one argument, the fulfillment value. - * @param {function} onRejected A Function called when the Promise is rejected. This function has one argument, the rejection reason. - * @returns {Promise} - */ - this.then = function (onFulfilled, onRejected) { - - return new Promise(function (resolve, reject) { - - function asyncOnFulfilled() { - var value; - try { - value = onFulfilled ? onFulfilled(result) : result; - } catch (error) { - reject(error); - return; - } - value = mswrap(value); - if (value && value.then && value.then.call) { - value.then(resolve, reject); - } else { - resolve(value); - } - } - - function asyncOnRejected() { - var reason; - try { - reason = onRejected ? onRejected(result) : result; - } catch (error) { - reject(error); - return; - } - reason = mswrap(reason); - if (reason && reason.then && reason.then.call) { - reason.then(resolve, reject); - } else { - reject(reason); - } - } - - if (state === 'fulfilled') { - asyncOnFulfilled(); - } else if (state === 'rejected') { - asyncOnRejected(); - } else { - resolveQueue.push(asyncOnFulfilled); - rejectQueue.push(asyncOnRejected); - } - - }); - - }; - /** - * The catch() method returns a Promise and deals with rejected cases only. - * It behaves the same as calling Promise.prototype.then(undefined, onRejected). - * - * @method catch - * @memberOf Promise - * @instance - * @param {function} onRejected A Function called when the Promise is rejected. This function has one argument, the rejection reason. - * @returns {Promise} - */ - this['catch'] = function (onRejected) { - return this.then(undefined, onRejected); - }; - } - - /** - * The Promise.all(iterable) method returns a promise that resolves when all - * of the promises in the iterable argument have resolved.

- * - * The result is passed as an array of values from all the promises. - * If something passed in the iterable array is not a promise, it's converted to - * one by Promise.resolve. If any of the passed in promises rejects, the - * all Promise immediately rejects with the value of the promise that rejected, - * discarding all the other promises whether or not they have resolved. - * - * @method all - * @memberOf Promise - * @static - * @param {KeyUsages} promises Array with promises. - * @returns {Promise} - */ - Promise.all = function (promises) { - return new Promise(function (resolve, reject) { - var result = [], count = 0; - function asyncResolve(k) { - count++; - return function (data) { - result[k] = data; - count--; - if (count === 0) - resolve(result); - }; - } - - function asyncReject(reason) { - if (count > 0) - reject(reason); - count = 0; - } - - for (var i = 0, n = promises.length; i < n; i++) { - var data = promises[i]; - if (data.then && data.then.call) - data.then(asyncResolve(i), asyncReject); - else - result[i] = data; - } - - if (count === 0) - resolve(result); - }); - }; - - return Promise; - })(); - } //
- - /* - * Worker executor - * - */ // - - var baseUrl = '', nameSuffix = ''; - // Try to define from DOM model - if (typeof document !== 'undefined') { - (function () { - var regs = /^(.*)gostCrypto(.*)\.js$/i; - var list = document.querySelectorAll('script'); - for (var i = 0, n = list.length; i < n; i++) { - var value = list[i].getAttribute('src'); - var test = regs.exec(value); - if (test) { - baseUrl = test[1]; - nameSuffix = test[2]; - } - } - })(); - } - - // Local importScripts procedure for include dependens - function importScripts() { - for (var i = 0, n = arguments.length; i < n; i++) { - var name = arguments[i].split('.'), - src = baseUrl + name[0] + nameSuffix + '.' + name[1]; - var el = document.querySelector('script[src="' + src + '"]'); - if (!el) { - el = document.createElement('script'); - el.setAttribute('src', src); - document.head.appendChild(el); - } - } - } - - // Create Worker - var worker = false, tasks = [], sequence = 0; - // Worker will create only for first child process and - // Gost implementation libraries not yet loaded - if (!root.importScripts && !root.gostEngine) { - - try { - worker = new Worker(baseUrl + 'gostEngine' + nameSuffix + '.js'); - - // Result of opertion - worker.onmessage = function (event) { - // Find task - var id = event.data.id; - for (var i = 0, n = tasks.length; i < n; i++) - if (tasks[i].id === id) - break; - if (i < n) { - var task = tasks[i]; - tasks.splice(i, 1); - // Reject if error or resolve with result - if (event.data.error) - task.reject(new OperationError(event.data.error)); - else - task.resolve(event.data.result); - } - }; - - // Worker error - reject all waiting tasks - worker.onerror = function (event) { - for (var i = 0, n = tasks.length; i < n; i++) - tasks[i].reject(event.error); - tasks = []; - }; - - } catch (e) { - // Worker is't supported - worker = false; - } - } - - if (!root.importScripts) { - // This procedure emulate load dependents as in Worker - root.importScripts = importScripts; - - } - - if (!worker) { - // Import main module - // Reason: we are already in worker process or Worker interface is not - // yet supported - root.gostEngine //|| importScripts('gostEngine.js'); - } - - // Executor for any method - function execute(algorithm, method, args) { - return new Promise(function (resolve, reject) { - try { - if (worker) { - var id = ++sequence; - tasks.push({ - id: id, - resolve: resolve, - reject: reject - }); - worker.postMessage({ - id: id, algorithm: algorithm, - method: method, args: args - }); - } else { - if (root.gostEngine) - resolve(root.gostEngine.execute(algorithm, method, args)); - else - reject(new OperationError('Module gostEngine not found')); - } - } catch (error) { - reject(error); - } - }); - } - - // Self resolver - function call(callback) { - try { - callback(); - } catch (e) { - } - } - - // - - /* - * WebCrypto common class references - * - */ // - /** - * The Algorithm object is a dictionary object [WebIDL] which is used to - * specify an algorithm and any additional parameters required to fully - * specify the desired operation.
- *
-     *  dictionary Algorithm {
-     *      DOMString name;
-     *  };
-     * 
- * WebCrypto API reference {@link http://www.w3.org/TR/WebCryptoAPI/#algorithm-dictionary} - * @class Algorithm - * @param {DOMString} name The name of the registered algorithm to use. - */ - - /** - * AlgorithmIdentifier - Algorithm or DOMString name of algorithm
- *
-     *  typedef (Algorithm or DOMString) AlgorithmIdentifier;
-     * 
- * WebCrypto API reference {@link http://www.w3.org/TR/WebCryptoAPI/#algorithm-dictionary} - * @class AlgorithmIdentifier - */ - - /** - * The KeyAlgorithm interface represents information about the contents of a - * given Key object. - *
-     *  interface KeyAlgorithm {
-     *      readonly attribute DOMString name
-     *  };
-     * 
- * WebCrypto API reference {@link http://www.w3.org/TR/WebCryptoAPI/#key-algorithm-interface} - * @class KeyAlgorithm - * @param {DOMString} name The name of the algorithm used to generate the Key - */ - - /** - * The type of a key. The recognized key type values are "public", "private" - * and "secret". Opaque keying material, including that used for symmetric - * algorithms, is represented by "secret", while keys used as part of asymmetric - * algorithms composed of public/private keypairs will be either "public" or "private". - *
-     *  typedef DOMString KeyType;
-     * 
- * WebCrypto API reference {@link http://www.w3.org/TR/WebCryptoAPI/#key-interface} - * @class KeyType - */ - - /** - * Sequence of operation type that may be performed using a key. The recognized - * key usage values are "encrypt", "decrypt", "sign", "verify", "deriveKey", - * "deriveBits", "wrapKey" and "unwrapKey". - *
-     *  typedef DOMString[] KeyUsages;
-     * 
- * WebCrypto API reference {@link http://www.w3.org/TR/WebCryptoAPI/#key-interface} - * @class KeyUsages - */ - - /** - * The Key object represents an opaque reference to keying material that is - * managed by the user agent.
- * This specification provides a uniform interface for many different kinds of - * keying material managed by the user agent. This may include keys that have - * been generated by the user agent, derived from other keys by the user agent, - * imported to the user agent through user actions or using this API, - * pre-provisioned within software or hardware to which the user agent has - * access or made available to the user agent in other ways. The term key refers - * broadly to any keying material including actual keys for cryptographic - * operations and secret values obtained within key derivation or exchange operations.
- * The Key object is not required to directly interface with the underlying key - * storage mechanism, and may instead simply be a reference for the user agent - * to understand how to obtain the keying material when needed, eg. when performing - * a cryptographic operation. - *
-     *  interface Key {
-     *      readonly attribute KeyType type;
-     *      readonly attribute boolean extractable;
-     *      readonly attribute KeyAlgorithm algorithm;
-     *      readonly attribute KeyUsages usages;
-     *  };     
-     * 
- * WebCrypto API reference {@link http://www.w3.org/TR/WebCryptoAPI/#key-interface} - * @class Key - * @param {KeyType} type The type of a key. The recognized key type values are "public", "private" and "secret". - * @param {boolean} extractable Whether or not the raw keying material may be exported by the application. - * @param {KeyAlgorithm} algorithm The Algorithm used to generate the key. - * @param {KeyUsages} usages Key usage array: type of operation that may be performed using a key. - */ - - /** - * The KeyPair interface represents an asymmetric key pair that is comprised of both public and private keys. - *
-     *  interface KeyPair {
-     *      readonly attribute Key publicKey;
-     *      readonly attribute Key privateKey;
-     *  };     
-     * 
- * WebCrypto API reference {@link http://www.w3.org/TR/WebCryptoAPI/#keypair} - * @class KeyPair - * @param {Key} privateKey Private key - * @param {Key} publicKey Public key - */ - - /** - * Specifies a serialization format for a key. The recognized key format values are: - *
    - *
  • 'raw' - An unformatted sequence of bytes. Intended for secret keys.
  • - *
  • 'pkcs8' - The DER encoding of the PrivateKeyInfo structure from RFC 5208.
  • - *
  • 'spki' - The DER encoding of the SubjectPublicKeyInfo structure from RFC 5280.
  • - *
  • 'jwk' - The key is represented as JSON according to the JSON Web Key format.
  • - *
- *
-     *  typedef DOMString KeyFormat;
-     *  
- * WebCrypto API reference {@link http://www.w3.org/TR/WebCryptoAPI/#key-interface} - * @class KeyFormat - */ - - /** - * Binary data - *
-     *  typedef (ArrayBuffer or ArrayBufferView) CryptoOperationData;
-     *  
- * @class CryptoOperationData - */ - var CryptoOperationData = root.ArrayBuffer; - - /** - * DER-encoded ArrayBuffer or PEM-encoded DOMString constains ASN.1 object
- *
-     *  typedef (ArrayBuffer or DOMString) FormatedData;
-     * 
- * @class FormatedData - */ - //
- - /** - * The gostCrypto provide general purpose cryptographic functionality for - * GOST standards including a cryptographically strong pseudo-random number - * generator seeded with truly random values. - * - * @namespace gostCrypto - */ - var gostCrypto = {}; - - /** - * The SubtleCrypto class provides low-level cryptographic primitives and algorithms. - * WebCrypto API reference {@link http://www.w3.org/TR/WebCryptoAPI/#subtlecrypto-interface} - * - * @class SubtleCrypto - */ // - function SubtleCrypto() { - } - - /** - * The encrypt method returns a new Promise object that will encrypt data - * using the specified algorithm identifier with the supplied Key. - * WebCrypto API reference {@link http://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-encrypt}

- * - * Supported algorithm names: - *
    - *
  • GOST 28147-ECB "prostaya zamena" (ECB) mode (default)
  • - *
  • GOST 28147-CFB "gammirovanie s obratnoj svyaziyu po shifrotekstu" (CFB) mode
  • - *
  • GOST 28147-OFB "gammirovanie s obratnoj svyaziyu po vyhodu" (OFB) mode
  • - *
  • GOST 28147-CTR "gammirovanie" (counter) mode
  • - *
  • GOST 28147-CBC Cipher-Block-Chaining (CBC) mode
  • - *
  • GOST R 34.12-ECB "prostaya zamena" (ECB) mode (default)
  • - *
  • GOST R 34.12-CFB "gammirovanie s obratnoj svyaziyu po shifrotekstu" (CFB) mode
  • - *
  • GOST R 34.12-OFB "gammirovanie s obratnoj svyaziyu po vyhodu" (OFB) mode
  • - *
  • GOST R 34.12-CTR "gammirovanie" (counter) mode
  • - *
  • GOST R 34.12-CBC Cipher-Block-Chaining (CBC) mode
  • - *
- * For more information see {@link GostCipher} - * - * @memberOf SubtleCrypto - * @method encrypt - * @instance - * @param {AlgorithmIdentifier} algorithm Algorithm identifier - * @param {Key} key Key object - * @param {CryptoOperationData} data Operation data - * @returns {Promise} Promise that resolves with {@link CryptoOperationData} - */ - SubtleCrypto.prototype.encrypt = function (algorithm, key, data) // - { - return new Promise(call).then(function () { - if (checkNative(algorithm)) - return rootCrypto.subtle.encrypt(algorithm, key, data); - - algorithm = normalize(algorithm, 'encrypt'); - return execute(algorithm, 'encrypt', - [extractKey('encrypt', algorithm, key), data]); - }); - }; // - - /** - * The decrypt method returns a new Promise object that will decrypt data - * using the specified algorithm identifier with the supplied Key. - * WebCrypto API reference {@link http://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-decrypt}

- * - * Supported algorithm names: - *
    - *
  • GOST 28147-ECB "prostaya zamena" (ECB) mode (default)
  • - *
  • GOST 28147-CFB "gammirovanie s obratnoj svyaziyu po shifrotekstu" (CFB) mode
  • - *
  • GOST 28147-OFB "gammirovanie s obratnoj svyaziyu po vyhodu" (OFB) mode
  • - *
  • GOST 28147-CTR "gammirovanie" (counter) mode
  • - *
  • GOST 28147-CBC Cipher-Block-Chaining (CBC) mode
  • - *
  • GOST R 34.12-ECB "prostaya zamena" (ECB) mode (default)
  • - *
  • GOST R 34.12-CFB "gammirovanie s obratnoj svyaziyu po shifrotekstu" (CFB) mode
  • - *
  • GOST R 34.12-OFB "gammirovanie s obratnoj svyaziyu po vyhodu" (OFB) mode
  • - *
  • GOST R 34.12-CTR "gammirovanie" (counter) mode
  • - *
  • GOST R 34.12-CBC Cipher-Block-Chaining (CBC) mode
  • - *
- * For additional modes see {@link GostCipher} - * - * @memberOf SubtleCrypto - * @method decrypt - * @instance - * @param {AlgorithmIdentifier} algorithm Algorithm identifier - * @param {Key} key Key object - * @param {CryptoOperationData} data Operation data - * @returns {Promise} Promise that resolves with {@link CryptoOperationData} - */ - SubtleCrypto.prototype.decrypt = function (algorithm, key, data) // - { - return new Promise(call).then(function () { - if (checkNative(algorithm)) - return rootCrypto.subtle.decrypt(algorithm, key, data); - - algorithm = normalize(algorithm, 'decrypt'); - return execute(algorithm, 'decrypt', - [extractKey('decrypt', algorithm, key), data]); - }); - }; // - - /** - * The sign method returns a new Promise object that will sign data using - * the specified algorithm identifier with the supplied Key. - * WebCrypto API reference {@link http://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-sign}

- * - * Supported algorithm names: - *
    - *
  • GOST R 34.10-94 GOST Signature
  • - *
  • GOST R 34.10-94/GOST R 34.11-94 GOST Signature with Hash
  • - *
  • GOST R 34.10 ECGOST Signature
  • - *
  • GOST R 34.10/GOST R 34.11-94 ECGOST Signature with Old-Style Hash
  • - *
  • GOST R 34.10/GOST R 34.11 ECGOST Signature with Streebog Hash
  • - *
  • GOST 28147-MAC MAC base on GOST 28147
  • - *
  • GOST R 34.12-MAC MAC base on GOST R 43.12
  • - *
  • GOST R 34.11-HMAC HMAC base on GOST 34.11
  • - *
  • SHA-HMAC HMAC base on SHA
  • - *
- * For additional modes see {@link GostSign}, {@link GostDigest} and {@link GostCipher} - * - * @memberOf SubtleCrypto - * @method sign - * @instance - * @param {AlgorithmIdentifier} algorithm Algorithm identifier - * @param {Key} key Key object - * @param {CryptoOperationData} data Operation data - * @returns {Promise} Promise that resolves with {@link CryptoOperationData} - */ - SubtleCrypto.prototype.sign = function (algorithm, key, data) // - { - return new Promise(call).then(function () { - if (checkNative(algorithm)) - return rootCrypto.subtle.sign(algorithm, key, data); - - algorithm = normalize(algorithm, 'sign'); - var value = execute(algorithm, 'sign', - [extractKey('sign', algorithm, key), data]).then(function (data) { - if (algorithm.procreator === 'SC' && algorithm.mode === 'SIGN') { - data = gostCrypto.asn1.GostSignature.encode(data); - } - return data; - }); - return value; - }); - }; // - - /** - * The verify method returns a new Promise object that will verify data - * using the specified algorithm identifier with the supplied Key. - * WebCrypto API reference {@link http://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-verify}

- * - * Supported algorithm names: - *
    - *
  • GOST R 34.10-94 GOST Signature
  • - *
  • GOST R 34.10-94/GOST R 34.11-94 GOST Signature with Hash
  • - *
  • GOST R 34.10 ECGOST Signature
  • - *
  • GOST R 34.10/GOST R 34.11-94 ECGOST Signature with Old-Style Hash
  • - *
  • GOST R 34.10/GOST R 34.11 ECGOST Signature with Streebog Hash
  • - *
  • GOST 28147-MAC MAC base on GOST 28147
  • - *
  • GOST R 34.12-MAC MAC base on GOST R 34.12
  • - *
  • GOST R 34.11-HMAC HMAC base on GOST 34.11
  • - *
  • SHA-HMAC HMAC base on SHA
  • - *
- * For additional modes see {@link GostSign}, {@link GostDigest} and {@link GostCipher} - * - * @memberOf SubtleCrypto - * @method verify - * @instance - * @param {AlgorithmIdentifier} algorithm Algorithm identifier - * @param {Key} key Key object - * @param {CryptoOperationData} signature Signature data - * @param {CryptoOperationData} data Operation data - * @returns {Promise} Promise that resolves with boolean value of verification result - */ - SubtleCrypto.prototype.verify = function (algorithm, key, signature, data) // - { - return new Promise(call).then(function () { - if (checkNative(algorithm)) - return rootCrypto.subtle.verify(algorithm, key, signature, data); - - algorithm = normalize(algorithm, 'verify'); - if (algorithm.procreator === 'SC' && algorithm.mode === 'SIGN') { - var obj = gostCrypto.asn1.GostSignature.decode(signature); - signature = {r: obj.r, s: obj.s}; - } - return execute(algorithm, 'verify', - [extractKey('verify', algorithm, key), signature, data]); - }); - }; // - - /** - * The digest method returns a new Promise object that will digest data - * using the specified algorithm identifier. - * WebCrypto API reference {@link http://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-digest}

- * - * Supported algorithm names: - *
    - *
  • GOST R 34.11-94 Old-Style GOST Hash
  • - *
  • GOST R 34.11 GOST Streebog Hash
  • - *
  • SHA SHA Hash
  • - *
- * For additional modes see {@link GostDigest} - * - * @memberOf SubtleCrypto - * @method digest - * @instance - * @param {AlgorithmIdentifier} algorithm Algorithm identifier - * @param {CryptoOperationData} data Operation data - * @returns {Promise} Promise that resolves with {@link CryptoOperationData} - */ - SubtleCrypto.prototype.digest = function (algorithm, data) // - { - return new Promise(call).then(function () { - if (checkNative(algorithm)) - return rootCrypto.subtle.digest(algorithm, data); - - algorithm = normalize(algorithm, 'digest'); - return execute(algorithm, 'digest', [data]); - }); - }; // - - /** - * The generateKey method returns a new Promise object that will key(s) using - * the specified algorithm identifier. Key can be used in according with - * KeyUsages sequence. The recognized key usage values are "encrypt", "decrypt", - * "sign", "verify", "deriveKey", "deriveBits", "wrapKey" and "unwrapKey". - * WebCrypto API reference {@link http://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-generateKey}

- * - * Supported algorithm names: - *
    - *
  • GOST R 34.10 ECGOST Key Pairs
  • - *
  • GOST 28147 Key for encryption GOST 28147 modes
  • - *
  • GOST 28147-KW Key for wrapping GOST 28147 modes
  • - *
  • GOST R 34.12 Key for encryption GOST R 34.12 modes
  • - *
  • GOST R 34.12-KW Key for wrapping GOST R 34.12 modes
  • - *
  • GOST R 34.11-KDF Key for Derivation Algorithm
  • - *
- * For additional modes see {@link GostSign}, {@link GostDigest} and {@link GostCipher}
- * Note: Generation key for GOST R 34.10-94 not supported. - * - * @memberOf SubtleCrypto - * @method generateKey - * @instance - * @param {AlgorithmIdentifier} algorithm Key algorithm identifier - * @param {boolean} extractable Whether or not the raw keying material may be exported by the application - * @param {KeyUsages} keyUsages Key usage array: type of operation that may be performed using a key - * @returns {Promise} Promise that resolves with {@link Key} or {@link KeyPair} in according to key algorithm - */ - SubtleCrypto.prototype.generateKey = function (algorithm, extractable, keyUsages) // - { - return new Promise(call).then(function () { - if (checkNative(algorithm)) - return rootCrypto.subtle.generateKey(algorithm, extractable, keyUsages); - - var privateAlgorithm = algorithm.privateKey, - publicAlgorithm = algorithm.publicKey; - algorithm = normalize(algorithm, 'generateKey'); - if (privateAlgorithm) - privateAlgorithm = normalize(privateAlgorithm, 'generateKey'); - else - privateAlgorithm = algorithm; - if (publicAlgorithm) - publicAlgorithm = normalize(publicAlgorithm, 'generateKey'); - else - publicAlgorithm = algorithm; - return execute(algorithm, 'generateKey', []).then(function (data) { - if (data.publicKey && data.privateKey) - return convertKeyPair(publicAlgorithm, privateAlgorithm, extractable, keyUsages, data.publicKey, data.privateKey); - else - return convertKey(algorithm, extractable, keyUsages, data); - }); - }); - }; // - - /** - * The deriveKey method returns a new Promise object that will key(s) using - * the specified algorithm identifier. Key can be used in according with - * KeyUsage sequence. The recognized key usage values are "encrypt", "decrypt", - * "sign", "verify", "deriveKey", "deriveBits", "wrapKey" and "unwrapKey". - * WebCrypto API reference {@link http://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-deriveKey}

- * - * Supported algorithm names: - *
    - *
  • GOST R 34.10-DH ECDH Key Agreement mode
  • - *
  • GOST R 34.11-KDF Key for Derivation Algorithm
  • - *
  • GOST R 34.11-PBKDF2 Password Based Key for Derivation Algorithm
  • - *
  • GOST R 34.11-PFXKDF PFX Key for Derivation Algorithm
  • - *
  • GOST R 34.11-CPKDF Password Based Key for CryptoPro Derivation Algorithm
  • - *
  • SHA-PBKDF2 Password Based Key for Derivation Algorithm
  • - *
  • SHA-PFXKDF PFX Key for Derivation Algorithm
  • - *
- * For additional modes see {@link GostSign} and {@link GostDigest} - * - * @memberOf SubtleCrypto - * @method deriveKey - * @instance - * @param {AlgorithmIdentifier} algorithm Algorithm identifier - * @param {Key} baseKey Derivation key object - * @param {AlgorithmIdentifier} derivedKeyType Derived key algorithm identifier - * @param {boolean} extractable Whether or not the raw keying material may be exported by the application - * @param {KeyUsages} keyUsages Key usage array: type of operation that may be performed using a key - * @returns {Promise} Promise that resolves with {@link Key} - */ - SubtleCrypto.prototype.deriveKey = function (algorithm, baseKey, - derivedKeyType, extractable, keyUsages) // - { - return new Promise(call).then(function () { - if (checkNative(algorithm)) - return rootCrypto.subtle.deriveKey(algorithm, baseKey, - derivedKeyType, extractable, keyUsages); - - algorithm = normalize(algorithm, 'deriveKey'); - derivedKeyType = normalize(derivedKeyType, 'generateKey'); - algorithm.keySize = derivedKeyType.keySize; - if (algorithm['public']) { - algorithm['public'].algorithm = normalize(algorithm['public'].algorithm); - algorithm['public'] = extractKey('deriveKey', algorithm, algorithm['public']); - } - return execute(algorithm, 'deriveKey', [extractKey('deriveKey', algorithm, baseKey)]).then(function (data) { - return convertKey(derivedKeyType, extractable, keyUsages, data); - }); - }); - }; // - - /** - * The deriveBits method returns length bits on baseKey using the - * specified algorithm identifier. - * WebCrypto API reference {@link http://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-deriveBits}

- * - * Supported algorithm names: - *
    - *
  • GOST R 34.10-DH ECDH Key Agreement mode
  • - *
  • GOST R 34.11-KDF Key for Derivation Algorithm
  • - *
  • GOST R 34.11-PBKDF2 Password Based Key for Derivation Algorithm
  • - *
  • GOST R 34.11-PFXKDF PFX Key for Derivation Algorithm
  • - *
  • GOST R 34.11-CPKDF Password Based Key for CryptoPro Derivation Algorithm
  • - *
  • SHA-PBKDF2 Password Based Key for Derivation Algorithm
  • - *
  • SHA-PFXKDF PFX Key for Derivation Algorithm
  • - *
- * For additional modes see {@link GostSign} and {@link GostDigest} - * - * @memberOf SubtleCrypto - * @method deriveBits - * @instance - * @param {AlgorithmIdentifier} algorithm Algorithm identifier - * @param {Key} baseKey Derivation key object - * @param {number} length Length bits - * @returns {Promise} Promise that resolves with {@link CryptoOperationData} - */ - SubtleCrypto.prototype.deriveBits = function (algorithm, baseKey, length) // - { - return new Promise(call).then(function () { - if (checkNative(algorithm)) - return rootCrypto.subtle.deriveBits(algorithm, baseKey, length); - - algorithm = normalize(algorithm, 'deriveBits'); - if (algorithm['public']) - algorithm['public'] = extractKey('deriveBits', algorithm, algorithm['public']); - return execute(algorithm, 'deriveBits', [extractKey('deriveBits', algorithm, baseKey), length]); - }); - }; // - - /** - * The importKey method returns a new Promise object that will key(s) using - * the specified algorithm identifier. Key can be used in according with - * KeyUsage sequence. The recognized key usage values are "encrypt", "decrypt", - * "sign", "verify", "deriveKey", "deriveBits", "wrapKey" and "unwrapKey".

- * Parameter keyData contains data in defined format. - * The suppored key format values are: - *
    - *
  • 'raw' - An unformatted sequence of bytes. Intended for secret keys.
  • - *
  • 'pkcs8' - The DER encoding of the PrivateKeyInfo structure from RFC 5208.
  • - *
  • 'spki' - The DER encoding of the SubjectPublicKeyInfo structure from RFC 5280.
  • - *
- * WebCrypto API reference {@link http://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-importKey}

- * - * Supported algorithm names: - *
    - *
  • GOST R 34.10-94 GOST Private and Public keys
  • - *
  • GOST R 34.10 ECGOST Private and Public keys
  • - *
  • GOST 28147 Key for encryption GOST 28147 modes
  • - *
  • GOST 28147-KW Key for key wrapping GOST 28147 modes
  • - *
  • GOST R 34.12 Key for encryption GOST 34.12 modes
  • - *
  • GOST R 34.12-KW Key for key wrapping GOST 34.12 modes
  • - *
  • GOST R 34.11-KDF Key for Derivation Algorithm
  • - *
- * For additional modes see {@link GostSign}, {@link GostDigest} and {@link GostCipher}
- * - * @memberOf SubtleCrypto - * @method importKey - * @instance - * @param {KeyFormat} format Key format Format specifies a serialization format for a key - * @param {CryptoOperationData} keyData - * @param {AlgorithmIdentifier} algorithm Key algorithm identifier - * @param {boolean} extractable Whether or not the raw keying material may be exported by the application - * @param {KeyUsages} keyUsages Key usage array: type of operation that may be performed using a key - * @returns {Promise} Promise that resolves with {@link Key} - */ - SubtleCrypto.prototype.importKey = function (format, keyData, algorithm, extractable, keyUsages) // - { - var type; - return new Promise(call).then(function () { - if (checkNative(algorithm)) - return rootCrypto.subtle.importKey(format, keyData, algorithm, extractable, keyUsages); - - if (format === 'raw') { - algorithm = normalize(algorithm, 'importKey'); - if (keyUsages && keyUsages.indexOf) { - var name = algorithm.name.toUpperCase().replace(/[\.\s]/g, ''); - if (name.indexOf('3410') >= 0 && keyUsages.indexOf('sign') >= 0) - type = 'private'; - else if (name.indexOf('3410') >= 0 && keyUsages.indexOf('verify') >= 0) - type = 'public'; - } - return keyData; - } else { - var key; - if (format === 'pkcs8') - key = gostCrypto.asn1.GostPrivateKeyInfo.decode(keyData).object; - else if (format === 'spki') - key = gostCrypto.asn1.GostSubjectPublicKeyInfo.decode(keyData).object; - else - throw new NotSupportedError('Key format not supported'); - - algorithm = normalize(key.algorithm, 'importKey'); - type = key.type; - if (extractable !== false) - extractable = extractable || key.extractable; - if (keyUsages) { - for (var i = 0; i < keyUsages.length; i++) { - if (key.usages.indexOf(keyUsages[i]) < 0) - throw DataError('Key usage not valid for this key'); - } - } else - keyUsages = key.usages; - var data = key.buffer, keySize = algorithm.keySize, dataLen = data.byteLength; - if (type === 'public' || keySize === dataLen) - return data; - else { - // Remove private key masks - if (dataLen % keySize > 0) - throw new DataError('Invalid key size'); - algorithm.mode = 'MASK'; - algorithm.procreator = 'VN'; - var chain = []; - for (var i = keySize; i < dataLen; i += keySize) { - chain.push((function (mask) { - return function (data) { - return execute(algorithm, 'unwrapKey', [mask, data]).then(function (data) { - var next = chain.pop(); - if (next) - return next(data); - else { - delete algorithm.mode; - return data; - } - }); - }; - })(new Uint8Array(data, i, keySize))); - } - return chain.pop()(new Uint8Array(data, 0, keySize)); - } - } - }).then(function (data) { - return convertKey(algorithm, extractable, keyUsages, data, type); - }); - }; // - - /** - * The exportKey method returns a new Promise object that will key data in - * defined format.

- * The suppored key format values are: - *
    - *
  • 'raw' - An unformatted sequence of bytes. Intended for secret keys.
  • - *
  • 'pkcs8' - The DER encoding of the PrivateKeyInfo structure from RFC 5208.
  • - *
  • 'spki' - The DER encoding of the SubjectPublicKeyInfo structure from RFC 5280.
  • - *
- * WebCrypto API reference {@link http://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-exportKey}

- * - * Supported algorithm names: - *
    - *
  • GOST R 34.10-94 GOST Private and Public keys
  • - *
  • GOST R 34.10 ECGOST Private and Public keys
  • - *
  • GOST 28147 Key for encryption GOST 28147 modes
  • - *
  • GOST 28147-KW Key for key wrapping GOST 28147 modes
  • - *
  • GOST R 34.12 Key for encryption GOST R 34.12 modes
  • - *
  • GOST R 34.12-KW Key for key wrapping GOST R 34.12 modes
  • - *
  • GOST R 34.11-KDF Key for Derivation Algorithm
  • - *
  • GOST R 34.11-PBKDF2 Import Password for Key for Derivation Algorithm
  • - *
  • GOST R 34.11-PFXKDF Import PFX Key for Derivation Algorithm
  • - *
  • GOST R 34.11-CPKDF Import Password Key for CryptoPro Derivation Algorithm
  • - *
  • SHA-PBKDF2 Import Password for Key for Derivation Algorithm
  • - *
  • SHA-PFXKDF Import PFX Key for Derivation Algorithm
  • - *
- * For additional modes see {@link GostSign}, {@link GostDigest} and {@link GostCipher}
- * - * @memberOf SubtleCrypto - * @method exportKey - * @instance - * @param {KeyFormat} format Format specifies a serialization format for a key - * @param {Key} key Key object - * @returns {Promise} Promise that resolves with {@link CryptoOperationData} - */ - SubtleCrypto.prototype.exportKey = function (format, key) // - { - return new Promise(call).then(function () { - if (key && checkNative(key.algorithm)) - return rootCrypto.subtle.exportKey(format, key); - - if (!key.extractable) - throw new InvalidAccessError('Key not extractable'); - - var raw = extractKey(null, null, key); - if (format === 'raw') - return raw; - else if (format === 'pkcs8' && key.algorithm && key.algorithm.id) { - if (key.algorithm.procreator === 'VN') { - // Add masks for ViPNet - var algorithm = key.algorithm, mask; - algorithm.mode = 'MASK'; - return execute(algorithm, 'generateKey').then(function (data) { - mask = data; - return execute(algorithm, 'wrapKey', [mask, key.buffer]); - }).then(function (data) { - delete algorithm.mode; - var d = new Uint8Array(data.byteLength + mask.byteLength); - d.set(new Uint8Array(data, 0, data.byteLength)); - d.set(new Uint8Array(mask, 0, mask.byteLength), data.byteLength); - var buffer = d.buffer; - buffer.enclosed = true; - return gostCrypto.asn1.GostPrivateKeyInfo.encode({ - algorithm: algorithm, - buffer: buffer - }); - }); - } else - return gostCrypto.asn1.GostPrivateKeyInfo.encode(key); - } else if (format === 'spki' && key.algorithm && key.algorithm.id) - return gostCrypto.asn1.GostSubjectPublicKeyInfo.encode(key); - else - throw new NotSupportedError('Key format not supported'); - }); - }; // - - /** - * The wrapKey method returns a new Promise object that will wrapped key(s). - * WebCrypto API reference {@link http://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-wrapKey}

- * - * Supported algorithm names: - *
    - *
  • GOST 28147-KW Key Wrapping GOST 28147 modes
  • - *
  • GOST R 34.12-KW Key Wrapping GOST R 34.12 modes
  • - *
  • GOST 28147-MASK Key Mask GOST 28147 modes
  • - *
  • GOST R 34.12-MASK Key Mask GOST R 34.12 modes
  • - *
  • GOST R 34.10-MASK Key Mask GOST R 34.10 modes
  • - *
- * For additional modes see {@link GostCipher}
- * - * @memberOf SubtleCrypto - * @method wrapKey - * @instance - * @param {KeyFormat} format Format specifies a serialization format for a key. Now suppored only 'raw' key format. - * @param {Key} key Key object - * @param {Key} wrappingKey Wrapping key object - * @param {AlgorithmIdentifier} wrapAlgorithm Algorithm identifier - * @returns {Promise} Promise that resolves with {@link CryptoOperationData} - */ - SubtleCrypto.prototype.wrapKey = function (format, key, wrappingKey, wrapAlgorithm) // - { - return new Promise(call).then(function () { - if (checkNative(wrapAlgorithm)) - return rootCrypto.subtle.wrapKey(format, key, wrappingKey, wrapAlgorithm); - - wrapAlgorithm = normalize(wrapAlgorithm, 'wrapKey'); - var keyData = extractKey(null, null, key); - if (wrapAlgorithm.procreator === 'SC' && key.type === 'private') - keyData = swapBytes(keyData); - return execute(wrapAlgorithm, 'wrapKey', - [extractKey('wrapKey', wrapAlgorithm, wrappingKey), keyData]).then(function (data) { - if (format === 'raw') - return data; - else - throw new NotSupportedError('Key format not supported'); - }); - }); - }; // - - /** - * The unwrapKey method returns a new Promise object that will unwrapped key(s). - * WebCrypto API reference {@link http://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-unwrapKey}

- * - * Supported algorithm names: - *
    - *
  • GOST 28147-KW Key Wrapping GOST 28147 modes
  • - *
  • GOST R 34.12-KW Key Wrapping GOST R 34.12 modes
  • - *
  • GOST 28147-MASK Key Mask GOST 28147 modes
  • - *
  • GOST R 34.12-MASK Key Mask GOST R 34.12 modes
  • - *
  • GOST R 34.10-MASK Key Mask GOST R 34.10 modes
  • - *
- * For additional modes see {@link GostCipher}
- * - * @memberOf SubtleCrypto - * @method unwrapKey - * @instance - * @param {KeyFormat} format Format specifies a serialization format for a key. Now suppored only 'raw' key format. - * @param {CryptoOperationData} wrappedKey Wrapped key data - * @param {Key} unwrappingKey Unwrapping key object - * @param {AlgorithmIdentifier} unwrapAlgorithm Algorithm identifier - * @param {AlgorithmIdentifier} unwrappedKeyAlgorithm Key algorithm identifier - * @param {boolean} extractable Whether or not the raw keying material may be exported by the application - * @param {KeyUsages} keyUsages Key usage array: type of operation that may be performed using a key - * @returns {Promise} Promise that resolves with {@link Key} - */ - SubtleCrypto.prototype.unwrapKey = function (format, wrappedKey, unwrappingKey, - unwrapAlgorithm, unwrappedKeyAlgorithm, extractable, keyUsages) // - { - return new Promise(call).then(function () { - if (checkNative(unwrapAlgorithm)) - return rootCrypto.subtle.unwrapKey(format, wrappedKey, unwrappingKey, - unwrapAlgorithm, unwrappedKeyAlgorithm, extractable, keyUsages); - - unwrapAlgorithm = normalize(unwrapAlgorithm, 'unwrapKey'); - unwrappedKeyAlgorithm = normalize(unwrappedKeyAlgorithm, 'importKey'); - if (format !== 'raw') - throw new NotSupportedError('Key format not supported'); - - return execute(unwrapAlgorithm, 'unwrapKey', [extractKey('unwrapKey', unwrapAlgorithm, unwrappingKey), wrappedKey]).then(function (data) { - var type; - if (unwrappedKeyAlgorithm && unwrappedKeyAlgorithm.name) { - var name = unwrappedKeyAlgorithm.name.toUpperCase().replace(/[\.\s]/g, ''); - if (name.indexOf('3410') >= 0 && keyUsages.indexOf('sign') >= 0) - type = 'private'; - else if (name.indexOf('3410') >= 0 && keyUsages.indexOf('verify') >= 0) - type = 'public'; - } - if (unwrapAlgorithm.procreator === 'SC' && type === 'private') - data = swapBytes(data); - return convertKey(unwrappedKeyAlgorithm, extractable, keyUsages, data, type); - }); - }); - }; // - - /** - * The subtle attribute provides an instance of the SubtleCrypto - * interface which provides low-level cryptographic primitives and - * algorithms. - * - * @memberOf gostCrypto - * @type SubtleCrypto - */ - gostCrypto.subtle = new SubtleCrypto(); - - /** - * The getRandomValues method generates cryptographically random values. - * - * First try to use Web Crypto random genereator. Next make random - * bytes based on standart Math.random mixed with time and mouse pointer - * - * @memberOf gostCrypto - * @param {(CryptoOperationData)} array Destination buffer for random data - */ - gostCrypto.getRandomValues = function (array) // - { - // Execute randomizer - GostRandom = GostRandom || root.GostRandom; - var randomSource = GostRandom ? new GostRandom() : rootCrypto; - if (randomSource.getRandomValues) - randomSource.getRandomValues(array); - else - throw new NotSupportedError('Random generator not found'); - }; // - //
- - return gostCrypto; -})); diff --git a/src/core/vendor/streebog/gostCrypto.mjs b/src/core/vendor/streebog/gostCrypto.mjs new file mode 100644 index 00000000..0e02f6e4 --- /dev/null +++ b/src/core/vendor/streebog/gostCrypto.mjs @@ -0,0 +1,1653 @@ +/** + * Implementation Web Crypto interfaces for GOST algorithms + * 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'; +import gostEngine from './gostEngine'; + +import crypto from 'crypto' + +/* +* Algorithm normalization +* +*/ // + +var root = {}; +root.gostEngine = gostEngine; + +var rootCrypto = crypto + +var SyntaxError = Error, + DataError = Error, + NotSupportedError = Error, + OperationError = Error, + InvalidStateError = Error, + InvalidAccessError = Error; + +// Normalize algorithm +function normalize(algorithm, method) { + if (typeof algorithm === 'string' || algorithm instanceof String) + algorithm = {name: algorithm}; + var name = algorithm.name; + if (!name) + throw new SyntaxError('Algorithm name not defined'); + // Extract algorithm modes from name + var modes = name.split('/'), modes = modes[0].split('-').concat(modes.slice(1)); + // Normalize the name with default modes + var na = {}; + name = modes[0].replace(/[\.\s]/g, ''); + modes = modes.slice(1); + if (name.indexOf('28147') >= 0) { + na = { + name: 'GOST 28147', + version: 1989, + mode: (algorithm.mode || (// ES, MAC, KW + (method === 'sign' || method === 'verify') ? 'MAC' : + (method === 'wrapKey' || method === 'unwrapKey') ? 'KW' : 'ES')).toUpperCase(), + length: algorithm.length || 64 + }; + } else if (name.indexOf('3412') >= 0) { + na = { + name: 'GOST R 34.12', + version: 2015, + mode: (algorithm.mode || (// ES, MAC, KW + (method === 'sign' || method === 'verify') ? 'MAC' : + (method === 'wrapKey' || method === 'unwrapKey') ? 'KW' : 'ES')).toUpperCase(), + length: algorithm.length || 64 // 128 + }; + } else if (name.indexOf('3411') >= 0) { + na = { + name: 'GOST R 34.11', + version: 2012, // 1994 + mode: (algorithm.mode || (// HASH, KDF, HMAC, PBKDF2, PFXKDF, CPKDF + (method === 'deriveKey' || method === 'deriveBits') ? 'KDF' : + (method === 'sign' || method === 'verify') ? 'HMAC' : 'HASH')).toUpperCase(), + length: algorithm.length || 256 // 512 + }; + } else if (name.indexOf('3410') >= 0) { + na = { + name: 'GOST R 34.10', + version: 2012, // 1994, 2001 + mode: (algorithm.mode || (// SIGN, DH, MASK + (method === 'deriveKey' || method === 'deriveBits') ? 'DH' : 'SIGN')).toUpperCase(), + length: algorithm.length || 256 // 512 + }; + } else if (name.indexOf('SHA') >= 0) { + na = { + name: 'SHA', + version: (algorithm.length || 160) === 160 ? 1 : 2, // 1, 2 + mode: (algorithm.mode || (// HASH, KDF, HMAC, PBKDF2, PFXKDF + (method === 'deriveKey' || method === 'deriveBits') ? 'KDF' : + (method === 'sign' || method === 'verify') ? 'HMAC' : 'HASH')).toUpperCase(), + length: algorithm.length || 160 + }; + } else if (name.indexOf('RC2') >= 0) { + na = { + name: 'RC2', + version: 1, + mode: (algorithm.mode || (// ES, MAC, KW + (method === 'sign' || method === 'verify') ? 'MAC' : + (method === 'wrapKey' || method === 'unwrapKey') ? 'KW' : 'ES')).toUpperCase(), + length: algorithm.length || 32 // 1 - 1024 + }; + } else if (name.indexOf('PBKDF2') >= 0) { + na = normalize(algorithm.hash, 'digest'); + na.mode = 'PBKDF2'; + } else if (name.indexOf('PFXKDF') >= 0) { + na = normalize(algorithm.hash, 'digest'); + na.mode = 'PFXKDF'; + } else if (name.indexOf('CPKDF') >= 0) { + na = normalize(algorithm.hash, 'digest'); + na.mode = 'CPKDF'; + } else if (name.indexOf('HMAC') >= 0) { + na = normalize(algorithm.hash, 'digest'); + na.mode = 'HMAC'; + } else + throw new NotSupportedError('Algorithm not supported'); + + // Compile modes + modes.forEach(function (mode) { + mode = mode.toUpperCase(); + if (/^[0-9]+$/.test(mode)) { + if ((['8', '16', '32'].indexOf(mode) >= 0) || (na.length === '128' && mode === '64')) { // Shift bits + if (na.mode === 'ES') + na.shiftBits = parseInt(mode); + else if (na.mode === 'MAC') + na.macLength = parseInt(mode); + else + throw new NotSupportedError('Algorithm ' + na.name + ' mode ' + mode + ' not supported'); + } else if (['89', '94', '01', '12', '15', '1989', '1994', '2001', '2012', '2015'].indexOf(mode) >= 0) { // GOST Year + var version = parseInt(mode); + version = version < 1900 ? (version < 80 ? 2000 + version : 1900 + version) : version; + na.version = version; + } else if (['1'].indexOf(mode) >= 0 && na.name === 'SHA') { // SHA-1 + na.version = 1; + na.length = 160; + } else if (['256', '384', '512'].indexOf(mode) >= 0 && na.name === 'SHA') { // SHA-2 + na.version = 2; + na.length = parseInt(mode); + } else if (['40', '128'].indexOf(mode) >= 0 && na.name === 'RC2') { // RC2 + na.version = 1; + na.length = parseInt(mode); // key size + } else if (['64', '128', '256', '512'].indexOf(mode) >= 0) // block size + na.length = parseInt(mode); + else if (['1000', '2000'].indexOf(mode) >= 0) // Iterations + na.iterations = parseInt(mode); + // Named Paramsets + } else if (['E-TEST', 'E-A', 'E-B', 'E-C', 'E-D', 'E-SC', 'E-Z', 'D-TEST', 'D-A', 'D-SC'].indexOf(mode) >= 0) { + na.sBox = mode; + } else if (['S-TEST', 'S-A', 'S-B', 'S-C', 'S-D', 'X-A', 'X-B', 'X-C'].indexOf(mode) >= 0) { + na.namedParam = mode; + } else if (['S-256-TEST', 'S-256-A', 'S-256-B', 'S-256-C', 'P-256', 'T-512-TEST', 'T-512-A', + 'T-512-B', 'X-256-A', 'X-256-B', 'T-256-TEST', 'T-256-A', 'T-256-B', 'S-256-B', 'T-256-C', 'S-256-C'].indexOf(mode) >= 0) { + na.namedCurve = mode; + } else if (['SC', 'CP', 'VN'].indexOf(mode) >= 0) { + na.procreator = mode; + + // Encription GOST 28147 or GOST R 34.12 + } else if (na.name === 'GOST 28147' || na.name === 'GOST R 34.12' || na.name === 'RC2') { + if (['ES', 'MAC', 'KW', 'MASK'].indexOf(mode) >= 0) { + na.mode = mode; + } else if (['ECB', 'CFB', 'OFB', 'CTR', 'CBC'].indexOf(mode) >= 0) { + na.mode = 'ES'; + na.block = mode; + } else if (['CPKW', 'NOKW', 'SCKW'].indexOf(mode) >= 0) { + na.mode = 'KW'; + na.keyWrapping = mode.replace('KW', ''); + } else if (['ZEROPADDING', 'PKCS5PADDING', 'NOPADDING', 'RANDOMPADDING', 'BITPADDING'].indexOf(mode) >= 0) { + na.padding = mode.replace('PADDING', ''); + } else if (['NOKM', 'CPKM'].indexOf(mode) >= 0) { + na.keyMeshing = mode.replace('KM', ''); + } else + throw new NotSupportedError('Algorithm ' + na.name + ' mode ' + mode + ' not supported'); + + // Digesting GOST 34.11 + } else if (na.name === 'GOST R 34.11' || na.name === 'SHA') { + if (['HASH', 'KDF', 'HMAC', 'PBKDF2', 'PFXKDF', 'CPKDF'].indexOf(mode) >= 0) + na.mode = mode; + else + throw new NotSupportedError('Algorithm ' + na.name + ' mode ' + mode + ' not supported'); + + // Signing GOST 34.10 + } else if (na.name === 'GOST R 34.10') { + var hash = mode.replace(/[\.\s]/g, ''); + if (hash.indexOf('GOST') >= 0 && hash.indexOf('3411') >= 0) + na.hash = mode; + else if (['SIGN', 'DH', 'MASK'].indexOf(mode)) + na.mode = mode; + else + throw new NotSupportedError('Algorithm ' + na.name + ' mode ' + mode + ' not supported'); + } + }); + + // Procreator + na.procreator = algorithm.procreator || na.procreator || 'CP'; + + // Key size + switch (na.name) { + case 'GOST R 34.10': + na.keySize = na.length / (na.version === 1994 ? 4 : 8); + break; + case 'GOST R 34.11': + na.keySize = 32; + break; + case 'GOST 28147': + case 'GOST R 34.12': + na.keySize = 32; + break; + case 'RC2': + na.keySize = Math.ceil(na.length / 8); + break; + case 'SHA': + na.keySize = na.length / 8; + break; + } + + // Encrypt additional modes + if (na.mode === 'ES') { + if (algorithm.block) + na.block = algorithm.block; // ECB, CFB, OFB, CTR, CBC + if (na.block) + na.block = na.block.toUpperCase(); + if (algorithm.padding) + na.padding = algorithm.padding; // NO, ZERO, PKCS5, RANDOM, BIT + if (na.padding) + na.padding = na.padding.toUpperCase(); + if (algorithm.shiftBits) + na.shiftBits = algorithm.shiftBits; // 8, 16, 32, 64 + if (algorithm.keyMeshing) + na.keyMeshing = algorithm.keyMeshing; // NO, CP + if (na.keyMeshing) + na.keyMeshing = na.keyMeshing.toUpperCase(); + // Default values + if (method !== 'importKey' && method !== 'generateKey') { + na.block = na.block || 'ECB'; + na.padding = na.padding || (na.block === 'CBC' || na.block === 'ECB' ? 'ZERO' : 'NO'); + if (na.block === 'CFB' || na.block === 'OFB') + na.shiftBits = na.shiftBits || na.length; + na.keyMeshing = na.keyMeshing || 'NO'; + } + } + if (na.mode === 'KW') { + if (algorithm.keyWrapping) + na.keyWrapping = algorithm.keyWrapping; // NO, CP, SC + if (na.keyWrapping) + na.keyWrapping = na.keyWrapping.toUpperCase(); + if (method !== 'importKey' && method !== 'generateKey') + na.keyWrapping = na.keyWrapping || 'NO'; + } + + // Paramsets + ['sBox', 'namedParam', 'namedCurve', 'curve', 'param', 'modulusLength'].forEach(function (name) { + algorithm[name] && (na[name] = algorithm[name]); + }); + // Default values + if (method !== 'importKey' && method !== 'generateKey') { + if (na.name === 'GOST 28147') { + na.sBox = na.sBox || (na.procreator === 'SC' ? 'E-SC' : 'E-A'); // 'E-A', 'E-B', 'E-C', 'E-D', 'E-SC' + } else if (na.name === 'GOST R 34.12' && na.length === 64) { + na.sBox = 'E-Z'; + } else if (na.name === 'GOST R 34.11' && na.version === 1994) { + na.sBox = na.sBox || (na.procreator === 'SC' ? 'D-SC' : 'D-A'); // 'D-SC' + } else if (na.name === 'GOST R 34.10' && na.version === 1994) { + na.namedParam = na.namedParam || (na.mode === 'DH' ? 'X-A' : 'S-A'); // 'S-B', 'S-C', 'S-D', 'X-B', 'X-C' + } else if (na.name === 'GOST R 34.10' && na.version === 2001) { + na.namedCurve = na.namedCurve || (na.length === 256 ? + na.procreator === 'SC' ? 'P-256' : (na.mode === 'DH' ? 'X-256-A' : 'S-256-A') : // 'S-256-B', 'S-256-C', 'X-256-B', 'T-256-A', 'T-256-B', 'T-256-C', 'P-256' + na.mode === 'T-512-A'); // 'T-512-B', 'T-512-C' + } else if (na.name === 'GOST R 34.10' && na.version === 2012) { + na.namedCurve = na.namedCurve || (na.length === 256 ? + na.procreator === 'SC' ? 'P-256' : (na.mode === 'DH' ? 'X-256-A' : 'S-256-A') : // 'S-256-B', 'S-256-C', 'X-256-B', 'T-256-A', 'T-256-B', 'T-256-C', 'P-256' + na.mode === 'T-512-A'); // 'T-512-B', 'T-512-C' + } + } + + // Vectors + switch (na.mode) { + case 'DH': + algorithm.ukm && (na.ukm = algorithm.ukm); + algorithm['public'] && (na['public'] = algorithm['public']); + break; + case 'SIGN': + case 'KW': + algorithm.ukm && (na.ukm = algorithm.ukm); + break; + case 'ES': + case 'MAC': + algorithm.iv && (na.iv = algorithm.iv); + break; + case 'KDF': + algorithm.label && (na.label = algorithm.label); + algorithm.contex && (na.context = algorithm.contex); + break; + case 'PBKDF2': + algorithm.salt && (na.salt = algorithm.salt); + algorithm.iterations && (na.iterations = algorithm.iterations); + algorithm.diversifier && (na.diversifier = algorithm.diversifier); + break; + case 'PFXKDF': + algorithm.salt && (na.salt = algorithm.salt); + algorithm.iterations && (na.iterations = algorithm.iterations); + algorithm.diversifier && (na.diversifier = algorithm.diversifier); + break; + case 'CPKDF': + algorithm.salt && (na.salt = algorithm.salt); + algorithm.iterations && (na.iterations = algorithm.iterations); + break; + } + + // Verification method and modes + if (method && ( + ((na.mode !== 'ES' && na.mode !== 'SIGN' && na.mode !== 'MAC' && + na.mode !== 'HMAC' && na.mode !== 'KW' && na.mode !== 'DH' + && na.mode !== 'MASK') && + (method === 'generateKey')) || + ((na.mode !== 'ES') && + (method === 'encrypt' || method === 'decrypt')) || + ((na.mode !== 'SIGN' && na.mode !== 'MAC' && na.mode !== 'HMAC') && + (method === 'sign' || method === 'verify')) || + ((na.mode !== 'HASH') && + (method === 'digest')) || + ((na.mode !== 'KW' && na.mode !== 'MASK') && + (method === 'wrapKey' || method === 'unwrapKey')) || + ((na.mode !== 'DH' && na.mode !== 'PBKDF2' && na.mode !== 'PFXKDF' && + na.mode !== 'CPKDF' && na.mode !== 'KDF') && + (method === 'deriveKey' || method === 'deriveBits')))) + throw new NotSupportedError('Algorithm mode ' + na.mode + ' not valid for method ' + method); + + // Normalize hash algorithm + algorithm.hash && (na.hash = algorithm.hash); + if (na.hash) { + if ((typeof na.hash === 'string' || na.hash instanceof String) + && na.procreator) + na.hash = na.hash + '/' + na.procreator; + na.hash = normalize(na.hash, 'digest'); + } + + // Algorithm object identirifer + algorithm.id && (na.id = algorithm.id); + + return na; +} + +// Check for possibility use native crypto.subtle +function checkNative(algorithm) { + if (!rootCrypto || !rootCrypto.subtle || !algorithm) + return false; + // Prepare name + var name = (typeof algorithm === 'string' || algorithm instanceof String) ? + name = algorithm : algorithm.name; + if (!name) + return false; + name = name.toUpperCase(); + // Digest algorithm for key derivation + if ((name.indexOf('KDF') >= 0 || name.indexOf('HMAC') >= 0) && algorithm.hash) + return checkNative(algorithm.hash); + // True if no supported names + return name.indexOf('GOST') === -1 && + name.indexOf('SHA-1') === -1 && + name.indexOf('RC2') === -1 && + name.indexOf('?DES') === -1; +} +// + +/* + * Key conversion methods + * + */ // + +// Check key parameter +function checkKey(key, method) { + if (!key.algorithm) + throw new SyntaxError('Key algorithm not defined'); + + if (!key.algorithm.name) + throw new SyntaxError('Key algorithm name not defined'); + + var name = key.algorithm.name, + gostCipher = name === 'GOST 28147' || name === 'GOST R 34.12' || name === 'RC2', + gostDigest = name === 'GOST R 34.11' || name === 'SHA', + gostSign = name === 'GOST R 34.10'; + + if (!gostCipher && !gostSign && !gostDigest) + throw new NotSupportedError('Key algorithm ' + name + ' is unsupproted'); + + if (!key.type) + throw new SyntaxError('Key type not defined'); + + if (((gostCipher || gostDigest) && key.type !== 'secret') || + (gostSign && !(key.type === 'public' || key.type === 'private'))) + throw new DataError('Key type ' + key.type + ' is not valid for algorithm ' + name); + + if (!key.usages || !key.usages.indexOf) + throw new SyntaxError('Key usages not defined'); + + for (var i = 0, n = key.usages.length; i < n; i++) { + var md = key.usages[i]; + if (((md === 'encrypt' || md === 'decrypt') && key.type !== 'secret') || + (md === 'sign' && key.type === 'public') || + (md === 'verify' && key.type === 'private')) + throw new InvalidStateError('Key type ' + key.type + ' is not valid for ' + md); + } + + if (method) + if (key.usages.indexOf(method) === -1) + throw new InvalidAccessError('Key usages is not contain method ' + method); + + if (!key.buffer) + throw new SyntaxError('Key buffer is not defined'); + + var size = key.buffer.byteLength * 8, keySize = 8 * key.algorithm.keySize; + if ((key.type === 'secret' && size !== (keySize || 256) && + (key.usages.indexOf('encrypt') >= 0 || key.usages.indexOf('decrypt') >= 0)) || + (key.type === 'private' && !(size === 256 || size === 512)) || + (key.type === 'public' && !(size === 512 || size === 1024))) + throw new SyntaxError('Key buffer has wrong size ' + size + ' bit'); +} + +// Extract key and enrich cipher algorithm +function extractKey(method, algorithm, key) { + checkKey(key, method); + if (algorithm) { + var params; + switch (algorithm.mode) { + case 'ES': + params = ['sBox', 'keyMeshing', 'padding', 'block']; + break; + case 'SIGN': + params = ['namedCurve', 'namedParam', 'sBox', 'curve', 'param', 'modulusLength']; + break; + case 'MAC': + params = ['sBox']; + break; + case 'KW': + params = ['keyWrapping', 'ukm']; + break; + case 'DH': + params = ['namedCurve', 'namedParam', 'sBox', 'ukm', 'curve', 'param', 'modulusLength']; + break; + case 'KDF': + params = ['context', 'label']; + break; + case 'PBKDF2': + params = ['sBox', 'iterations', 'salt']; + break; + case 'PFXKDF': + params = ['sBox', 'iterations', 'salt', 'diversifier']; + break; + case 'CPKDF': + params = ['sBox', 'salt']; + break; + } + if (params) + params.forEach(function (name) { + key.algorithm[name] && (algorithm[name] = key.algorithm[name]); + }); + } + return key.buffer; +} + +// Make key definition +function convertKey(algorithm, extractable, keyUsages, keyData, keyType) { + var key = { + type: keyType || (algorithm.name === 'GOST R 34.10' ? 'private' : 'secret'), + extractable: extractable || 'false', + algorithm: algorithm, + usages: keyUsages || [], + buffer: keyData + }; + checkKey(key); + return key; +} + +function convertKeyPair(publicAlgorithm, privateAlgorithm, extractable, keyUsages, publicBuffer, privateBuffer) { + + if (!keyUsages || !keyUsages.indexOf) + throw new SyntaxError('Key usages not defined'); + + var publicUsages = keyUsages.filter(function (value) { + return value !== 'sign'; + }); + var privateUsages = keyUsages.filter(function (value) { + return value !== 'verify'; + }); + + return { + publicKey: convertKey(publicAlgorithm, extractable, publicUsages, publicBuffer, 'public'), + privateKey: convertKey(privateAlgorithm, extractable, privateUsages, privateBuffer, 'private') + }; +} + +// Swap bytes in buffer +function swapBytes(src) { + if (src instanceof CryptoOperationData) + src = new Uint8Array(src); + var dst = new Uint8Array(src.length); + for (var i = 0, n = src.length; i < n; i++) + dst[n - i - 1] = src[i]; + return dst.buffer; +} +// + +/** + * Promise stub object (not fulfill specification, only for internal use) + * Class not defined if Promise class already defined in root context

+ * + * The Promise object is used for deferred and asynchronous computations. A Promise is in one of the three states: + *
    + *
  • pending: initial state, not fulfilled or rejected.
  • + *
  • fulfilled: successful operation
  • + *
  • rejected: failed operation.
  • + *
+ * Another term describing the state is settled: the Promise is either fulfilled or rejected, but not pending.

+ * @class Promise + * @global + * @param {function} executor Function object with two arguments resolve and reject. + * The first argument fulfills the promise, the second argument rejects it. + * We can call these functions, once our operation is completed. + */ // +if (!Promise) { + + root.Promise = (function () { + + function mswrap(value) { + if (value && value.oncomplete === null && value.onerror === null) { + return new Promise(function (resolve, reject) { + value.oncomplete = function () { + resolve(value.result); + }; + value.onerror = function () { + reject(new OperationError(value.toString())); + }; + }); + } else + return value; + } + + function Promise(executor) { + + var state = 'pending', result, + resolveQueue = [], rejectQueue = []; + + function call(callback) { + try { + callback(); + } catch (e) { + } + } + + try { + executor(function (value) { + if (state === 'pending') { + state = 'fulfilled'; + result = value; + resolveQueue.forEach(call); + } + }, function (reason) { + if (state === 'pending') { + state = 'rejected'; + result = reason; + rejectQueue.forEach(call); + } + }); + } catch (error) { + if (state === 'pending') { + state = 'rejected'; + result = error; + rejectQueue.forEach(call); + } + } + /** + * The then() method returns a Promise. It takes two arguments, both are + * callback functions for the success and failure cases of the Promise. + * + * @method then + * @memberOf Promise + * @instance + * @param {function} onFulfilled A Function called when the Promise is fulfilled. This function has one argument, the fulfillment value. + * @param {function} onRejected A Function called when the Promise is rejected. This function has one argument, the rejection reason. + * @returns {Promise} + */ + this.then = function (onFulfilled, onRejected) { + + return new Promise(function (resolve, reject) { + + function asyncOnFulfilled() { + var value; + try { + value = onFulfilled ? onFulfilled(result) : result; + } catch (error) { + reject(error); + return; + } + value = mswrap(value); + if (value && value.then && value.then.call) { + value.then(resolve, reject); + } else { + resolve(value); + } + } + + function asyncOnRejected() { + var reason; + try { + reason = onRejected ? onRejected(result) : result; + } catch (error) { + reject(error); + return; + } + reason = mswrap(reason); + if (reason && reason.then && reason.then.call) { + reason.then(resolve, reject); + } else { + reject(reason); + } + } + + if (state === 'fulfilled') { + asyncOnFulfilled(); + } else if (state === 'rejected') { + asyncOnRejected(); + } else { + resolveQueue.push(asyncOnFulfilled); + rejectQueue.push(asyncOnRejected); + } + + }); + + }; + /** + * The catch() method returns a Promise and deals with rejected cases only. + * It behaves the same as calling Promise.prototype.then(undefined, onRejected). + * + * @method catch + * @memberOf Promise + * @instance + * @param {function} onRejected A Function called when the Promise is rejected. This function has one argument, the rejection reason. + * @returns {Promise} + */ + this['catch'] = function (onRejected) { + return this.then(undefined, onRejected); + }; + } + + /** + * The Promise.all(iterable) method returns a promise that resolves when all + * of the promises in the iterable argument have resolved.

+ * + * The result is passed as an array of values from all the promises. + * If something passed in the iterable array is not a promise, it's converted to + * one by Promise.resolve. If any of the passed in promises rejects, the + * all Promise immediately rejects with the value of the promise that rejected, + * discarding all the other promises whether or not they have resolved. + * + * @method all + * @memberOf Promise + * @static + * @param {KeyUsages} promises Array with promises. + * @returns {Promise} + */ + Promise.all = function (promises) { + return new Promise(function (resolve, reject) { + var result = [], count = 0; + function asyncResolve(k) { + count++; + return function (data) { + result[k] = data; + count--; + if (count === 0) + resolve(result); + }; + } + + function asyncReject(reason) { + if (count > 0) + reject(reason); + count = 0; + } + + for (var i = 0, n = promises.length; i < n; i++) { + var data = promises[i]; + if (data.then && data.then.call) + data.then(asyncResolve(i), asyncReject); + else + result[i] = data; + } + + if (count === 0) + resolve(result); + }); + }; + + return Promise; + })(); +} //
+ +/* + * Worker executor + * + */ // + +var baseUrl = '', nameSuffix = ''; +// Try to define from DOM model +if (typeof document !== 'undefined') { + (function () { + var regs = /^(.*)gostCrypto(.*)\.js$/i; + var list = document.querySelectorAll('script'); + for (var i = 0, n = list.length; i < n; i++) { + var value = list[i].getAttribute('src'); + var test = regs.exec(value); + if (test) { + baseUrl = test[1]; + nameSuffix = test[2]; + } + } + })(); +} + +// Local importScripts procedure for include dependens +function importScripts() { + for (var i = 0, n = arguments.length; i < n; i++) { + var name = arguments[i].split('.'), + src = baseUrl + name[0] + nameSuffix + '.' + name[1]; + var el = document.querySelector('script[src="' + src + '"]'); + if (!el) { + el = document.createElement('script'); + el.setAttribute('src', src); + document.head.appendChild(el); + } + } +} + +// Create Worker +var worker = false, tasks = [], sequence = 0; +// Worker will create only for first child process and +// Gost implementation libraries not yet loaded +if (!root.importScripts && !root.gostEngine) { + + try { + worker = new Worker(baseUrl + 'gostEngine' + nameSuffix + '.js'); + + // Result of opertion + worker.onmessage = function (event) { + // Find task + var id = event.data.id; + for (var i = 0, n = tasks.length; i < n; i++) + if (tasks[i].id === id) + break; + if (i < n) { + var task = tasks[i]; + tasks.splice(i, 1); + // Reject if error or resolve with result + if (event.data.error) + task.reject(new OperationError(event.data.error)); + else + task.resolve(event.data.result); + } + }; + + // Worker error - reject all waiting tasks + worker.onerror = function (event) { + for (var i = 0, n = tasks.length; i < n; i++) + tasks[i].reject(event.error); + tasks = []; + }; + + } catch (e) { + // Worker is't supported + worker = false; + } +} + +if (!root.importScripts) { + // This procedure emulate load dependents as in Worker + root.importScripts = importScripts; + +} + +if (!worker) { + // Import main module + // Reason: we are already in worker process or Worker interface is not + // yet supported + root.gostEngine || require('./gostEngine'); +} + +// Executor for any method +function execute(algorithm, method, args) { + return new Promise(function (resolve, reject) { + try { + if (worker) { + var id = ++sequence; + tasks.push({ + id: id, + resolve: resolve, + reject: reject + }); + worker.postMessage({ + id: id, algorithm: algorithm, + method: method, args: args + }); + } else { + if (root.gostEngine) + resolve(root.gostEngine.execute(algorithm, method, args)); + else + reject(new OperationError('Module gostEngine not found')); + } + } catch (error) { + reject(error); + } + }); +} + +// Self resolver +function call(callback) { + try { + callback(); + } catch (e) { + } +} + +// + +/* + * WebCrypto common class references + * + */ // +/** + * The Algorithm object is a dictionary object [WebIDL] which is used to + * specify an algorithm and any additional parameters required to fully + * specify the desired operation.
+ *
+ *  dictionary Algorithm {
+ *      DOMString name;
+ *  };
+ * 
+ * WebCrypto API reference {@link http://www.w3.org/TR/WebCryptoAPI/#algorithm-dictionary} + * @class Algorithm + * @param {DOMString} name The name of the registered algorithm to use. + */ + +/** + * AlgorithmIdentifier - Algorithm or DOMString name of algorithm
+ *
+ *  typedef (Algorithm or DOMString) AlgorithmIdentifier;
+ * 
+ * WebCrypto API reference {@link http://www.w3.org/TR/WebCryptoAPI/#algorithm-dictionary} + * @class AlgorithmIdentifier + */ + +/** + * The KeyAlgorithm interface represents information about the contents of a + * given Key object. + *
+ *  interface KeyAlgorithm {
+ *      readonly attribute DOMString name
+ *  };
+ * 
+ * WebCrypto API reference {@link http://www.w3.org/TR/WebCryptoAPI/#key-algorithm-interface} + * @class KeyAlgorithm + * @param {DOMString} name The name of the algorithm used to generate the Key + */ + +/** + * The type of a key. The recognized key type values are "public", "private" + * and "secret". Opaque keying material, including that used for symmetric + * algorithms, is represented by "secret", while keys used as part of asymmetric + * algorithms composed of public/private keypairs will be either "public" or "private". + *
+ *  typedef DOMString KeyType;
+ * 
+ * WebCrypto API reference {@link http://www.w3.org/TR/WebCryptoAPI/#key-interface} + * @class KeyType + */ + +/** + * Sequence of operation type that may be performed using a key. The recognized + * key usage values are "encrypt", "decrypt", "sign", "verify", "deriveKey", + * "deriveBits", "wrapKey" and "unwrapKey". + *
+ *  typedef DOMString[] KeyUsages;
+ * 
+ * WebCrypto API reference {@link http://www.w3.org/TR/WebCryptoAPI/#key-interface} + * @class KeyUsages + */ + +/** + * The Key object represents an opaque reference to keying material that is + * managed by the user agent.
+ * This specification provides a uniform interface for many different kinds of + * keying material managed by the user agent. This may include keys that have + * been generated by the user agent, derived from other keys by the user agent, + * imported to the user agent through user actions or using this API, + * pre-provisioned within software or hardware to which the user agent has + * access or made available to the user agent in other ways. The term key refers + * broadly to any keying material including actual keys for cryptographic + * operations and secret values obtained within key derivation or exchange operations.
+ * The Key object is not required to directly interface with the underlying key + * storage mechanism, and may instead simply be a reference for the user agent + * to understand how to obtain the keying material when needed, eg. when performing + * a cryptographic operation. + *
+ *  interface Key {
+ *      readonly attribute KeyType type;
+ *      readonly attribute boolean extractable;
+ *      readonly attribute KeyAlgorithm algorithm;
+ *      readonly attribute KeyUsages usages;
+ *  };     
+ * 
+ * WebCrypto API reference {@link http://www.w3.org/TR/WebCryptoAPI/#key-interface} + * @class Key + * @param {KeyType} type The type of a key. The recognized key type values are "public", "private" and "secret". + * @param {boolean} extractable Whether or not the raw keying material may be exported by the application. + * @param {KeyAlgorithm} algorithm The Algorithm used to generate the key. + * @param {KeyUsages} usages Key usage array: type of operation that may be performed using a key. + */ + +/** + * The KeyPair interface represents an asymmetric key pair that is comprised of both public and private keys. + *
+ *  interface KeyPair {
+ *      readonly attribute Key publicKey;
+ *      readonly attribute Key privateKey;
+ *  };     
+ * 
+ * WebCrypto API reference {@link http://www.w3.org/TR/WebCryptoAPI/#keypair} + * @class KeyPair + * @param {Key} privateKey Private key + * @param {Key} publicKey Public key + */ + +/** + * Specifies a serialization format for a key. The recognized key format values are: + *
    + *
  • 'raw' - An unformatted sequence of bytes. Intended for secret keys.
  • + *
  • 'pkcs8' - The DER encoding of the PrivateKeyInfo structure from RFC 5208.
  • + *
  • 'spki' - The DER encoding of the SubjectPublicKeyInfo structure from RFC 5280.
  • + *
  • 'jwk' - The key is represented as JSON according to the JSON Web Key format.
  • + *
+ *
+ *  typedef DOMString KeyFormat;
+ *  
+ * WebCrypto API reference {@link http://www.w3.org/TR/WebCryptoAPI/#key-interface} + * @class KeyFormat + */ + +/** + * Binary data + *
+ *  typedef (ArrayBuffer or ArrayBufferView) CryptoOperationData;
+ *  
+ * @class CryptoOperationData + */ +var CryptoOperationData = ArrayBuffer; + +/** + * DER-encoded ArrayBuffer or PEM-encoded DOMString constains ASN.1 object
+ *
+ *  typedef (ArrayBuffer or DOMString) FormatedData;
+ * 
+ * @class FormatedData + */ +//
+ +/** + * The gostCrypto provide general purpose cryptographic functionality for + * GOST standards including a cryptographically strong pseudo-random number + * generator seeded with truly random values. + * + * @namespace gostCrypto + */ +var gostCrypto = {}; + +/** + * The SubtleCrypto class provides low-level cryptographic primitives and algorithms. + * WebCrypto API reference {@link http://www.w3.org/TR/WebCryptoAPI/#subtlecrypto-interface} + * + * @class SubtleCrypto + */ // +function SubtleCrypto() { +} + +/** + * The encrypt method returns a new Promise object that will encrypt data + * using the specified algorithm identifier with the supplied Key. + * WebCrypto API reference {@link http://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-encrypt}

+ * + * Supported algorithm names: + *
    + *
  • GOST 28147-ECB "prostaya zamena" (ECB) mode (default)
  • + *
  • GOST 28147-CFB "gammirovanie s obratnoj svyaziyu po shifrotekstu" (CFB) mode
  • + *
  • GOST 28147-OFB "gammirovanie s obratnoj svyaziyu po vyhodu" (OFB) mode
  • + *
  • GOST 28147-CTR "gammirovanie" (counter) mode
  • + *
  • GOST 28147-CBC Cipher-Block-Chaining (CBC) mode
  • + *
  • GOST R 34.12-ECB "prostaya zamena" (ECB) mode (default)
  • + *
  • GOST R 34.12-CFB "gammirovanie s obratnoj svyaziyu po shifrotekstu" (CFB) mode
  • + *
  • GOST R 34.12-OFB "gammirovanie s obratnoj svyaziyu po vyhodu" (OFB) mode
  • + *
  • GOST R 34.12-CTR "gammirovanie" (counter) mode
  • + *
  • GOST R 34.12-CBC Cipher-Block-Chaining (CBC) mode
  • + *
+ * For more information see {@link GostCipher} + * + * @memberOf SubtleCrypto + * @method encrypt + * @instance + * @param {AlgorithmIdentifier} algorithm Algorithm identifier + * @param {Key} key Key object + * @param {CryptoOperationData} data Operation data + * @returns {Promise} Promise that resolves with {@link CryptoOperationData} + */ +SubtleCrypto.prototype.encrypt = function (algorithm, key, data) // +{ + return new Promise(call).then(function () { + if (checkNative(algorithm)) + return rootCrypto.subtle.encrypt(algorithm, key, data); + + algorithm = normalize(algorithm, 'encrypt'); + return execute(algorithm, 'encrypt', + [extractKey('encrypt', algorithm, key), data]); + }); +}; // + +/** + * The decrypt method returns a new Promise object that will decrypt data + * using the specified algorithm identifier with the supplied Key. + * WebCrypto API reference {@link http://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-decrypt}

+ * + * Supported algorithm names: + *
    + *
  • GOST 28147-ECB "prostaya zamena" (ECB) mode (default)
  • + *
  • GOST 28147-CFB "gammirovanie s obratnoj svyaziyu po shifrotekstu" (CFB) mode
  • + *
  • GOST 28147-OFB "gammirovanie s obratnoj svyaziyu po vyhodu" (OFB) mode
  • + *
  • GOST 28147-CTR "gammirovanie" (counter) mode
  • + *
  • GOST 28147-CBC Cipher-Block-Chaining (CBC) mode
  • + *
  • GOST R 34.12-ECB "prostaya zamena" (ECB) mode (default)
  • + *
  • GOST R 34.12-CFB "gammirovanie s obratnoj svyaziyu po shifrotekstu" (CFB) mode
  • + *
  • GOST R 34.12-OFB "gammirovanie s obratnoj svyaziyu po vyhodu" (OFB) mode
  • + *
  • GOST R 34.12-CTR "gammirovanie" (counter) mode
  • + *
  • GOST R 34.12-CBC Cipher-Block-Chaining (CBC) mode
  • + *
+ * For additional modes see {@link GostCipher} + * + * @memberOf SubtleCrypto + * @method decrypt + * @instance + * @param {AlgorithmIdentifier} algorithm Algorithm identifier + * @param {Key} key Key object + * @param {CryptoOperationData} data Operation data + * @returns {Promise} Promise that resolves with {@link CryptoOperationData} + */ +SubtleCrypto.prototype.decrypt = function (algorithm, key, data) // +{ + return new Promise(call).then(function () { + if (checkNative(algorithm)) + return rootCrypto.subtle.decrypt(algorithm, key, data); + + algorithm = normalize(algorithm, 'decrypt'); + return execute(algorithm, 'decrypt', + [extractKey('decrypt', algorithm, key), data]); + }); +}; // + +/** + * The sign method returns a new Promise object that will sign data using + * the specified algorithm identifier with the supplied Key. + * WebCrypto API reference {@link http://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-sign}

+ * + * Supported algorithm names: + *
    + *
  • GOST R 34.10-94 GOST Signature
  • + *
  • GOST R 34.10-94/GOST R 34.11-94 GOST Signature with Hash
  • + *
  • GOST R 34.10 ECGOST Signature
  • + *
  • GOST R 34.10/GOST R 34.11-94 ECGOST Signature with Old-Style Hash
  • + *
  • GOST R 34.10/GOST R 34.11 ECGOST Signature with Streebog Hash
  • + *
  • GOST 28147-MAC MAC base on GOST 28147
  • + *
  • GOST R 34.12-MAC MAC base on GOST R 43.12
  • + *
  • GOST R 34.11-HMAC HMAC base on GOST 34.11
  • + *
  • SHA-HMAC HMAC base on SHA
  • + *
+ * For additional modes see {@link GostSign}, {@link GostDigest} and {@link GostCipher} + * + * @memberOf SubtleCrypto + * @method sign + * @instance + * @param {AlgorithmIdentifier} algorithm Algorithm identifier + * @param {Key} key Key object + * @param {CryptoOperationData} data Operation data + * @returns {Promise} Promise that resolves with {@link CryptoOperationData} + */ +SubtleCrypto.prototype.sign = function (algorithm, key, data) // +{ + return new Promise(call).then(function () { + if (checkNative(algorithm)) + return rootCrypto.subtle.sign(algorithm, key, data); + + algorithm = normalize(algorithm, 'sign'); + var value = execute(algorithm, 'sign', + [extractKey('sign', algorithm, key), data]).then(function (data) { + if (algorithm.procreator === 'SC' && algorithm.mode === 'SIGN') { + data = gostCrypto.asn1.GostSignature.encode(data); + } + return data; + }); + return value; + }); +}; // + +/** + * The verify method returns a new Promise object that will verify data + * using the specified algorithm identifier with the supplied Key. + * WebCrypto API reference {@link http://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-verify}

+ * + * Supported algorithm names: + *
    + *
  • GOST R 34.10-94 GOST Signature
  • + *
  • GOST R 34.10-94/GOST R 34.11-94 GOST Signature with Hash
  • + *
  • GOST R 34.10 ECGOST Signature
  • + *
  • GOST R 34.10/GOST R 34.11-94 ECGOST Signature with Old-Style Hash
  • + *
  • GOST R 34.10/GOST R 34.11 ECGOST Signature with Streebog Hash
  • + *
  • GOST 28147-MAC MAC base on GOST 28147
  • + *
  • GOST R 34.12-MAC MAC base on GOST R 34.12
  • + *
  • GOST R 34.11-HMAC HMAC base on GOST 34.11
  • + *
  • SHA-HMAC HMAC base on SHA
  • + *
+ * For additional modes see {@link GostSign}, {@link GostDigest} and {@link GostCipher} + * + * @memberOf SubtleCrypto + * @method verify + * @instance + * @param {AlgorithmIdentifier} algorithm Algorithm identifier + * @param {Key} key Key object + * @param {CryptoOperationData} signature Signature data + * @param {CryptoOperationData} data Operation data + * @returns {Promise} Promise that resolves with boolean value of verification result + */ +SubtleCrypto.prototype.verify = function (algorithm, key, signature, data) // +{ + return new Promise(call).then(function () { + if (checkNative(algorithm)) + return rootCrypto.subtle.verify(algorithm, key, signature, data); + + algorithm = normalize(algorithm, 'verify'); + if (algorithm.procreator === 'SC' && algorithm.mode === 'SIGN') { + var obj = gostCrypto.asn1.GostSignature.decode(signature); + signature = {r: obj.r, s: obj.s}; + } + return execute(algorithm, 'verify', + [extractKey('verify', algorithm, key), signature, data]); + }); +}; // + +/** + * The digest method returns a new Promise object that will digest data + * using the specified algorithm identifier. + * WebCrypto API reference {@link http://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-digest}

+ * + * Supported algorithm names: + *
    + *
  • GOST R 34.11-94 Old-Style GOST Hash
  • + *
  • GOST R 34.11 GOST Streebog Hash
  • + *
  • SHA SHA Hash
  • + *
+ * For additional modes see {@link GostDigest} + * + * @memberOf SubtleCrypto + * @method digest + * @instance + * @param {AlgorithmIdentifier} algorithm Algorithm identifier + * @param {CryptoOperationData} data Operation data + * @returns {Promise} Promise that resolves with {@link CryptoOperationData} + */ +SubtleCrypto.prototype.digest = function (algorithm, data) // +{ + return new Promise(call).then(function () { + if (checkNative(algorithm)) + return rootCrypto.subtle.digest(algorithm, data); + + algorithm = normalize(algorithm, 'digest'); + return execute(algorithm, 'digest', [data]); + }); +}; // + +/** + * The generateKey method returns a new Promise object that will key(s) using + * the specified algorithm identifier. Key can be used in according with + * KeyUsages sequence. The recognized key usage values are "encrypt", "decrypt", + * "sign", "verify", "deriveKey", "deriveBits", "wrapKey" and "unwrapKey". + * WebCrypto API reference {@link http://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-generateKey}

+ * + * Supported algorithm names: + *
    + *
  • GOST R 34.10 ECGOST Key Pairs
  • + *
  • GOST 28147 Key for encryption GOST 28147 modes
  • + *
  • GOST 28147-KW Key for wrapping GOST 28147 modes
  • + *
  • GOST R 34.12 Key for encryption GOST R 34.12 modes
  • + *
  • GOST R 34.12-KW Key for wrapping GOST R 34.12 modes
  • + *
  • GOST R 34.11-KDF Key for Derivation Algorithm
  • + *
+ * For additional modes see {@link GostSign}, {@link GostDigest} and {@link GostCipher}
+ * Note: Generation key for GOST R 34.10-94 not supported. + * + * @memberOf SubtleCrypto + * @method generateKey + * @instance + * @param {AlgorithmIdentifier} algorithm Key algorithm identifier + * @param {boolean} extractable Whether or not the raw keying material may be exported by the application + * @param {KeyUsages} keyUsages Key usage array: type of operation that may be performed using a key + * @returns {Promise} Promise that resolves with {@link Key} or {@link KeyPair} in according to key algorithm + */ +SubtleCrypto.prototype.generateKey = function (algorithm, extractable, keyUsages) // +{ + return new Promise(call).then(function () { + if (checkNative(algorithm)) + return rootCrypto.subtle.generateKey(algorithm, extractable, keyUsages); + + var privateAlgorithm = algorithm.privateKey, + publicAlgorithm = algorithm.publicKey; + algorithm = normalize(algorithm, 'generateKey'); + if (privateAlgorithm) + privateAlgorithm = normalize(privateAlgorithm, 'generateKey'); + else + privateAlgorithm = algorithm; + if (publicAlgorithm) + publicAlgorithm = normalize(publicAlgorithm, 'generateKey'); + else + publicAlgorithm = algorithm; + return execute(algorithm, 'generateKey', []).then(function (data) { + if (data.publicKey && data.privateKey) + return convertKeyPair(publicAlgorithm, privateAlgorithm, extractable, keyUsages, data.publicKey, data.privateKey); + else + return convertKey(algorithm, extractable, keyUsages, data); + }); + }); +}; // + +/** + * The deriveKey method returns a new Promise object that will key(s) using + * the specified algorithm identifier. Key can be used in according with + * KeyUsage sequence. The recognized key usage values are "encrypt", "decrypt", + * "sign", "verify", "deriveKey", "deriveBits", "wrapKey" and "unwrapKey". + * WebCrypto API reference {@link http://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-deriveKey}

+ * + * Supported algorithm names: + *
    + *
  • GOST R 34.10-DH ECDH Key Agreement mode
  • + *
  • GOST R 34.11-KDF Key for Derivation Algorithm
  • + *
  • GOST R 34.11-PBKDF2 Password Based Key for Derivation Algorithm
  • + *
  • GOST R 34.11-PFXKDF PFX Key for Derivation Algorithm
  • + *
  • GOST R 34.11-CPKDF Password Based Key for CryptoPro Derivation Algorithm
  • + *
  • SHA-PBKDF2 Password Based Key for Derivation Algorithm
  • + *
  • SHA-PFXKDF PFX Key for Derivation Algorithm
  • + *
+ * For additional modes see {@link GostSign} and {@link GostDigest} + * + * @memberOf SubtleCrypto + * @method deriveKey + * @instance + * @param {AlgorithmIdentifier} algorithm Algorithm identifier + * @param {Key} baseKey Derivation key object + * @param {AlgorithmIdentifier} derivedKeyType Derived key algorithm identifier + * @param {boolean} extractable Whether or not the raw keying material may be exported by the application + * @param {KeyUsages} keyUsages Key usage array: type of operation that may be performed using a key + * @returns {Promise} Promise that resolves with {@link Key} + */ +SubtleCrypto.prototype.deriveKey = function (algorithm, baseKey, + derivedKeyType, extractable, keyUsages) // +{ + return new Promise(call).then(function () { + if (checkNative(algorithm)) + return rootCrypto.subtle.deriveKey(algorithm, baseKey, + derivedKeyType, extractable, keyUsages); + + algorithm = normalize(algorithm, 'deriveKey'); + derivedKeyType = normalize(derivedKeyType, 'generateKey'); + algorithm.keySize = derivedKeyType.keySize; + if (algorithm['public']) { + algorithm['public'].algorithm = normalize(algorithm['public'].algorithm); + algorithm['public'] = extractKey('deriveKey', algorithm, algorithm['public']); + } + return execute(algorithm, 'deriveKey', [extractKey('deriveKey', algorithm, baseKey)]).then(function (data) { + return convertKey(derivedKeyType, extractable, keyUsages, data); + }); + }); +}; // + +/** + * The deriveBits method returns length bits on baseKey using the + * specified algorithm identifier. + * WebCrypto API reference {@link http://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-deriveBits}

+ * + * Supported algorithm names: + *
    + *
  • GOST R 34.10-DH ECDH Key Agreement mode
  • + *
  • GOST R 34.11-KDF Key for Derivation Algorithm
  • + *
  • GOST R 34.11-PBKDF2 Password Based Key for Derivation Algorithm
  • + *
  • GOST R 34.11-PFXKDF PFX Key for Derivation Algorithm
  • + *
  • GOST R 34.11-CPKDF Password Based Key for CryptoPro Derivation Algorithm
  • + *
  • SHA-PBKDF2 Password Based Key for Derivation Algorithm
  • + *
  • SHA-PFXKDF PFX Key for Derivation Algorithm
  • + *
+ * For additional modes see {@link GostSign} and {@link GostDigest} + * + * @memberOf SubtleCrypto + * @method deriveBits + * @instance + * @param {AlgorithmIdentifier} algorithm Algorithm identifier + * @param {Key} baseKey Derivation key object + * @param {number} length Length bits + * @returns {Promise} Promise that resolves with {@link CryptoOperationData} + */ +SubtleCrypto.prototype.deriveBits = function (algorithm, baseKey, length) // +{ + return new Promise(call).then(function () { + if (checkNative(algorithm)) + return rootCrypto.subtle.deriveBits(algorithm, baseKey, length); + + algorithm = normalize(algorithm, 'deriveBits'); + if (algorithm['public']) + algorithm['public'] = extractKey('deriveBits', algorithm, algorithm['public']); + return execute(algorithm, 'deriveBits', [extractKey('deriveBits', algorithm, baseKey), length]); + }); +}; // + +/** + * The importKey method returns a new Promise object that will key(s) using + * the specified algorithm identifier. Key can be used in according with + * KeyUsage sequence. The recognized key usage values are "encrypt", "decrypt", + * "sign", "verify", "deriveKey", "deriveBits", "wrapKey" and "unwrapKey".

+ * Parameter keyData contains data in defined format. + * The suppored key format values are: + *
    + *
  • 'raw' - An unformatted sequence of bytes. Intended for secret keys.
  • + *
  • 'pkcs8' - The DER encoding of the PrivateKeyInfo structure from RFC 5208.
  • + *
  • 'spki' - The DER encoding of the SubjectPublicKeyInfo structure from RFC 5280.
  • + *
+ * WebCrypto API reference {@link http://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-importKey}

+ * + * Supported algorithm names: + *
    + *
  • GOST R 34.10-94 GOST Private and Public keys
  • + *
  • GOST R 34.10 ECGOST Private and Public keys
  • + *
  • GOST 28147 Key for encryption GOST 28147 modes
  • + *
  • GOST 28147-KW Key for key wrapping GOST 28147 modes
  • + *
  • GOST R 34.12 Key for encryption GOST 34.12 modes
  • + *
  • GOST R 34.12-KW Key for key wrapping GOST 34.12 modes
  • + *
  • GOST R 34.11-KDF Key for Derivation Algorithm
  • + *
+ * For additional modes see {@link GostSign}, {@link GostDigest} and {@link GostCipher}
+ * + * @memberOf SubtleCrypto + * @method importKey + * @instance + * @param {KeyFormat} format Key format Format specifies a serialization format for a key + * @param {CryptoOperationData} keyData + * @param {AlgorithmIdentifier} algorithm Key algorithm identifier + * @param {boolean} extractable Whether or not the raw keying material may be exported by the application + * @param {KeyUsages} keyUsages Key usage array: type of operation that may be performed using a key + * @returns {Promise} Promise that resolves with {@link Key} + */ +SubtleCrypto.prototype.importKey = function (format, keyData, algorithm, extractable, keyUsages) // +{ + var type; + return new Promise(call).then(function () { + if (checkNative(algorithm)) + return rootCrypto.subtle.importKey(format, keyData, algorithm, extractable, keyUsages); + + if (format === 'raw') { + algorithm = normalize(algorithm, 'importKey'); + if (keyUsages && keyUsages.indexOf) { + var name = algorithm.name.toUpperCase().replace(/[\.\s]/g, ''); + if (name.indexOf('3410') >= 0 && keyUsages.indexOf('sign') >= 0) + type = 'private'; + else if (name.indexOf('3410') >= 0 && keyUsages.indexOf('verify') >= 0) + type = 'public'; + } + return keyData; + } else { + var key; + if (format === 'pkcs8') + key = gostCrypto.asn1.GostPrivateKeyInfo.decode(keyData).object; + else if (format === 'spki') + key = gostCrypto.asn1.GostSubjectPublicKeyInfo.decode(keyData).object; + else + throw new NotSupportedError('Key format not supported'); + + algorithm = normalize(key.algorithm, 'importKey'); + type = key.type; + if (extractable !== false) + extractable = extractable || key.extractable; + if (keyUsages) { + for (var i = 0; i < keyUsages.length; i++) { + if (key.usages.indexOf(keyUsages[i]) < 0) + throw DataError('Key usage not valid for this key'); + } + } else + keyUsages = key.usages; + var data = key.buffer, keySize = algorithm.keySize, dataLen = data.byteLength; + if (type === 'public' || keySize === dataLen) + return data; + else { + // Remove private key masks + if (dataLen % keySize > 0) + throw new DataError('Invalid key size'); + algorithm.mode = 'MASK'; + algorithm.procreator = 'VN'; + var chain = []; + for (var i = keySize; i < dataLen; i += keySize) { + chain.push((function (mask) { + return function (data) { + return execute(algorithm, 'unwrapKey', [mask, data]).then(function (data) { + var next = chain.pop(); + if (next) + return next(data); + else { + delete algorithm.mode; + return data; + } + }); + }; + })(new Uint8Array(data, i, keySize))); + } + return chain.pop()(new Uint8Array(data, 0, keySize)); + } + } + }).then(function (data) { + return convertKey(algorithm, extractable, keyUsages, data, type); + }); +}; // + +/** + * The exportKey method returns a new Promise object that will key data in + * defined format.

+ * The suppored key format values are: + *
    + *
  • 'raw' - An unformatted sequence of bytes. Intended for secret keys.
  • + *
  • 'pkcs8' - The DER encoding of the PrivateKeyInfo structure from RFC 5208.
  • + *
  • 'spki' - The DER encoding of the SubjectPublicKeyInfo structure from RFC 5280.
  • + *
+ * WebCrypto API reference {@link http://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-exportKey}

+ * + * Supported algorithm names: + *
    + *
  • GOST R 34.10-94 GOST Private and Public keys
  • + *
  • GOST R 34.10 ECGOST Private and Public keys
  • + *
  • GOST 28147 Key for encryption GOST 28147 modes
  • + *
  • GOST 28147-KW Key for key wrapping GOST 28147 modes
  • + *
  • GOST R 34.12 Key for encryption GOST R 34.12 modes
  • + *
  • GOST R 34.12-KW Key for key wrapping GOST R 34.12 modes
  • + *
  • GOST R 34.11-KDF Key for Derivation Algorithm
  • + *
  • GOST R 34.11-PBKDF2 Import Password for Key for Derivation Algorithm
  • + *
  • GOST R 34.11-PFXKDF Import PFX Key for Derivation Algorithm
  • + *
  • GOST R 34.11-CPKDF Import Password Key for CryptoPro Derivation Algorithm
  • + *
  • SHA-PBKDF2 Import Password for Key for Derivation Algorithm
  • + *
  • SHA-PFXKDF Import PFX Key for Derivation Algorithm
  • + *
+ * For additional modes see {@link GostSign}, {@link GostDigest} and {@link GostCipher}
+ * + * @memberOf SubtleCrypto + * @method exportKey + * @instance + * @param {KeyFormat} format Format specifies a serialization format for a key + * @param {Key} key Key object + * @returns {Promise} Promise that resolves with {@link CryptoOperationData} + */ +SubtleCrypto.prototype.exportKey = function (format, key) // +{ + return new Promise(call).then(function () { + if (key && checkNative(key.algorithm)) + return rootCrypto.subtle.exportKey(format, key); + + if (!key.extractable) + throw new InvalidAccessError('Key not extractable'); + + var raw = extractKey(null, null, key); + if (format === 'raw') + return raw; + else if (format === 'pkcs8' && key.algorithm && key.algorithm.id) { + if (key.algorithm.procreator === 'VN') { + // Add masks for ViPNet + var algorithm = key.algorithm, mask; + algorithm.mode = 'MASK'; + return execute(algorithm, 'generateKey').then(function (data) { + mask = data; + return execute(algorithm, 'wrapKey', [mask, key.buffer]); + }).then(function (data) { + delete algorithm.mode; + var d = new Uint8Array(data.byteLength + mask.byteLength); + d.set(new Uint8Array(data, 0, data.byteLength)); + d.set(new Uint8Array(mask, 0, mask.byteLength), data.byteLength); + var buffer = d.buffer; + buffer.enclosed = true; + return gostCrypto.asn1.GostPrivateKeyInfo.encode({ + algorithm: algorithm, + buffer: buffer + }); + }); + } else + return gostCrypto.asn1.GostPrivateKeyInfo.encode(key); + } else if (format === 'spki' && key.algorithm && key.algorithm.id) + return gostCrypto.asn1.GostSubjectPublicKeyInfo.encode(key); + else + throw new NotSupportedError('Key format not supported'); + }); +}; // + +/** + * The wrapKey method returns a new Promise object that will wrapped key(s). + * WebCrypto API reference {@link http://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-wrapKey}

+ * + * Supported algorithm names: + *
    + *
  • GOST 28147-KW Key Wrapping GOST 28147 modes
  • + *
  • GOST R 34.12-KW Key Wrapping GOST R 34.12 modes
  • + *
  • GOST 28147-MASK Key Mask GOST 28147 modes
  • + *
  • GOST R 34.12-MASK Key Mask GOST R 34.12 modes
  • + *
  • GOST R 34.10-MASK Key Mask GOST R 34.10 modes
  • + *
+ * For additional modes see {@link GostCipher}
+ * + * @memberOf SubtleCrypto + * @method wrapKey + * @instance + * @param {KeyFormat} format Format specifies a serialization format for a key. Now suppored only 'raw' key format. + * @param {Key} key Key object + * @param {Key} wrappingKey Wrapping key object + * @param {AlgorithmIdentifier} wrapAlgorithm Algorithm identifier + * @returns {Promise} Promise that resolves with {@link CryptoOperationData} + */ +SubtleCrypto.prototype.wrapKey = function (format, key, wrappingKey, wrapAlgorithm) // +{ + return new Promise(call).then(function () { + if (checkNative(wrapAlgorithm)) + return rootCrypto.subtle.wrapKey(format, key, wrappingKey, wrapAlgorithm); + + wrapAlgorithm = normalize(wrapAlgorithm, 'wrapKey'); + var keyData = extractKey(null, null, key); + if (wrapAlgorithm.procreator === 'SC' && key.type === 'private') + keyData = swapBytes(keyData); + return execute(wrapAlgorithm, 'wrapKey', + [extractKey('wrapKey', wrapAlgorithm, wrappingKey), keyData]).then(function (data) { + if (format === 'raw') + return data; + else + throw new NotSupportedError('Key format not supported'); + }); + }); +}; // + +/** + * The unwrapKey method returns a new Promise object that will unwrapped key(s). + * WebCrypto API reference {@link http://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-unwrapKey}

+ * + * Supported algorithm names: + *
    + *
  • GOST 28147-KW Key Wrapping GOST 28147 modes
  • + *
  • GOST R 34.12-KW Key Wrapping GOST R 34.12 modes
  • + *
  • GOST 28147-MASK Key Mask GOST 28147 modes
  • + *
  • GOST R 34.12-MASK Key Mask GOST R 34.12 modes
  • + *
  • GOST R 34.10-MASK Key Mask GOST R 34.10 modes
  • + *
+ * For additional modes see {@link GostCipher}
+ * + * @memberOf SubtleCrypto + * @method unwrapKey + * @instance + * @param {KeyFormat} format Format specifies a serialization format for a key. Now suppored only 'raw' key format. + * @param {CryptoOperationData} wrappedKey Wrapped key data + * @param {Key} unwrappingKey Unwrapping key object + * @param {AlgorithmIdentifier} unwrapAlgorithm Algorithm identifier + * @param {AlgorithmIdentifier} unwrappedKeyAlgorithm Key algorithm identifier + * @param {boolean} extractable Whether or not the raw keying material may be exported by the application + * @param {KeyUsages} keyUsages Key usage array: type of operation that may be performed using a key + * @returns {Promise} Promise that resolves with {@link Key} + */ +SubtleCrypto.prototype.unwrapKey = function (format, wrappedKey, unwrappingKey, + unwrapAlgorithm, unwrappedKeyAlgorithm, extractable, keyUsages) // +{ + return new Promise(call).then(function () { + if (checkNative(unwrapAlgorithm)) + return rootCrypto.subtle.unwrapKey(format, wrappedKey, unwrappingKey, + unwrapAlgorithm, unwrappedKeyAlgorithm, extractable, keyUsages); + + unwrapAlgorithm = normalize(unwrapAlgorithm, 'unwrapKey'); + unwrappedKeyAlgorithm = normalize(unwrappedKeyAlgorithm, 'importKey'); + if (format !== 'raw') + throw new NotSupportedError('Key format not supported'); + + return execute(unwrapAlgorithm, 'unwrapKey', [extractKey('unwrapKey', unwrapAlgorithm, unwrappingKey), wrappedKey]).then(function (data) { + var type; + if (unwrappedKeyAlgorithm && unwrappedKeyAlgorithm.name) { + var name = unwrappedKeyAlgorithm.name.toUpperCase().replace(/[\.\s]/g, ''); + if (name.indexOf('3410') >= 0 && keyUsages.indexOf('sign') >= 0) + type = 'private'; + else if (name.indexOf('3410') >= 0 && keyUsages.indexOf('verify') >= 0) + type = 'public'; + } + if (unwrapAlgorithm.procreator === 'SC' && type === 'private') + data = swapBytes(data); + return convertKey(unwrappedKeyAlgorithm, extractable, keyUsages, data, type); + }); + }); +}; // + +/** + * The subtle attribute provides an instance of the SubtleCrypto + * interface which provides low-level cryptographic primitives and + * algorithms. + * + * @memberOf gostCrypto + * @type SubtleCrypto + */ +gostCrypto.subtle = new SubtleCrypto(); + +/** + * The getRandomValues method generates cryptographically random values. + * + * First try to use Web Crypto random genereator. Next make random + * bytes based on standart Math.random mixed with time and mouse pointer + * + * @memberOf gostCrypto + * @param {(CryptoOperationData)} array Destination buffer for random data + */ +gostCrypto.getRandomValues = function (array) // +{ + // Execute randomizer + GostRandom = GostRandom || root.GostRandom; + var randomSource = GostRandom ? new GostRandom() : rootCrypto; + if (randomSource.getRandomValues) + randomSource.getRandomValues(array); + else + throw new NotSupportedError('Random generator not found'); +}; // +//
+ +export default gostCrypto; diff --git a/src/core/vendor/streebog/gostDigest.js b/src/core/vendor/streebog/gostDigest.js deleted file mode 100644 index e6f5db33..00000000 --- a/src/core/vendor/streebog/gostDigest.js +++ /dev/null @@ -1,1269 +0,0 @@ -/** - * GOST R 34.11-94 / GOST R 34.11-12 implementation - * 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. - * - * Converted to JavaScript from source https://www.streebog.net/ - * Copyright (c) 2013, Alexey Degtyarev. - * All rights reserved. - * - * 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. - * - */ - -(function (root, factory) { - - /* - * Module imports and exports - * - */ // - module.exports = factory(require('./gostRandom'), require('./gostCipher')); - // - -}(this, function (GostRandom, GostCipher) { - - /* - * GOST R 34.11 - * Common methods - * - */ // - - var root = this; - var rootCrypto = root.crypto || root.msCrypto; - - var DataError = root.DataError || Error, - NotSupportedError = root.NotSupportedError || Error; - - // Copy len values from s[sOfs] to d[dOfs] - function arraycopy(s, sOfs, d, dOfs, len) { - for (var i = 0; i < len; i++) - d[dOfs + i] = s[sOfs + i]; - } - - // Swap bytes in buffer - function swap(s) { - var src = new Uint8Array(s), - dst = new Uint8Array(src.length); - for (var i = 0, n = src.length; i < n; i++) - dst[n - i - 1] = src[i]; - return dst.buffer; - } - - // Convert BASE64 string to Uint8Array - // for decompression of constants and precalc values - function b64decode(s) { - // s = s.replace(/[^A-Za-z0-9\+\/]/g, ''); - var n = s.length, - k = n * 3 + 1 >> 2, r = new Uint8Array(k); - - for (var m3, m4, u24 = 0, j = 0, i = 0; i < n; i++) { - m4 = i & 3; - var c = s.charCodeAt(i); - - c = c > 64 && c < 91 ? - c - 65 : c > 96 && c < 123 ? - c - 71 : c > 47 && c < 58 ? - c + 4 : c === 43 ? - 62 : c === 47 ? - 63 : 0; - - u24 |= c << 18 - 6 * m4; - if (m4 === 3 || n - i === 1) { - for (m3 = 0; m3 < 3 && j < k; m3++, j++) { - r[j] = u24 >>> (16 >>> m3 & 24) & 255; - } - u24 = 0; - - } - } - return r.buffer; - } - - // Random seed - function getSeed(length) { - GostRandom = GostRandom || root.GostRandom; - var randomSource = GostRandom ? new (GostRandom || root.GostRandom) : rootCrypto; - if (randomSource.getRandomValues) { - var d = new Uint8Array(Math.ceil(length / 8)); - randomSource.getRandomValues(d); - return d; - } else - throw new NotSupportedError('Random generator not found'); - } - - // Check buffer - function buffer(d) { - if (d instanceof ArrayBuffer) - return d; - else if (d && d.buffer && d.buffer instanceof ArrayBuffer) - 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('ArrayBuffer or ArrayBufferView required'); - } // - - /** - * Algorithm name GOST R 34.11 or GOST R 34.11-12

- * - * http://tools.ietf.org/html/rfc6986 - * - * The digest method returns digest data in according to GOST R 4311-2012.
- * Size of digest also defines in algorithm name. - *
    - *
  • GOST R 34.11-256-12 - 256 bits digest
  • - *
  • GOST R 34.11-512-12 - 512 bits digest
  • - *
- * - * @memberOf GostDigest - * @method digest - * @instance - * @param {(ArrayBuffer|TypedArray)} data Data - * @returns {ArrayBuffer} Digest of data - */ - var digest2012 = (function () // - { - // Constants - var buffer0 = new Int32Array(16); // [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; - - var buffer512 = new Int32Array(16); // [512, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; - buffer512[0] = 512; - - // Constant C - var C = (function (s) { - var h = new Int32Array(b64decode(s)), - r = new Array(12); - for (var i = 0; i < 12; i++) - r[i] = new Int32Array(h.buffer, i * 64, 16); - return r; - })( - 'B0Wm8lllgN0jTXTMNnR2BRXTYKQIKkKiAWlnkpHgfEv8xIV1jbhOcRbQRS5DdmovH3xlwIEvy+vp2soe2lsIsbebsSFwBHnmVs3L1xui3VXKpwrbwmG1XFiZ1hJrF7WaMQG1Fg9e1WGYKyMKcur+89e1cA9GneNPGi+dqYq1o2+yCroK9ZYemTHbeoZD9LbCCdtiYDc6ycGxnjWQ5A/i03t7KbEUderyix+cUl9e8QY1hD1qKPw5Cscvzius3HT1LtHjhLy+DCLxN+iToepTNL4DUpMzE7fYddYD7YIs16k/NV5orRxynX08XDN+hY5I3eRxXaDhSPnSZhXos98f71f+bHz9WBdg9WPqqX6iVnoWGicjtwD/36P1OiVHF82/vf8PgNc1njVKEIYWHxwVf2MjqWwMQT+amUdHraxr6ktufWRGekBo+jVPkDZyxXG/tsa+wmYf8gq0t5oct6b6z8aO8Jq0mn8YbKRCUfnEZi3AOTB6O8Okb9nTOh2urk+uk9QUOk1WhojzSjyiTEUXNQQFSiiDaUcGNyyCLcWrkgnJk3oZMz5H08mHv+bHxp45VAkkv/6GrFHsxaruFg7H9B7nAr/UDX+k' + - '2ahRWTXCrDYvxKXRK43RaZAGm5LLK4n0msTbTTtEtIke3jaccfi3TkFBbgwCqucDp8mTTUJbH5vbWiODUURhcmAqH8uS3DgOVJwHppqKK3uxzrLbC0QKgIQJDeC3Vdk8JEKJJRs6fTreXxbs2JpMlJsiMRZUWo837ZxFmPvHtHTDtjsV0fqYNvRSdjswbB56SzNprwJn558DYTMbiuH/H9t4iv8c50GJ8/PkskjlKjhSbwWApt6+qxst84HNpMprXdhvwEpZot6Ybkd9Hc2678q5SOrvcR2KeWaEFCGAASBhB6vru2v62JT+WmPNxgIw+4nI79CezXsg1xvxSpK8SJkbstnVF/T6UijhiKqkHeeGzJEYne+AXZufITDUEiD4dx3fvDI8pM16sUkEsIAT0roxFvFn5443'); - - // Precalc Ax - var Ax = (function (s) { - return new Int32Array(b64decode(s)); - })( - '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'); //== - - // Variables - var sigma, N, h; - - // 64bit tools - function get8(x, i) { - return (x[i >> 2] >> ((i & 3) << 3)) & 0xff; - } - - // 512bit tools - function add512(x, y) { - var CF = 0, w0, w1; - for (var i = 0; i < 16; i++) { - w0 = (x[i] & 0xffff) + (y[i] & 0xffff) + (CF || 0); - w1 = (x[i] >>> 16) + (y[i] >>> 16) + (w0 >>> 16); - x[i] = (w0 & 0xffff) | (w1 << 16); - CF = (w1 >>> 16); - } - } - - function get512(d) { - return new Int32Array(d.buffer, d.byteOffset, 16); - } - - - function copy512(r, d) { - for (var i = 0; i < 16; i++) - r[i] = d[i]; - } - - function new512() { - return new Int32Array(16); - } - - // Core private algorithms - function xor512(x, y) { - for (var i = 0; i < 16; i++) - x[i] = x[i] ^ y[i]; - } - - - var r = new512(); - function XLPS(x, y) { - copy512(r, x); - xor512(r, y); - for (var i = 0; i < 8; i++) { - var z0, z1, k = get8(r, i) << 1; - z0 = Ax[k]; - z1 = Ax[k + 1]; - for (var j = 1; j < 8; j++) { - k = (j << 9) + (get8(r, (j << 3) + i) << 1); - z0 = z0 ^ Ax[k]; - z1 = z1 ^ Ax[k + 1]; - } - x[i << 1] = z0; - x[(i << 1) + 1] = z1; - } - } - - var data = new512(), Ki = new512(); - function g(h, N, m) - { - var i; - - copy512(data, h); - XLPS(data, N); - - /* Starting E() */ - copy512(Ki, data); - XLPS(data, m); - - for (i = 0; i < 11; i++) { - XLPS(Ki, C[i]); - XLPS(data, Ki); - } - - XLPS(Ki, C[11]); - xor512(data, Ki); - /* E() done */ - - xor512(h, data); - xor512(h, m); - } - - // Stages - function stage2(d) { - var m = get512(d); - g(h, N, m); - - add512(N, buffer512); - add512(sigma, m); - } - - function stage3(d) { - var n = d.length; - if (n > 63) - return; - - var b0 = new Int32Array(16); - b0[0] = n << 3; - - var b = new Uint8Array(64); - for (var i = 0; i < n; i++) - b[i] = d[i]; - b[n] = 0x01; - - var m = get512(b), m0 = get512(b0); - g(h, N, m); - - add512(N, m0); - add512(sigma, m); - - g(h, buffer0, N); - g(h, buffer0, sigma); - } - - return function (data) { - - // Cleanup - sigma = new512(); - N = new512(); - - // Initial vector - h = new512(); - for (var i = 0; i < 16; i++) - if (this.bitLength === 256) - h[i] = 0x01010101; - - // Make data - var d = new Uint8Array(buffer(data)); - - var n = d.length; - var r = n % 64, q = (n - r) / 64; - - for (var i = 0; i < q; i++) - stage2.call(this, new Uint8Array(d.buffer, i * 64, 64)); - - stage3.call(this, new Uint8Array(d.buffer, q * 64, r)); - - var digest; - if (this.bitLength === 256) { - digest = new Int32Array(8); - for (var i = 0; i < 8; i++) - digest[i] = h[8 + i]; - } else { - digest = new Int32Array(16); - for (var i = 0; i < 16; i++) - digest[i] = h[i]; - } - // Swap hash for SignalCom - if (this.procreator === 'SC' || this.procreator === 'VN') - return swap(digest.buffer); - else - return digest.buffer; - }; - } // - )(); - - /** - * Algorithm name GOST R 34.11-94

- * - * http://tools.ietf.org/html/rfc5831 - * - * The digest method returns digest data in according to GOST R 34.11-94. - * @memberOf GostDigest - * @method digest - * @instance - * @param {(ArrayBuffer|TypedArray)} data Data - * @returns {ArrayBuffer} Digest of data - */ - var digest94 = (function () // - { - var C, H, M, Sum; - - // (i + 1 + 4(k - 1)) = 8i + k i = 0-3, k = 1-8 - function P(d) { - var K = new Uint8Array(32); - - for (var k = 0; k < 8; k++) { - K[4 * k] = d[k]; - K[1 + 4 * k] = d[ 8 + k]; - K[2 + 4 * k] = d[16 + k]; - K[3 + 4 * k] = d[24 + k]; - } - - return K; - } - - //A (x) = (x0 ^ x1) || x3 || x2 || x1 - function A(d) - { - var a = new Uint8Array(8); - - for (var j = 0; j < 8; j++) - { - a[j] = (d[j] ^ d[j + 8]); - } - - arraycopy(d, 8, d, 0, 24); - arraycopy(a, 0, d, 24, 8); - - return d; - } - - // (in:) n16||..||n1 ==> (out:) n1^n2^n3^n4^n13^n16||n16||..||n2 - function fw(d) { - var wS = new Uint16Array(d.buffer, 0, 16); - var wS15 = wS[0] ^ wS[1] ^ wS[2] ^ wS[3] ^ wS[12] ^ wS[15]; - arraycopy(wS, 1, wS, 0, 15); - wS[15] = wS15; - } - - //Encrypt function, ECB mode - function encrypt(key, s, sOff, d, dOff) { - var t = new Uint8Array(8); - arraycopy(d, dOff, t, 0, 8); - var r = new Uint8Array(this.cipher.encrypt(key, t)); - arraycopy(r, 0, s, sOff, 8); - } - - // block processing - function process(d, dOff) { - var S = new Uint8Array(32), U = new Uint8Array(32), - V = new Uint8Array(32), W = new Uint8Array(32); - - arraycopy(d, dOff, M, 0, 32); - - //key step 1 - - // H = h3 || h2 || h1 || h0 - // S = s3 || s2 || s1 || s0 - arraycopy(H, 0, U, 0, 32); - arraycopy(M, 0, V, 0, 32); - for (var j = 0; j < 32; j++) - { - W[j] = (U[j] ^ V[j]); - } - // Encrypt GOST 28147-ECB - encrypt.call(this, P(W), S, 0, H, 0); // s0 = EK0 [h0] - - //keys step 2,3,4 - for (var i = 1; i < 4; i++) { - var tmpA = A(U); - for (var j = 0; j < 32; j++) { - U[j] = (tmpA[j] ^ C[i][j]); - } - V = A(A(V)); - for (var j = 0; j < 32; j++) { - W[j] = (U[j] ^ V[j]); - } - // Encrypt GOST 28147-ECB - encrypt.call(this, P(W), S, i * 8, H, i * 8); // si = EKi [hi] - } - - // x(M, H) = y61(H^y(M^y12(S))) - for (var n = 0; n < 12; n++) { - fw(S); - } - for (var n = 0; n < 32; n++) { - S[n] = (S[n] ^ M[n]); - } - - fw(S); - - for (var n = 0; n < 32; n++) { - S[n] = (H[n] ^ S[n]); - } - for (var n = 0; n < 61; n++) { - fw(S); - } - arraycopy(S, 0, H, 0, H.length); - } - - - // 256 bitsblock modul -> (Sum + a mod (2^256)) - function summing(d) - { - var carry = 0; - for (var i = 0; i < Sum.length; i++) - { - var sum = (Sum[i] & 0xff) + (d[i] & 0xff) + carry; - - Sum[i] = sum; - - carry = sum >>> 8; - } - } - - // reset the chaining variables to the IV values. - var C2 = new Uint8Array([ - 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, - 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, - 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF - ]); - - return function (data) { - - // Reset buffers - H = new Uint8Array(32); - M = new Uint8Array(32); - Sum = new Uint8Array(32); - - // Reset IV value - C = new Array(4); - for (var i = 0; i < 4; i++) - C[i] = new Uint8Array(32); - arraycopy(C2, 0, C[2], 0, C2.length); - - // Make data - var d = new Uint8Array(buffer(data)); - - var n = d.length; - var r = n % 32, q = (n - r) / 32; - - // Proccess full blocks - for (var i = 0; i < q; i++) { - var b = new Uint8Array(d.buffer, i * 32, 32); - - summing.call(this, b); // calc sum M - process.call(this, b, 0); - } - - // load d the remadder with padding zero; - if (r > 0) { - var b = new Uint8Array(d.buffer, q * 32), - c = new Uint8Array(32); - arraycopy(b, 0, c, 0, r); - summing.call(this, c); // calc sum M - process.call(this, c, 0); - - } - - // get length into L (byteCount * 8 = bitCount) in little endian. - var L = new Uint8Array(32), n8 = n * 8, k = 0; - while (n8 > 0) { - L[k++] = n8 & 0xff; - n8 = Math.floor(n8 / 256); - } - process.call(this, L, 0); - process.call(this, Sum, 0); - - var h = H.buffer; - - // Swap hash for SignalCom - if (this.procreator === 'SC') - h = swap(h); - - return h; - }; - - } // - )(); - - /** - * Algorithm name SHA-1

- * - * https://tools.ietf.org/html/rfc3174 - * - * The digest method returns digest data in according to SHA-1.
- * - * @memberOf GostDigest - * @method digest - * @instance - * @param {(ArrayBuffer|TypedArray)} data Data - * @returns {ArrayBuffer} Digest of data - */ - var digestSHA1 = (function () // - { - - // Create a buffer for each 80 word block. - var state, block = new Uint32Array(80); - - function common(a, e, w, k, f) { - return (f + e + w + k + ((a << 5) | (a >>> 27))) >>> 0; - } - - function f1(a, b, c, d, e, w) { - return common(a, e, w, 0x5A827999, d ^ (b & (c ^ d))); - } - - function f2(a, b, c, d, e, w) { - return common(a, e, w, 0x6ED9EBA1, b ^ c ^ d); - } - - function f3(a, b, c, d, e, w) { - return common(a, e, w, 0x8F1BBCDC, (b & c) | (d & (b | c))); - } - - function f4(a, b, c, d, e, w) { - return common(a, e, w, 0xCA62C1D6, b ^ c ^ d); - } - - function cycle(state, block) { - var a = state[0], - b = state[1], - c = state[2], - d = state[3], - e = state[4]; - - // Partially unroll loops so we don't have to shift variables. - var fn = f1; - for (var i = 0; i < 80; i += 5) { - if (i === 20) { - fn = f2; - } - else if (i === 40) { - fn = f3; - } - else if (i === 60) { - fn = f4; - } - e = fn(a, b, c, d, e, block[i]); - b = ((b << 30) | (b >>> 2)) >>> 0; - d = fn(e, a, b, c, d, block[i + 1]); - a = ((a << 30) | (a >>> 2)) >>> 0; - c = fn(d, e, a, b, c, block[i + 2]); - e = ((e << 30) | (e >>> 2)) >>> 0; - b = fn(c, d, e, a, b, block[i + 3]); - d = ((d << 30) | (d >>> 2)) >>> 0; - a = fn(b, c, d, e, a, block[i + 4]); - c = ((c << 30) | (c >>> 2)) >>> 0; - } - state[0] += a; - state[1] += b; - state[2] += c; - state[3] += d; - state[4] += e; - } - - // Swap bytes for 32bits word - function swap32(b) { - return ((b & 0xff) << 24) - | ((b & 0xff00) << 8) - | ((b >> 8) & 0xff00) - | ((b >> 24) & 0xff); - } - - // input is a Uint8Array bitstream of the data - return function (data) { - var d = new Uint8Array(buffer(data)), dlen = d.length; - - // Pad the input string length. - var len = dlen + 9; - if (len % 64) { - len += 64 - (len % 64); - } - - state = new Uint32Array(5); - state[0] = 0x67452301; - state[1] = 0xefcdab89; - state[2] = 0x98badcfe; - state[3] = 0x10325476; - state[4] = 0xc3d2e1f0; - - for (var ofs = 0; ofs < len; ofs += 64) { - - // Copy input to block and write padding as needed - for (var i = 0; i < 64; i++) { - var b = 0, - o = ofs + i; - if (o < dlen) { - b = d[o]; - } - else if (o === dlen) { - b = 0x80; - } - else { - // Write original bit length as a 64bit big-endian integer to the end. - var x = len - o - 1; - if (x >= 0 && x < 4) { - b = (dlen << 3 >>> (x * 8)) & 0xff; - } - } - - // Interpret the input bytes as big-endian per the spec - if (i % 4 === 0) { - block[i >> 2] = b << 24; - } - else { - block[i >> 2] |= b << ((3 - (i % 4)) * 8); - } - } - - // Extend the block - for (var i = 16; i < 80; i++) { - var w = block[i - 3] ^ block[i - 8] ^ block[i - 14] ^ block[i - 16]; - block[i] = (w << 1) | (w >>> 31); - } - - cycle(state, block); - - } - - // Swap the bytes around since they are big endian internally - for (var i = 0; i < 5; i++) - state[i] = swap32(state[i]); - return state.buffer; - }; - - } // - )(); - - /** - * Algorithm name GOST R 34.11-HMAC

- * - * HMAC with the specified hash function. - * @memberOf GostDigest - * @method sign - * @instance - * @param {ArrayBuffer} key The key for HMAC. - * @param {Hash} data Data - */ - function signHMAC(key, data) // - { - // GOST R 34.11-94 - B=32b, L=32b - // GOST R 34.11-256 - B=64b, L=32b - // GOST R 34.11-512 - B=64b, L=64b - var b = (this.digest === digest94) ? 32 : 64, - l = this.bitLength / 8, - k = buffer(key), - d = buffer(data), k0; - if (k.byteLength === b) - k0 = new Uint8Array(k); - else { - var k0 = new Uint8Array(b); - if (k.byteLength > b) { - k0.set(new Uint8Array(this.digest(k))); - } else { - k0.set(new Uint8Array(k)); - } - } - var s0 = new Uint8Array(b + d.byteLength), - s1 = new Uint8Array(b + l); - for (var i = 0; i < b; i++) { - s0[i] = k0[i] ^ 0x36; - s1[i] = k0[i] ^ 0x5C; - } - s0.set(new Uint8Array(d), b); - s1.set(new Uint8Array(this.digest(s0)), b); - return this.digest(s1); - } // - - /** - * Algorithm name GOST R 34.11-HMAC

- * - * Verify HMAC based on GOST R 34.11 hash - * - * @memberOf GostDigest - * @method verify - * @instance - * @param {(ArrayBuffer|TypedArray)} key Key which used for HMAC generation - * @param {(ArrayBuffer|TypedArray)} signature generated HMAC - * @param {(ArrayBuffer|TypedArray)} data Data - * @returns {boolean} HMAC verified = true - */ - function verifyHMAC(key, signature, data) // - { - var hmac = new Uint8Array(this.sign(key, data)), - test = new Uint8Array(signature); - if (hmac.length !== test.length) - return false; - for (var i = 0, n = hmac.length; i < n; i++) - if (hmac[i] !== test[i]) - return false; - return true; - } // - - - /** - * Algorithm name GOST R 34.11-KDF

- * - * Simple generate key 256/512 bit random seed for derivation algorithms - * - * @memberOf GostDigest - * @method generateKey - * @instance - * @returns {ArrayBuffer} Generated key - */ - function generateKey() // - { - return getSeed(this.bitLength).buffer; - } // - - /** - * Algorithm name GOST R 34.11-PFXKDF

- * - * Derive bits from password (PKCS12 mode) - *
    - *
  • algorithm.salt - random value, salt
  • - *
  • algorithm.iterations - number of iterations
  • - *
- * @memberOf GostDigest - * @method deriveBits - * @instance - * @param {ArrayBuffer} baseKey - password after UTF-8 decoding - * @param {number} length output bit-length - * @returns {ArrayBuffer} result - */ - function deriveBitsPFXKDF(baseKey, length) // - { - if (length % 8 > 0) - throw new DataError('Length must multiple of 8'); - var u = this.bitLength / 8, v = (this.digest === digest94) ? 32 : 64, - n = length / 8, r = this.iterations; - // 1. Construct a string, D (the "diversifier"), by concatenating v/8 - // copies of ID. - var ID = this.diversifier, D = new Uint8Array(v); - for (var i = 0; i < v; i++) - D[i] = ID; - // 2. Concatenate copies of the salt together to create a string S of - // length v(ceiling(s/v)) bits (the final copy of the salt may be - // truncated to create S). Note that if the salt is the empty - // string, then so is S. - var S0 = new Uint8Array(buffer(this.salt)), s = S0.length, - slen = v * Math.ceil(s / v), S = new Uint8Array(slen); - for (var i = 0; i < slen; i++) - S[i] = S0[i % s]; - // 3. Concatenate copies of the password together to create a string P - // of length v(ceiling(p/v)) bits (the final copy of the password - // may be truncated to create P). Note that if the password is the - // empty string, then so is P. - var P0 = new Uint8Array(buffer(baseKey)), p = P0.length, - plen = v * Math.ceil(p / v), P = new Uint8Array(plen); - for (var i = 0; i < plen; i++) - P[i] = P0[i % p]; - // 4. Set I=S||P to be the concatenation of S and P. - var I = new Uint8Array(slen + plen); - arraycopy(S, 0, I, 0, slen); - arraycopy(P, 0, I, slen, plen); - // 5. Set c=ceiling(n/u). - var c = Math.ceil(n / u); - // 6. For i=1, 2, ..., c, do the following: - var A = new Uint8Array(c * u); - for (var i = 0; i < c; i++) { - // A. Set A2=H^r(D||I). (i.e., the r-th hash of D||1, - // H(H(H(... H(D||I)))) - var H = new Uint8Array(v + slen + plen); - arraycopy(D, 0, H, 0, v); - arraycopy(I, 0, H, v, slen + plen); - for (var j = 0; j < r; j++) - H = new Uint8Array(this.digest(H)); - arraycopy(H, 0, A, i * u, u); - // B. Concatenate copies of Ai to create a string B of length v - // bits (the final copy of Ai may be truncated to create B). - var B = new Uint8Array(v); - for (var j = 0; j < v; j++) - B[j] = H[j % u]; - // C. Treating I as a concatenation I_0, I_1, ..., I_(k-1) of v-bit - // blocks, where k=ceiling(s/v)+ceiling(p/v), modify I by - // setting I_j=(I_j+B+1) mod 2^v for each j. - var k = (slen + plen) / v; - for (j = 0; j < k; j++) { - var cf = 1, w; - for (var l = v - 1; l >= 0; --l) { - w = I[v * j + l] + B[l] + cf; - cf = w >>> 8; - I[v * j + l] = w & 0xff; - } - } - } - // 7. Concatenate A_1, A_2, ..., A_c together to form a pseudorandom - // bit string, A. - // 8. Use the first n bits of A as the output of this entire process. - var R = new Uint8Array(n); - arraycopy(A, 0, R, 0, n); - return R.buffer; - } // - - /** - * Algorithm name GOST R 34.11-KDF

- * - * Derive bits for KEK deversification in 34.10-2012 algorithm - * KDF(KEK, UKM, label) = HMAC256 (KEK, 0x01|label|0x00|UKM|0x01|0x00) - * Default label = 0x26|0xBD|0xB8|0x78 - * - * @memberOf GostDigest - * @method deriveBits - * @instance - * @param {(ArrayBuffer|TypedArray)} baseKey base key for deriviation - * @param {number} length output bit-length - * @returns {ArrayBuffer} result - */ - function deriveBitsKDF(baseKey, length) // - { - if (length % 8 > 0) - throw new DataError('Length must be multiple of 8'); - var rlen = length / 8, label, context = new Uint8Array(buffer(this.context)), - blen = this.bitLength / 8, n = Math.ceil(rlen / blen); - if (this.label) - label = new Uint8Array(buffer(this.label)); - else - label = new Uint8Array([0x26, 0xBD, 0xB8, 0x78]); - var result = new Uint8Array(rlen); - for (var i = 0; i < n; i++) { - var data = new Uint8Array(label.length + context.length + 4); - data[0] = i + 1; - data.set(label, 1); - data[label.length + 1] = 0x00; - data.set(context, label.length + 2); - data[data.length - 2] = length >>> 8; - data[data.length - 1] = length & 0xff; - result.set(new Uint8Array(signHMAC.call(this, baseKey, data), 0, - i < n - 1 ? blen : rlen - i * blen), i * blen); - } - return result.buffer; - } // - - /** - * Algorithm name GOST R 34.11-PBKDF1

- * - * Derive bits from password - *
    - *
  • algorithm.salt - random value, salt
  • - *
  • algorithm.iterations - number of iterations
  • - *
- * @memberOf GostDigest - * @method deriveBits - * @instance - * @param {ArrayBuffer} baseKey - password after UTF-8 decoding - * @param {number} length output bit-length - * @returns {ArrayBuffer} result - */ - function deriveBitsPBKDF1(baseKey, length) // - { - if (length < this.bitLength / 2 || length % 8 > 0) - throw new DataError('Length must be more than ' + this.bitLength / 2 + ' bits and multiple of 8'); - var hLen = this.bitLength / 8, dkLen = length / 8, - c = this.iterations, - P = new Uint8Array(buffer(baseKey)), - S = new Uint8Array(buffer(this.salt)), - slen = S.length, plen = P.length, - T = new Uint8Array(plen + slen), - DK = new Uint8Array(dkLen); - if (dkLen > hLen) - throw new DataError('Invalid parameters: Length value'); - arraycopy(P, 0, T, 0, plen); - arraycopy(S, 0, T, plen, slen); - for (var i = 0; i < c; i++) - T = new Uint8Array(this.digest(T)); - arraycopy(T, 0, DK, 0, dkLen); - return DK.buffer; - } // - - /** - * Algorithm name GOST R 34.11-PBKDF2

- * - * Derive bits from password - *
    - *
  • algorithm.salt - random value, salt
  • - *
  • algorithm.iterations - number of iterations
  • - *
- * @memberOf GostDigest - * @method deriveBits - * @instance - * @param {ArrayBuffer} baseKey - password after UTF-8 decoding - * @param {number} length output bit-length - * @returns {ArrayBuffer} result - */ - function deriveBitsPBKDF2(baseKey, length) // - { - var diversifier = this.diversifier || 1; // For PKCS12 MAC required 3*length - length = length * diversifier; - if (length < this.bitLength / 2 || length % 8 > 0) - throw new DataError('Length must be more than ' + this.bitLength / 2 + ' bits and multiple of 8'); - var hLen = this.bitLength / 8, dkLen = length / 8, - c = this.iterations, - P = new Uint8Array(buffer(baseKey)), - S = new Uint8Array(buffer(this.salt)); - var slen = S.byteLength, - data = new Uint8Array(slen + 4); - arraycopy(S, 0, data, 0, slen); - - if (dkLen > (0xffffffff - 1) * 32) - throw new DataError('Invalid parameters: Length value'); - var n = Math.ceil(dkLen / hLen), - DK = new Uint8Array(dkLen); - for (var i = 1; i <= n; i++) { - data[slen] = i >>> 24 & 0xff; - data[slen + 1] = i >>> 16 & 0xff; - data[slen + 2] = i >>> 8 & 0xff; - data[slen + 3] = i & 0xff; - - var U = new Uint8Array(signHMAC.call(this, P, data)), Z = U; - for (var j = 1; j < c; j++) { - U = new Uint8Array(signHMAC.call(this, P, U)); - for (var k = 0; k < hLen; k++) - Z[k] = U[k] ^ Z[k]; - } - var ofs = (i - 1) * hLen; - arraycopy(Z, 0, DK, ofs, Math.min(hLen, dkLen - ofs)); - } - if (diversifier > 1) { - var rLen = dkLen / diversifier, R = new Uint8Array(rLen); - arraycopy(DK, dkLen - rLen, R, 0, rLen); - return R.buffer; - } else - return DK.buffer; - } // - - /** - * Algorithm name GOST R 34.11-CPKDF

- * - * Derive bits from password. CryptoPro algorithm - *
    - *
  • algorithm.salt - random value, salt
  • - *
  • algorithm.iterations - number of iterations
  • - *
- * @memberOf GostDigest - * @method deriveBits - * @instance - * @param {ArrayBuffer} baseKey - password after UTF-8 decoding - * @param {number} length output bit-length - * @returns {ArrayBuffer} result - */ - function deriveBitsCP(baseKey, length) { - if (length > this.bitLength || length % 8 > 0) - throw new DataError('Length can\'t be more than ' + this.bitLength + ' bits and multiple of 8'); - // GOST R 34.11-94 - B=32b, L=32b - // GOST R 34.11-256 - B=64b, L=32b - // GOST R 34.11-512 - B=64b, L=64b - var b = (this.digest === digest94) ? 32 : 64, - l = this.bitLength / 8, - p = baseKey && baseKey.byteLength > 0 ? new Uint8Array(buffer(baseKey)) : false, - plen = p ? p.length : 0, - iterations = this.iterations, - salt = new Uint8Array(buffer(this.salt)), - slen = salt.length, - d = new Uint8Array(slen + plen); - arraycopy(salt, 0, d, 0, slen); - if (p) - arraycopy(p, 0, d, slen, plen); - - var h = new Uint8Array(this.digest(d)), - k = new Uint8Array(b), - s0 = new Uint8Array(b), - s1 = new Uint8Array(b); - var c = 'DENEFH028.760246785.IUEFHWUIO.EF'; - for (var i = 0; i < c.length; i++) - k[i] = c.charCodeAt(i); - - d = new Uint8Array(2 * (b + l)); - for (var j = 0; j < iterations; j++) { - for (var i = 0; i < b; i++) { - s0[i] = k[i] ^ 0x36; - s1[i] = k[i] ^ 0x5C; - k[i] = 0; - } - arraycopy(s0, 0, d, 0, b); - arraycopy(h, 0, d, b, l); - arraycopy(s1, 0, d, b + l, b); - arraycopy(h, 0, d, b + l + b, l); - arraycopy(new Uint8Array(this.digest(d)), 0, k, 0, l); - } - for (var i = 0; i < l; i++) { - s0[i] = k[i] ^ 0x36; - s1[i] = k[i] ^ 0x5C; - k[i] = 0; - } - d = new Uint8Array(2 * l + slen + plen); - arraycopy(s0, 0, d, 0, l); - arraycopy(salt, 0, d, l, slen); - arraycopy(s1, 0, d, l + slen, l); - if (p) - arraycopy(p, 0, d, l + slen + l, plen); - h = this.digest(this.digest(d)); - if (length === this.bitLength) - return h; - else { - var rlen = length / 8, r = new Uint8Array(rlen); - arraycopy(h, 0, r, 0, rlen); - return r.buffer; - } - } - - /** - * Algorithm name GOST R 34.11-KDF or GOST R 34.11-PBKDF2 or other

- * - * Derive key from derive bits subset - * - * @memberOf GostDigest - * @method deriveKey - * @instance - * @param {ArrayBuffer} baseKey - * @returns {ArrayBuffer} - */ - function deriveKey(baseKey) // - { - return this.deriveBits(baseKey, this.keySize * 8); - } // - - /** - * GOST R 34.11 Algorithm

- * - * References: {@link http://tools.ietf.org/html/rfc6986} and {@link http://tools.ietf.org/html/rfc5831}

- * - * Normalized algorithm identifier common parameters: - * - *
    - *
  • name Algorithm name 'GOST R 34.11'
  • - *
  • version Algorithm version - *
      - *
    • 1994 old-style 256 bits digest based on GOST 28147-89
    • - *
    • 2012 256 ro 512 bits digest algorithm "Streebog" GOST R 34.11-2012 (default)
    • - *
    - *
  • - *
  • length Digest length - *
      - *
    • 256 256 bits digest
    • - *
    • 512 512 bits digest, valid only for algorithm "Streebog"
    • - *
    - *
  • - *
  • mode Algorithm mode - *
      - *
    • HASH simple digest mode (default)
    • - *
    • HMAC HMAC algorithm based on GOST R 34.11
    • - *
    • KDF Derive bits for KEK deversification
    • - *
    • PBKDF2 Password based key dirivation algorithms PBKDF2 (based on HMAC)
    • - *
    • PFXKDF Password based PFX key dirivation algorithms
    • - *
    • CPKDF CpyptoPro Password based key dirivation algorithms
    • - *
    - *
  • - *
  • sBox Paramset sBox for GOST 28147-89. Used only if version = 1994
  • - *
- * - * Supported algorithms, modes and parameters: - * - *
    - *
  • Digest HASH mode (default)
  • - *
  • Sign/Verify HMAC modes parameters depends on version and length - *
      - *
    • version: 1994 HMAC parameters (B = 32, L = 32)
    • - *
    • version: 2012, length: 256 HMAC parameters (B = 64, L = 32)
    • - *
    • version: 2012, length: 512 HMAC parameters (B = 64, L = 64)
    • - *
    - *
  • - *
  • DeriveBits/DeriveKey KDF mode - *
      - *
    • context {@link CryptoOperationData} Context of the key derivation
    • - *
    • label {@link CryptoOperationData} Label that identifies the purpose for the derived keying material
    • - *
    - *
  • - *
  • DeriveBits/DeriveKey PBKDF2 mode - *
      - *
    • salt {@link CryptoOperationData} Random salt as input for HMAC algorithm
    • - *
    • iterations Iteration count. GOST recomended value 1000 (default) or 2000
    • - *
    • diversifier Deversifier, ID=1 - key material for performing encryption or decryption, ID=3 - integrity key for MACing
    • - *
    - *
  • - *
  • DeriveBits/DeriveKey PFXKDF mode - *
      - *
    • salt {@link CryptoOperationData} Random salt as input for HMAC algorithm
    • - *
    • iterations Iteration count. GOST recomended value 1000 (default) or 2000
    • - *
    • diversifier Deversifier, ID=1 - key material for performing encryption or decryption, - * ID=2 - IV (Initial Value) for encryption or decryption, ID=3 - integrity key for MACing
    • - *
    - *
  • - *
  • DeriveBits/DeriveKey CPKDF mode - *
      - *
    • salt {@link CryptoOperationData} Random salt as input for HMAC algorithm
    • - *
    • iterations Iteration count. GOST recomended value 1000 (default) or 2000
    • - *
    - *
  • - *
- * - * @class GostDigest - * @param {AlgorithmIdentifier} algorithm WebCryptoAPI algorithm identifier - */ - function GostDigest(algorithm) // - { - - algorithm = algorithm || {}; - - this.name = (algorithm.name || 'GOST R 34.10') + '-' + ((algorithm.version || 2012) % 100) + - ((algorithm.version || 2012) > 1 ? '-' + (algorithm.length || 256) : '') + - (((algorithm.mode || 'HASH') !== 'HASH') ? '-' + algorithm.mode : '') + - (algorithm.procreator ? '/' + algorithm.procreator : '') + - (typeof algorithm.sBox === 'string' ? '/' + algorithm.sBox : ''); - - // Algorithm procreator - this.procreator = algorithm.procreator; - - // Bit length - this.bitLength = algorithm.length || 256; - - switch (algorithm.version || 2012) { - case 1: // SHA-1 - this.digest = digestSHA1; - this.bitLength = 160; - break; - case 1994: - this.digest = digest94; - // Define chiper algorithm - this.sBox = (algorithm.sBox || (algorithm.procreator === 'SC' ? 'D-SC' : 'D-A')).toUpperCase(); - - if (!GostCipher) - GostCipher = root.GostCipher; - if (!GostCipher) - throw new NotSupportedError('Object GostCipher not found'); - - this.cipher = new GostCipher({ - name: 'GOST 28147', - block: 'ECB', - sBox: this.sBox, - procreator: this.procreator - }); - - break; - case 2012: - this.digest = digest2012; - break; - default: - throw new NotSupportedError('Algorithm version ' + algorithm.version + ' not supported'); - } - - // Key size - this.keySize = algorithm.keySize || (algorithm.version <= 2 ? this.bitLength / 8 : 32); - - switch (algorithm.mode || 'HASH') { - case 'HASH': - break; - case 'HMAC': - this.sign = signHMAC; - this.verify = verifyHMAC; - this.generateKey = generateKey; - break; - case 'KDF': - this.deriveKey = deriveKey; - this.deriveBits = deriveBitsKDF; - this.label = algorithm.label; - this.context = algorithm.context; - break; - case 'PBKDF2': - this.deriveKey = deriveKey; - this.deriveBits = deriveBitsPBKDF2; - this.generateKey = generateKey; - this.salt = algorithm.salt; - this.iterations = algorithm.iterations || 2000; - this.diversifier = algorithm.diversifier || 1; - break; - case 'PFXKDF': - this.deriveKey = deriveKey; - this.deriveBits = deriveBitsPFXKDF; - this.generateKey = generateKey; - this.salt = algorithm.salt; - this.iterations = algorithm.iterations || 2000; - this.diversifier = algorithm.diversifier || 1; - break; - case 'CPKDF': - this.deriveKey = deriveKey; - this.deriveBits = deriveBitsCP; - this.generateKey = generateKey; - this.salt = algorithm.salt; - this.iterations = algorithm.iterations || 2000; - break; - default: - throw new NotSupportedError('Algorithm mode ' + algorithm.mode + ' not supported'); - } - } // - - return GostDigest; - -})); \ No newline at end of file diff --git a/src/core/vendor/streebog/gostDigest.mjs b/src/core/vendor/streebog/gostDigest.mjs new file mode 100644 index 00000000..0ead2b79 --- /dev/null +++ b/src/core/vendor/streebog/gostDigest.mjs @@ -0,0 +1,1260 @@ +/** + * GOST R 34.11-94 / GOST R 34.11-12 implementation + * 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. + * + * Converted to JavaScript from source https://www.streebog.net/ + * Copyright (c) 2013, Alexey Degtyarev. + * All rights reserved. + * + * 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'; + import GostCipher from './gostCipher'; + import crypto from 'crypto'; + +/* + * GOST R 34.11 + * Common methods + * + */ // + +var root = {}; +var rootCrypto = crypto + +var DataError = Error, + NotSupportedError = Error; + +// Copy len values from s[sOfs] to d[dOfs] +function arraycopy(s, sOfs, d, dOfs, len) { + for (var i = 0; i < len; i++) + d[dOfs + i] = s[sOfs + i]; +} + +// Swap bytes in buffer +function swap(s) { + var src = new Uint8Array(s), + dst = new Uint8Array(src.length); + for (var i = 0, n = src.length; i < n; i++) + dst[n - i - 1] = src[i]; + return dst.buffer; +} + +// Convert BASE64 string to Uint8Array +// for decompression of constants and precalc values +function b64decode(s) { + // s = s.replace(/[^A-Za-z0-9\+\/]/g, ''); + var n = s.length, + k = n * 3 + 1 >> 2, r = new Uint8Array(k); + + for (var m3, m4, u24 = 0, j = 0, i = 0; i < n; i++) { + m4 = i & 3; + var c = s.charCodeAt(i); + + c = c > 64 && c < 91 ? + c - 65 : c > 96 && c < 123 ? + c - 71 : c > 47 && c < 58 ? + c + 4 : c === 43 ? + 62 : c === 47 ? + 63 : 0; + + u24 |= c << 18 - 6 * m4; + if (m4 === 3 || n - i === 1) { + for (m3 = 0; m3 < 3 && j < k; m3++, j++) { + r[j] = u24 >>> (16 >>> m3 & 24) & 255; + } + u24 = 0; + + } + } + return r.buffer; +} + +// Random seed +function getSeed(length) { + GostRandom = GostRandom || root.GostRandom; + var randomSource = GostRandom ? new (GostRandom || root.GostRandom) : rootCrypto; + if (randomSource.getRandomValues) { + var d = new Uint8Array(Math.ceil(length / 8)); + randomSource.getRandomValues(d); + return d; + } else + throw new NotSupportedError('Random generator not found'); +} + +// Check buffer +function buffer(d) { + if (d instanceof ArrayBuffer) + return d; + else if (d && d.buffer && d.buffer instanceof ArrayBuffer) + 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('ArrayBuffer or ArrayBufferView required'); +} // + +/** + * Algorithm name GOST R 34.11 or GOST R 34.11-12

+ * + * http://tools.ietf.org/html/rfc6986 + * + * The digest method returns digest data in according to GOST R 4311-2012.
+ * Size of digest also defines in algorithm name. + *
    + *
  • GOST R 34.11-256-12 - 256 bits digest
  • + *
  • GOST R 34.11-512-12 - 512 bits digest
  • + *
+ * + * @memberOf GostDigest + * @method digest + * @instance + * @param {(ArrayBuffer|TypedArray)} data Data + * @returns {ArrayBuffer} Digest of data + */ +var digest2012 = (function () // +{ + // Constants + var buffer0 = new Int32Array(16); // [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + + var buffer512 = new Int32Array(16); // [512, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + buffer512[0] = 512; + + // Constant C + var C = (function (s) { + var h = new Int32Array(b64decode(s)), + r = new Array(12); + for (var i = 0; i < 12; i++) + r[i] = new Int32Array(h.buffer, i * 64, 16); + return r; + })( + 'B0Wm8lllgN0jTXTMNnR2BRXTYKQIKkKiAWlnkpHgfEv8xIV1jbhOcRbQRS5DdmovH3xlwIEvy+vp2soe2lsIsbebsSFwBHnmVs3L1xui3VXKpwrbwmG1XFiZ1hJrF7WaMQG1Fg9e1WGYKyMKcur+89e1cA9GneNPGi+dqYq1o2+yCroK9ZYemTHbeoZD9LbCCdtiYDc6ycGxnjWQ5A/i03t7KbEUderyix+cUl9e8QY1hD1qKPw5Cscvzius3HT1LtHjhLy+DCLxN+iToepTNL4DUpMzE7fYddYD7YIs16k/NV5orRxynX08XDN+hY5I3eRxXaDhSPnSZhXos98f71f+bHz9WBdg9WPqqX6iVnoWGicjtwD/36P1OiVHF82/vf8PgNc1njVKEIYWHxwVf2MjqWwMQT+amUdHraxr6ktufWRGekBo+jVPkDZyxXG/tsa+wmYf8gq0t5oct6b6z8aO8Jq0mn8YbKRCUfnEZi3AOTB6O8Okb9nTOh2urk+uk9QUOk1WhojzSjyiTEUXNQQFSiiDaUcGNyyCLcWrkgnJk3oZMz5H08mHv+bHxp45VAkkv/6GrFHsxaruFg7H9B7nAr/UDX+k' + + '2ahRWTXCrDYvxKXRK43RaZAGm5LLK4n0msTbTTtEtIke3jaccfi3TkFBbgwCqucDp8mTTUJbH5vbWiODUURhcmAqH8uS3DgOVJwHppqKK3uxzrLbC0QKgIQJDeC3Vdk8JEKJJRs6fTreXxbs2JpMlJsiMRZUWo837ZxFmPvHtHTDtjsV0fqYNvRSdjswbB56SzNprwJn558DYTMbiuH/H9t4iv8c50GJ8/PkskjlKjhSbwWApt6+qxst84HNpMprXdhvwEpZot6Ybkd9Hc2678q5SOrvcR2KeWaEFCGAASBhB6vru2v62JT+WmPNxgIw+4nI79CezXsg1xvxSpK8SJkbstnVF/T6UijhiKqkHeeGzJEYne+AXZufITDUEiD4dx3fvDI8pM16sUkEsIAT0roxFvFn5443'); + + // Precalc Ax + var Ax = (function (s) { + return new Int32Array(b64decode(s)); + })( + '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'); //== + + // Variables + var sigma, N, h; + + // 64bit tools + function get8(x, i) { + return (x[i >> 2] >> ((i & 3) << 3)) & 0xff; + } + + // 512bit tools + function add512(x, y) { + var CF = 0, w0, w1; + for (var i = 0; i < 16; i++) { + w0 = (x[i] & 0xffff) + (y[i] & 0xffff) + (CF || 0); + w1 = (x[i] >>> 16) + (y[i] >>> 16) + (w0 >>> 16); + x[i] = (w0 & 0xffff) | (w1 << 16); + CF = (w1 >>> 16); + } + } + + function get512(d) { + return new Int32Array(d.buffer, d.byteOffset, 16); + } + + + function copy512(r, d) { + for (var i = 0; i < 16; i++) + r[i] = d[i]; + } + + function new512() { + return new Int32Array(16); + } + + // Core private algorithms + function xor512(x, y) { + for (var i = 0; i < 16; i++) + x[i] = x[i] ^ y[i]; + } + + + var r = new512(); + function XLPS(x, y) { + copy512(r, x); + xor512(r, y); + for (var i = 0; i < 8; i++) { + var z0, z1, k = get8(r, i) << 1; + z0 = Ax[k]; + z1 = Ax[k + 1]; + for (var j = 1; j < 8; j++) { + k = (j << 9) + (get8(r, (j << 3) + i) << 1); + z0 = z0 ^ Ax[k]; + z1 = z1 ^ Ax[k + 1]; + } + x[i << 1] = z0; + x[(i << 1) + 1] = z1; + } + } + + var data = new512(), Ki = new512(); + function g(h, N, m) + { + var i; + + copy512(data, h); + XLPS(data, N); + + /* Starting E() */ + copy512(Ki, data); + XLPS(data, m); + + for (i = 0; i < 11; i++) { + XLPS(Ki, C[i]); + XLPS(data, Ki); + } + + XLPS(Ki, C[11]); + xor512(data, Ki); + /* E() done */ + + xor512(h, data); + xor512(h, m); + } + + // Stages + function stage2(d) { + var m = get512(d); + g(h, N, m); + + add512(N, buffer512); + add512(sigma, m); + } + + function stage3(d) { + var n = d.length; + if (n > 63) + return; + + var b0 = new Int32Array(16); + b0[0] = n << 3; + + var b = new Uint8Array(64); + for (var i = 0; i < n; i++) + b[i] = d[i]; + b[n] = 0x01; + + var m = get512(b), m0 = get512(b0); + g(h, N, m); + + add512(N, m0); + add512(sigma, m); + + g(h, buffer0, N); + g(h, buffer0, sigma); + } + + return function (data) { + + // Cleanup + sigma = new512(); + N = new512(); + + // Initial vector + h = new512(); + for (var i = 0; i < 16; i++) + if (this.bitLength === 256) + h[i] = 0x01010101; + + // Make data + var d = new Uint8Array(buffer(data)); + + var n = d.length; + var r = n % 64, q = (n - r) / 64; + + for (var i = 0; i < q; i++) + stage2.call(this, new Uint8Array(d.buffer, i * 64, 64)); + + stage3.call(this, new Uint8Array(d.buffer, q * 64, r)); + + var digest; + if (this.bitLength === 256) { + digest = new Int32Array(8); + for (var i = 0; i < 8; i++) + digest[i] = h[8 + i]; + } else { + digest = new Int32Array(16); + for (var i = 0; i < 16; i++) + digest[i] = h[i]; + } + // Swap hash for SignalCom + if (this.procreator === 'SC' || this.procreator === 'VN') + return swap(digest.buffer); + else + return digest.buffer; + }; +} // +)(); + +/** + * Algorithm name GOST R 34.11-94

+ * + * http://tools.ietf.org/html/rfc5831 + * + * The digest method returns digest data in according to GOST R 34.11-94. + * @memberOf GostDigest + * @method digest + * @instance + * @param {(ArrayBuffer|TypedArray)} data Data + * @returns {ArrayBuffer} Digest of data + */ +var digest94 = (function () // +{ + var C, H, M, Sum; + + // (i + 1 + 4(k - 1)) = 8i + k i = 0-3, k = 1-8 + function P(d) { + var K = new Uint8Array(32); + + for (var k = 0; k < 8; k++) { + K[4 * k] = d[k]; + K[1 + 4 * k] = d[ 8 + k]; + K[2 + 4 * k] = d[16 + k]; + K[3 + 4 * k] = d[24 + k]; + } + + return K; + } + + //A (x) = (x0 ^ x1) || x3 || x2 || x1 + function A(d) + { + var a = new Uint8Array(8); + + for (var j = 0; j < 8; j++) + { + a[j] = (d[j] ^ d[j + 8]); + } + + arraycopy(d, 8, d, 0, 24); + arraycopy(a, 0, d, 24, 8); + + return d; + } + + // (in:) n16||..||n1 ==> (out:) n1^n2^n3^n4^n13^n16||n16||..||n2 + function fw(d) { + var wS = new Uint16Array(d.buffer, 0, 16); + var wS15 = wS[0] ^ wS[1] ^ wS[2] ^ wS[3] ^ wS[12] ^ wS[15]; + arraycopy(wS, 1, wS, 0, 15); + wS[15] = wS15; + } + + //Encrypt function, ECB mode + function encrypt(key, s, sOff, d, dOff) { + var t = new Uint8Array(8); + arraycopy(d, dOff, t, 0, 8); + var r = new Uint8Array(this.cipher.encrypt(key, t)); + arraycopy(r, 0, s, sOff, 8); + } + + // block processing + function process(d, dOff) { + var S = new Uint8Array(32), U = new Uint8Array(32), + V = new Uint8Array(32), W = new Uint8Array(32); + + arraycopy(d, dOff, M, 0, 32); + + //key step 1 + + // H = h3 || h2 || h1 || h0 + // S = s3 || s2 || s1 || s0 + arraycopy(H, 0, U, 0, 32); + arraycopy(M, 0, V, 0, 32); + for (var j = 0; j < 32; j++) + { + W[j] = (U[j] ^ V[j]); + } + // Encrypt GOST 28147-ECB + encrypt.call(this, P(W), S, 0, H, 0); // s0 = EK0 [h0] + + //keys step 2,3,4 + for (var i = 1; i < 4; i++) { + var tmpA = A(U); + for (var j = 0; j < 32; j++) { + U[j] = (tmpA[j] ^ C[i][j]); + } + V = A(A(V)); + for (var j = 0; j < 32; j++) { + W[j] = (U[j] ^ V[j]); + } + // Encrypt GOST 28147-ECB + encrypt.call(this, P(W), S, i * 8, H, i * 8); // si = EKi [hi] + } + + // x(M, H) = y61(H^y(M^y12(S))) + for (var n = 0; n < 12; n++) { + fw(S); + } + for (var n = 0; n < 32; n++) { + S[n] = (S[n] ^ M[n]); + } + + fw(S); + + for (var n = 0; n < 32; n++) { + S[n] = (H[n] ^ S[n]); + } + for (var n = 0; n < 61; n++) { + fw(S); + } + arraycopy(S, 0, H, 0, H.length); + } + + + // 256 bitsblock modul -> (Sum + a mod (2^256)) + function summing(d) + { + var carry = 0; + for (var i = 0; i < Sum.length; i++) + { + var sum = (Sum[i] & 0xff) + (d[i] & 0xff) + carry; + + Sum[i] = sum; + + carry = sum >>> 8; + } + } + + // reset the chaining variables to the IV values. + var C2 = new Uint8Array([ + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, + 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF + ]); + + return function (data) { + + // Reset buffers + H = new Uint8Array(32); + M = new Uint8Array(32); + Sum = new Uint8Array(32); + + // Reset IV value + C = new Array(4); + for (var i = 0; i < 4; i++) + C[i] = new Uint8Array(32); + arraycopy(C2, 0, C[2], 0, C2.length); + + // Make data + var d = new Uint8Array(buffer(data)); + + var n = d.length; + var r = n % 32, q = (n - r) / 32; + + // Proccess full blocks + for (var i = 0; i < q; i++) { + var b = new Uint8Array(d.buffer, i * 32, 32); + + summing.call(this, b); // calc sum M + process.call(this, b, 0); + } + + // load d the remadder with padding zero; + if (r > 0) { + var b = new Uint8Array(d.buffer, q * 32), + c = new Uint8Array(32); + arraycopy(b, 0, c, 0, r); + summing.call(this, c); // calc sum M + process.call(this, c, 0); + + } + + // get length into L (byteCount * 8 = bitCount) in little endian. + var L = new Uint8Array(32), n8 = n * 8, k = 0; + while (n8 > 0) { + L[k++] = n8 & 0xff; + n8 = Math.floor(n8 / 256); + } + process.call(this, L, 0); + process.call(this, Sum, 0); + + var h = H.buffer; + + // Swap hash for SignalCom + if (this.procreator === 'SC') + h = swap(h); + + return h; + }; + +} // +)(); + +/** + * Algorithm name SHA-1

+ * + * https://tools.ietf.org/html/rfc3174 + * + * The digest method returns digest data in according to SHA-1.
+ * + * @memberOf GostDigest + * @method digest + * @instance + * @param {(ArrayBuffer|TypedArray)} data Data + * @returns {ArrayBuffer} Digest of data + */ +var digestSHA1 = (function () // +{ + + // Create a buffer for each 80 word block. + var state, block = new Uint32Array(80); + + function common(a, e, w, k, f) { + return (f + e + w + k + ((a << 5) | (a >>> 27))) >>> 0; + } + + function f1(a, b, c, d, e, w) { + return common(a, e, w, 0x5A827999, d ^ (b & (c ^ d))); + } + + function f2(a, b, c, d, e, w) { + return common(a, e, w, 0x6ED9EBA1, b ^ c ^ d); + } + + function f3(a, b, c, d, e, w) { + return common(a, e, w, 0x8F1BBCDC, (b & c) | (d & (b | c))); + } + + function f4(a, b, c, d, e, w) { + return common(a, e, w, 0xCA62C1D6, b ^ c ^ d); + } + + function cycle(state, block) { + var a = state[0], + b = state[1], + c = state[2], + d = state[3], + e = state[4]; + + // Partially unroll loops so we don't have to shift variables. + var fn = f1; + for (var i = 0; i < 80; i += 5) { + if (i === 20) { + fn = f2; + } + else if (i === 40) { + fn = f3; + } + else if (i === 60) { + fn = f4; + } + e = fn(a, b, c, d, e, block[i]); + b = ((b << 30) | (b >>> 2)) >>> 0; + d = fn(e, a, b, c, d, block[i + 1]); + a = ((a << 30) | (a >>> 2)) >>> 0; + c = fn(d, e, a, b, c, block[i + 2]); + e = ((e << 30) | (e >>> 2)) >>> 0; + b = fn(c, d, e, a, b, block[i + 3]); + d = ((d << 30) | (d >>> 2)) >>> 0; + a = fn(b, c, d, e, a, block[i + 4]); + c = ((c << 30) | (c >>> 2)) >>> 0; + } + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + } + + // Swap bytes for 32bits word + function swap32(b) { + return ((b & 0xff) << 24) + | ((b & 0xff00) << 8) + | ((b >> 8) & 0xff00) + | ((b >> 24) & 0xff); + } + + // input is a Uint8Array bitstream of the data + return function (data) { + var d = new Uint8Array(buffer(data)), dlen = d.length; + + // Pad the input string length. + var len = dlen + 9; + if (len % 64) { + len += 64 - (len % 64); + } + + state = new Uint32Array(5); + state[0] = 0x67452301; + state[1] = 0xefcdab89; + state[2] = 0x98badcfe; + state[3] = 0x10325476; + state[4] = 0xc3d2e1f0; + + for (var ofs = 0; ofs < len; ofs += 64) { + + // Copy input to block and write padding as needed + for (var i = 0; i < 64; i++) { + var b = 0, + o = ofs + i; + if (o < dlen) { + b = d[o]; + } + else if (o === dlen) { + b = 0x80; + } + else { + // Write original bit length as a 64bit big-endian integer to the end. + var x = len - o - 1; + if (x >= 0 && x < 4) { + b = (dlen << 3 >>> (x * 8)) & 0xff; + } + } + + // Interpret the input bytes as big-endian per the spec + if (i % 4 === 0) { + block[i >> 2] = b << 24; + } + else { + block[i >> 2] |= b << ((3 - (i % 4)) * 8); + } + } + + // Extend the block + for (var i = 16; i < 80; i++) { + var w = block[i - 3] ^ block[i - 8] ^ block[i - 14] ^ block[i - 16]; + block[i] = (w << 1) | (w >>> 31); + } + + cycle(state, block); + + } + + // Swap the bytes around since they are big endian internally + for (var i = 0; i < 5; i++) + state[i] = swap32(state[i]); + return state.buffer; + }; + +} // +)(); + +/** + * Algorithm name GOST R 34.11-HMAC

+ * + * HMAC with the specified hash function. + * @memberOf GostDigest + * @method sign + * @instance + * @param {ArrayBuffer} key The key for HMAC. + * @param {Hash} data Data + */ +function signHMAC(key, data) // +{ + // GOST R 34.11-94 - B=32b, L=32b + // GOST R 34.11-256 - B=64b, L=32b + // GOST R 34.11-512 - B=64b, L=64b + var b = (this.digest === digest94) ? 32 : 64, + l = this.bitLength / 8, + k = buffer(key), + d = buffer(data), k0; + if (k.byteLength === b) + k0 = new Uint8Array(k); + else { + var k0 = new Uint8Array(b); + if (k.byteLength > b) { + k0.set(new Uint8Array(this.digest(k))); + } else { + k0.set(new Uint8Array(k)); + } + } + var s0 = new Uint8Array(b + d.byteLength), + s1 = new Uint8Array(b + l); + for (var i = 0; i < b; i++) { + s0[i] = k0[i] ^ 0x36; + s1[i] = k0[i] ^ 0x5C; + } + s0.set(new Uint8Array(d), b); + s1.set(new Uint8Array(this.digest(s0)), b); + return this.digest(s1); +} // + +/** + * Algorithm name GOST R 34.11-HMAC

+ * + * Verify HMAC based on GOST R 34.11 hash + * + * @memberOf GostDigest + * @method verify + * @instance + * @param {(ArrayBuffer|TypedArray)} key Key which used for HMAC generation + * @param {(ArrayBuffer|TypedArray)} signature generated HMAC + * @param {(ArrayBuffer|TypedArray)} data Data + * @returns {boolean} HMAC verified = true + */ +function verifyHMAC(key, signature, data) // +{ + var hmac = new Uint8Array(this.sign(key, data)), + test = new Uint8Array(signature); + if (hmac.length !== test.length) + return false; + for (var i = 0, n = hmac.length; i < n; i++) + if (hmac[i] !== test[i]) + return false; + return true; +} // + + +/** + * Algorithm name GOST R 34.11-KDF

+ * + * Simple generate key 256/512 bit random seed for derivation algorithms + * + * @memberOf GostDigest + * @method generateKey + * @instance + * @returns {ArrayBuffer} Generated key + */ +function generateKey() // +{ + return getSeed(this.bitLength).buffer; +} // + +/** + * Algorithm name GOST R 34.11-PFXKDF

+ * + * Derive bits from password (PKCS12 mode) + *
    + *
  • algorithm.salt - random value, salt
  • + *
  • algorithm.iterations - number of iterations
  • + *
+ * @memberOf GostDigest + * @method deriveBits + * @instance + * @param {ArrayBuffer} baseKey - password after UTF-8 decoding + * @param {number} length output bit-length + * @returns {ArrayBuffer} result + */ +function deriveBitsPFXKDF(baseKey, length) // +{ + if (length % 8 > 0) + throw new DataError('Length must multiple of 8'); + var u = this.bitLength / 8, v = (this.digest === digest94) ? 32 : 64, + n = length / 8, r = this.iterations; + // 1. Construct a string, D (the "diversifier"), by concatenating v/8 + // copies of ID. + var ID = this.diversifier, D = new Uint8Array(v); + for (var i = 0; i < v; i++) + D[i] = ID; + // 2. Concatenate copies of the salt together to create a string S of + // length v(ceiling(s/v)) bits (the final copy of the salt may be + // truncated to create S). Note that if the salt is the empty + // string, then so is S. + var S0 = new Uint8Array(buffer(this.salt)), s = S0.length, + slen = v * Math.ceil(s / v), S = new Uint8Array(slen); + for (var i = 0; i < slen; i++) + S[i] = S0[i % s]; + // 3. Concatenate copies of the password together to create a string P + // of length v(ceiling(p/v)) bits (the final copy of the password + // may be truncated to create P). Note that if the password is the + // empty string, then so is P. + var P0 = new Uint8Array(buffer(baseKey)), p = P0.length, + plen = v * Math.ceil(p / v), P = new Uint8Array(plen); + for (var i = 0; i < plen; i++) + P[i] = P0[i % p]; + // 4. Set I=S||P to be the concatenation of S and P. + var I = new Uint8Array(slen + plen); + arraycopy(S, 0, I, 0, slen); + arraycopy(P, 0, I, slen, plen); + // 5. Set c=ceiling(n/u). + var c = Math.ceil(n / u); + // 6. For i=1, 2, ..., c, do the following: + var A = new Uint8Array(c * u); + for (var i = 0; i < c; i++) { + // A. Set A2=H^r(D||I). (i.e., the r-th hash of D||1, + // H(H(H(... H(D||I)))) + var H = new Uint8Array(v + slen + plen); + arraycopy(D, 0, H, 0, v); + arraycopy(I, 0, H, v, slen + plen); + for (var j = 0; j < r; j++) + H = new Uint8Array(this.digest(H)); + arraycopy(H, 0, A, i * u, u); + // B. Concatenate copies of Ai to create a string B of length v + // bits (the final copy of Ai may be truncated to create B). + var B = new Uint8Array(v); + for (var j = 0; j < v; j++) + B[j] = H[j % u]; + // C. Treating I as a concatenation I_0, I_1, ..., I_(k-1) of v-bit + // blocks, where k=ceiling(s/v)+ceiling(p/v), modify I by + // setting I_j=(I_j+B+1) mod 2^v for each j. + var k = (slen + plen) / v; + for (j = 0; j < k; j++) { + var cf = 1, w; + for (var l = v - 1; l >= 0; --l) { + w = I[v * j + l] + B[l] + cf; + cf = w >>> 8; + I[v * j + l] = w & 0xff; + } + } + } + // 7. Concatenate A_1, A_2, ..., A_c together to form a pseudorandom + // bit string, A. + // 8. Use the first n bits of A as the output of this entire process. + var R = new Uint8Array(n); + arraycopy(A, 0, R, 0, n); + return R.buffer; +} // + +/** + * Algorithm name GOST R 34.11-KDF

+ * + * Derive bits for KEK deversification in 34.10-2012 algorithm + * KDF(KEK, UKM, label) = HMAC256 (KEK, 0x01|label|0x00|UKM|0x01|0x00) + * Default label = 0x26|0xBD|0xB8|0x78 + * + * @memberOf GostDigest + * @method deriveBits + * @instance + * @param {(ArrayBuffer|TypedArray)} baseKey base key for deriviation + * @param {number} length output bit-length + * @returns {ArrayBuffer} result + */ +function deriveBitsKDF(baseKey, length) // +{ + if (length % 8 > 0) + throw new DataError('Length must be multiple of 8'); + var rlen = length / 8, label, context = new Uint8Array(buffer(this.context)), + blen = this.bitLength / 8, n = Math.ceil(rlen / blen); + if (this.label) + label = new Uint8Array(buffer(this.label)); + else + label = new Uint8Array([0x26, 0xBD, 0xB8, 0x78]); + var result = new Uint8Array(rlen); + for (var i = 0; i < n; i++) { + var data = new Uint8Array(label.length + context.length + 4); + data[0] = i + 1; + data.set(label, 1); + data[label.length + 1] = 0x00; + data.set(context, label.length + 2); + data[data.length - 2] = length >>> 8; + data[data.length - 1] = length & 0xff; + result.set(new Uint8Array(signHMAC.call(this, baseKey, data), 0, + i < n - 1 ? blen : rlen - i * blen), i * blen); + } + return result.buffer; +} // + +/** + * Algorithm name GOST R 34.11-PBKDF1

+ * + * Derive bits from password + *
    + *
  • algorithm.salt - random value, salt
  • + *
  • algorithm.iterations - number of iterations
  • + *
+ * @memberOf GostDigest + * @method deriveBits + * @instance + * @param {ArrayBuffer} baseKey - password after UTF-8 decoding + * @param {number} length output bit-length + * @returns {ArrayBuffer} result + */ +function deriveBitsPBKDF1(baseKey, length) // +{ + if (length < this.bitLength / 2 || length % 8 > 0) + throw new DataError('Length must be more than ' + this.bitLength / 2 + ' bits and multiple of 8'); + var hLen = this.bitLength / 8, dkLen = length / 8, + c = this.iterations, + P = new Uint8Array(buffer(baseKey)), + S = new Uint8Array(buffer(this.salt)), + slen = S.length, plen = P.length, + T = new Uint8Array(plen + slen), + DK = new Uint8Array(dkLen); + if (dkLen > hLen) + throw new DataError('Invalid parameters: Length value'); + arraycopy(P, 0, T, 0, plen); + arraycopy(S, 0, T, plen, slen); + for (var i = 0; i < c; i++) + T = new Uint8Array(this.digest(T)); + arraycopy(T, 0, DK, 0, dkLen); + return DK.buffer; +} // + +/** + * Algorithm name GOST R 34.11-PBKDF2

+ * + * Derive bits from password + *
    + *
  • algorithm.salt - random value, salt
  • + *
  • algorithm.iterations - number of iterations
  • + *
+ * @memberOf GostDigest + * @method deriveBits + * @instance + * @param {ArrayBuffer} baseKey - password after UTF-8 decoding + * @param {number} length output bit-length + * @returns {ArrayBuffer} result + */ +function deriveBitsPBKDF2(baseKey, length) // +{ + var diversifier = this.diversifier || 1; // For PKCS12 MAC required 3*length + length = length * diversifier; + if (length < this.bitLength / 2 || length % 8 > 0) + throw new DataError('Length must be more than ' + this.bitLength / 2 + ' bits and multiple of 8'); + var hLen = this.bitLength / 8, dkLen = length / 8, + c = this.iterations, + P = new Uint8Array(buffer(baseKey)), + S = new Uint8Array(buffer(this.salt)); + var slen = S.byteLength, + data = new Uint8Array(slen + 4); + arraycopy(S, 0, data, 0, slen); + + if (dkLen > (0xffffffff - 1) * 32) + throw new DataError('Invalid parameters: Length value'); + var n = Math.ceil(dkLen / hLen), + DK = new Uint8Array(dkLen); + for (var i = 1; i <= n; i++) { + data[slen] = i >>> 24 & 0xff; + data[slen + 1] = i >>> 16 & 0xff; + data[slen + 2] = i >>> 8 & 0xff; + data[slen + 3] = i & 0xff; + + var U = new Uint8Array(signHMAC.call(this, P, data)), Z = U; + for (var j = 1; j < c; j++) { + U = new Uint8Array(signHMAC.call(this, P, U)); + for (var k = 0; k < hLen; k++) + Z[k] = U[k] ^ Z[k]; + } + var ofs = (i - 1) * hLen; + arraycopy(Z, 0, DK, ofs, Math.min(hLen, dkLen - ofs)); + } + if (diversifier > 1) { + var rLen = dkLen / diversifier, R = new Uint8Array(rLen); + arraycopy(DK, dkLen - rLen, R, 0, rLen); + return R.buffer; + } else + return DK.buffer; +} // + +/** + * Algorithm name GOST R 34.11-CPKDF

+ * + * Derive bits from password. CryptoPro algorithm + *
    + *
  • algorithm.salt - random value, salt
  • + *
  • algorithm.iterations - number of iterations
  • + *
+ * @memberOf GostDigest + * @method deriveBits + * @instance + * @param {ArrayBuffer} baseKey - password after UTF-8 decoding + * @param {number} length output bit-length + * @returns {ArrayBuffer} result + */ +function deriveBitsCP(baseKey, length) { + if (length > this.bitLength || length % 8 > 0) + throw new DataError('Length can\'t be more than ' + this.bitLength + ' bits and multiple of 8'); + // GOST R 34.11-94 - B=32b, L=32b + // GOST R 34.11-256 - B=64b, L=32b + // GOST R 34.11-512 - B=64b, L=64b + var b = (this.digest === digest94) ? 32 : 64, + l = this.bitLength / 8, + p = baseKey && baseKey.byteLength > 0 ? new Uint8Array(buffer(baseKey)) : false, + plen = p ? p.length : 0, + iterations = this.iterations, + salt = new Uint8Array(buffer(this.salt)), + slen = salt.length, + d = new Uint8Array(slen + plen); + arraycopy(salt, 0, d, 0, slen); + if (p) + arraycopy(p, 0, d, slen, plen); + + var h = new Uint8Array(this.digest(d)), + k = new Uint8Array(b), + s0 = new Uint8Array(b), + s1 = new Uint8Array(b); + var c = 'DENEFH028.760246785.IUEFHWUIO.EF'; + for (var i = 0; i < c.length; i++) + k[i] = c.charCodeAt(i); + + d = new Uint8Array(2 * (b + l)); + for (var j = 0; j < iterations; j++) { + for (var i = 0; i < b; i++) { + s0[i] = k[i] ^ 0x36; + s1[i] = k[i] ^ 0x5C; + k[i] = 0; + } + arraycopy(s0, 0, d, 0, b); + arraycopy(h, 0, d, b, l); + arraycopy(s1, 0, d, b + l, b); + arraycopy(h, 0, d, b + l + b, l); + arraycopy(new Uint8Array(this.digest(d)), 0, k, 0, l); + } + for (var i = 0; i < l; i++) { + s0[i] = k[i] ^ 0x36; + s1[i] = k[i] ^ 0x5C; + k[i] = 0; + } + d = new Uint8Array(2 * l + slen + plen); + arraycopy(s0, 0, d, 0, l); + arraycopy(salt, 0, d, l, slen); + arraycopy(s1, 0, d, l + slen, l); + if (p) + arraycopy(p, 0, d, l + slen + l, plen); + h = this.digest(this.digest(d)); + if (length === this.bitLength) + return h; + else { + var rlen = length / 8, r = new Uint8Array(rlen); + arraycopy(h, 0, r, 0, rlen); + return r.buffer; + } +} + +/** + * Algorithm name GOST R 34.11-KDF or GOST R 34.11-PBKDF2 or other

+ * + * Derive key from derive bits subset + * + * @memberOf GostDigest + * @method deriveKey + * @instance + * @param {ArrayBuffer} baseKey + * @returns {ArrayBuffer} + */ +function deriveKey(baseKey) // +{ + return this.deriveBits(baseKey, this.keySize * 8); +} // + +/** + * GOST R 34.11 Algorithm

+ * + * References: {@link http://tools.ietf.org/html/rfc6986} and {@link http://tools.ietf.org/html/rfc5831}

+ * + * Normalized algorithm identifier common parameters: + * + *
    + *
  • name Algorithm name 'GOST R 34.11'
  • + *
  • version Algorithm version + *
      + *
    • 1994 old-style 256 bits digest based on GOST 28147-89
    • + *
    • 2012 256 ro 512 bits digest algorithm "Streebog" GOST R 34.11-2012 (default)
    • + *
    + *
  • + *
  • length Digest length + *
      + *
    • 256 256 bits digest
    • + *
    • 512 512 bits digest, valid only for algorithm "Streebog"
    • + *
    + *
  • + *
  • mode Algorithm mode + *
      + *
    • HASH simple digest mode (default)
    • + *
    • HMAC HMAC algorithm based on GOST R 34.11
    • + *
    • KDF Derive bits for KEK deversification
    • + *
    • PBKDF2 Password based key dirivation algorithms PBKDF2 (based on HMAC)
    • + *
    • PFXKDF Password based PFX key dirivation algorithms
    • + *
    • CPKDF CpyptoPro Password based key dirivation algorithms
    • + *
    + *
  • + *
  • sBox Paramset sBox for GOST 28147-89. Used only if version = 1994
  • + *
+ * + * Supported algorithms, modes and parameters: + * + *
    + *
  • Digest HASH mode (default)
  • + *
  • Sign/Verify HMAC modes parameters depends on version and length + *
      + *
    • version: 1994 HMAC parameters (B = 32, L = 32)
    • + *
    • version: 2012, length: 256 HMAC parameters (B = 64, L = 32)
    • + *
    • version: 2012, length: 512 HMAC parameters (B = 64, L = 64)
    • + *
    + *
  • + *
  • DeriveBits/DeriveKey KDF mode + *
      + *
    • context {@link CryptoOperationData} Context of the key derivation
    • + *
    • label {@link CryptoOperationData} Label that identifies the purpose for the derived keying material
    • + *
    + *
  • + *
  • DeriveBits/DeriveKey PBKDF2 mode + *
      + *
    • salt {@link CryptoOperationData} Random salt as input for HMAC algorithm
    • + *
    • iterations Iteration count. GOST recomended value 1000 (default) or 2000
    • + *
    • diversifier Deversifier, ID=1 - key material for performing encryption or decryption, ID=3 - integrity key for MACing
    • + *
    + *
  • + *
  • DeriveBits/DeriveKey PFXKDF mode + *
      + *
    • salt {@link CryptoOperationData} Random salt as input for HMAC algorithm
    • + *
    • iterations Iteration count. GOST recomended value 1000 (default) or 2000
    • + *
    • diversifier Deversifier, ID=1 - key material for performing encryption or decryption, + * ID=2 - IV (Initial Value) for encryption or decryption, ID=3 - integrity key for MACing
    • + *
    + *
  • + *
  • DeriveBits/DeriveKey CPKDF mode + *
      + *
    • salt {@link CryptoOperationData} Random salt as input for HMAC algorithm
    • + *
    • iterations Iteration count. GOST recomended value 1000 (default) or 2000
    • + *
    + *
  • + *
+ * + * @class GostDigest + * @param {AlgorithmIdentifier} algorithm WebCryptoAPI algorithm identifier + */ +function GostDigest(algorithm) // +{ + + algorithm = algorithm || {}; + + this.name = (algorithm.name || 'GOST R 34.10') + '-' + ((algorithm.version || 2012) % 100) + + ((algorithm.version || 2012) > 1 ? '-' + (algorithm.length || 256) : '') + + (((algorithm.mode || 'HASH') !== 'HASH') ? '-' + algorithm.mode : '') + + (algorithm.procreator ? '/' + algorithm.procreator : '') + + (typeof algorithm.sBox === 'string' ? '/' + algorithm.sBox : ''); + + // Algorithm procreator + this.procreator = algorithm.procreator; + + // Bit length + this.bitLength = algorithm.length || 256; + + switch (algorithm.version || 2012) { + case 1: // SHA-1 + this.digest = digestSHA1; + this.bitLength = 160; + break; + case 1994: + this.digest = digest94; + // Define chiper algorithm + this.sBox = (algorithm.sBox || (algorithm.procreator === 'SC' ? 'D-SC' : 'D-A')).toUpperCase(); + + if (!GostCipher) + GostCipher = root.GostCipher; + if (!GostCipher) + throw new NotSupportedError('Object GostCipher not found'); + + this.cipher = new GostCipher({ + name: 'GOST 28147', + block: 'ECB', + sBox: this.sBox, + procreator: this.procreator + }); + + break; + case 2012: + this.digest = digest2012; + break; + default: + throw new NotSupportedError('Algorithm version ' + algorithm.version + ' not supported'); + } + + // Key size + this.keySize = algorithm.keySize || (algorithm.version <= 2 ? this.bitLength / 8 : 32); + + switch (algorithm.mode || 'HASH') { + case 'HASH': + break; + case 'HMAC': + this.sign = signHMAC; + this.verify = verifyHMAC; + this.generateKey = generateKey; + break; + case 'KDF': + this.deriveKey = deriveKey; + this.deriveBits = deriveBitsKDF; + this.label = algorithm.label; + this.context = algorithm.context; + break; + case 'PBKDF2': + this.deriveKey = deriveKey; + this.deriveBits = deriveBitsPBKDF2; + this.generateKey = generateKey; + this.salt = algorithm.salt; + this.iterations = algorithm.iterations || 2000; + this.diversifier = algorithm.diversifier || 1; + break; + case 'PFXKDF': + this.deriveKey = deriveKey; + this.deriveBits = deriveBitsPFXKDF; + this.generateKey = generateKey; + this.salt = algorithm.salt; + this.iterations = algorithm.iterations || 2000; + this.diversifier = algorithm.diversifier || 1; + break; + case 'CPKDF': + this.deriveKey = deriveKey; + this.deriveBits = deriveBitsCP; + this.generateKey = generateKey; + this.salt = algorithm.salt; + this.iterations = algorithm.iterations || 2000; + break; + default: + throw new NotSupportedError('Algorithm mode ' + algorithm.mode + ' not supported'); + } +} // + +export default GostDigest; \ No newline at end of file diff --git a/src/core/vendor/streebog/gostEngine.mjs b/src/core/vendor/streebog/gostEngine.mjs new file mode 100755 index 00000000..be8fd4e8 --- /dev/null +++ b/src/core/vendor/streebog/gostEngine.mjs @@ -0,0 +1,451 @@ +/** + * @file GOST 34.10-2012 signature function with 1024/512 bits digest + * @version 1.76 + * @copyright 2014-2016, Rudolf Nickolaev. All rights reserved. + */ + +/* + * 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'; +import GostCipher from './gostCipher'; +import GostDigest from './gostDigest'; +import GostSign from './gostSign'; + +/* + * Engine definition base on normalized algorithm identifier + * + */ // + +var root = {}; + +// Define engine +function defineEngine(method, algorithm) { + if (!algorithm) + throw new (root.SyntaxError || Error)('Algorithm not defined'); + + if (!algorithm.name) + throw new (root.SyntaxError || Error)('Algorithm name not defined'); + + var name = algorithm.name, mode = algorithm.mode; + if ((name === 'GOST 28147' || name === 'GOST R 34.12' || name === 'RC2') && (method === 'generateKey' || + (mode === 'MAC' && (method === 'sign' || method === 'verify')) || + ((mode === 'KW' || mode === 'MASK') && (method === 'wrapKey' || method === 'unwrapKey')) || + ((!mode || mode === 'ES') && (method === 'encrypt' || method === 'decrypt')))) { + return 'GostCipher'; + + } else if ((name === 'GOST R 34.11' || name === 'SHA') && (method === 'digest' || + (mode === 'HMAC' && (method === 'sign' || method === 'verify' || method === 'generateKey')) || + ((mode === 'KDF' || mode === 'PBKDF2' || mode === 'PFXKDF' || mode === 'CPKDF') && + (method === 'deriveKey' || method === 'deriveBits' || method === 'generateKey')))) { + return 'GostDigest'; + + } else if (name === 'GOST R 34.10' && (method === 'generateKey' || + ((!mode || mode === 'SIGN') && (method === 'sign' || method === 'verify')) || + (mode === 'MASK' && (method === 'wrapKey' || method === 'unwrapKey')) || + (mode === 'DH' && (method === 'deriveKey' || method === 'deriveBits')))) { + return 'GostSign'; + } else + throw new (root.NotSupportedError || Error)('Algorithm ' + name + '-' + mode + ' is not valid for ' + method); +} // + +/** + * Object implements dedicated Web Workers and provide a simple way to create + * and run GOST cryptographic algorithms in background thread. + * + * Object provide interface to GOST low-level cryptogric classes: + *
    + *
  • GostCipher - implementation of GOST 28147, GOST R 34.12, GOST R 34.13 Encryption algorithms. Reference {@link http://tools.ietf.org/html/rfc5830}
  • + *
  • GostDigest - implementation of GOST R 34.11 Hash Function algorithms. References {@link http://tools.ietf.org/html/rfc5831} and {@link http://tools.ietf.org/html/rfc6986}
  • + *
  • GostSign - implementation of GOST R 34.10 Digital Signature algorithms. References {@link http://tools.ietf.org/html/rfc5832} and {@link http://tools.ietf.org/html/rfc7091}
  • + *
+ * @namespace gostEngine + */ +var gostEngine = { + /** + * gostEngine.execute(algorithm, method, args) Entry point to execution + * all low-level GOST cryptographic methods + * + *
    + *
  • Determine the appropriate engine for a given execution method
  • + *
  • Create cipher object for determineted engine
  • + *
  • Execute method of cipher with given args
  • + *
+ * + * @memberOf gostEngine + * @param {AlgorithmIndentifier} algorithm Algorithm identifier + * @param {string} method Crypto method for execution + * @param {Array} args Method arguments (keys, data, additional parameters) + * @returns {(CryptoOperationData|Key|KeyPair|boolean)} Result of method execution + */ + execute: function (algorithm, method, args) // + { + // Define engine for GOST algorithms + var engine = defineEngine(method, algorithm); + // Create cipher + var cipher = this['get' + engine](algorithm); + // Execute method + return cipher[method].apply(cipher, args); + }, // + /** + * gostEngine.getGostCipher(algorithm) returns GOST 28147 / GOST R 34.12 cipher instance

+ * + * GOST 28147-89 / GOST R 34.12-15 Encryption Algorithm

+ * When keys and initialization vectors are converted to/from byte arrays, + * little-endian byte order is assumed.

+ * + * Normalized algorithm identifier common parameters: + * + *
    + *
  • name Algorithm name 'GOST 28147' or 'GOST R 34.12'
  • + *
  • version Algorithm version, number + *
      + *
    • 1989 Current version of standard
    • + *
    • 2015 New draft version of standard
    • + *
    + *
  • + *
  • length Block length + *
      + *
    • 64 64 bits length (default)
    • + *
    • 128 128 bits length (only for version 2015)
    • + *
    + *
  • + *
  • mode Algorithm mode, string + *
      + *
    • ES Encryption mode (default)
    • + *
    • MAC "imitovstavka" (MAC) mode
    • + *
    • KW Key wrapping mode
    • + *
    • MASK Key mask mode
    • + *
    + *
  • + *
  • sBox Paramset sBox for GOST 28147-89, string. Used only if version = 1989
  • + *
+ * + * Supported algorithms, modes and parameters: + * + *
    + *
  • Encript/Decrypt mode (ES) + *
      + *
    • block Block mode, string. Default ECB
    • + *
    • keyMeshing Key meshing mode, string. Default NO
    • + *
    • padding Padding mode, string. Default NO for CFB and CTR modes, or ZERO for others
    • + *
    • iv {@link CryptoOperationData} Initial vector with length of block. Default - zero block
    • + *
    + *
  • + *
  • Sign/Verify mode (MAC) + *
      + *
    • macLength Length of mac in bits (default - 32 bits)
    • + *
    • iv {@link CryptoOperationData} Initial vector with length of block. Default - zero block
    • + *
    + *
  • + *
  • Wrap/Unwrap key mode (KW) + *
      + *
    • keyWrapping Mode of keywrapping, string. Default NO - standard GOST key wrapping
    • + *
    • ukm {@link CryptoOperationData} User key material. Default - random generated value
    • + *
    + *
  • + *
  • Wrap/Unwrap key mode (MASK)
  • + *
+ * + * Supported paramters values: + * + *
    + *
  • Block modes (parameter 'block') + *
      + *
    • ECB "prostaya zamena" (ECB) mode (default)
    • + *
    • CFB "gammirovanie s obratnoj svyaziyu" (64-bit CFB) mode
    • + *
    • CTR "gammirovanie" (counter) mode
    • + *
    • CBC Cipher-Block-Chaining (CBC) mode
    • + *
    + *
  • + *
  • Key meshing modes (parameter 'keyMeshing') + *
      + *
    • NO No key wrapping (default)
    • + *
    • CP CryptoPor Key key meshing
    • + *
    + *
  • + *
  • Padding modes (parameter 'padding') + *
      + *
    • NO No padding only for CFB and CTR modes
    • + *
    • PKCS5 PKCS#5 padding mode
    • + *
    • ZERO Zero bits padding mode
    • + *
    • RANDOM Random bits padding mode
    • + *
    + *
  • + *
  • Wrapping key modes (parameter 'keyWrapping') + *
      + *
    • NO Ref. rfc4357 6.1 GOST 28147-89 Key wrapping
    • + *
    • CP CryptoPro Key wrapping mode
    • + *
    • SC SignalCom Key wrapping mode
    • + *
    + *
  • + *
+ * + * @memberOf gostEngine + * @param {AlgorithmIndentifier} algorithm Algorithm identifier + * @returns {GostCipher} Instance of GostCipher + */ + getGostCipher: function (algorithm) // + { + return new (GostCipher || (GostCipher = root.GostCipher))(algorithm); + }, // + /** + * gostEngine.getGostDigest(algorithm) returns GOST R 34.11 cipher instance

+ * + * Normalized algorithm identifier common parameters: + * + *
    + *
  • name Algorithm name 'GOST R 34.11'
  • + *
  • version Algorithm version + *
      + *
    • 1994 old-style 256 bits digest based on GOST 28147-89
    • + *
    • 2012 256 ro 512 bits digest algorithm "Streebog" GOST R 34.11-2012 (default)
    • + *
    + *
  • + *
  • length Digest length + *
      + *
    • 256 256 bits digest
    • + *
    • 512 512 bits digest, valid only for algorithm "Streebog"
    • + *
    + *
  • + *
  • mode Algorithm mode + *
      + *
    • HASH simple digest mode (default)
    • + *
    • HMAC HMAC algorithm based on GOST R 34.11
    • + *
    • KDF Derive bits for KEK deversification
    • + *
    • PBKDF2 Password based key dirivation algorithms PBKDF2 (based on HMAC)
    • + *
    • PFXKDF PFX key dirivation algorithms PFXKDF
    • + *
    • CPKDF CryptoPro Password based key dirivation algorithms
    • + *
    + *
  • + *
  • sBox Paramset sBox for GOST 28147-89. Used only if version = 1994
  • + *
+ * + * Supported algorithms, modes and parameters: + * + *
    + *
  • Digest HASH mode (default)
  • + *
  • Sign/Verify HMAC modes parameters depends on version and length + *
      + *
    • version: 1994 HMAC parameters (B = 32, L = 32)
    • + *
    • version: 2012, length: 256 HMAC parameters (B = 64, L = 32)
    • + *
    • version: 2012, length: 512 HMAC parameters (B = 64, L = 64)
    • + *
    + *
  • + *
  • DeriveBits/DeriveKey KDF mode + *
      + *
    • context {@link CryptoOperationData} Context of the key derivation
    • + *
    • label {@link CryptoOperationData} Label that identifies the purpose for the derived keying material
    • + *
    + *
  • + *
  • DeriveBits/DeriveKey PBKDF2 mode + *
      + *
    • salt {@link CryptoOperationData} Random salt as input for HMAC algorithm
    • + *
    • iterations Iteration count. GOST recomended value 1000 (default) or 2000
    • + *
    + *
  • + *
  • DeriveBits/DeriveKey PFXKDF mode + *
      + *
    • salt {@link CryptoOperationData} Random salt as input for HMAC algorithm
    • + *
    • iterations Iteration count. GOST recomended value 1000 (default) or 2000
    • + *
    • diversifier Deversifier, ID=1 - key material for performing encryption or decryption, + * ID=2 - IV (Initial Value) for encryption or decryption, ID=3 - integrity key for MACing
    • + *
    + *
  • + *
  • DeriveBits/DeriveKey CPKDF mode + *
      + *
    • salt {@link CryptoOperationData} Random salt as input for HMAC algorithm
    • + *
    • iterations Iteration count. GOST recomended value 1000 (default) or 2000
    • + *
    + *
  • + *
+ * + * @memberOf gostEngine + * @param {AlgorithmIndentifier} algorithm Algorithm identifier + * @returns {GostDigest} Instance of GostDigest + */ + getGostDigest: function (algorithm) // + { + return new (GostDigest || (GostDigest = root.GostDigest))(algorithm); + }, // + /** + * gostEngine.getGostSign(algorithm) returns GOST R 34.10 cipher instance

+ * + * Normalized algorithm identifier common parameters: + * + *
    + *
  • name Algorithm name 'GOST R 34.10'
  • + *
  • version Algorithm version + *
      + *
    • 1994 - Old-style GOST R 34.10-94 ExpMod algorithm with GOST R 34.11-94 hash
    • + *
    • 2001 - GOST R 34.10-2001 Eliptic curve algorithm with old GOST R 34.11-94 hash
    • + *
    • 2012 - GOST R 34.10-2012 Eliptic curve algorithm with GOST R 34.11-12 hash, default mode
    • + *
    + *
  • + *
  • length Length of hash and signature. Key length == hash length for EC algorithms and 2 * hash length for ExpMod algorithm + *
      + *
    • GOST R 34.10-256 - 256 bits digest, default mode
    • + *
    • GOST R 34.10-512 - 512 bits digest only for GOST R 34.11-2012 hash
    • + *
    + *
  • + *
  • mode Algorithm mode + *
      + *
    • SIGN Digital signature mode (default)
    • + *
    • DH Diffie-Hellman key generation and key agreement mode
    • + *
    • MASK Key mask mode
    • + *
    + *
  • + *
  • sBox Paramset sBox for GOST 34.11-94. Used only if version = 1994 or 2001
  • + *
+ * + * Supported algorithms, modes and parameters: + * + *
    + *
  • Sign/Verify mode (SIGN)
  • + *
  • Wrap/Unwrap mode (MASK)
  • + *
  • DeriveKey/DeriveBits mode (DH) + *
      + *
    • {@link CryptoOperationData} ukm User key material. Default - random generated value
    • + *
    • {@link CryptoOperationData} public The peer's EC public key data
    • + *
    + *
  • + *
  • GenerateKey mode (SIGN and DH and MASK) version = 1994 + *
      + *
    • namedParam Paramset for key generation algorithm. If specified no additianal parameters required
    • + *
    + * Additional parameters, if namedParam not specified + *
      + *
    • modulusLength Bit length of p (512 or 1024 bits). Default = 1024
    • + *
    • p {@link CryptoOperationData} Modulus, prime number, 2^(t-1) + *
    • q {@link CryptoOperationData} Order of cyclic group, prime number, 2^254 + *
    • a {@link CryptoOperationData} Generator, integer, 1 + *
    + *
  • + *
  • GenerateKey mode (SIGN and DH and MASK) version = 2001 or 2012 + *
      + *
    • namedCurve Paramset for key generation algorithm. If specified no additianal parameters required
    • + *
    + * Additional EC parameters, if namedCurve not specified + *
      + *
    • p {@link CryptoOperationData} Prime number - elliptic curve modulus
    • + *
    • a {@link CryptoOperationData} Coefficients a of the elliptic curve E
    • + *
    • b {@link CryptoOperationData} Coefficients b of the elliptic curve E
    • + *
    • q {@link CryptoOperationData} Prime number - order of cyclic group
    • + *
    • x {@link CryptoOperationData} Base point p x-coordinate
    • + *
    • y {@link CryptoOperationData} Base point p y-coordinate
    • + *
    + *
  • + *
+ * + * @memberOf gostEngine + * @param {AlgorithmIndentifier} algorithm Algorithm identifier + * @returns {GostSign} Instance of GostSign + */ + getGostSign: function (algorithm) // + { + return new (GostSign || (GostSign = root.GostSign))(algorithm); + } // +}; + +/* + * Worker method execution + * + */ // + +// Worker for gostCripto method execution +if (root.importScripts) { + + /** + * Method called when {@link SubtleCrypto} calls its own postMessage() + * method with data parameter: algorithm, method and arg.
+ * Call method execute and postMessage() results to onmessage event handler + * in the main process.
+ * If error occured onerror event handler executed in main process. + * + * @memberOf gostEngine + * @name onmessage + * @param {MessageEvent} event Message event with data {algorithm, method, args} + */ + root.onmessage = function (event) { + try { + postMessage({ + id: event.data.id, + result: gostEngine.execute(event.data.algorithm, + event.data.method, event.data.args)}); + } catch (e) { + postMessage({ + id: event.data.id, + error: e.message + }); + } + }; +} else { + + // Load dependens + var baseUrl = '', nameSuffix = ''; + // Try to define from DOM model + if (typeof document !== 'undefined') { + (function () { + var regs = /^(.*)gostCrypto(.*)\.js$/i; + var list = document.querySelectorAll('script'); + for (var i = 0, n = list.length; i < n; i++) { + var value = list[i].getAttribute('src'); + var test = regs.exec(value); + if (test) { + baseUrl = test[1]; + nameSuffix = test[2]; + } + } + })(); + } + + // Local importScripts procedure for include dependens + var importScripts = function () { + for (var i = 0, n = arguments.length; i < n; i++) { + var name = arguments[i].split('.'), + src = baseUrl + name[0] + nameSuffix + '.' + name[1]; + var el = document.querySelector('script[src="' + src + '"]'); + if (!el) { + el = document.createElement('script'); + el.setAttribute('src', src); + document.head.appendChild(el); + } + } + }; + + // Import engines + if (!GostRandom) + importScripts('gostRandom.js'); + if (!GostCipher) + importScripts('gostCipher.js'); + if (!GostDigest) + importScripts('gostDigest.js'); + if (!GostSign) + importScripts('gostSign.js'); +} //
+ +export default gostEngine; + diff --git a/src/core/vendor/streebog/gostRandom.js b/src/core/vendor/streebog/gostRandom.js deleted file mode 100644 index 93e0c845..00000000 --- a/src/core/vendor/streebog/gostRandom.js +++ /dev/null @@ -1,139 +0,0 @@ -/** - * Implementation Web Crypto random generatore for GOST algorithms - * 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. - * - */ - -(function (root, factory) { - - /* - * Module imports and exports - * - */ // - module.exports = factory(); - // - -}(this, function () { - - /** - * The gostCrypto provide general purpose cryptographic functionality for - * GOST standards including a cryptographically strong pseudo-random number - * generator seeded with truly random values. - * - * @Class GostRandom - * - */ // - - var root = this; - var rootCrypto = root.crypto || root.msCrypto; - - var TypeMismatchError = root.TypeMismatchError || Error; - var QuotaExceededError = root.QuotaExceededError || Error; - - // Initialize mouse and time counters for random generator - var randomRing = { - seed: new Uint8Array(1024), - getIndex: 0, - setIndex: 0, - set: function (x) { - if (this.setIndex >= 1024) - this.setIndex = 0; - this.seed[this.setIndex++] = x; - }, - get: function () { - if (this.getIndex >= 1024) - this.getIndex = 0; - return this.seed[this.getIndex++]; - } - }; - - if (typeof document !== 'undefiend') { - try { - // Mouse move event to fill random array - document.addEventListener('mousemove', function (e) { - randomRing.set((new Date().getTime() & 255) ^ - ((e.clientX || e.pageX) & 255) ^ - ((e.clientY || e.pageY) & 255)); - }, false); - } catch (e) { - } - - try { - // Keypress event to fill random array - document.addEventListener('keydown', function (e) { - randomRing.set((new Date().getTime() & 255) ^ - (e.keyCode & 255)); - }, false); - } catch (e) { - } - } // - - function GostRandom() { - } - - /** - * The getRandomValues method generates cryptographically random values.

- * - * Random generator based on JavaScript Web Crypto random genereator - * (if it is possible) or Math.random mixed with time and parameters of - * mouse and keyboard events - * - * @memberOf GostRandom - * @param {(ArrayBuffer|ArrayBufferView)} array Destination buffer for random data - */ - GostRandom.prototype.getRandomValues = function (array) // - { - - if (!array.byteLength) - throw new TypeMismatchError('Array is not of an integer type (Int8Array, Uint8Array, Int16Array, Uint16Array, Int32Array, or Uint32Array)'); - - if (array.byteLength > 65536) - throw new QuotaExceededError('Byte length of array can\'t be greate then 65536'); - - var u8 = new Uint8Array(array.buffer, array.byteOffset, array.byteLength); - if (rootCrypto && rootCrypto.getRandomValues) { - // Native window cryptographic interface - rootCrypto.getRandomValues(u8); - } else { - // Standard Javascript method - for (var i = 0, n = u8.length; i < n; i++) - u8[i] = Math.floor(256 * Math.random()) & 255; - } - - // Mix bio randomizator - for (var i = 0, n = u8.length; i < n; i++) - u8[i] = u8[i] ^ randomRing.get(); - return array; - }; // - - return GostRandom; - -})); diff --git a/src/core/vendor/streebog/gostRandom.mjs b/src/core/vendor/streebog/gostRandom.mjs new file mode 100644 index 00000000..03ce8937 --- /dev/null +++ b/src/core/vendor/streebog/gostRandom.mjs @@ -0,0 +1,128 @@ +/** + * Implementation Web Crypto random generatore for GOST algorithms + * 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 crypto from 'crypto'; + + +/** + * The gostCrypto provide general purpose cryptographic functionality for + * GOST standards including a cryptographically strong pseudo-random number + * generator seeded with truly random values. + * + * @Class GostRandom + * + */ // + +var root = {}; +var rootCrypto = crypto; + +var TypeMismatchError = Error; +var QuotaExceededError = Error; + +// Initialize mouse and time counters for random generator +var randomRing = { + seed: new Uint8Array(1024), + getIndex: 0, + setIndex: 0, + set: function (x) { + if (this.setIndex >= 1024) + this.setIndex = 0; + this.seed[this.setIndex++] = x; + }, + get: function () { + if (this.getIndex >= 1024) + this.getIndex = 0; + return this.seed[this.getIndex++]; + } +}; + +if (typeof document !== 'undefined') { + try { + // Mouse move event to fill random array + document.addEventListener('mousemove', function (e) { + randomRing.set((new Date().getTime() & 255) ^ + ((e.clientX || e.pageX) & 255) ^ + ((e.clientY || e.pageY) & 255)); + }, false); + } catch (e) { + } + + try { + // Keypress event to fill random array + document.addEventListener('keydown', function (e) { + randomRing.set((new Date().getTime() & 255) ^ + (e.keyCode & 255)); + }, false); + } catch (e) { + } +} // + +function GostRandom() { +} + +/** + * The getRandomValues method generates cryptographically random values.

+ * + * Random generator based on JavaScript Web Crypto random genereator + * (if it is possible) or Math.random mixed with time and parameters of + * mouse and keyboard events + * + * @memberOf GostRandom + * @param {(ArrayBuffer|ArrayBufferView)} array Destination buffer for random data + */ +GostRandom.prototype.getRandomValues = function (array) // +{ + + if (!array.byteLength) + throw new TypeMismatchError('Array is not of an integer type (Int8Array, Uint8Array, Int16Array, Uint16Array, Int32Array, or Uint32Array)'); + + if (array.byteLength > 65536) + throw new QuotaExceededError('Byte length of array can\'t be greate then 65536'); + + var u8 = new Uint8Array(array.buffer, array.byteOffset, array.byteLength); + if (rootCrypto && rootCrypto.getRandomValues) { + // Native window cryptographic interface + rootCrypto.getRandomValues(u8); + } else { + // Standard Javascript method + for (var i = 0, n = u8.length; i < n; i++) + u8[i] = Math.floor(256 * Math.random()) & 255; + } + + // Mix bio randomizator + for (var i = 0, n = u8.length; i < n; i++) + u8[i] = u8[i] ^ randomRing.get(); + return array; +}; // + +export default GostRandom; diff --git a/src/core/vendor/streebog/gostSign.mjs b/src/core/vendor/streebog/gostSign.mjs new file mode 100755 index 00000000..31c6b572 --- /dev/null +++ b/src/core/vendor/streebog/gostSign.mjs @@ -0,0 +1,2023 @@ +/** + * @file GOST 34.10-2012 signature function with 1024/512 bits digest + * @version 1.76 + * @copyright 2014-2016, Rudolf Nickolaev. All rights reserved. + */ + +/* + * 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. + * + * Used library JSBN http://www-cs-students.stanford.edu/~tjw/jsbn/ + * Copyright (c) 2003-2005 Tom Wu (tjw@cs.Stanford.EDU) + * + * 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'; + import GostDigest from './gostDigest'; + + import crypto from 'crypto'; + + /* + * Predefined curves and params collection + * + * http://tools.ietf.org/html/rfc5832 + * http://tools.ietf.org/html/rfc7091 + * http://tools.ietf.org/html/rfc4357 + * + */ // + +var root = {}; +var rootCrypto = crypto; +var CryptoOperationData = ArrayBuffer; + +var OperationError = Error, + DataError = Error, + NotSupportedError = Error; + +// Predefined named curve collection +var ECGostParams = { + 'S-256-TEST': { + a: 7, + b: '0x5FBFF498AA938CE739B8E022FBAFEF40563F6E6A3472FC2A514C0CE9DAE23B7E', + p: '0x8000000000000000000000000000000000000000000000000000000000000431', + q: '0x8000000000000000000000000000000150FE8A1892976154C59CFC193ACCF5B3', + x: 2, + y: '0x8E2A8A0E65147D4BD6316030E16D19C85C97F0A9CA267122B96ABBCEA7E8FC8' + }, + 'S-256-A': { + a: '0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD94', + b: 166, + p: '0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD97', + q: '0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6C611070995AD10045841B09B761B893', + x: 1, + y: '0x8D91E471E0989CDA27DF505A453F2B7635294F2DDF23E3B122ACC99C9E9F1E14' + }, + 'S-256-B': { + a: '0x8000000000000000000000000000000000000000000000000000000000000C96', + b: '0x3E1AF419A269A5F866A7D3C25C3DF80AE979259373FF2B182F49D4CE7E1BBC8B', + p: '0x8000000000000000000000000000000000000000000000000000000000000C99', + q: '0x800000000000000000000000000000015F700CFFF1A624E5E497161BCC8A198F', + x: 1, + y: '0x3FA8124359F96680B83D1C3EB2C070E5C545C9858D03ECFB744BF8D717717EFC' + }, + 'S-256-C': { + a: '0x9B9F605F5A858107AB1EC85E6B41C8AACF846E86789051D37998F7B9022D7598', + b: 32858, + p: '0x9B9F605F5A858107AB1EC85E6B41C8AACF846E86789051D37998F7B9022D759B', + q: '0x9B9F605F5A858107AB1EC85E6B41C8AA582CA3511EDDFB74F02F3A6598980BB9', + x: 0, + y: '0x41ECE55743711A8C3CBF3783CD08C0EE4D4DC440D4641A8F366E550DFDB3BB67' + }, + 'P-256': { + p: '0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF', + a: '0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC', + b: '0x5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B', + x: '0x6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296', + y: '0x4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5', + q: '0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551' + }, + 'T-512-TEST': { + a: 7, + b: '0x1CFF0806A31116DA29D8CFA54E57EB748BC5F377E49400FDD788B649ECA1AC4361834013B2AD7322480A89CA58E0CF74BC9E540C2ADD6897FAD0A3084F302ADC', + p: '0x4531ACD1FE0023C7550D267B6B2FEE80922B14B2FFB90F04D4EB7C09B5D2D15DF1D852741AF4704A0458047E80E4546D35B8336FAC224DD81664BBF528BE6373', + q: '0x4531ACD1FE0023C7550D267B6B2FEE80922B14B2FFB90F04D4EB7C09B5D2D15DA82F2D7ECB1DBAC719905C5EECC423F1D86E25EDBE23C595D644AAF187E6E6DF', + x: '0x24D19CC64572EE30F396BF6EBBFD7A6C5213B3B3D7057CC825F91093A68CD762FD60611262CD838DC6B60AA7EEE804E28BC849977FAC33B4B530F1B120248A9A', + y: '0x2BB312A43BD2CE6E0D020613C857ACDDCFBF061E91E5F2C3F32447C259F39B2C83AB156D77F1496BF7EB3351E1EE4E43DC1A18B91B24640B6DBB92CB1ADD371E' + }, + 'T-512-A': { + p: '0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC7', + a: '0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC4', + b: '0xE8C2505DEDFC86DDC1BD0B2B6667F1DA34B82574761CB0E879BD081CFD0B6265EE3CB090F30D27614CB4574010DA90DD862EF9D4EBEE4761503190785A71C760', + q: '0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF27E69532F48D89116FF22B8D4E0560609B4B38ABFAD2B85DCACDB1411F10B275', + x: 3, + y: '0x7503CFE87A836AE3A61B8816E25450E6CE5E1C93ACF1ABC1778064FDCBEFA921DF1626BE4FD036E93D75E6A50E3A41E98028FE5FC235F5B889A589CB5215F2A4' + }, + 'T-512-B': { + p: '0x8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006F', + a: '0x8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006C', + b: '0x687D1B459DC841457E3E06CF6F5E2517B97C7D614AF138BCBF85DC806C4B289F3E965D2DB1416D217F8B276FAD1AB69C50F78BEE1FA3106EFB8CCBC7C5140116', + q: '0x800000000000000000000000000000000000000000000000000000000000000149A1EC142565A545ACFDB77BD9D40CFA8B996712101BEA0EC6346C54374F25BD', + x: 2, + y: '0x1A8F7EDA389B094C2C071E3647A8940F3C123B697578C213BE6DD9E6C8EC7335DCB228FD1EDF4A39152CBCAAF8C0398828041055F94CEEEC7E21340780FE41BD' + } +}; +ECGostParams['X-256-A'] = ECGostParams['S-256-A']; +ECGostParams['X-256-B'] = ECGostParams['S-256-C']; +ECGostParams['T-256-TEST'] = ECGostParams['S-256-TEST']; +ECGostParams['T-256-A'] = ECGostParams['S-256-A']; +ECGostParams['T-256-B'] = ECGostParams['S-256-B']; +ECGostParams['T-256-C'] = ECGostParams['S-256-C']; + + +var GostParams = { + 'S-TEST': { + modulusLength: 512, // bit length of p (512 or 1024 bits) + p: '0xEE8172AE8996608FB69359B89EB82A69854510E2977A4D63BC97322CE5DC3386EA0A12B343E9190F23177539845839786BB0C345D165976EF2195EC9B1C379E3', + q: '0x98915E7EC8265EDFCDA31E88F24809DDB064BDC7285DD50D7289F0AC6F49DD2D', + a: '0x9e96031500c8774a869582d4afde2127afad2538b4b6270a6f7c8837b50d50f206755984a49e509304d648be2ab5aab18ebe2cd46ac3d8495b142aa6ce23e21c' + }, + 'S-A': { + modulusLength: 1024, + p: '0xB4E25EFB018E3C8B87505E2A67553C5EDC56C2914B7E4F89D23F03F03377E70A2903489DD60E78418D3D851EDB5317C4871E40B04228C3B7902963C4B7D85D52B9AA88F2AFDBEB28DA8869D6DF846A1D98924E925561BD69300B9DDD05D247B5922D967CBB02671881C57D10E5EF72D3E6DAD4223DC82AA1F7D0294651A480DF', + q: '0x972432A437178B30BD96195B773789AB2FFF15594B176DD175B63256EE5AF2CF', + a: '0x8FD36731237654BBE41F5F1F8453E71CA414FFC22C25D915309E5D2E62A2A26C7111F3FC79568DAFA028042FE1A52A0489805C0DE9A1A469C844C7CABBEE625C3078888C1D85EEA883F1AD5BC4E6776E8E1A0750912DF64F79956499F1E182475B0B60E2632ADCD8CF94E9C54FD1F3B109D81F00BF2AB8CB862ADF7D40B9369A' + }, + 'S-B': { + modulusLength: 1024, + p: '0xC6971FC57524B30C9018C5E621DE15499736854F56A6F8AEE65A7A404632B1BCF0349FFCAFCB0A103177971FC1612ADCDB8C8CC938C70225C8FD12AFF01B1D064E0AD6FDE6AB9159166CB9F2FC171D92F0CC7B6A6B2CD7FA342ACBE2C9315A42D576B1ECCE77A963157F3D0BD96A8EB0B0F3502AD238101B05116334F1E5B7AB', + q: '0xB09D634C10899CD7D4C3A7657403E05810B07C61A688BAB2C37F475E308B0607', + a: '0x3D26B467D94A3FFC9D71BF8DB8934084137264F3C2E9EB16DCA214B8BC7C872485336744934FD2EF5943F9ED0B745B90AA3EC8D70CDC91682478B664A2E1F8FB56CEF2972FEE7EDB084AF746419B854FAD02CC3E3646FF2E1A18DD4BEB3C44F7F2745588029649674546CC9187C207FB8F2CECE8E2293F68395C4704AF04BAB5' + }, + 'S-C': { + modulusLength: 1024, + p: '0x9D88E6D7FE3313BD2E745C7CDD2AB9EE4AF3C8899E847DE74A33783EA68BC30588BA1F738C6AAF8AB350531F1854C3837CC3C860FFD7E2E106C3F63B3D8A4C034CE73942A6C3D585B599CF695ED7A3C4A93B2B947B7157BB1A1C043AB41EC8566C6145E938A611906DE0D32E562494569D7E999A0DDA5C879BDD91FE124DF1E9', + q: '0xFADD197ABD19A1B4653EECF7ECA4D6A22B1F7F893B641F901641FBB555354FAF', + a: '0x7447ED7156310599070B12609947A5C8C8A8625CF1CF252B407B331F93D639DDD1BA392656DECA992DD035354329A1E95A6E32D6F47882D960B8F10ACAFF796D13CD9611F853DAB6D2623483E46788708493937A1A29442598AEC2E0742022563440FE9C18740ECE6765AC05FAF024A64B026E7E408840819E962E7E5F401AE3' + }, + 'S-D': { + modulusLength: 1024, + p: '0x80F102D32B0FD167D069C27A307ADAD2C466091904DBAA55D5B8CC7026F2F7A1919B890CB652C40E054E1E9306735B43D7B279EDDF9102001CD9E1A831FE8A163EED89AB07CF2ABE8242AC9DEDDDBF98D62CDDD1EA4F5F15D3A42A6677BDD293B24260C0F27C0F1D15948614D567B66FA902BAA11A69AE3BCEADBB83E399C9B5', + q: '0xF0F544C418AAC234F683F033511B65C21651A6078BDA2D69BB9F732867502149', + a: '0x6BCC0B4FADB3889C1E06ADD23CC09B8AB6ECDEDF73F04632595EE4250005D6AF5F5ADE44CB1E26E6263C672347CFA26F9E9393681E6B759733784CDE5DBD9A14A39369DFD99FA85CC0D10241C4010343F34A91393A706CF12677CBFA1F578D6B6CFBE8A1242CFCC94B3B653A476E145E3862C18CC3FED8257CFEF74CDB205BF1' + }, + 'X-A': { + modulusLength: 1024, + p: '0xCA3B3F2EEE9FD46317D49595A9E7518E6C63D8F4EB4D22D10D28AF0B8839F079F8289E603B03530784B9BB5A1E76859E4850C670C7B71C0DF84CA3E0D6C177FE9F78A9D8433230A883CD82A2B2B5C7A3306980278570CDB79BF01074A69C9623348824B0C53791D53C6A78CAB69E1CFB28368611A397F50F541E16DB348DBE5F', + q: '0xCAE4D85F80C147704B0CA48E85FB00A9057AA4ACC44668E17F1996D7152690D9', + a: '0xBE27D652F2F1E339DA734211B85B06AE4DE236AA8FBEEB3F1ADCC52CD43853777E834A6A518138678A8ADBD3A55C70A7EAB1BA7A0719548677AAF4E609FFB47F6B9D7E45B0D06D83D7ADC53310ABD85783E7317F7EC73268B6A9C08D260B85D8485696CA39C17B17F044D1E050489036ABD381C5E6BF82BA352A1AFF136601AF' + }, + 'X-B': { + modulusLength: 1024, + p: '0x9286DBDA91ECCFC3060AA5598318E2A639F5BA90A4CA656157B2673FB191CD0589EE05F4CEF1BD13508408271458C30851CE7A4EF534742BFB11F4743C8F787B11193BA304C0E6BCA25701BF88AF1CB9B8FD4711D89F88E32B37D95316541BF1E5DBB4989B3DF13659B88C0F97A3C1087B9F2D5317D557DCD4AFC6D0A754E279', + q: '0xC966E9B3B8B7CDD82FF0F83AF87036C38F42238EC50A876CD390E43D67B6013F', + a: '0x7E9C3096676F51E3B2F9884CF0AC2156779496F410E049CED7E53D8B7B5B366B1A6008E5196605A55E89C3190DABF80B9F1163C979FCD18328DAE5E9048811B370107BB7715F82091BB9DE0E33EE2FED6255474F8769FCE5EAFAEEF1CB5A32E0D5C6C2F0FC0B3447072947F5B4C387666993A333FC06568E534AD56D2338D729' + }, + 'X-C': { + modulusLength: 1024, + p: '0xB194036ACE14139D36D64295AE6C50FC4B7D65D8B340711366CA93F383653908EE637BE428051D86612670AD7B402C09B820FA77D9DA29C8111A8496DA6C261A53ED252E4D8A69A20376E6ADDB3BDCD331749A491A184B8FDA6D84C31CF05F9119B5ED35246EA4562D85928BA1136A8D0E5A7E5C764BA8902029A1336C631A1D', + q: '0x96120477DF0F3896628E6F4A88D83C93204C210FF262BCCB7DAE450355125259', + a: '0x3F1817052BAA7598FE3E4F4FC5C5F616E122CFF9EBD89EF81DC7CE8BF56CC64B43586C80F1C4F56DD5718FDD76300BE336784259CA25AADE5A483F64C02A20CF4A10F9C189C433DEFE31D263E6C9764660A731ECCAECB74C8279303731E8CF69205BC73E5A70BDF93E5BB681DAB4EEB9C733CAAB2F673C475E0ECA921D29782E' + } +}; // + +/* + * BigInteger arithmetic tools + * optimized release of http://www-cs-students.stanford.edu/~tjw/jsbn/jsbn.js + * + */ // + +// Bits per one element +var DB = 28, DM = (1 << DB) - 1, DV = 1 << DB, + FV = Math.pow(2, 52), F1 = 52 - DB, F2 = 2 * DB - 52; + +function am(y, i, x, w, j, c, n) { + var xl = x & 0x3fff, xh = x >> 14; + while (--n >= 0) { + var l = y[i] & 0x3fff; + var h = y[i++] >> 14; + var m = xh * l + h * xl; + l = xl * l + ((m & 0x3fff) << 14) + w[j] + c; + c = (l >> 28) + (m >> 14) + xh * h; + w[j++] = l & 0xfffffff; + } + return c; +} + +function nbi(words) { + var r = new Array(Math.ceil(words)); + r.s = 0; + r.t = 0; + return r; +} + +function copyTo(x, r) { + for (var i = x.t - 1; i >= 0; --i) + r[i] = x[i]; + r.t = x.t; + r.s = x.s; + return r; +} + +function copy(x) { + return copyTo(x, nbi(x.t)); +} + +function setInt(x, i) { + x.t = 1; + x.s = (i < 0) ? -1 : 0; + if (i > 0) + x[0] = i; + else if (i < -1) + x[0] = i + DV; + else + x.t = 0; + return x; +} + +function nbv(i) { + var r = nbi(1); + setInt(r, i); + return r; +} + +var ZERO = nbv(0), ONE = nbv(1), THREE = nbv(3); + +function clamp(x) { + var c = x.s & DM; + while (x.t > 0 && x[x.t - 1] === c) + --x.t; + return x; +} + +function subTo(x, a, r) { + var i = 0, c = 0, m = Math.min(a.t, x.t); + while (i < m) { + c += x[i] - a[i]; + r[i++] = c & DM; + c >>= DB; + } + if (a.t < x.t) { + c -= a.s; + while (i < x.t) { + c += x[i]; + r[i++] = c & DM; + c >>= DB; + } + c += x.s; + } + else { + c += x.s; + while (i < a.t) { + c -= a[i]; + r[i++] = c & DM; + c >>= DB; + } + c -= a.s; + } + r.s = (c < 0) ? -1 : 0; + if (c < -1) + r[i++] = DV + c; + else if (c > 0) + r[i++] = c; + r.t = i; + return clamp(r); +} + +function sub(x, y) { + return subTo(x, y, nbi(x.t)); +} + +function addTo(x, a, r) { + var i = 0, c = 0, m = Math.min(a.t, x.t); + while (i < m) { + c += x[i] + a[i]; + r[i++] = c & DM; + c >>= DB; + } + if (a.t < x.t) { + c += a.s; + while (i < x.t) { + c += x[i]; + r[i++] = c & DM; + c >>= DB; + } + c += x.s; + } + else { + c += x.s; + while (i < a.t) { + c += a[i]; + r[i++] = c & DM; + c = c >> DB; + } + c += a.s; + } + r.s = (c < 0) ? -1 : 0; + if (c > 0) + r[i++] = c; + else if (c < -1) + r[i++] = DV + c; + r.t = i; + return clamp(r); +} + +function add(x, y) { + return addTo(x, y, nbi(x.t)); +} + +function negTo(x, r) { + return subTo(ZERO, x, r); +} + +function neg(x) { + return negTo(x, nbi(x.t)); +} + +function absTo(x, r) { + return (x.s < 0) ? negTo(r) : copyTo(r); +} + +function abs(x) { + return (x.s < 0) ? neg(x) : x; +} + +function compare(x, a) { + var r = x.s - a.s; + if (r !== 0) + return r; + var i = x.t; + r = i - a.t; + if (r !== 0) + return (x.s < 0) ? -r : r; + while (--i >= 0) + if ((r = x[i] - a[i]) !== 0) + return r; + return 0; +} + +function equals(x, y) { + return(compare(x, y) === 0); +} + +function min(x, y) { + return(compare(x, y) < 0) ? x : y; +} + +function max(x, y) { + return(compare(x, y) > 0) ? x : y; +} + +function nbits(x) { + var r = 1, t; + if ((t = x >>> 16) !== 0) { + x = t; + r += 16; + } + if ((t = x >> 8) !== 0) { + x = t; + r += 8; + } + if ((t = x >> 4) !== 0) { + x = t; + r += 4; + } + if ((t = x >> 2) !== 0) { + x = t; + r += 2; + } + if ((t = x >> 1) !== 0) { + x = t; + r += 1; + } + return r; +} + +function dshlTo(x, n, r) { + var i; + for (i = x.t - 1; i >= 0; --i) + r[i + n] = x[i]; + for (i = n - 1; i >= 0; --i) + r[i] = 0; + r.t = x.t + n; + r.s = x.s; + return r; +} +function dshrTo(x, n, r) { + for (var i = n; i < x.t; ++i) + r[i - n] = x[i]; + r.t = Math.max(x.t - n, 0); + r.s = x.s; + return r; +} + +function shlTo(x, n, r) { + var bs = n % DB; + var cbs = DB - bs; + var bm = (1 << cbs) - 1; + var ds = Math.floor(n / DB), c = (x.s << bs) & DM, i; + for (i = x.t - 1; i >= 0; --i) { + r[i + ds + 1] = (x[i] >> cbs) | c; + c = (x[i] & bm) << bs; + } + for (i = ds - 1; i >= 0; --i) + r[i] = 0; + r[ds] = c; + r.t = x.t + ds + 1; + r.s = x.s; + return clamp(r); +} + +function shrTo(x, n, r) { + r.s = x.s; + var ds = Math.floor(n / DB); + if (ds >= x.t) { + r.t = 0; + return; + } + var bs = n % DB; + var cbs = DB - bs; + var bm = (1 << bs) - 1; + r[0] = x[ds] >> bs; + for (var i = ds + 1; i < x.t; ++i) { + r[i - ds - 1] |= (x[i] & bm) << cbs; + r[i - ds] = x[i] >> bs; + } + if (bs > 0) + r[x.t - ds - 1] |= (x.s & bm) << cbs; + r.t = x.t - ds; + return clamp(r); +} + +function shl(x, n) { + var r = nbi(x.t); + if (n < 0) + shrTo(x, -n, r); + else + shlTo(x, n, r); + return r; +} + +function shr(x, n) { + var r = nbi(x.t); + if (n < 0) + shlTo(x, -n, r); + else + shrTo(x, n, r); + return r; +} + +function bitLength(x) { + if (x.t <= 0) + return 0; + return DB * (x.t - 1) + nbits(x[x.t - 1] ^ (x.s & DM)); +} + +function mulTo(b, a, r) { + var x = abs(b), y = abs(a); + var i = x.t; + r.t = i + y.t; + while (--i >= 0) + r[i] = 0; + for (i = 0; i < y.t; ++i) + r[i + x.t] = am(x, 0, y[i], r, i, 0, x.t); + r.s = 0; + if (b.s !== a.s) + subTo(ZERO, r, r); + return clamp(r); +} + +function mul(x, y) { + return mulTo(x, y, nbi(x.t + y.t)); +} + +function sqrTo(a, r) { + var x = abs(a); + var i = r.t = 2 * x.t; + while (--i >= 0) + r[i] = 0; + for (i = 0; i < x.t - 1; ++i) { + var c = am(x, i, x[i], r, 2 * i, 0, 1); + if ((r[i + x.t] += am(x, i + 1, 2 * x[i], r, 2 * i + 1, c, x.t - i - 1)) >= x.DV) { + r[i + x.t] -= x.DV; + r[i + x.t + 1] = 1; + } + } + if (r.t > 0) + r[r.t - 1] += am(x, i, x[i], r, 2 * i, 0, 1); + r.s = 0; + return clamp(r); +} + +function sqr(a) { + return sqrTo(a, nbi(a.t * 2)); +} + +function divRemTo(n, m, q, r) { + var pm = abs(m); + if (pm.t <= 0) + throw new OperationError('Division by zero'); + var pt = abs(n); + if (pt.t < pm.t) { + if (q) + setInt(q, 0); + if (r) + copyTo(n, r); + return q; + } + if (!r) + r = nbi(m.t); + var y = nbi(m.t), ts = n.s, ms = m.s; + var nsh = DB - nbits(pm[pm.t - 1]); + if (nsh > 0) { + shlTo(pm, nsh, y); + shlTo(pt, nsh, r); + } + else { + copyTo(pm, y); + copyTo(pt, r); + } + var ys = y.t; + var y0 = y[ys - 1]; + if (y0 === 0) + return q; + var yt = y0 * (1 << F1) + ((ys > 1) ? y[ys - 2] >> F2 : 0); + var d1 = FV / yt, d2 = (1 << F1) / yt, e = 1 << F2; + var i = r.t, j = i - ys, t = !q ? nbi(Math.max(n.t - m.t, 1)) : q; + dshlTo(y, j, t); + if (compare(r, t) >= 0) { + r[r.t++] = 1; + subTo(r, t, r); + } + dshlTo(ONE, ys, t); + subTo(t, y, y); + while (y.t < ys) + y[y.t++] = 0; + while (--j >= 0) { + var qd = (r[--i] === y0) ? DM : Math.floor(r[i] * d1 + (r[i - 1] + e) * d2); + if ((r[i] += am(y, 0, qd, r, j, 0, ys)) < qd) { + dshlTo(y, j, t); + subTo(r, t, r); + while (r[i] < --qd) + subTo(r, t, r); + } + } + if (q) { + dshrTo(r, ys, q); + if (ts !== ms) + subTo(ZERO, q, q); + } + r.t = ys; + clamp(r); + if (nsh > 0) + shrTo(r, nsh, r); + if (ts < 0) + subTo(ZERO, r, r); + return q; +} + +function modTo(b, a, r) { + divRemTo(abs(b), a, null, r); + if (b.s < 0 && compare(r, ZERO) > 0) + subTo(a, r, r); + return r; +} + +function mod(b, a) { + return modTo(b, a, nbi(a.t)); +} + +function div(b, a) { + return divRemTo(b, a, nbi(Math.max(b.t - a.t, 1)), null); +} + +function isEven(x) { + + return ((x.t > 0) ? (x[0] & 1) : x.s) === 0; +} + +function isZero(x) { + return equals(x, ZERO); +} + +function sig(x) { + if (x.s < 0) + return -1; + else if (x.t <= 0 || (x.t === 1 && x[0] <= 0)) + return 0; + else + return 1; +} + +function invMod(x, m) { + var ac = isEven(m); + if ((isEven(x) && ac) || sig(m) === 0) + return ZERO; + var u = copy(m), v = copy(x); + var a = nbv(1), b = nbv(0), c = nbv(0), d = nbv(1); + while (sig(u) !== 0) { + while (isEven(u)) { + shrTo(u, 1, u); + if (ac) { + if (!isEven(a) || !isEven(b)) { + addTo(a, x, a); + subTo(b, m, b); + } + shrTo(a, 1, a); + } + else if (!isEven(b)) + subTo(b, m, b); + shrTo(b, 1, b); + } + while (isEven(v)) { + shrTo(v, 1, v); + if (ac) { + if (!isEven(c) || !isEven(d)) { + addTo(c, x, c); + subTo(d, m, d); + } + shrTo(c, 1, c); + } + else if (!isEven(d)) + subTo(d, m, d); + shrTo(d, 1, d); + } + if (compare(u, v) >= 0) { + subTo(u, v, u); + if (ac) + subTo(a, c, a); + subTo(b, d, b); + } + else { + subTo(v, u, v); + if (ac) + subTo(c, a, c); + subTo(d, b, d); + } + } + if (compare(v, ONE) !== 0) + return ZERO; + if (compare(d, m) >= 0) + return subtract(d, m); + if (sig(d) < 0) + addTo(d, m, d); + else + return d; + if (sig(d) < 0) + return add(d, m); + else + return d; +} + +function testBit(x, n) { + var j = Math.floor(n / DB); + if (j >= x.t) + return (x.s !== 0); + return ((x[j] & (1 << (n % DB))) !== 0); +} + +function nothing(x) { + return x; +} + +function extend(c, o) { + for (var i in o) + c.prototype[i] = o[i]; +} // + +/* + * Classic, Barret, Mongomery reductions, optimized ExpMod algorithms + * optimized release of http://www-cs-students.stanford.edu/~tjw/jsbn/jsbn2.js + * + */ // + +// Classic reduction +var Classic = function (m) { + this.m = m; +}; + +extend(Classic, { + convert: function (x) { + if (x.s < 0 || compare(x, this.m) >= 0) + return mod(x, this.m); + else + return x; + }, + revert: nothing, + reduce: function (x) { + modTo(x, this.m, x); + }, + sqrTo: function (x, r) { + sqrTo(x, r); + this.reduce(r); + }, + mulTo: function (x, y, r) { + mulTo(x, y, r); + this.reduce(r); + } +}); + +function invDig(a) { + if (a.t < 1) + return 0; + var x = a[0]; + if ((x & 1) === 0) + return 0; + var y = x & 3; + y = (y * (2 - (x & 0xf) * y)) & 0xf; + y = (y * (2 - (x & 0xff) * y)) & 0xff; + y = (y * (2 - (((x & 0xffff) * y) & 0xffff))) & 0xffff; + y = (y * (2 - x * y % DV)) % DV; + return (y > 0) ? DV - y : -y; +} + +// Montgomery reduction +var Montgomery = function (m) { + this.m = m; + this.mp = invDig(m); + this.mpl = this.mp & 0x7fff; + this.mph = this.mp >> 15; + this.um = (1 << (DB - 15)) - 1; + this.mt2 = 2 * m.t; +}; + +extend(Montgomery, { + // xR mod m + convert: function (x) { + var r = nbi(x.t); + dshlTo(abs(x), this.m.t, r); + divRemTo(r, this.m, null, r); + if (x.s < 0 && compare(r, ZERO) > 0) + subTo(this.m, r, r); + return r; + }, + // x/R mod m + revert: function (x) { + var r = nbi(x.t); + copyTo(x, r); + this.reduce(r); + return r; + }, + // x = x/R mod m (HAC 14.32) + reduce: function (x) { + while (x.t <= this.mt2) + x[x.t++] = 0; + for (var i = 0; i < this.m.t; ++i) { + var j = x[i] & 0x7fff; + var u0 = (j * this.mpl + (((j * this.mph + (x[i] >> 15) * this.mpl) & this.um) << 15)) & DM; + j = i + this.m.t; + x[j] += am(this.m, 0, u0, x, i, 0, this.m.t); + while (x[j] >= DV) { + x[j] -= DV; + x[++j]++; + } + } + clamp(x); + dshrTo(x, this.m.t, x); + if (compare(x, this.m) >= 0) + subTo(x, this.m, x); + }, + // r = "x^2/R mod m"; x != r + sqrTo: function (x, r) { + sqrTo(x, r); + this.reduce(r); + }, + // r = "xy/R mod m"; x,y != r + mulTo: function (x, y, r) { + mulTo(x, y, r); + this.reduce(r); + } +}); + +function dAddOffset(x, n, w) { + if (n === 0) + return; + while (x.t <= w) + x[x.t++] = 0; + x[w] += n; + while (x[w] >= DV) { + x[w] -= DV; + if (++w >= x.t) + x[x.t++] = 0; + ++x[w]; + } +} + +function mulLowerTo(x, a, n, r) { + var i = Math.min(x.t + a.t, n); + r.s = 0; // assumes a,x >= 0 + r.t = i; + while (i > 0) + r[--i] = 0; + var j; + for (j = r.t - x.t; i < j; ++i) + r[i + x.t] = am(x, 0, a[i], r, i, 0, x.t); + for (j = Math.min(a.t, n); i < j; ++i) + am(x, 0, a[i], r, i, 0, n - i); + return clamp(r); +} + +function mulUpperTo(x, a, n, r) { + --n; + var i = r.t = x.t + a.t - n; + r.s = 0; // assumes a,x >= 0 + while (--i >= 0) + r[i] = 0; + for (i = Math.max(n - x.t, 0); i < a.t; ++i) + r[x.t + i - n] = am(x, n - i, a[i], r, 0, 0, x.t + i - n); + clamp(r); + return dshrTo(r, 1, r); +} + +// Barrett modular reduction +function Barrett(m) { + // setup Barrett + this.r2 = nbi(2 * m.t); + this.q3 = nbi(2 * m.t); + dshlTo(ONE, 2 * m.t, this.r2); + this.mu = div(this.r2, m); + this.m = m; +} + +extend(Barrett, { + convert: function (x) { + if (x.s < 0 || x.t > 2 * this.m.t) + return mod(x, this.m); + else if (compare(x, this.m) < 0) + return x; + else { + var r = nbi(x.t); + copyTo(x, r); + this.reduce(r); + return r; + } + }, + revert: function (x) { + return x; + }, + // x = x mod m (HAC 14.42) + reduce: function (x) { + dshrTo(x, this.m.t - 1, this.r2); + if (x.t > this.m.t + 1) { + x.t = this.m.t + 1; + clamp(x); + } + mulUpperTo(this.mu, this.r2, this.m.t + 1, this.q3); + mulLowerTo(this.m, this.q3, this.m.t + 1, this.r2); + while (compare(x, this.r2) < 0) + dAddOffset(x, 1, this.m.t + 1); + subTo(x, this.r2, x); + while (compare(x, this.m) >= 0) + subTo(x, this.m, x); + }, + // r = x^2 mod m; x != r + sqrTo: function (x, r) { + sqrTo(x, r); + this.reduce(r); + }, + // r = x*y mod m; x,y != r + mulTo: function (x, y, r) { + mulTo(x, y, r); + this.reduce(r); + } + +}); + +// x^e % m (HAC 14.85) +function expMod(x, e, m) { + var i = bitLength(e), k, r = nbv(1), z; + if (i <= 0) + return r; + else if (i < 18) + k = 1; + else if (i < 48) + k = 3; + else if (i < 144) + k = 4; + else if (i < 768) + k = 5; + else + k = 6; + if (i < 8) + z = new Classic(m); + else if (isEven(m)) + z = new Barrett(m); + else + z = new Montgomery(m); + + // precomputation + var g = new Array(), n = 3, k1 = k - 1, km = (1 << k) - 1; + g[1] = z.convert(x); + if (k > 1) { + var g2 = nbi(m.t * 2); + z.sqrTo(g[1], g2); + while (n <= km) { + g[n] = nbi(m.t * 2); + z.mulTo(g2, g[n - 2], g[n]); + n += 2; + } + } + + var j = e.t - 1, w, is1 = true, r2 = nbi(m.t * 2), t; + i = nbits(e[j]) - 1; + while (j >= 0) { + if (i >= k1) + w = (e[j] >> (i - k1)) & km; + else { + w = (e[j] & ((1 << (i + 1)) - 1)) << (k1 - i); + if (j > 0) + w |= e[j - 1] >> (DB + i - k1); + } + + n = k; + while ((w & 1) == 0) { + w >>= 1; + --n; + } + if ((i -= n) < 0) { + i += DB; + --j; + } + if (is1) { // ret == 1, don't bother squaring or multiplying it + copyTo(g[w], r); + is1 = false; + } + else { + while (n > 1) { + z.sqrTo(r, r2); + z.sqrTo(r2, r); + n -= 2; + } + if (n > 0) + z.sqrTo(r, r2); + else { + t = r; + r = r2; + r2 = t; + } + z.mulTo(r2, g[w], r); + } + while (j >= 0 && (e[j] & (1 << i)) == 0) { + z.sqrTo(r, r2); + t = r; + r = r2; + r2 = t; + if (--i < 0) { + i = DB - 1; + --j; + } + } + } + return z.revert(r); +} // + +/* + * EC Field Elements, Points, Curves + * optimized release of http://www-cs-students.stanford.edu/~tjw/jsbn/ec.js + * + */ // + +// EC Field Elemets +function newFE(a, x) { + a.r.reduce(x); + x.q = a.q; + x.r = a.r; + return x; +} + +function copyFE(a, x) { + x.q = a.q; + x.r = a.r; + return x; +} + +function negFE(a) { + return copyFE(a, sub(a.q, a)); +} + +function addFE(a, b) { + var r = add(a, b); + if (compare(r, a.q) > 0) + subTo(r, a.q, r); + return copyFE(a, r); +} + +function subFE(a, b) { + var r = sub(a, b); + if (r.s < 0) + addTo(a.q, r, r); + return copyFE(a, r); +} + +function mulFE(a, b) { + return newFE(a, mul(a, b)); +} + +function sqrFE(a) { + return newFE(a, sqr(a)); +} + +function shlFE(a, i) { + return newFE(a, shl(a, i)); +} + +function invFE(a) { + return copyFE(a, invMod(a, a.q)); +} + +// EC Points +function newEC(curve, x, y, z) { + return { + curve: curve, + x: x, + y: y, + z: z || newFE(curve, ONE) + }; +} + +function getX(point) { + if (!point.zinv) + point.zinv = invFE(point.z); + return mulFE(point.x, point.zinv); +} + +function getY(point) { + if (!point.zinv) + point.zinv = invFE(point.z); + return mulFE(point.y, point.zinv); +} + +function isInfinity(a) { + if ((!a.x) && (!a.y)) + return true; + return isZero(a.z) && !isZero(a.y); +} + +function getInfinity(a) { + return a.curve.infinity; +} + +function equalsEC(a, b) { + if (a === b) + return true; + if (isInfinity(a)) + return isInfinity(b); + if (isInfinity(b)) + return isInfinity(a); + var u, v; + // u = Y2 * Z1 - Y1 * Z2 + u = subFE(mulFE(b.y, a.z), mulFE(a.y, b.z)); + if (!isZero(u)) + return false; + // v = X2 * Z1 - X1 * Z2 + v = subFE(mulFE(b.x, a.z), mulFE(a.x, b.z)); + return isZero(v); +} + +function negEC(a) { + return newEC(a.curve, a.x, negFE(a.y), a.z); +} + +function addEC(a, b) { + if (isInfinity(a)) + return b; + if (isInfinity(b)) + return a; + + // u = Y2 * Z1 - Y1 * Z2 + var u = subFE(mulFE(b.y, a.z), mulFE(a.y, b.z)); + // v = X2 * Z1 - X1 * Z2 + var v = subFE(mulFE(b.x, a.z), mulFE(a.x, b.z)); + + if (isZero(v)) { + if (isZero(u)) { + return twiceEC(a); // a == b, so double + } + return getInfinity(a); // a = -b, so infinity + } + + var x1 = a.x; + var y1 = a.y; + + var v2 = sqrFE(v); + var v3 = mulFE(v2, v); + var x1v2 = mulFE(x1, v2); + var zu2 = mulFE(sqrFE(u), a.z); + + // x3 = v * (z2 * (z1 * u^2 - 2 * x1 * v^2) - v^3) + var x3 = mulFE(subFE(mulFE(subFE(zu2, shlFE(x1v2, 1)), b.z), v3), v); + // y3 = z2 * (3 * x1 * u * v^2 - y1 * v^3 - z1 * u^3) + u * v^3 + var y3 = addFE(mulFE(subFE(subFE(mulFE(mulFE(x1v2, THREE), u), mulFE(y1, v3)), mulFE(zu2, u)), b.z), mulFE(u, v3)); + // z3 = v^3 * z1 * z2 + var z3 = mulFE(mulFE(v3, a.z), b.z); + + return newEC(a.curve, x3, y3, z3); +} + +function twiceEC(b) { + if (isInfinity(b)) + return b; + if (sig(b.y) === 0) + return getInfinity(b); + + var x1 = b.x; + var y1 = b.y; + + var y1z1 = mulFE(y1, b.z); + var y1sqz1 = mulFE(y1z1, y1); + var a = b.curve.a; + + // w = 3 * x1^2 + a * z1^2 + var w = mulFE(sqrFE(x1), THREE); + if (!isZero(a)) { + w = addFE(w, mulFE(sqrFE(b.z), a)); + } + + // x3 = 2 * y1 * z1 * (w^2 - 8 * x1 * y1^2 * z1) + var x3 = mulFE(shlFE(subFE(sqrFE(w), mulFE(shlFE(x1, 3), y1sqz1)), 1), y1z1); + // y3 = 4 * y1^2 * z1 * (3 * w * x1 - 2 * y1^2 * z1) - w^3 + var y3 = subFE(mulFE(shlFE(subFE(mulFE(mulFE(w, THREE), x1), shlFE(y1sqz1, 1)), 2), y1sqz1), mulFE(sqrFE(w), w)); + // z3 = 8 * (y1 * z1)^3 + var z3 = shlFE(mulFE(sqrFE(y1z1), y1z1), 3); + + return newEC(b.curve, x3, y3, z3); +} + +// Simple NAF (Non-Adjacent Form) multiplication algorithm +function mulEC(a, k) { + if (isInfinity(a)) + return a; + if (sig(k) === 0) + return getInfinity(a); + + var e = k; + var h = mul(e, THREE); + + var neg = negEC(a); + var R = a; + + var i; + for (i = bitLength(h) - 2; i > 0; --i) { + R = twiceEC(R); + + var hBit = testBit(h, i); + var eBit = testBit(e, i); + + if (hBit !== eBit) { + R = addEC(R, hBit ? a : neg); + } + } + + return R; +} + +function mul2AndAddEC(a, k) { + var nbits = bitLength(k); + var R = a, + Q = getInfinity(a); + + for (var i = 0; i < nbits - 1; i++) { + if (testBit(k, i) === 1) + Q = addEC(Q, R); + + R = twiceEC(R); + } + + if (testBit(k, nbits - 1) === 1) + Q = addEC(Q, R); + + return Q; +} + +// Compute a*j + x*k (simultaneous multiplication) +function mulTwoEC(a, j, x, k) { + var i; + if (bitLength(j) > bitLength(k)) + i = bitLength(j) - 1; + else + i = bitLength(k) - 1; + + var R = getInfinity(a); + var both = addEC(a, x); + while (i >= 0) { + R = twiceEC(R); + if (testBit(j, i)) { + if (testBit(k, i)) { + R = addEC(R, both); + } + else { + R = addEC(R, a); + } + } + else { + if (testBit(k, i)) { + R = addEC(R, x); + } + } + --i; + } + + return R; +} + +// EC Curve +function newCurve(q, a, b) { + var curve = {}; + curve.q = q; + curve.r = new Barrett(q); + curve.a = newFE(curve, a); + curve.b = newFE(curve, b); + curve.infinity = newEC(curve); + return curve; +} // + +/* + * Converion tools (hex, binary) + * + */ // + +function atobi(d) { + var k = 8; + var a = new Uint8Array(d); + var r = nbi(a.length * 8 / DB); + r.t = 0; + r.s = 0; + var sh = 0; + for (var i = 0, n = a.length; i < n; i++) { + var x = a[i]; + if (sh === 0) + r[r.t++] = x; + else if (sh + k > DB) { + r[r.t - 1] |= (x & ((1 << (DB - sh)) - 1)) << sh; + r[r.t++] = (x >> (DB - sh)); + } + else + r[r.t - 1] |= x << sh; + sh += k; + if (sh >= DB) + sh -= DB; + } + return clamp(r); +} + +function bitoa(s, bitLength) { + var k = 8; + var km = (1 << k) - 1, d, m = false, r = [], i = s.t; + var p = DB - (i * DB) % k; + if (i-- > 0) { + if (p < DB && (d = s[i] >> p) > 0) { + m = true; + r.push(d); + } + while (i >= 0) { + if (p < k) { + d = (s[i] & ((1 << p) - 1)) << (k - p); + d |= s[--i] >> (p += DB - k); + } + else { + d = (s[i] >> (p -= k)) & km; + if (p <= 0) { + p += DB; + --i; + } + } + if (d > 0) + m = true; + if (m) + r.push(d); + } + } + var r8 = new Uint8Array(bitLength ? bitLength / 8 : r.length); + if (m) + r8.set(r.reverse()); + return r8.buffer; +} + + +function htobi(s) { + if (typeof s === 'number' || s instanceof Number) + return nbv(s); + s = s.replace(/[^\-A-Fa-f0-9]/g, ''); + if (!s) + s = '0'; + var k = 4; + var r = nbi(s.length / 7); + var i = s.length, mi = false, sh = 0; + while (--i >= 0) { + var c = s.charAt(i); + if (c === '-') { + mi = true; + continue; + } + var x = parseInt(s.charAt(i), 16); + mi = false; + if (sh === 0) + r[r.t++] = x; + else if (sh + k > DB) { + r[r.t - 1] |= (x & ((1 << (DB - sh)) - 1)) << sh; + r[r.t++] = (x >> (DB - sh)); + } + else + r[r.t - 1] |= x << sh; + sh += k; + if (sh >= DB) + sh -= DB; + } + if (mi) + subTo(ZERO, r, r); + return clamp(r); +} + +function bitoh(x) { + if (x.s < 0) + return "-" + bitoh(negTo(x, nbi(x.t))); + var k = 4; + var km = (1 << k) - 1, d, m = false, r = "", i = x.t; + var p = DB - (i * DB) % k; + if (i-- > 0) { + if (p < DB && (d = x[i] >> p) > 0) { + m = true; + r = d.toString(16); + } + while (i >= 0) { + if (p < k) { + d = (x[i] & ((1 << p) - 1)) << (k - p); + d |= x[--i] >> (p += DB - k); + } + else { + d = (x[i] >> (p -= k)) & km; + if (p <= 0) { + p += DB; + --i; + } + } + if (d > 0) + m = true; + if (m) + r += d.toString(16); + } + } + return "0x" + (m ? r : "0"); +} + +// biginteger to big-endian integer bytearray +function bitoi(s) { + var i = s.t, r = []; + r[0] = s.s; + var p = DB - (i * DB) % 8, d, k = 0; + if (i-- > 0) { + if (p < DB && (d = s[i] >> p) !== (s.s & DM) >> p) + r[k++] = d | (s.s << (DB - p)); + while (i >= 0) { + if (p < 8) { + d = (s[i] & ((1 << p) - 1)) << (8 - p); + d |= s[--i] >> (p += DB - 8); + } + else { + d = (s[i] >> (p -= 8)) & 0xff; + if (p <= 0) { + p += DB; + --i; + } + } + if ((d & 0x80) !== 0) + d |= -256; + if (k === 0 && (s.s & 0x80) !== (d & 0x80)) + ++k; + if (k > 0 || d !== s.s) + r[k++] = d; + } + } + return new Uint8Array(r).buffer; +} + +// big-endian integer bytearray to biginteger +function itobi(d) { + var k = 8, s = new Uint8Array(d), + r = nbi(s.length / 7); + r.t = 0; + r.s = 0; + var i = s.length, sh = 0; + while (--i >= 0) { + var x = s[i] & 0xff; + if (sh === 0) + r[r.t++] = x; + else if (sh + k > DB) { + r[r.t - 1] |= (x & ((1 << (DB - sh)) - 1)) << sh; + r[r.t++] = (x >> (DB - sh)); + } + else + r[r.t - 1] |= x << sh; + sh += k; + if (sh >= DB) + sh -= DB; + } + if ((s[0] & 0x80) !== 0) { + r.s = -1; + if (sh > 0) + r[r.t - 1] |= ((1 << (DB - sh)) - 1) << sh; + } + return clamp(r); +} + + +// Swap bytes in buffer +function swap(s) { + var src = new Uint8Array(s), + dst = new Uint8Array(src.length); + for (var i = 0, n = src.length; i < n; i++) + dst[n - i - 1] = src[i]; + return dst.buffer; +} + +// Calculate hash of data +function hash(d) { + if (this.hash) + d = this.hash.digest(d); + // Swap hash for SignalCom + if (this.procreator === 'SC' || + (this.procreator === 'VN' && this.hash.version === 2012)) + d = swap(d); + return d; +} + +// Check buffer +function buffer(d) { + if (d instanceof CryptoOperationData) + return d; + else if (d && d.buffer && 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 or CryptoOperationDataView required'); +} + +// Check double buffer +function to2(d) { + var b = buffer(d); + if (b.byteLength % 2 > 0) + throw new DataError('Buffer length must be even'); + var n = b.byteLength / 2; + return [atobi(new Uint8Array(b, 0, n)), atobi(new Uint8Array(b, n, n))]; +} + +function from2(x, y, bitLength) { + var a = bitoa(x, bitLength), + b = bitoa(y, bitLength), + d = new Uint8Array(a.byteLength + b.byteLength); + d.set(new Uint8Array(a)); + d.set(new Uint8Array(b), a.byteLength); + return d.buffer; +} + +function getSeed(length) { + GostRandom = GostRandom || root.GostRandom; + var randomSource = GostRandom ? new (GostRandom || root.GostRandom) : rootCrypto; + if (randomSource.getRandomValues) { + var d = new Uint8Array(Math.ceil(length / 8)); + randomSource.getRandomValues(d); + return d; + } else + throw new NotSupportedError('Random generator not found'); +} // + +/** + * Algorithm name GOST R 34.10

+ * + * The sign method returns sign data generated with the supplied privateKey.
+ * + * @memberOf GostSign + * @method sign + * @instance + * @param {(CryptoOperationData|TypedArray)} privateKey Private key + * @param {(CryptoOperationData|TypedArray)} data Data + * @returns {CryptoOperationData} Signature + */ +function sign(privateKey, data) // +{ + + // Stage 1 + var b = buffer(data); + var alpha = atobi(hash.call(this, b)); + + var q = this.q; + var x = mod(atobi(buffer(privateKey)), q); + + // Stage 2 + var e = mod(alpha, q); + if (isZero(e)) + e = ONE; + + var s = ZERO; + while (isZero(s)) { + var r = ZERO; + while (isZero(r)) { + + // Stage 3 + var k = mod(atobi(this.ukm || + getSeed(this.bitLength)), q); // pseudo random 0 < k < q + // Stage 4 + if (this.curve) { + // Gost R 34.10-2001 || Gost R 34.10-2012 + var P = this.P; + var C = mulEC(P, k); + r = mod(getX(C), q); + } else { + // Gost R 34.10-94 + var p = this.p, a = this.a; + r = mod(expMod(a, k, p), q); + } + } + // Stage 5 + s = mod(add(mul(r, x), mul(k, e)), q); + } + // Stage 6 + // console.log('s', bitoh(s)); + // console.log('r', bitoh(r)); + var zetta; + // Integer structure for SignalCom algorithm + if (this.procreator === 'SC') { + zetta = { + r: bitoh(r), + s: bitoh(s) + }; + } else { + zetta = from2(r, s, this.bitLength); + // Swap bytes for CryptoPro algorithm + if (this.procreator === 'CP' || this.procreator === 'VN') + zetta = swap(zetta); + } + return zetta; +} // + +/** + * Algorithm name GOST R 34.10

+ * + * The verify method returns signature verification for the supplied publicKey.
+ * + * @memberOf GostSign + * @method sign + * @instance + * @param {(CryptoOperationData|TypedArray)} publicKey Public key + * @param {(CryptoOperationData|TypedArray)} signature Signature + * @param {(CryptoOperationData|TypedArray)} data Data + * @returns {boolean} Signature verified = true + */ +function verify(publicKey, signature, data) // +{ + + // Stage 1 + var q = this.q; + var r, s; + // Ready int for SignalCom algorithm + if (this.procreator === 'SC') { + r = htobi(signature.r); + s = htobi(signature.s); + } else { + if (this.procreator === 'CP' || this.procreator === 'VN') + signature = swap(signature); + var zetta = to2(signature); + // Swap bytes for CryptoPro algorithm + s = zetta[1]; // first 32 octets contain the big-endian representation of s + r = zetta[0]; // and second 32 octets contain the big-endian representation of r + } + if (compare(r, q) >= 0 || compare(s, q) >= 0) + return false; + // Stage 2 + var b = buffer(data); + var alpha = atobi(hash.call(this, b)); + // Stage 3 + var e = mod(alpha, q); + if (isZero(e) === 0) + e = ONE; + // Stage 4 + var v = invMod(e, q); + // Stage 5 + var z1 = mod(mul(s, v), q); + var z2 = sub(q, mod(mul(r, v), q)); + // Stage 6 + if (this.curve) { + // Gost R 34.10-2001 || Gost R 34.10-2012 + var k2 = to2(publicKey), + curve = this.curve, + P = this.P, + x = newFE(curve, k2[0]), // first 32 octets contain the little-endian representation of x + y = newFE(curve, k2[1]), // and second 32 octets contain the little-endian representation of y. + Q = new newEC(curve, x, y); // This corresponds to the binary representation of (256||256) + var C = mulTwoEC(P, z1, Q, z2); + var R = mod(getX(C), q); + } else { + // Gost R 34.10-94 + var p = this.p, a = this.a; + var y = atobi(publicKey); + var R = mod(mod(mul(expMod(a, z1, p), expMod(y, z2, p)), p), q); + } + // Stage 7 + return (compare(R, r) === 0); +} // + +/** + * Algorithm name GOST R 34.10

+ * + * The generateKey method returns a new generated key pair using the specified + * AlgorithmIdentifier. + * + * @memberOf GostSign + * @method generateKey + * @instance + * @returns {Object} Object with two CryptoOperationData members: privateKey and publicKey + */ +function generateKey() // +{ + var curve = this.curve; + if (curve) { + + var Q = curve.infinity; + while (isInfinity(Q)) { + + // Generate random private key + var d = ZERO; + if (this.ukm) { + d = atobi(this.ukm); + } else { + while (isZero(d)) + d = mod(atobi(getSeed(this.bitLength)), this.q); // 0 < d < q + } + + // Calculate public key + Q = mulEC(this.P, d); + var x = getX(Q), y = getY(Q); + // console.log('d', bitoh(d)); + // console.log('x', bitoh(x)); + // console.log('y', bitoh(y)); + } + + // Return result + return { + privateKey: bitoa(d, this.bitLength), + publicKey: from2(x, y, this.bitLength) // This corresponds to the binary representation of (256||256) + }; + + } else + throw new NotSupportedError('Key generation for GOST R 34.10-94 not supported'); +} // + +/** + * Algorithm name GOST R 34.10 mode MASK

+ * + * The generateMaskKey method returns a new generated key mask using for wrapping. + * + * @memberOf GostSign + * @method generateMaskKey + * @instance + * @returns {Object} Object with two CryptoOperationData members: privateKey and publicKey + */ +function generateMaskKey() // +{ + var curve = this.curve; + if (curve) { + // Generate random private key + var d = ZERO; + while (isZero(d)) + d = mod(atobi(getSeed(this.bitLength)), this.q); // 0 < d < q + + // Return result + return bitoa(d, this.bitLength); + } else + throw new NotSupportedError('Key generation for GOST R 34.10-94 not supported'); +} // + +/** + * Algorithm name GOST R 34.10

+ * + * Unwrap private key from private key and ukm (mask) + * + * @memberOf GostSign + * @method unwrap + * @instance + * @param {(CryptoOperationData|TypedArray)} baseKey Unwrapping key + * @param {(CryptoOperationData|TypedArray)} data Wrapped key + * @returns {Object} CryptoOperationData unwrapped privateKey + */ +function unwrapKey(baseKey, data) // +{ + var curve = this.curve; + if (curve) { + var q = this.q; + var x = mod(atobi(buffer(data)), q); + var y = mod(atobi(buffer(baseKey)), q); + var z = this.procreator === 'VN' ? mod(mul(x, y), q) : mod(mul(x, invMod(y, q)), q); + return bitoa(z); + } else + throw new NotSupportedError('Key wrapping GOST R 34.10-94 not supported'); +} // + +/** + * Algorithm name GOST R 34.10

+ * + * Wrap private key with private key and ukm (mask) + * + * @memberOf GostSign + * @method unwrap + * @instance + * @param {(CryptoOperationData|TypedArray)} baseKey Wrapping key + * @param {(CryptoOperationData|TypedArray)} data Key + * @returns {Object} CryptoOperationData unwrapped privateKey + */ +function wrapKey(baseKey, data) // +{ + var curve = this.curve; + if (curve) { + var q = this.q; + var x = mod(atobi(buffer(data)), q); + var y = mod(atobi(buffer(baseKey)), q); + var z = this.procreator === 'VN' ? mod(mul(x, invMod(y, q)), q) : mod(mul(x, y), q); + return bitoa(z); + } else + throw new NotSupportedError('Key wrapping GOST R 34.10-94 not supported'); +} // + +/** + * Algorithm name GOST R 34.10

+ * + * @memberOf GostSign + * @method derive + * @instance + * @private + * @param {CryptoOperationData} baseKey Key for deriviation + * @returns {CryptoOperationData} + */ +function derive(baseKey) // +{ + + var k, ukm = atobi(this.ukm); + var q = this.q; + var x = mod(atobi(buffer(baseKey)), q); + + if (this.curve) { + // 1) Let K(x,y,UKM) = ((UKM*x)(mod q)) . (y.P) (512 bit), where + // x - sender’s private key (256 bit) + // x.P - sender’s public key (512 bit) + // y - recipient’s private key (256 bit) + // y.P - recipient’s public key (512 bit) + // UKM - non-zero integer, produced as in step 2 p. 6.1 [GOSTR341001] + // P - base point on the elliptic curve (two 256-bit coordinates) + // UKM*x - x multiplied by UKM as integers + // x.P - a multiple point + var K = mulEC(this.peer_Q, mod(mul(ukm, x), q)); + k = from2(getX(K), getY(K), // This corresponds to the binary representation of (256||256) + this.bitLength); + } else { + // 1) Let K(x,y) = a^(x*y) (mod p), where + // x - sender’s private key, a^x - sender’s public key + // y - recipient’s private key, a^y - recipient’s public key + // a, p - parameters + var p = this.p, a = this.a; + k = bitoa(expMod(this.peer_y, x, p)); + } + // 2) Calculate a 256-bit hash of K(x,y,UKM): + // KEK(x,y,UKM) = gostSign (K(x,y,UKM) + return hash.call(this, k); +} // + +/** + * Algorithm name GOST R 34.10

+ * + * The deriveBits method returns length bits on baseKey. + * + * @memberOf GostSign + * @method deriveBits + * @instance + * @param {(CryptoOperationData|TypedArray)} baseKey Key for deriviation + * @param {number} length output bit-length + * @returns {CryptoOperationData} result + */ +function deriveBits(baseKey, length) // +{ + if (length < 8 || length > this.bitLength || length % 8 > 0) + throw new DataError('Length must be no more than ' + this.bitLength + ' bits and multiple of 8'); + var n = length / 8, + b = derive.call(this, baseKey), + r = new Uint8Array(n); + + r.set(new Uint8Array(b, 0, n)); + return r.buffer; +} // + +/** + * Algorithm name GOST R 34.10

+ * + * The deriveKey method returns 256 bit Key encryption key on baseKey. + * + * This algorithm creates a key encryption key (KEK) using 64 bit UKM, + * the sender’s private key, and the recipient’s public key (or the + * reverse of the latter pair + * + * @memberOf GostSign + * @method deriveKey + * @instance + * @param {(CryptoOperationData|TypedArray)} baseKey Key for deriviation + * @returns {CryptoOperationData} result + */ +function deriveKey(baseKey) // +{ + var b = derive.call(this, baseKey), + r = new Uint8Array(32); + + r.set(new Uint8Array(b, 0, 32)); + return r.buffer; +} // + + +/** + * Gost R 34.10 universal object

+ * + * References: {@link http://tools.ietf.org/html/rfc6986} and {@link http://tools.ietf.org/html/rfc5831}

+ * + * Normalized algorithm identifier common parameters: + * + *
    + *
  • name Algorithm name 'GOST R 34.10'
  • + *
  • version Algorithm version + *
      + *
    • 1994 - Old-style GOST R 34.10-94 ExpMod algorithm with GOST R 34.11-94 hash
    • + *
    • 2001 - GOST R 34.10-2001 Eliptic curve algorithm with old GOST R 34.11-94 hash
    • + *
    • 2012 - GOST R 34.10-2012 Eliptic curve algorithm with GOST R 34.11-12 hash, default mode
    • + *
    + *
  • + *
  • length Length of hash and signature. Key length == hash length for EC algorithms and 2 * hash length for ExpMod algorithm + *
      + *
    • GOST R 34.10-256 - 256 bits digest, default mode
    • + *
    • GOST R 34.10-512 - 512 bits digest only for GOST R 34.11-2012 hash
    • + *
    + *
  • + *
  • mode Algorithm mode + *
      + *
    • SIGN Digital signature mode (default)
    • + *
    • DH Diffie-Hellman key generation and key agreement mode
    • + *
    + *
  • + *
  • sBox Paramset sBox for GOST 34.11-94. Used only if version = 1994 or 2001
  • + *
+ * + * Supported algorithms, modes and parameters: + * + *
    + *
  • Sign/Verify mode (SIGN)
  • + *
  • DeriveKey/DeriveBits mode (DH) + *
      + *
    • {@link CryptoOperationData} ukm User key material. Default - random generated value
    • + *
    • {@link CryptoOperationData} public The peer's EC public key data
    • + *
    + *
  • + *
  • GenerateKey mode (SIGN and DH) version = 1994 + *
      + *
    • namedParam Paramset for key generation algorithm. If specified no additianal parameters required
    • + *
    + * Additional parameters, if namedParam not specified + *
      + *
    • modulusLength Bit length of p (512 or 1024 bits). Default = 1024
    • + *
    • p {@link CryptoOperationData} Modulus, prime number, 2^(t-1) + *
    • q {@link CryptoOperationData} Order of cyclic group, prime number, 2^254 + *
    • a {@link CryptoOperationData} Generator, integer, 1 + *
    + *
  • + *
  • GenerateKey mode (SIGN and DH) version = 2001 or 2012 + *
      + *
    • namedCurve Paramset for key generation algorithm. If specified no additianal parameters required
    • + *
    + * Additional EC parameters, if namedCurve not specified + *
      + *
    • p {@link CryptoOperationData} Prime number - elliptic curve modulus
    • + *
    • a {@link CryptoOperationData} Coefficients a of the elliptic curve E
    • + *
    • b {@link CryptoOperationData} Coefficients b of the elliptic curve E
    • + *
    • q {@link CryptoOperationData} Prime number - order of cyclic group
    • + *
    • x {@link CryptoOperationData} Base point p x-coordinate
    • + *
    • y {@link CryptoOperationData} Base point p y-coordinate
    • + *
    + *
  • + *
+ * + * @class GostSign + * @param {AlgorithmIndentifier} algorithm + */ +function GostSign(algorithm) // +{ + algorithm = algorithm || {}; + this.name = (algorithm.name || 'GOST R 34.10') + '-' + + ((algorithm.version || 2012) % 100) + '-' + (algorithm.length || 256) + + (((algorithm.mode || 'SIGN') !== 'SIGN') ? '-' + algorithm.mode : '') + + (typeof algorithm.namedParam === 'string' ? '/' + algorithm.namedParam : '') + + (typeof algorithm.namedCurve === 'string' ? '/' + algorithm.namedCurve : '') + + (typeof algorithm.sBox === 'string' ? '/' + algorithm.sBox : ''); + + var version = algorithm.version || 2012; + + // Functions + switch (algorithm.mode || 'SIGN') { + case 'SIGN': + this.sign = sign; + this.verify = verify; + this.generateKey = generateKey; + break; + case 'DH': + this.deriveBits = deriveBits; + this.deriveKey = deriveKey; + this.generateKey = generateKey; + break; + case 'MASK': + this.wrapKey = wrapKey; + this.unwrapKey = unwrapKey; + this.generateKey = generateMaskKey; + break; + } + + // Define parameters + if (version === 1994) { + // Named or parameters algorithm + var param = algorithm.param; + if (!param) + param = GostParams[this.namedParam = (algorithm.namedParam || 'S-A').toUpperCase()]; + this.modulusLength = algorithm.modulusLength || param.modulusLength || 1024; + this.p = htobi(param.p); + this.q = htobi(param.q); + this.a = htobi(param.a); + // Public key for derive + if (algorithm['public']) + this.peer_y = atobi(algorithm['public']); + } else { + // Named or parameters algorithm + var param = algorithm.curve; + if (!param) + param = ECGostParams[this.namedCurve = (algorithm.namedCurve || 'S-256-A').toUpperCase()]; + var curve = this.curve = newCurve(htobi(param.p), htobi(param.a), htobi(param.b)); + this.P = newEC(curve, + newFE(curve, htobi(param.x)), + newFE(curve, htobi(param.y))); + this.q = htobi(param.q); + // Public key for derive + if (algorithm['public']) { + var k2 = to2(algorithm['public']); + this.peer_Q = new newEC(this.curve, // This corresponds to the binary representation of (256||256) + newFE(this.curve, k2[0]), // first 32 octets contain the little-endian representation of x + newFE(this.curve, k2[1])); // and second 32 octets contain the little-endian representation of y. + } + } + + // Check bit length + var hashLen, keyLen; + if (this.curve) { + keyLen = algorithm.length || bitLength(this.q); + if (keyLen > 508 && keyLen <= 512) + keyLen = 512; + else if (keyLen > 254 && keyLen <= 256) + keyLen = 256; + else + throw new NotSupportedError('Support keys only 256 or 512 bits length'); + hashLen = keyLen; + } else { + keyLen = algorithm.modulusLength || bitLength(this.p); + if (keyLen > 1016 && keyLen <= 1024) + keyLen = 1024; + else if (keyLen > 508 && keyLen <= 512) + keyLen = 512; + else + throw new NotSupportedError('Support keys only 512 or 1024 bits length'); + hashLen = 256; + } + this.bitLength = hashLen; + this.keyLength = keyLen; + + // Algorithm proceator for result conversion + this.procreator = algorithm.procreator; + + // Hash function definition + var hash = algorithm.hash; + if (hash) { + if (typeof hash === 'string' || hash instanceof String) + hash = {name: hash}; + if (algorithm.version === 1994 || algorithm.version === 2001) { + hash.version = 1994; + hash.length = 256; + hash.sBox = algorithm.sBox || hash.sBox; + } else { + hash.version = 2012; + hash.length = hashLen; + } + hash.procreator = hash.procreator || algorithm.procreator; + + if (!GostDigest) + GostDigest = root.GostDigest; + if (!GostDigest) + throw new NotSupportedError('Object GostDigest not found'); + + this.hash = new GostDigest(hash); + } + + // Pregenerated seed for key exchange algorithms + if (algorithm.ukm) // Now don't check size + this.ukm = algorithm.ukm; + +} // + +export default GostSign; diff --git a/tests/operations/tests/Hash.mjs b/tests/operations/tests/Hash.mjs index 31ebc3a6..430ad05a 100644 --- a/tests/operations/tests/Hash.mjs +++ b/tests/operations/tests/Hash.mjs @@ -1033,6 +1033,84 @@ TestRegister.addTests([ } ] }, + { + name: "Streebog-256: Test Case 1", + input: "", + expectedOutput: "3f539a213e97c802cc229d474c6aa32a825a360b2a933a949fd925208d9ce1bb", + recipeConfig: [ + { + op: "Streebog", + args: [ + "2012", "D-A", "256" + ] + } + ] + }, + { + name: "Streebog-256: Test Case 2", + input: "The quick brown fox jumps over the lazy dog", + expectedOutput: "3e7dea7f2384b6c5a3d0e24aaa29c05e89ddd762145030ec22c71a6db8b2c1f4", + recipeConfig: [ + { + op: "Streebog", + args: [ + "2012", "D-A", "256" + ] + } + ] + }, + { + name: "Streebog-512: Test Case 1", + input: "", + expectedOutput: "8e945da209aa869f0455928529bcae4679e9873ab707b55315f56ceb98bef0a7362f715528356ee83cda5f2aac4c6ad2ba3a715c1bcd81cb8e9f90bf4c1c1a8a", + recipeConfig: [ + { + op: "Streebog", + args: [ + "2012", "D-A", "512" + ] + } + ] + }, + { + name: "Streebog-512: Test Case 2", + input: "The quick brown fox jumps over the lazy dog", + expectedOutput: "d2b793a0bb6cb5904828b5b6dcfb443bb8f33efc06ad09368878ae4cdc8245b97e60802469bed1e7c21a64ff0b179a6a1e0bb74d92965450a0adab69162c00fe", + recipeConfig: [ + { + op: "Streebog", + args: [ + "2012", "D-A", "512" + ] + } + ] + }, + { + name: "GOST R 34.11-94: Test Case 1", + input: "", + expectedOutput: "981e5f3ca30c841487830f84fb433e13ac1101569b9c13584ac483234cd656c0", + recipeConfig: [ + { + op: "Streebog", + args: [ + "1994", "D-A", "256" + ] + } + ] + }, + { + name: "GOST R 34.11-94: Test Case 2", + input: "This is message, length=32 bytes", + expectedOutput: "2cefc2f7b7bdc514e18ea57fa74ff357e7fa17d652c75f69cb1be7893ede48eb", + recipeConfig: [ + { + op: "Streebog", + args: [ + "1994", "D-A", "256" + ] + } + ] + } /*{ // This takes a LONG time to run (over a minute usually). name: "Scrypt: RFC test vector 4", input: "pleaseletmein", From 99f4091c1a026ae82b718ba57555913df8887efc Mon Sep 17 00:00:00 2001 From: n1474335 Date: Wed, 3 Jul 2019 17:23:45 +0100 Subject: [PATCH 4/5] Tidied up Streebog operation, splitting out GOST hash into a separate op. --- src/core/config/Categories.json | 5 +- src/core/lib/Hex.mjs | 6 +- src/core/operations/Streebog.mjs | 67 +++++-------------- .../vendor/{streebog => gost}/gostCipher.mjs | 0 .../vendor/{streebog => gost}/gostCoding.mjs | 0 .../vendor/{streebog => gost}/gostCrypto.mjs | 0 .../vendor/{streebog => gost}/gostDigest.mjs | 4 +- .../vendor/{streebog => gost}/gostEngine.mjs | 0 .../vendor/{streebog => gost}/gostRandom.mjs | 0 .../vendor/{streebog => gost}/gostSign.mjs | 0 tests/operations/tests/Hash.mjs | 28 +++----- 11 files changed, 33 insertions(+), 77 deletions(-) rename src/core/vendor/{streebog => gost}/gostCipher.mjs (100%) rename src/core/vendor/{streebog => gost}/gostCoding.mjs (100%) rename src/core/vendor/{streebog => gost}/gostCrypto.mjs (100%) rename src/core/vendor/{streebog => gost}/gostDigest.mjs (99%) rename src/core/vendor/{streebog => gost}/gostEngine.mjs (100%) rename src/core/vendor/{streebog => gost}/gostRandom.mjs (100%) rename src/core/vendor/{streebog => gost}/gostSign.mjs (100%) diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json index e55d3659..6b12afbb 100755 --- a/src/core/config/Categories.json +++ b/src/core/config/Categories.json @@ -106,8 +106,7 @@ "Enigma", "Bombe", "Multiple Bombe", - "Typex", - "Streebog" + "Typex" ] }, { @@ -303,6 +302,8 @@ "Snefru", "BLAKE2b", "BLAKE2s", + "GOST hash", + "Streebog", "SSDEEP", "CTPH", "Compare SSDEEP hashes", diff --git a/src/core/lib/Hex.mjs b/src/core/lib/Hex.mjs index 5ec12e86..071e9f1c 100644 --- a/src/core/lib/Hex.mjs +++ b/src/core/lib/Hex.mjs @@ -12,7 +12,7 @@ import Utils from "../Utils"; /** * Convert a byte array into a hex string. * - * @param {Uint8Array|byteArray} data + * @param {byteArray|Uint8Array|ArrayBuffer} data * @param {string} [delim=" "] * @param {number} [padding=2] * @returns {string} @@ -26,6 +26,7 @@ import Utils from "../Utils"; */ export function toHex(data, delim=" ", padding=2) { if (!data) return ""; + if (data instanceof ArrayBuffer) data = new Uint8Array(data); let output = ""; @@ -47,7 +48,7 @@ export function toHex(data, delim=" ", padding=2) { /** * Convert a byte array into a hex string as efficiently as possible with no options. * - * @param {byteArray} data + * @param {byteArray|Uint8Array|ArrayBuffer} data * @returns {string} * * @example @@ -56,6 +57,7 @@ export function toHex(data, delim=" ", padding=2) { */ export function toHexFast(data) { if (!data) return ""; + if (data instanceof ArrayBuffer) data = new Uint8Array(data); const output = []; diff --git a/src/core/operations/Streebog.mjs b/src/core/operations/Streebog.mjs index 7f054fb4..6795459c 100644 --- a/src/core/operations/Streebog.mjs +++ b/src/core/operations/Streebog.mjs @@ -6,8 +6,8 @@ import Operation from "../Operation"; import OperationError from "../errors/OperationError"; -import GostCoding from "../vendor/streebog/gostCoding"; -import GostDigest from "../vendor/streebog/gostDigest"; +import GostDigest from "../vendor/gost/gostDigest"; +import {toHexFast} from "../lib/Hex"; /** * Streebog operation @@ -21,37 +21,14 @@ class Streebog extends Operation { super(); this.name = "Streebog"; - this.module = "Crypto"; - this.description = "Streebog is a cryptographic hash function defined in the Russian national standard GOST R 34.11-2012 Information Technology \u2013 Cryptographic Information Security \u2013 Hash Function. It was created to replace an obsolete GOST hash function defined in the old standard GOST R 34.11-94, and as an asymmetric reply to SHA-3 competition by the US National Institute of Standards and Technology."; - this.infoURL = "https://en.wikipedia.org/wiki/Streebog"; - this.inputType = "string"; + this.module = "Hashing"; + this.description = "Streebog is a cryptographic hash function defined in the Russian national standard GOST R 34.11-2012 Information Technology \u2013 Cryptographic Information Security \u2013 Hash Function. It was created to replace an obsolete GOST hash function defined in the old standard GOST R 34.11-94, and as an asymmetric reply to SHA-3 competition by the US National Institute of Standards and Technology."; + this.infoURL = "https://wikipedia.org/wiki/Streebog"; + this.inputType = "ArrayBuffer"; this.outputType = "string"; this.args = [ { - "name": "Version", - "type": "option", - "value": ["2012", "1994"] - }, - // Paramset sBox for GOST 28147-89. Used only if version = 1994 - { - "name": "S-Box", - "type": "option", - "value": [ - "D-A", - "D-SC", - "E-TEST", - "E-A", - "E-B", - "E-C", - "E-D", - "E-SC", - "E-Z", - "D-TEST" - ] - }, - // 512 bits digest, valid only for algorithm "Streebog" - { - "name": "Length", + "name": "Size", "type": "option", "value": ["256", "512"] } @@ -59,34 +36,22 @@ class Streebog extends Operation { } /** - * @param {string} input + * @param {ArrayBuffer} input * @param {Object[]} args * @returns {string} */ run(input, args) { try { - const version = parseInt(args[0], 10); - let sBox = args[1]; - let length = parseInt(args[2], 10); + const length = parseInt(args[0], 10); + const gostDigest = new GostDigest({ + name: "GOST R 34.11", + version: 2012, + length: length + }); - // 1994 old-style 256 bits digest based on GOST 28147-89 - if (version === 1994) { - length = 256; - } - - if (version === 2012) { - sBox = ""; - } - - const gostDigest = new GostDigest({name: "GOST R 34.11", version, sBox, length }); - const gostCoding = new GostCoding(); - - const decode = gostCoding.Chars.decode(input); - const hexEncode = gostCoding.Hex.encode(gostDigest.digest(decode)); - - return hexEncode.replace(/[^\-A-Fa-f0-9]/g, "").toLowerCase(); + return toHexFast(gostDigest.digest(input)); } catch (err) { - throw new OperationError(`Invalid Input, Details ${err.message}`); + throw new OperationError(err); } } diff --git a/src/core/vendor/streebog/gostCipher.mjs b/src/core/vendor/gost/gostCipher.mjs similarity index 100% rename from src/core/vendor/streebog/gostCipher.mjs rename to src/core/vendor/gost/gostCipher.mjs diff --git a/src/core/vendor/streebog/gostCoding.mjs b/src/core/vendor/gost/gostCoding.mjs similarity index 100% rename from src/core/vendor/streebog/gostCoding.mjs rename to src/core/vendor/gost/gostCoding.mjs diff --git a/src/core/vendor/streebog/gostCrypto.mjs b/src/core/vendor/gost/gostCrypto.mjs similarity index 100% rename from src/core/vendor/streebog/gostCrypto.mjs rename to src/core/vendor/gost/gostCrypto.mjs diff --git a/src/core/vendor/streebog/gostDigest.mjs b/src/core/vendor/gost/gostDigest.mjs similarity index 99% rename from src/core/vendor/streebog/gostDigest.mjs rename to src/core/vendor/gost/gostDigest.mjs index 0ead2b79..2404317e 100644 --- a/src/core/vendor/streebog/gostDigest.mjs +++ b/src/core/vendor/gost/gostDigest.mjs @@ -1192,8 +1192,8 @@ function GostDigest(algorithm) // // Define chiper algorithm this.sBox = (algorithm.sBox || (algorithm.procreator === 'SC' ? 'D-SC' : 'D-A')).toUpperCase(); - if (!GostCipher) - GostCipher = root.GostCipher; + //if (!GostCipher) + // GostCipher = root.GostCipher; if (!GostCipher) throw new NotSupportedError('Object GostCipher not found'); diff --git a/src/core/vendor/streebog/gostEngine.mjs b/src/core/vendor/gost/gostEngine.mjs similarity index 100% rename from src/core/vendor/streebog/gostEngine.mjs rename to src/core/vendor/gost/gostEngine.mjs diff --git a/src/core/vendor/streebog/gostRandom.mjs b/src/core/vendor/gost/gostRandom.mjs similarity index 100% rename from src/core/vendor/streebog/gostRandom.mjs rename to src/core/vendor/gost/gostRandom.mjs diff --git a/src/core/vendor/streebog/gostSign.mjs b/src/core/vendor/gost/gostSign.mjs similarity index 100% rename from src/core/vendor/streebog/gostSign.mjs rename to src/core/vendor/gost/gostSign.mjs diff --git a/tests/operations/tests/Hash.mjs b/tests/operations/tests/Hash.mjs index 430ad05a..1a4688c8 100644 --- a/tests/operations/tests/Hash.mjs +++ b/tests/operations/tests/Hash.mjs @@ -1040,9 +1040,7 @@ TestRegister.addTests([ recipeConfig: [ { op: "Streebog", - args: [ - "2012", "D-A", "256" - ] + args: ["256"] } ] }, @@ -1053,9 +1051,7 @@ TestRegister.addTests([ recipeConfig: [ { op: "Streebog", - args: [ - "2012", "D-A", "256" - ] + args: ["256"] } ] }, @@ -1066,9 +1062,7 @@ TestRegister.addTests([ recipeConfig: [ { op: "Streebog", - args: [ - "2012", "D-A", "512" - ] + args: ["512"] } ] }, @@ -1079,9 +1073,7 @@ TestRegister.addTests([ recipeConfig: [ { op: "Streebog", - args: [ - "2012", "D-A", "512" - ] + args: ["512"] } ] }, @@ -1091,10 +1083,8 @@ TestRegister.addTests([ expectedOutput: "981e5f3ca30c841487830f84fb433e13ac1101569b9c13584ac483234cd656c0", recipeConfig: [ { - op: "Streebog", - args: [ - "1994", "D-A", "256" - ] + op: "GOST hash", + args: ["D-A"] } ] }, @@ -1104,10 +1094,8 @@ TestRegister.addTests([ expectedOutput: "2cefc2f7b7bdc514e18ea57fa74ff357e7fa17d652c75f69cb1be7893ede48eb", recipeConfig: [ { - op: "Streebog", - args: [ - "1994", "D-A", "256" - ] + op: "GOST hash", + args: ["D-A"] } ] } From 09bea6e2319fb1023882b1e613a3620a153a028d Mon Sep 17 00:00:00 2001 From: n1474335 Date: Wed, 3 Jul 2019 17:24:11 +0100 Subject: [PATCH 5/5] Added 'GOST Hash' operation --- src/core/operations/GOSTHash.mjs | 71 ++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 src/core/operations/GOSTHash.mjs diff --git a/src/core/operations/GOSTHash.mjs b/src/core/operations/GOSTHash.mjs new file mode 100644 index 00000000..c7d4d403 --- /dev/null +++ b/src/core/operations/GOSTHash.mjs @@ -0,0 +1,71 @@ +/** + * @author n1474335 [n1474335@gmail.com] + * @copyright Crown Copyright 2019 + * @license Apache-2.0 + */ + +import Operation from "../Operation"; +import OperationError from "../errors/OperationError"; +import GostDigest from "../vendor/gost/gostDigest"; +import {toHexFast} from "../lib/Hex"; + +/** + * GOST hash operation + */ +class GOSTHash extends Operation { + + /** + * GOSTHash constructor + */ + constructor() { + super(); + + this.name = "GOST hash"; + this.module = "Hashing"; + this.description = "The GOST hash function, defined in the standards GOST R 34.11-94 and GOST 34.311-95 is a 256-bit cryptographic hash function. It was initially defined in the Russian national standard GOST R 34.11-94 Information Technology – Cryptographic Information Security – Hash Function. The equivalent standard used by other member-states of the CIS is GOST 34.311-95.

This function must not be confused with a different Streebog hash function, which is defined in the new revision of the standard GOST R 34.11-2012.

The GOST hash function is based on the GOST block cipher."; + this.infoURL = "https://wikipedia.org/wiki/GOST_(hash_function)"; + this.inputType = "ArrayBuffer"; + this.outputType = "string"; + this.args = [ + { + "name": "S-Box", + "type": "option", + "value": [ + "D-A", + "D-SC", + "E-TEST", + "E-A", + "E-B", + "E-C", + "E-D", + "E-SC", + "E-Z", + "D-TEST" + ] + } + ]; + } + + /** + * @param {ArrayBuffer} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + try { + const sBox = args[1]; + const gostDigest = new GostDigest({ + name: "GOST R 34.11", + version: 1994, + sBox: sBox + }); + + return toHexFast(gostDigest.digest(input)); + } catch (err) { + throw new OperationError(err); + } + } + +} + +export default GOSTHash;