/** * 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. * * * @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'); } } // export default GostDigest;