/** * @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.mjs'; import GostDigest from './gostDigest.mjs'; 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 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: * * * * Supported algorithms, modes and parameters: * * * * @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;