├── min ├── gostRandom.min.js ├── gostEngine.min.js ├── gostCoding.min.js ├── gostCert.min.js ├── gostCMS.min.js ├── gostCrypto.min.js ├── gostCipher.min.js └── gostSign.min.js ├── README.md ├── gostRandom.js ├── gostSign.test.js ├── gostViewer.js ├── gostCipher.test.js ├── gostDigest.test.js └── gostEngine.js /min/gostRandom.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | 2014-2016, Rudolf Nickolaev. All rights reserved. 3 | */ 4 | (function(b,d){"function"===typeof define&&define.amd?define(d):"object"===typeof exports?module.exports=d():b.GostRandom=d()})(this,function(){function b(){}var d=this.crypto||this.msCrypto,g=this.TypeMismatchError||Error,h=this.QuotaExceededError||Error,f={seed:new Uint8Array(1024),getIndex:0,setIndex:0,set:function(a){1024<=this.setIndex&&(this.setIndex=0);this.seed[this.setIndex++]=a},get:function(){1024<=this.getIndex&&(this.getIndex=0);return this.seed[this.getIndex++]}};if("undefiend"!==typeof document){try{document.addEventListener("mousemove", 5 | function(a){f.set((new Date).getTime()&255^(a.clientX||a.pageX)&255^(a.clientY||a.pageY)&255)},!1)}catch(k){}try{document.addEventListener("keydown",function(a){f.set((new Date).getTime()&255^a.keyCode&255)},!1)}catch(l){}}b.prototype.getRandomValues=function(a){if(!a.byteLength)throw new g("Array is not of an integer type (Int8Array, Uint8Array, Int16Array, Uint16Array, Int32Array, or Uint32Array)");if(65536 39 | if (typeof define === 'function' && define.amd) { 40 | define(factory); 41 | } else if (typeof exports === 'object') { 42 | module.exports = factory(); 43 | } else { 44 | root.GostRandom = factory(); 45 | } 46 | // 47 | 48 | }(this, function () { 49 | 50 | /** 51 | * The gostCrypto provide general purpose cryptographic functionality for 52 | * GOST standards including a cryptographically strong pseudo-random number 53 | * generator seeded with truly random values. 54 | * 55 | * @Class GostRandom 56 | * 57 | */ // 58 | 59 | var root = this; 60 | var rootCrypto = root.crypto || root.msCrypto; 61 | 62 | var TypeMismatchError = root.TypeMismatchError || Error; 63 | var QuotaExceededError = root.QuotaExceededError || Error; 64 | 65 | // Initialize mouse and time counters for random generator 66 | var randomRing = { 67 | seed: new Uint8Array(1024), 68 | getIndex: 0, 69 | setIndex: 0, 70 | set: function (x) { 71 | if (this.setIndex >= 1024) 72 | this.setIndex = 0; 73 | this.seed[this.setIndex++] = x; 74 | }, 75 | get: function () { 76 | if (this.getIndex >= 1024) 77 | this.getIndex = 0; 78 | return this.seed[this.getIndex++]; 79 | } 80 | }; 81 | 82 | if (typeof document !== 'undefiend') { 83 | try { 84 | // Mouse move event to fill random array 85 | document.addEventListener('mousemove', function (e) { 86 | randomRing.set((new Date().getTime() & 255) ^ 87 | ((e.clientX || e.pageX) & 255) ^ 88 | ((e.clientY || e.pageY) & 255)); 89 | }, false); 90 | } catch (e) { 91 | } 92 | 93 | try { 94 | // Keypress event to fill random array 95 | document.addEventListener('keydown', function (e) { 96 | randomRing.set((new Date().getTime() & 255) ^ 97 | (e.keyCode & 255)); 98 | }, false); 99 | } catch (e) { 100 | } 101 | } // 102 | 103 | function GostRandom() { 104 | } 105 | 106 | /** 107 | * The getRandomValues method generates cryptographically random values.

108 | * 109 | * Random generator based on JavaScript Web Crypto random genereator 110 | * (if it is possible) or Math.random mixed with time and parameters of 111 | * mouse and keyboard events 112 | * 113 | * @memberOf GostRandom 114 | * @param {(ArrayBuffer|ArrayBufferView)} array Destination buffer for random data 115 | */ 116 | GostRandom.prototype.getRandomValues = function (array) // 117 | { 118 | 119 | if (!array.byteLength) 120 | throw new TypeMismatchError('Array is not of an integer type (Int8Array, Uint8Array, Int16Array, Uint16Array, Int32Array, or Uint32Array)'); 121 | 122 | if (array.byteLength > 65536) 123 | throw new QuotaExceededError('Byte length of array can\'t be greate then 65536'); 124 | 125 | var u8 = new Uint8Array(array.buffer, array.byteOffset, array.byteLength); 126 | if (rootCrypto && rootCrypto.getRandomValues) { 127 | // Native window cryptographic interface 128 | rootCrypto.getRandomValues(u8); 129 | } else { 130 | // Standard Javascript method 131 | for (var i = 0, n = u8.length; i < n; i++) 132 | u8[i] = Math.floor(256 * Math.random()) & 255; 133 | } 134 | 135 | // Mix bio randomizator 136 | for (var i = 0, n = u8.length; i < n; i++) 137 | u8[i] = u8[i] ^ randomRing.get(); 138 | return array; 139 | }; // 140 | 141 | return GostRandom; 142 | 143 | })); 144 | 145 | -------------------------------------------------------------------------------- /min/gostCoding.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | 2014-2016, Rudolf Nickolaev. All rights reserved. 3 | */ 4 | (function(A,t){"function"===typeof define&&define.amd?define(["gostCrypto"],t):"object"===typeof exports?module.exports=t(require("gostCrypto")):A.GostCoding=t(A.gostCrypto)})(this,function(A){function t(e){if(e instanceof y)return e;if(e&&e.buffer&&e.buffer instanceof y)return 0===e.byteOffset&&e.byteLength===e.buffer.byteLength?e.buffer:(new Uint8Array(new Uint8Array(e,e.byteOffset,e.byteLength))).buffer;throw new u("CryptoOperationData required");}function s(){}var u=this.DataError||this.Error, 5 | y=this.ArrayBuffer,B=this.Date,C={decode:function(e){e=e.replace(/[^A-Za-z0-9\+\/]/g,"");for(var l=e.length,c=3*l+1>>2,p=new Uint8Array(c),d,a=0,r=0,g=0;gh?h-65:96h?h-71:47h?h+4:43===h?62:47===h?63:0,a=a|h<<18-6*d;if(3===d||1===l-g){for(d=0;3>d&&r>>(16>>>d&24)&255;a=0}}return p.buffer},encode:function(e){e=new Uint8Array(t(e));for(var l=2,c="",p=e.length,d=0,a=0;a>>l&24),2===l||1===p-a){for(var r=18;0<=r;r-=6)var g=d>>>r&63,g=26>g?g+65:52>g?g+71:62>g?g-4:62===g?43:63===g?47:65,c=c+String.fromCharCode(g);d=0}return c.substr(0,c.length-2+l)+(2===l?"":1===l?"=":"==")}};s.prototype.Base64=C;var w=function(){var e={1026:128,1027:129,8218:130,1107:131,8222:132,8230:133,8224:134,8225:135,8364:136,8240:137,1033:138,8249:139,1034:140,1036:141,1035:142,1039:143,1106:144,8216:145,8217:146,8220:147,8221:148,8226:149,8211:150,8212:151,8482:153,1113:154,8250:155,1114:156, 7 | 1116:157,1115:158,1119:159,160:160,1038:161,1118:162,1032:163,164:164,1168:165,166:166,167:167,1025:168,169:169,1028:170,171:171,172:172,173:173,174:174,1031:175,176:176,177:177,1030:178,1110:179,1169:180,181:181,182:182,183:183,1105:184,8470:185,1108:186,187:187,1112:188,1029:189,1109:190,1111:191},l={},c;for(c in e)l[e[c]]=c;return{decode:function(c,d){d=(d||"win1251").toLowerCase().replace("-","");for(var a=[],r=0,g=c.length;rh?a.push(h):(2048>h? 8 | a.push(192+(h>>>6)):(65536>h?a.push(224+(h>>>12)):(2097152>h?a.push(240+(h>>>18)):(67108864>h?a.push(248+(h>>>24)):(a.push(252+(h>>>30)),a.push(128+(h>>>24&63))),a.push(128+(h>>>18&63))),a.push(128+(h>>>12&63))),a.push(128+(h>>>6&63))),a.push(128+(h&63)));else if("unicode"===d||"ucs2"===d||"utf16"===d)if(55296>h||57344<=h&&65536>=h)a.push(h>>>8),a.push(h&255);else{if(65536<=h&&1114112>h){var h=h-65536,b=((1047552&h)>>10)+55296,h=(1023&h)+56320;a.push(b>>>8);a.push(b&255);a.push(h>>>8);a.push(h&255)}}else"utf32"=== 9 | d||"ucs4"===d?(a.push(h>>>24&255),a.push(h>>>16&255),a.push(h>>>8&255),a.push(h&255)):"win1251"===d?(128<=h&&(h=1040<=h&&1104>h?h-848:e[h]||0),a.push(h)):a.push(h&255)}return(new Uint8Array(a)).buffer},encode:function(e,d){d=(d||"win1251").toLowerCase().replace("-","");for(var a=[],c=new Uint8Array(t(e)),g=0,h=c.length;gb&&g+5>248&&252>b&&g+4>240&&248>b&&g+3b&&g+2b&&g+1b)var n=b-55296<<10,b=c[++g],b=(b<<8)+c[++g],b=n+(b-56320)+65536}else"utf32"===d||"ucs4"===d?(b=(b<<8)+c[++g],b=(b<<8)+c[++g],b=(b<<8)+c[++g]):"win1251"===d&&128<=b&&(b=192<= 11 | b&&256>b?b+848:l[b]||0);a.push(String.fromCharCode(b))}return a.join("")}}}();s.prototype.Chars=w;var F={decode:function(e,l){e=e.replace(/[^A-fa-f0-9]/g,"");var c=Math.ceil(e.length/2),p=new Uint8Array(c);e=(0l.toLowerCase().indexOf("little")))for(var d=0;dl.toLowerCase().indexOf("little")))for(var a=0;an;n++)var z=8*m+n,k=(k<<1)+(z>>=7;while(f);for(n=k.length-1;0<=n;--n)b.push(k[n]+(0===n?0:128))}b=new Uint8Array(b);break;case 12:b=w.decode(a,"utf8");break;case 18:case 22:case 19:case 20:case 21:case 25:case 26:case 27:m=0;for(f=a.length;mg)d.push(l|g&31);else{l|=31;d.push(l);f=g;g=[];do g.push(f&127),f>>>=7;while(f);for(n=g.length-1;0<=n;--n)d.push(g[n]+(0===n?0:128))}if(h&&"CER"===p)d.push(128);else if(p=b.length,127>>=8;while(h);d.push(p.length+128);for(n=p.length-1;0<=n;--n)d.push(p[n])}else d.push(p);c=c.header=new Uint8Array(d);p=new Uint8Array(c.length+b.length);p.set(c,0);p.set(b,c.length); 21 | return p}function l(c,e){var d=e||0,a=d,r,g,h,b,n,k,q;if(c.object)r=c.tagNumber,g=c.tagClass,h=c.tagConstructed,d=c.content,b=c.header,n=c.object instanceof y?new Uint8Array(c.object):null,k=c.object instanceof Array?c.object:null,q=n&&n.length||null;else{b=c[d++];r=b&31;g=b>>6;h=0!==(b&32);if(31===r){r=0;do{if(9007199254740864s;++s)f.push(q>>s&1?"1":"0");a=0}f= 25 | f.reverse().join("")}break;case 4:f=(new Uint8Array(n)).buffer;break;case 6:f="";for(m=v=x=0;mx?40>x?0:1:2,f=k+"."+(x-40*k)):f+="."+x.toString(),v=x=0);if(0k[1]?2E3:1900);q=new B(k[1],+k[2]-1,+k[3],+(k[4]||0),+(k[5]||0),+(k[6]||0),+(k[7]|| 27 | 0));a=q.getTimezoneOffset();if(k[8]||23===r)"Z"!==k[8].toUpperCase()&&k[9]&&(a+=parseInt(k[9])),q.setMinutes(q.getMinutes()-a);q.original=f;f=q}else f=(new Uint8Array(n)).buffer}else f=k;return{tagConstructed:h,tagClass:g,tagNumber:r,header:b,content:d,object:f}}return{encode:function(c,l,d){return e(c,l,d).buffer},decode:function(c){return l(c.object?c:new Uint8Array(t(c)),0)}}}();s.prototype.BER=E;s.prototype.PEM={encode:function(e,l){return(l?"-----BEGIN "+l.toUpperCase()+"-----\r\n":"")+C.encode(e instanceof 28 | y?e:E.encode(e))+(l?"\r\n-----END "+l.toUpperCase()+"-----":"")},decode:function(e,l,c,p){var d=/([A-Za-z0-9\+\/\s\=]+)/g.exec(e);d[1].length!==e.length&&(d=!1);!d&&l&&(d=(new RegExp("-----\\s?BEGIN "+l.toUpperCase()+"-----([A-Za-z0-9\\+\\/\\s\\=]+)-----\\s?END "+l.toUpperCase()+"-----","g")).exec(e));d||(d=/-----\s?BEGIN [A-Z0-9\s]+-----([A-Za-z0-9\+\/\s\=]+)-----\s?END [A-Z0-9\s]+-----/g.exec(e));e=d&&d[1+(p||0)];if(!e)throw new u("Not valid PEM format");e=C.decode(e);c&&(e=E.decode(e));return e}}; 29 | A&&(A.coding=new s);return s}); 30 | -------------------------------------------------------------------------------- /min/gostCert.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | 2014-2016, Rudolf Nickolaev. All rights reserved. 3 | */ 4 | (function(m,v){"function"===typeof define&&define.amd?define(["gostCrypto","gostASN1"],v):"object"===typeof exports?module.exports=v(require("gostCrypto"),require("gostASN1")):m.GostCert=v(m.gostCrypto,m.GostASN1)})(this,function(m){function v(a){for(var b=1,c=arguments.length;bb.date.getTime())}function C(a,b,c){a={subject:a.issuer,date:c};if(b=b&&b.authorityKeyIdentifier)a.subjectKeyIdentifier=b.keyIdentifier,b.authorityCertIssuer&&b.authorityCertIssuer[0]&&b.authorityCertSerialNumber&& 7 | (a.issuer=b.authorityCertIssuer[0],a.serialNumber=b.authorityCertSerialNumber);return a}function A(a,b){for(var c=[],d=0,e=a.length;dc.getTime()||d.notAfter.getTime()<=c.getTime())throw Error("The certificate has not yet started or expired");for(var b in e)if(e[b].critical&&0>"authorityKeyIdentifier subjectKeyIdentifier keyUsage certificatePolicies policyMappings basicConstraints nameConstraints policyConstraints extKeyUsage".split(" ").indexOf(b))throw Error("The critical extension '"+ 18 | b+"' is unrecognized");b=C(d,e,d.notBefore);!a&&x(d,b)&&(a=d);if(a){if(!x(a,b)||!a.checkUsage("keyCertSign",d.notBefore))throw Error("The issuer's certificate is not valid");return a.verifySignature(d.tbsCertificate.encode(),d.signatureValue,d.signatureAlgorithm)}return!0}).then(function(a){if(!a)throw Error("The certificate has invalid signature");if(b){if(!H(b,{issuer:d.issuer,date:c}))throw Error("The issuer's CRL is not valid");if(b.isRevoked(d.serialNumber))throw Error("The certificate is revoked"); 19 | }return d})},verifySignature:function(a,b,c){return this.getPublicKey().then(function(d){return k.verify(c,d,b,a)})},checkUsage:function(a,b){var c=this.extensions;b=b||w();return this.notBefore.getTime()<=b.getTime()&&this.notAfter.getTime()>b.getTime()&&(!c||!(0<["keyCertSign","cRLSign"].indexOf(a)&&c.basicConstraints&&!c.basicConstraints.cA||c.keyUsage&&0>c.keyUsage.indexOf(a)&&c.extKeyUsage&&0>c.extKeyUsage.indexOf(a)))}});r.prototype.X509=u;var z=function(a){z.super.call(this,a);this.version|| 20 | (this.version=1);this.revokedCertificates||(this.revokedCertificates=[]);this.thisUpdate||(this.thisUpdate=w())};t(h.CertificateList,z,{sign:function(a,b){var c=this;return(new n(q)).then(function(){if(!a)throw Error("The issuer's private key is not defined");if(!b)throw Error("The issuer's certificate is not defined");if(!c.issuer)c.issuer=b.issuer;else if(!B(c.issuer,b.issuer))throw Error("The CRL prototype and authority certificate have different issuers");if(!b.checkUsage("cRLSign",c.thisUpdate))throw Error("The issuer's certificate is not valid for signing a CRL"); 21 | var d=b.getProvider()||s[l.providerName];c.signature||(c.signature=d.signature);c.signatureAlgorithm=c.signature;c.issuer=b.subject;c.crlExtensions||(c.crlExtensions={});var d=c.crlExtensions,e=b.extensions;e&&e.subjectKeyIdentifier&&(d.authorityKeyIdentifier={keyIdentifier:e.subjectKeyIdentifier,authorityCertIssuer:[b.issuer],authorityCertSerialNumber:b.serialNumber});d.cRLNumber=d.cRLNumber||0;return k.importKey("pkcs8",a.encode(),a.privateKeyAlgorithm,!1,["sign"])}).then(function(a){return k.sign(c.signatureAlgorithm, 22 | a,c.tbsCertList.encode())}).then(function(a){c.signatureValue=a;return c})},verify:function(a,b){var c=this,d=c.crlExtensions;return(new n(q)).then(function(){b=b||w();if(!c.thisUpdate.getTime()>b.getTime())throw Error("The CRL has not yet started");if(a){if(!x(a,C(c,d,c.thisUpdate))||!a.checkUsage("cRLSign",c.thisUpdate))throw Error("The issuer's certificate is not valid");if(!c.signatureValue||!c.signatureAlgorithm)throw Error("The has no signature");return a.verifySignature(c.tbsCertList.encode(), 23 | c.signatureValue,c.signatureAlgorithm)}}).then(function(a){if(!a)throw Error("The CRL has invalid signature");return c})},isRevoked:function(a,b){var c=this.revokedCertificates;b=b||w();for(var d=0;d=c[d].revocationDate.getTime()&&G(c[d].userCertificate,a))return!0;return!1}});r.prototype.CRL=z;t(h.CertificationRequest,K,{generate:function(a){var b=this,c,d;(d=a?s[a]:this.getProvider()||s[l.providerName])&&(a=v(d.publicKey,{privateKey:d.privateKey}));return(new n(q)).then(function(){return k.generateKey(a, 24 | "true",["sign","verify"])}).then(function(a){c=a.privateKey;return k.exportKey("spki",a.publicKey)}).then(function(a){b.subjectPublicKeyInfo=new h.SubjectPublicKeyInfo(a);return k.exportKey("pkcs8",c)}).then(function(a){c=new h.PrivateKeyInfo(a);return b.sign(c)}).then(function(){return c})},getProvider:function(){return E(this.subjectPublicKeyInfo.algorithm)},sign:function(a){var b=this,c=b.subjectPublicKeyInfo;return(new n(q)).then(function(){if(!c||!c.algorithm||"noSignature"===c.algorithm)throw Error("Key pair was not generated for the certificate"); 25 | if(!a)throw Error("The private key is not defined");var d=E(c.algorithm)||s[l.providerName];b.signatureAlgorithm=d.signature;return k.importKey("pkcs8",a.encode(),a.privateKeyAlgorithm,!1,["sign"])}).then(function(a){return k.sign(b.signatureAlgorithm,a,b.requestInfo.encode())}).then(function(a){b.signatureValue=a;return b})},verify:function(){var a=this,b=a.subjectPublicKeyInfo;return(new n(q)).then(function(){return k.importKey("spki",b.encode(),b.algorithm,"false",["verify"])}).then(function(b){return k.verify(a.signatureAlgorithm, 26 | b,a.signatureValue,a.requestInfo.encode())}).then(function(b){if(!b)throw Error("The certification request has invalid signature");return a})}});r.prototype.Request=K;t(y,L,{getCertificates:function(a){return A(this.certificates,a)},getCRLs:function(a){return I(this.certificates,a)},load:function(a){var b=new h.ContentInfo(a);a=b.certificates;for(var b=b.crls,c=0;c' + (s || ' ') + ''}); 60 | } else { 61 | if (typeof document !== 'undefined') { 62 | var el = document.createElement(h ? 'h3' : 'div'); 63 | el.innerHTML = s || ' '; 64 | (document.getElementById('output') || document.body).appendChild(el); 65 | } 66 | if (typeof console !== 'undefined') 67 | console.log((s || '') + (h ? '' : '\n')); 68 | } 69 | } 70 | 71 | function perform(id, algorithm, message, privateKey, publicKey, output) { 72 | var Hex = gostCoding.Hex; 73 | if (algorithm.ukm) 74 | (algorithm.ukm = Hex.decode(algorithm.ukm, true)); 75 | else 76 | output = false; 77 | 78 | var cipher = new GostSign(algorithm); 79 | var result = 'Test ' + ' ' + ('0' + id).slice(-2) + ' ' + (cipher.name + ' ' + new Array(61).join('.')).substring(0, 60) + ' '; 80 | var data = typeof message === 'string' ? Hex.decode(message, true) : message; 81 | 82 | if (!privateKey) { 83 | var keyPair = cipher.generateKey(); 84 | privateKey = keyPair.privateKey; 85 | publicKey = keyPair.publicKey; 86 | output = false; 87 | } else { 88 | privateKey = Hex.decode(privateKey, true); 89 | publicKey = Hex.decode(publicKey, true); 90 | } 91 | 92 | try { 93 | var start, signed, verified; 94 | start = (new Date).getTime(); 95 | var out = Hex.encode(cipher.sign(privateKey, data), true); 96 | var test = 0 + (output && out.replace(/[^\-A-Fa-f0-9]/g, '').toLowerCase() !== output.toLowerCase()); 97 | if (!test) { 98 | signed = (new Date).getTime(); 99 | test = 0 + (!cipher.verify(publicKey, Hex.decode(out, true), data)); 100 | verified = (new Date).getTime(); 101 | if (!test) 102 | result += 'PASSED Sign ' + (signed - start) / 1000 + ' sec, Verify ' + (verified - signed) / 1000 + ' sec'; 103 | else 104 | result += 'FAILED - Verify return (false)'; 105 | } else 106 | result += 'FAILED - Sign expected ' + output.toLowerCase() + " got " + out.toLowerCase(); 107 | } catch (e) { 108 | result += 'FAILED - Throw error: ' + e.message; 109 | } 110 | 111 | println(result); 112 | return test; 113 | } 114 | 115 | function performDerive(id, algorithm) { 116 | var ukm = algorithm.ukm; 117 | delete algorithm.ukm; 118 | var cipher = new GostSign(algorithm); 119 | var result = 'Test ' + ' ' + ('0' + id).slice(-2) + ' ' + (cipher.name + ' ' + new Array(61).join('.')).substring(0, 60) + ' '; 120 | var keyPair1 = cipher.generateKey(), 121 | keyPair2 = cipher.generateKey(), 122 | privateKey1 = keyPair1.privateKey, 123 | publicKey1 = keyPair1.publicKey, 124 | privateKey2 = keyPair2.privateKey, 125 | publicKey2 = keyPair2.publicKey; 126 | 127 | try { 128 | if (ukm) 129 | (algorithm.ukm = gostCoding.Hex.decode(ukm)); 130 | 131 | var start = (new Date).getTime(); 132 | algorithm.public = publicKey2; 133 | cipher = new GostSign(algorithm); 134 | var kek1 = gostCoding.Hex.encode(cipher.deriveKey(privateKey1)); 135 | var finish = (new Date).getTime(); 136 | 137 | algorithm.public = publicKey1; 138 | cipher = new GostSign(algorithm); 139 | var kek2 = gostCoding.Hex.encode(cipher.deriveKey(privateKey2)); 140 | 141 | var test = 0 + (kek1 !== kek2); 142 | if (!test) 143 | result += 'PASSED DeriveKey ' + (finish - start) / 1000 + ' sec'; 144 | else 145 | result += 'PASSED DeriveKey - one side got ' + kek1 + ' but other side got ' + kek2; 146 | } catch (e) { 147 | result += 'FAILED - Throw error: ' + e.message; 148 | } 149 | println(result); 150 | return test; 151 | } 152 | 153 | return function() { 154 | 155 | GostCoding = GostCoding || root.GostCoding; 156 | gostCoding = new GostCoding(); 157 | GostSign = GostSign || root.GostSign; 158 | 159 | // GOST R 34.10 tests 160 | var tests = 0, i = 0; 161 | println('GOST R 34.10-94 TEST', true); 162 | 163 | tests += perform(++i, { 164 | name: 'GOST R 34.10', 165 | version: 1994, 166 | namedParam: 'S-TEST', 167 | ukm: '90F3A564439242F5186EBB224C8E223811B7105C64E4F5390807E6362DF4C72A', 168 | }, '3534454132454236443134453437313943363345374143423445413631454230', 169 | '3036314538303830343630454235324435324234314132373832433138443046', 170 | 'ee1902a40692d273edc1b5adc55f91128e35f9d165fa9901caf00d27018ba6df324519c11a6e272526589cd6e6a2eddaafe1c3081259be9fcee667a2701f4352', 171 | '3F0DD5D4400D47C08E4CE505FF7434B6DBF729592E37C74856DAB85115A609553E5F895E276D81D2D52C0763270A458157B784C57ABDBD807BC44FD43A32AC06'); 172 | 173 | println(); 174 | println('TOTAL ' + (tests ? tests + ' ERRORS' : 'OK')); 175 | println(); 176 | 177 | var tests2 = 0; 178 | i = 0; 179 | println('GOST R 34.10-2012 TEST', true); 180 | 181 | tests2 += perform(++i, { 182 | name: 'GOST R 34.10', 183 | namedCurve: 'S-256-TEST', 184 | ukm: '77105C9B20BCD3122823C8CF6FCC7B956DE33814E95B7FE64FED924594DCEAB3', 185 | }, '2DFBC1B372D89A1188C09C52E0EEC61FCE52032AB1022E8E67ECE6672B043EE5', 186 | '7A929ADE789BB9BE10ED359DD39A72C11B60961F49397EEE1D19CE9891EC3B28', 187 | '26F1B489D6701DD185C8413A977B3CBBAF64D1C593D26627DFFB101A87FF77DA7F2B49E270DB6D90D8595BEC458B50C58585BA1D4E9B788F6689DBD8E56FD80B', 188 | '01456C64BA4642A1653C235A98A60249BCD6D3F746B631DF928014F6C5BF9C4041AA28D2F1AB148280CD9ED56FEDA41974053554A42767B83AD043FD39DC0493'); 189 | 190 | tests2 += perform(++i, { 191 | name: 'GOST R 34.10', 192 | namedCurve: 'T-512-TEST', 193 | ukm: '359E7F4B1410FEACC570456C6801496946312120B39D019D455986E364F365886748ED7A44B3E794434006011842286212273A6D14CF70EA3AF71BB1AE679F1', 194 | }, '3754F3CFACC9E0615C4F4A7C4D8DAB531B09B6F9C170C533A71D147035B0C5917184EE536593F4414339976C647C5D5A407ADEDB1D560C4FC6777D2972075B8C', 195 | 'BA6048AADAE241BA40936D47756D7C93091A0E8514669700EE7508E508B102072E8123B2200A0563322DAD2827E2714A2636B7BFD18AADFC62967821FA18DD4', 196 | '37C7C90CD40B0F5621DC3AC1B751CFA0E2634FA0503B3D52639F5D7FB72AFD61EA199441D943FFE7F0C70A2759A3CDB84C114E1F9339FDF27F35ECA93677BEEC115DC5BC96760C7B48598D8AB9E740D4C4A85A65BE33C1815B5C320C854621DD5A515856D13314AF69BC5B924C8B4DDFF75C45415C1D9DD9DD33612CD530EFE1', 197 | '1081B394696FFE8E6585E7A9362D26B6325F56778AADBC081C0BFBE933D52FF5823CE288E8C4F362526080DF7F70CE406A6EEB1F56919CB92A9853BDE73E5B4A2F86FA60A081091A23DD795E1E3C689EE512A3C82EE0DCC2643C78EEA8FCACD35492558486B20F1C9EC197C90699850260C93BCBCD9C5C3317E19344E173AE36'); 198 | 199 | // Free random generator 200 | tests2 += perform(++i, { 201 | name: 'GOST R 34.10', 202 | namedCurve: 'S-256-TEST', 203 | }, '2DFBC1B372D89A1188C09C52E0EEC61FCE52032AB1022E8E67ECE6672B043EE5', 204 | '7A929ADE789BB9BE10ED359DD39A72C11B60961F49397EEE1D19CE9891EC3B28', 205 | '26F1B489D6701DD185C8413A977B3CBBAF64D1C593D26627DFFB101A87FF77DA7F2B49E270DB6D90D8595BEC458B50C58585BA1D4E9B788F6689DBD8E56FD80B'); 206 | 207 | // Free key & random generator 208 | tests2 += perform(++i, { 209 | name: 'GOST R 34.10', 210 | namedCurve: 'S-256-TEST', 211 | }, '2DFBC1B372D89A1188C09C52E0EEC61FCE52032AB1022E8E67ECE6672B043EE5'); 212 | 213 | // GostDigest-94-with-Gost-3410-2001 214 | tests2 += perform(++i, { 215 | name: 'GOST R 34.10', 216 | namedCurve: 'S-256-TEST', 217 | hash: { 218 | name: 'GOST R 34.11', 219 | version: 1994 220 | } 221 | }, gostCoding.Chars.decode('Suppose the original message has length = 50 bytes')); 222 | 223 | // GostDigest-2012-with-Gost-3410-2012 224 | tests2 += perform(++i, { 225 | name: 'GOST R 34.10', 226 | namedCurve: 'T-512-TEST', 227 | hash: { 228 | name: 'GOST R 34.11' 229 | } 230 | }, gostCoding.Chars.decode('Се ветри, Стрибожи внуци, веютъ с моря стрелами на храбрыя плъкы Игоревы')); 231 | 232 | // Derive key 233 | println(); 234 | println('Key exchange scenario'); 235 | performDerive(++i, { 236 | name: 'GOST R 34.10', 237 | namedCurve: 'S-256-TEST', 238 | mode: 'DH', 239 | ukm: '77105C9B20BCD312' 240 | }); 241 | performDerive(++i, { 242 | name: 'GOST R 34.10', 243 | namedCurve: 'X-256-A', 244 | mode: 'DH', 245 | ukm: '77105C9B20BCD312', 246 | hash: { 247 | name: 'GOST R 34.11' 248 | } 249 | }); 250 | performDerive(++i, { 251 | name: 'GOST R 34.10', 252 | namedCurve: 'X-256-A', 253 | mode: 'DH', 254 | ukm: '77105C9B20BCD312', 255 | hash: { 256 | name: 'GOST R 34.11', 257 | version: 1994 258 | } 259 | }); 260 | 261 | println(); 262 | 263 | println('TOTAL ' + (tests2 ? tests2 + ' ERRORS' : 'OK')); 264 | println(); 265 | 266 | return tests + tests2; 267 | }; 268 | })); 269 | 270 | 271 | 272 | var pk = '34BF9806FD77DF19F2BD0E3085FF53C1E18C3B58A0CD82BDA7466D9CC259FA23'; 273 | var maskdb = '5d6f4f794c0f584718252fb2d9ffffe6d2adc4c86616466fe032ed28790e6af6'; 274 | var mkdb = '\ 275 | 2208cd6bc96a009f05175f635bee6cc09c78260b9b7eee1e070d346462e6881b\ 276 | bf572f436df5716b1212a9fba3d022db4aed0a18530ae6c62d9bdd206479805c\ 277 | e652c17bc9cc07dcdce25cba19276285f6c54dfa940ab55473bde2d8338eaaed\ 278 | c59cdd808619f75296db91e016b588c0650686ff6929258a76d5ca7ba91b7fa8\ 279 | 7f41b2deb535a66b489a5485ac68971e00658836ce358dcda04b358621ebf08c\ 280 | e062b671d84a30706495ee2ed7d0f0a6a3e171a9daba04b582c3b7113905053a\ 281 | 5b9254c7e08bea27cb66e19699db55444f1e1f1b5a3b7db7cbcc04728e225e67\ 282 | ab8099dc82b1'; 283 | var kek = '7c34bf4e03d0bc120768164f355cf6180b32851e2ad6fc22b386bbea17fa1d5f1789eb95'; 284 | 285 | //var sign0 = 'EE92016C722C08F2FED0310E7D1C8D4EFD7224F52E53C3499E8A5392A2F41D04575BE6077F8E4008B3C3CCEC2EAC3BEC0AA0AA2AF6EFCB1D3906F2426D0394C2'; 286 | //var pubkey = '51cd2d8d96c67e0cf1ee74319cf89043c5f30ba34b68c8fc2284b5ef9e574eea0783c50ea37a2d3f2e222c038980ab0a182fe38945911e9513dfa6b1e87df63a'; 287 | 288 | var sign0 = '575BE6077F8E4008B3C3CCEC2EAC3BEC0AA0AA2AF6EFCB1D3906F2426D0394C2EE92016C722C08F2FED0310E7D1C8D4EFD7224F52E53C3499E8A5392A2F41D04'; 289 | var pubkey = '0783c50ea37a2d3f2e222c038980ab0a182fe38945911e9513dfa6b1e87df63a51cd2d8d96c67e0cf1ee74319cf89043c5f30ba34b68c8fc2284b5ef9e574eea'; 290 | 291 | -------------------------------------------------------------------------------- /min/gostCMS.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | 2014-2016, Rudolf Nickolaev. All rights reserved. 3 | */ 4 | (function(p,k){"function"===typeof define&&define.amd?define(["gostCrypto","gostASN1","gostCert"],k):"object"===typeof exports?module.exports=k(require("gostCrypto"),require("gostASN1"),require("gostCert")):p.GostCMS=k(p.gostCrypto,p.GostASN1,p.GostCert)})(this,function(p){function k(){for(var a={},b=0,c=arguments.length;b>>8&255);c.push(0);c.push(0)}return(new Uint8Array(c)).buffer}return 0<=a.name.indexOf("PFXKDF")?A.Chars.decode(b+"\x00","unicode"):A.Chars.decode(b,"utf8")}function x(){}function q(a,b){t.ContentInfo.call(this,a||b||{contentType:"data"});if(b&&this.contentType!==(b.contentType||"data"))throw Error("Invalid content type");}function J(a){q.call(this,a,{contentType:"digestedData",version:0,digestAlgorithm:v[r.providerName].digest, 11 | encapContentInfo:{eContentType:"data"},digest:new w(0)})}function K(a){q.call(this,a,{contentType:"signedData",version:1,digestAlgorithms:[],encapContentInfo:{eContentType:"data"},signerInfos:[]})}function L(a){q.call(this,a,{contentType:"encryptedData",version:0,encryptedContentInfo:{contentType:"data",contentEncryptionAlgorithm:v[r.providerName].encryption}})}function M(a){q.call(this,a,{contentType:"envelopedData",version:0,recipientInfos:[],encryptedContentInfo:{contentType:"data",contentEncryptionAlgorithm:v[r.providerName].encryption}})} 12 | var m=this.Promise,D=this.Object,w=this.ArrayBuffer,U=this.Date,h=p.subtle,t=p.asn1,A=p.coding,V=p.cert,v=p.security.providers,N=function(){var a=function(a){var b=typeof a;return"undefined"===b||""===a?"0":"number"===b||a instanceof Number?a.toString(16).toLowerCase():a.replace("0x","").toLowerCase()},b=function(a,b){return(Array(b+1).join("0")+a).slice(-b)};return function(c,d){c=a(c);d=a(d);var e=Math.max(c.length,d.length);return b(c,e)===b(d,e)}}(),r={providerName:"CP-01",autoAddCert:!1,useKeyIdentifier:!1}; 13 | x.prototype.options=r;y(t.ContentInfo,q,{isDetached:{value:!1,enumerable:!0,writable:!0},writeDetached:function(a){this.isDetached=a},encode:function(a){if(this.isDetached){var b=Q(this);H(this,{contentType:b.contentType});a=t.ContentInfo.method("encode").call(this,a);H(this,b);return a}return t.ContentInfo.method("encode").call(this,a)},encloseContent:function(a){var b=this;return(new m(l)).then(function(){b.setEnclosed(a);return b})},setEnclosed:function(a){H(this,I(a))},getEnclosed:function(){return z(Q(this))}}); 14 | x.prototype.DataContentInfo=q;y(q,J,{encloseContent:function(a,b){var c=this;return(new m(l)).then(function(){c.setEnclosed(a);if(b){var d=v[b];c.digestAlgorithm=d&&d.digest||b}return h.digest(c.digestAlgorithm,c.encapContentInfo.eContent)}).then(function(a){c.digest=a})},verify:function(a){var b=this;return(new m(l)).then(function(){a&&b.setEnclosed(a);if(!b.encapContentInfo||!b.encapContentInfo.eContent)throw Error("Detached content is not found");return h.digest(b.digestAlgorithm,b.encapContentInfo.eContent)}).then(function(a){if(!E(a, 15 | b.digest))throw Error("Message digest is not verified");return z({contentType:b.encapContentInfo.eContentType,content:b.encapContentInfo.eContent})})}});x.prototype.DigestedDataContentInfo=J;y(q,K,{addSignature:function(a,b,c,d){var e=this,f,g,n;return(new m(l)).then(function(){if(!a||!b)throw Error("Signer key or certificate is not defined");b instanceof Array?(n=b,b=n[0]):n=[b];var s=b.getProvider()||v[r.providerName],S=r.useKeyIdentifier&&b.extensions&&b.extensions.subjectKeyIdentifier;g=e.encapContentInfo.eContent; 16 | f={version:S?2:0,sid:S?b.extensions.subjectKeyIdentifier:{issuer:b.issuer,serialNumber:b.serialNumber},digestAlgorithm:s.digest,signatureAlgorithm:b.subjectPublicKeyInfo.algorithm};d&&(f.unsignedAttrs=d);if(c)return"object"!==typeof c&&(c={}),h.digest(f.digestAlgorithm,g)}).then(function(b){b&&(c.contentType=e.encapContentInfo.eContentType,c.messageDigest=b,c.signingTime=new U,f.signedAttrs=c,g=t.SignedAttributes.encode(f.signedAttrs));return h.importKey("pkcs8",t.PrivateKeyInfo.encode(a),a.privateKeyAlgorithm, 17 | !1,["sign"])}).then(function(a){var b=k(f.signatureAlgorithm,{hash:f.digestAlgorithm});return h.sign(b,a,g)}).then(function(a){f.signatureValue=a;G(e.digestAlgorithms,f.digestAlgorithm,function(a,b){return a.id===b.id});if(r.autoAddCert){e.certificates||(e.certificates=[]);a=0;for(var b=n.length;a 0 ? '' : '') + '\r\n' + start + '' : ' ') + 84 | ('00' + d[i].toString(16)).slice(-2); 85 | } 86 | return s ? s + '' : ''; 87 | } 88 | 89 | function childs(block, offset, ident) { 90 | var s = '', start = ' : '; 91 | if (block.object.length > 0) { 92 | s += ' {\r\n'; 93 | block.object.forEach(function (child) { 94 | s += process(child, offset, ident + ' '); 95 | offset += child.header.length + child.content.length; 96 | }); 97 | s += start + ident + '}'; 98 | } else 99 | s += ' {}'; 100 | return s; 101 | } 102 | 103 | function process(block, offset, ident) { 104 | if (block.tagClass > 2) 105 | throw new Error('Private and Application tags is not supported') 106 | offset = offset || 0; 107 | ident = ident || ''; 108 | // type name 109 | var typeName = block.tagClass === 1 ? 'Application_' + block.tagNumber : 110 | block.tagClass === 2 ? '[' + block.tagNumber.toString() + ']' : // Context 111 | block.tagClass === 3 ? 'Private_' + block.tagNumber : 112 | BERtypes[block.tagNumber] || "Universal_" + block.tagNumber.toString(); 113 | 114 | var start = ' : ', 115 | s = (' ' + offset).slice(-5) + 116 | ' ' + ('00' + block.header[0].toString(16)).slice(-2) + 117 | (' ' + block.content.length).slice(-5) + ': ' + 118 | ident + typeName; 119 | if (block.tagConstructed) 120 | s += childs(block, offset + block.header.length, ident); 121 | else 122 | switch (typeName.toUpperCase()) { 123 | case 'OBJECT IDENTIFIER': 124 | var id = block.object, 125 | name = names[id]; 126 | s += ' ' + (name ? name : '?') + ' (' + id + ')'; 127 | break; 128 | case 'INTEGER': 129 | case 'ENUMERATED': 130 | if (typeof block.object === 'number') { 131 | s += ' ' + block.object + ''; 132 | } else 133 | s += hex(start + ident + ' ', block.content); 134 | break; 135 | case 'GENERALIZEDTIME': 136 | case 'UTCTIME': 137 | s += ' ' + block.object + ''; 138 | break; 139 | case 'PRINTABLESTRING': 140 | case 'IA5STRING': 141 | case 'VISIBLESTRING': 142 | case 'VIDEOTEXSTRING': 143 | case 'NUMERICSTRING': 144 | case 'BMPSTRING': 145 | case 'UTF8STRING': 146 | case 'UNIVERSALSTRING': 147 | s += ' "' + block.object + '"'; 148 | break; 149 | case 'BOOLEAN': 150 | s += ' ' + (block.object ? 'true' : 'false') + ''; 151 | break; 152 | case 'OCTET STRING': 153 | try { 154 | s += ', encapsulates' + childs({object: [coding.BER.decode(block.content)]}, 155 | offset + block.header.length, ident); 156 | } catch (e) { 157 | s += hex(start + ident + ' ', block.content); 158 | } 159 | break; 160 | case 'BIT STRING': 161 | s += ', unused ' + block.content[0] + ' bits'; 162 | if (block.object instanceof ArrayBuffer) { 163 | try { 164 | s += ', encapsulates' + childs({object: [coding.BER.decode(block.object)]}, 165 | offset + block.header.length, ident); 166 | } catch (e) { 167 | s += hex(start + ident + ' ', block.object); 168 | } 169 | } else 170 | s += '\r\n' + start + ident + ' ' + block.object + 'B'; 171 | break; 172 | default: 173 | try { 174 | s += ', encapsulates' + childs({object: [coding.BER.decode(block.content)]}, 175 | offset + block.header.length, ident); 176 | } catch (e) { 177 | s += hex(start + ident + ' ', block.content); 178 | } 179 | } 180 | return s + '\r\n'; 181 | } 182 | 183 | return function (value) { 184 | if (typeof value === 'string' || value instanceof String) { // text 185 | var t = /([A-Fa-f0-9\s]+)/g.exec(value); 186 | if (t && t[1].length === value.length) // Hex format 187 | value = coding.Hex.decode(value); 188 | else // PEM format 189 | value = coding.PEM.decode(value); 190 | } else { // binary 191 | try { 192 | value = coding.PEM.decode(coding.Chars.encode(value, 'ascii')); 193 | } catch (e) { 194 | } 195 | } 196 | return process(coding.BER.decode(value)); 197 | }; 198 | })(); 199 | 200 | var printSyntax = (function () { 201 | 202 | function process(value, ident) { 203 | ident = ident || ''; 204 | if (typeof value === 'undefined') 205 | return 'undefined'; 206 | else if (value instanceof Array) { 207 | var r = [], l = 0; 208 | for (var i = 0, n = value.length; i < n; i++) { 209 | r[i] = process(value[i], ident + ' '); 210 | l += r[i].replace(/\<[^\>]+\>/g, '').length + 2; 211 | } 212 | if (l > 80) { 213 | var s = '[', m = 0; 214 | for (var i = 0, n = r.length; i < n; i++) { 215 | s += (i > 0 ? ', ' : '') + 216 | (m === 0 && l > 80 ? '\r\n' + ident + ' ' : ' ') + r[i]; 217 | m += r[i].replace(/\<[^\>]+\>/g, '').length + 2; 218 | if (m > 80) 219 | m = 0; 220 | } 221 | s += l > 80 ? '\r\n' + ident + ']' : ' ]'; 222 | return s; 223 | } else 224 | return '[ ' + r.join(', ') + ' ]'; 225 | } else if (typeof value === 'string' || value instanceof String) { 226 | if (value.toString() === '') // null 227 | return 'null'; 228 | else 229 | return '"' + value.replace(/([\"])/g, '\\$1') + '"'; 230 | } else if (typeof value === 'number' || value instanceof Number) { 231 | return '' + value + ''; 232 | } else if (value instanceof Date) { 233 | return '' + JSON.stringify(value) + ''; 234 | } else if (typeof value === 'boolean' || value instanceof Boolean) { 235 | return '' + value + ''; 236 | } else if (value instanceof ArrayBuffer || value instanceof Uint8Array) { 237 | var d = new Uint8Array(value); 238 | var s = ''; 239 | for (var i = 0, n = d.length; i < n; i++) { 240 | s += (i > 0 && i % 16 === 0 ? '\r\n' + ident + ' ' : ' ') + 241 | '0x' + ('00' + d[i].toString(16)).slice(-2) + '' + 242 | (i < n - 1 ? ',' : ''); 243 | } 244 | if (d.length > 16) 245 | return '[\r\n' + ident + ' ' + s + '\r\n' + ident + ']'; 246 | else 247 | return '[' + s + ' ]'; 248 | } else if (typeof value === 'object') { 249 | var first = true; 250 | var s = '{'; 251 | for (var name in value) { 252 | if (typeof value[name] === 'function' || value[name] === undefined) 253 | continue; 254 | var norm = /^[a-zA-Z\_][a-zA-Z0-9\_]*$/.test(name); 255 | if (first) 256 | first = false; 257 | else 258 | s += ','; 259 | s += '\r\n' + ident + ' ' + 260 | (norm ? '' : '"') + name + (norm ? '' : '"') + ': ' + 261 | process(value[name], ident + ' '); 262 | } 263 | s += (first ? '' : '\r\n' + ident) + '}'; 264 | return s; 265 | } 266 | return 'unrecognized'; 267 | } 268 | 269 | return function (value, type) { 270 | if (typeof value === 'string' || value instanceof String) { // text 271 | var t = /([A-Fa-f0-9\s]+)/g.exec(value); 272 | if (t && t[1].length === value.length) // Hex format 273 | value = coding.Hex.decode(value); 274 | else // PEM format 275 | value = coding.PEM.decode(value); 276 | } else { // binary 277 | try { 278 | value = coding.PEM.decode(coding.Chars.encode(value, 'ascii')); 279 | } catch (e) { 280 | } 281 | } 282 | if (type) { 283 | return process(asn1[type].decode(value)); 284 | } else 285 | return process(coding.BER.decode(value)); 286 | }; 287 | 288 | })(); 289 | 290 | function open(header, content, item) { 291 | var el = document.getElementById('print'); 292 | if (el) 293 | el.parentNode.removeChild(el); 294 | el = document.createElement('div'); 295 | el.id = 'print'; 296 | el.innerHTML = 297 | '' + header + '' + 298 | '
' + content + '
' + 299 | ''; 300 | var next = item.nextElementSibling; 301 | while (next.nodeName.toLowerCase() === 'button') 302 | next = next.nextElementSibling; 303 | next.parentNode.insertBefore(el, next); 304 | } 305 | 306 | function openASN1(item) { 307 | open('ASN.1 Data', printASN1(item.textContent), item); 308 | } 309 | 310 | function openSyntax(item, type) { 311 | open('Syntax ' + (type ? 'gostCrypto.asn1.' + type + '.decode(value):' : 312 | 'gostCrypto.coding.PEM.decode(value):'), printSyntax(item.textContent, type), item); 313 | } 314 | 315 | return { 316 | printASN1: printASN1, 317 | printSyntax: printSyntax, 318 | openASN1: openASN1, 319 | openSyntax: openSyntax 320 | }; 321 | 322 | })); 323 | -------------------------------------------------------------------------------- /min/gostCrypto.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | 2014-2016, Rudolf Nickolaev. All rights reserved. 3 | */ 4 | (function(y,g){"function"===typeof define&&define.amd?define(["gostRandom"],g):"object"===typeof exports?module.exports=g(require("gostRandom")):y.gostCrypto=g(y.GostRandom)})(this,function(y){function g(a,c){if("string"===typeof a||a instanceof String)a={name:a};var d=a.name;if(!d)throw new v("Algorithm name not defined");var e=d.split("/"),e=e[0].split("-").concat(e.slice(1)),b={},d=e[0].replace(/[\.\s]/g,""),e=e.slice(1);if(0<=d.indexOf("28147"))b={name:"GOST 28147",version:1989,mode:(a.mode|| 5 | ("sign"===c||"verify"===c?"MAC":"wrapKey"===c||"unwrapKey"===c?"KW":"ES")).toUpperCase(),length:a.length||64};else if(0<=d.indexOf("3412"))b={name:"GOST R 34.12",version:2015,mode:(a.mode||("sign"===c||"verify"===c?"MAC":"wrapKey"===c||"unwrapKey"===c?"KW":"ES")).toUpperCase(),length:a.length||64};else if(0<=d.indexOf("3411"))b={name:"GOST R 34.11",version:2012,mode:(a.mode||("deriveKey"===c||"deriveBits"===c?"KDF":"sign"===c||"verify"===c?"HMAC":"HASH")).toUpperCase(),length:a.length||256};else if(0<= 6 | d.indexOf("3410"))b={name:"GOST R 34.10",version:2012,mode:(a.mode||("deriveKey"===c||"deriveBits"===c?"DH":"SIGN")).toUpperCase(),length:a.length||256};else if(0<=d.indexOf("SHA"))b={name:"SHA",version:160===(a.length||160)?1:2,mode:(a.mode||("deriveKey"===c||"deriveBits"===c?"KDF":"sign"===c||"verify"===c?"HMAC":"HASH")).toUpperCase(),length:a.length||160};else if(0<=d.indexOf("RC2"))b={name:"RC2",version:1,mode:(a.mode||("sign"===c||"verify"===c?"MAC":"wrapKey"===c||"unwrapKey"===c?"KW":"ES")).toUpperCase(), 7 | length:a.length||32};else if(0<=d.indexOf("PBKDF2"))b=g(a.hash,"digest"),b.mode="PBKDF2";else if(0<=d.indexOf("PFXKDF"))b=g(a.hash,"digest"),b.mode="PFXKDF";else if(0<=d.indexOf("CPKDF"))b=g(a.hash,"digest"),b.mode="CPKDF";else if(0<=d.indexOf("HMAC"))b=g(a.hash,"digest"),b.mode="HMAC";else throw new s("Algorithm not supported");e.forEach(function(a){a=a.toUpperCase();if(/^[0-9]+$/.test(a))if(0<=["8","16","32"].indexOf(a)||"128"===b.length&&"64"===a)if("ES"===b.mode)b.shiftBits=parseInt(a);else if("MAC"=== 8 | b.mode)b.macLength=parseInt(a);else throw new s("Algorithm "+b.name+" mode "+a+" not supported");else 0<="89 94 01 12 15 1989 1994 2001 2012 2015".split(" ").indexOf(a)?(a=parseInt(a),b.version=1900>a?80>a?2E3+a:1900+a:a):0<=["1"].indexOf(a)&&"SHA"===b.name?(b.version=1,b.length=160):0<=["256","384","512"].indexOf(a)&&"SHA"===b.name?(b.version=2,b.length=parseInt(a)):0<=["40","128"].indexOf(a)&&"RC2"===b.name?(b.version=1,b.length=parseInt(a)):0<=["64","128","256","512"].indexOf(a)?b.length=parseInt(a): 9 | 0<=["1000","2000"].indexOf(a)&&(b.iterations=parseInt(a));else if(0<="E-TEST E-A E-B E-C E-D E-SC E-Z D-TEST D-A D-SC".split(" ").indexOf(a))b.sBox=a;else if(0<="S-TEST S-A S-B S-C S-D X-A X-B X-C".split(" ").indexOf(a))b.namedParam=a;else if(0<="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".split(" ").indexOf(a))b.namedCurve=a;else if(0<=["SC","CP","VN"].indexOf(a))b.procreator=a;else if("GOST 28147"===b.name|| 10 | "GOST R 34.12"===b.name||"RC2"===b.name)if(0<=["ES","MAC","KW","MASK"].indexOf(a))b.mode=a;else if(0<=["ECB","CFB","OFB","CTR","CBC"].indexOf(a))b.mode="ES",b.block=a;else if(0<=["CPKW","NOKW","SCKW"].indexOf(a))b.mode="KW",b.keyWrapping=a.replace("KW","");else if(0<=["ZEROPADDING","PKCS5PADDING","NOPADDING","RANDOMPADDING","BITPADDING"].indexOf(a))b.padding=a.replace("PADDING","");else if(0<=["NOKM","CPKM"].indexOf(a))b.keyMeshing=a.replace("KM","");else throw new s("Algorithm "+b.name+" mode "+ 11 | a+" not supported");else if("GOST R 34.11"===b.name||"SHA"===b.name)if(0<="HASH KDF HMAC PBKDF2 PFXKDF CPKDF".split(" ").indexOf(a))b.mode=a;else throw new s("Algorithm "+b.name+" mode "+a+" not supported");else if("GOST R 34.10"===b.name){var c=a.replace(/[\.\s]/g,"");if(0<=c.indexOf("GOST")&&0<=c.indexOf("3411"))b.hash=a;else if(["SIGN","DH","MASK"].indexOf(a))b.mode=a;else throw new s("Algorithm "+b.name+" mode "+a+" not supported");}});b.procreator=a.procreator||b.procreator||"CP";switch(b.name){case "GOST R 34.10":b.keySize= 12 | b.length/(1994===b.version?4:8);break;case "GOST R 34.11":b.keySize=32;break;case "GOST 28147":case "GOST R 34.12":b.keySize=32;break;case "RC2":b.keySize=Math.ceil(b.length/8);break;case "SHA":b.keySize=b.length/8}if("ES"===b.mode&&(a.block&&(b.block=a.block),b.block&&(b.block=b.block.toUpperCase()),a.padding&&(b.padding=a.padding),b.padding&&(b.padding=b.padding.toUpperCase()),a.shiftBits&&(b.shiftBits=a.shiftBits),a.keyMeshing&&(b.keyMeshing=a.keyMeshing),b.keyMeshing&&(b.keyMeshing=b.keyMeshing.toUpperCase()), 13 | "importKey"!==c&&"generateKey"!==c)){b.block=b.block||"ECB";b.padding=b.padding||("CBC"===b.block||"ECB"===b.block?"ZERO":"NO");if("CFB"===b.block||"OFB"===b.block)b.shiftBits=b.shiftBits||b.length;b.keyMeshing=b.keyMeshing||"NO"}"KW"===b.mode&&(a.keyWrapping&&(b.keyWrapping=a.keyWrapping),b.keyWrapping&&(b.keyWrapping=b.keyWrapping.toUpperCase()),"importKey"!==c&&"generateKey"!==c&&(b.keyWrapping=b.keyWrapping||"NO"));"sBox namedParam namedCurve curve param modulusLength".split(" ").forEach(function(c){a[c]&& 14 | (b[c]=a[c])});"importKey"!==c&&"generateKey"!==c&&("GOST 28147"===b.name?b.sBox=b.sBox||("SC"===b.procreator?"E-SC":"E-A"):"GOST R 34.12"===b.name&&64===b.length?b.sBox="E-Z":"GOST R 34.11"===b.name&&1994===b.version?b.sBox=b.sBox||("SC"===b.procreator?"D-SC":"D-A"):"GOST R 34.10"===b.name&&1994===b.version?b.namedParam=b.namedParam||("DH"===b.mode?"X-A":"S-A"):"GOST R 34.10"===b.name&&2001===b.version?b.namedCurve=b.namedCurve||(256===b.length?"SC"===b.procreator?"P-256":"DH"===b.mode?"X-256-A": 15 | "S-256-A":"T-512-A"===b.mode):"GOST R 34.10"===b.name&&2012===b.version&&(b.namedCurve=b.namedCurve||(256===b.length?"SC"===b.procreator?"P-256":"DH"===b.mode?"X-256-A":"S-256-A":"T-512-A"===b.mode)));switch(b.mode){case "DH":a.ukm&&(b.ukm=a.ukm);a["public"]&&(b["public"]=a["public"]);break;case "SIGN":case "KW":a.ukm&&(b.ukm=a.ukm);break;case "ES":case "MAC":a.iv&&(b.iv=a.iv);break;case "KDF":a.label&&(b.label=a.label);a.contex&&(b.context=a.contex);break;case "PBKDF2":a.salt&&(b.salt=a.salt);a.iterations&& 16 | (b.iterations=a.iterations);a.diversifier&&(b.diversifier=a.diversifier);break;case "PFXKDF":a.salt&&(b.salt=a.salt);a.iterations&&(b.iterations=a.iterations);a.diversifier&&(b.diversifier=a.diversifier);break;case "CPKDF":a.salt&&(b.salt=a.salt),a.iterations&&(b.iterations=a.iterations)}if(c&&("ES"!==b.mode&&"SIGN"!==b.mode&&"MAC"!==b.mode&&"HMAC"!==b.mode&&"KW"!==b.mode&&"DH"!==b.mode&&"MASK"!==b.mode&&"generateKey"===c||"ES"!==b.mode&&("encrypt"===c||"decrypt"===c)||"SIGN"!==b.mode&&"MAC"!==b.mode&& 17 | "HMAC"!==b.mode&&("sign"===c||"verify"===c)||"HASH"!==b.mode&&"digest"===c||"KW"!==b.mode&&"MASK"!==b.mode&&("wrapKey"===c||"unwrapKey"===c)||"DH"!==b.mode&&"PBKDF2"!==b.mode&&"PFXKDF"!==b.mode&&"CPKDF"!==b.mode&&"KDF"!==b.mode&&("deriveKey"===c||"deriveBits"===c)))throw new s("Algorithm mode "+b.mode+" not valid for method "+c);a.hash&&(b.hash=a.hash);b.hash&&(("string"===typeof b.hash||b.hash instanceof String)&&b.procreator&&(b.hash=b.hash+"/"+b.procreator),b.hash=g(b.hash,"digest"));a.id&&(b.id= 18 | a.id);return b}function q(a){if(!k||!k.subtle||!a)return!1;var c="string"===typeof a||a instanceof String?c=a:a.name;if(!c)return!1;c=c.toUpperCase();return(0<=c.indexOf("KDF")||0<=c.indexOf("HMAC"))&&a.hash?q(a.hash):-1===c.indexOf("GOST")&&-1===c.indexOf("SHA-1")&&-1===c.indexOf("RC2")&&-1===c.indexOf("?DES")}function F(a,c){if(!a.algorithm)throw new v("Key algorithm not defined");if(!a.algorithm.name)throw new v("Key algorithm name not defined");var d=a.algorithm.name,e="GOST 28147"===d||"GOST R 34.12"=== 19 | d||"RC2"===d,b="GOST R 34.11"===d||"SHA"===d,h="GOST R 34.10"===d;if(!e&&!h&&!b)throw new s("Key algorithm "+d+" is unsupproted");if(!a.type)throw new v("Key type not defined");if((e||b)&&"secret"!==a.type||h&&"public"!==a.type&&"private"!==a.type)throw new B("Key type "+a.type+" is not valid for algorithm "+d);if(!a.usages||!a.usages.indexOf)throw new v("Key usages not defined");d=0;for(e=a.usages.length;dr.usages.indexOf(b[f]))throw B("Key usage not valid for this key");}else b=r.usages;r=r.buffer;var p=d.keySize,l=r.byteLength;if("public"===h||p===l)return r;if(0b?b+4294967296:b}function H(b){var c=(v=v||r.GostRandom)?new (v||r.GostRandom):$;if(c.getRandomValues)c.getRandomValues(b);else throw new C("Random generator not found");}function q(b){if(b instanceof I)return b;if(b&&b.buffer&&b.buffer instanceof 5 | I)return 0===b.byteOffset&&b.byteLength===b.buffer.byteLength?b.buffer:(new Uint8Array(new Uint8Array(b,b.byteOffset,b.byteLength))).buffer;throw new p("CryptoOperationData required");}function s(b){return new Uint8Array(q(b))}function t(b){return new Uint8Array(s(b))}function D(b){return(b&255)<<24|(b&65280)<<8|b>>8&65280|b>>24&255}function E(b,c){for(var a=0;16>a;++a)b[a]^=c[a]}function O(b){for(var c=0;16>c;++c){for(var a=b,d=0,e=0;16>e;e++)d^=P[Q[e]][a[e]];for(e=16;0a;++a)b[a]=J[b[a]];O(b)}function aa(b){var c=new Uint8Array(160),a=new Uint8Array(16);c.set(s(b));for(b=0;4>b;b++){var d=32*(b+1);c.set(new Uint8Array(c.buffer,32*b,32),d);for(var e=1;9>e;e++){for(var f=8*b+e,g=a,h=0;15>h;h++)g[h]=0;g[15]=f;O(g);var f=new Uint8Array(c.buffer,d,16),g=new Uint8Array(c.buffer,d+16,16),h=a,l=new Uint8Array(f);R(f,h);E(f,g);g.set(l)}}return c}function ba(b,c,a,d){a=a||c.byteOffset;c=new Uint8Array(c.buffer,a,16);if(d){for(d=0;9>d;d++){a= 7 | c;var e=new Uint8Array(b.buffer,16*(9-d),16);E(a,e);for(var e=a,f=0;16>f;++f){for(var g=e,h=g[0],l=0;15>l;l++)g[l]=g[l+1];g[15]=h;for(l=h=0;16>l;l++)h^=P[Q[l]][g[l]];g[15]=h}for(e=0;16>e;++e)a[e]=ca[a[e]]}E(c,new Uint8Array(b.buffer,0,16))}else{for(d=0;9>d;d++)R(c,new Uint8Array(b.buffer,16*d,16));E(c,new Uint8Array(b.buffer,144,16))}}function K(b,c,a){a=c[0]+a&4294967295;var d=b[0+(a>>0&15)]<<0,d=d|b[16+(a>>4&15)]<<4,d=d|b[32+(a>>8&15)]<<8,d=d|b[48+(a>>12&15)]<<12,d=d|b[64+(a>>16&15)]<<16,d=d|b[80+ 8 | (a>>20&15)]<<20,d=d|b[96+(a>>24&15)]<<24,d=d|b[112+(a>>28&15)]<<28;a=(d<<11|d>>>21)^c[1];c[1]=c[0];c[0]=a}function da(b,c,a){a=a||c.byteOffset;var d=this.sBox;c=new Int32Array(c.buffer,a,2);for(a=0;32>a;a++)K(d,c,b[a]);b=c[0];c[0]=c[1];c[1]=b}function ea(b,c,a){a=a||c.byteOffset;var d=this.sBox;c=new Int32Array(c.buffer,a,2);a=D(c[0]);c[0]=D(c[1]);c[1]=a;for(a=0;32>a;a++)K(d,c,b[a]);c[0]=D(c[0]);c[1]=D(c[1])}function fa(b,c){for(var a=new Int32Array(32),d=new Int32Array(q(b)),e=0;8>e;e++)a[e]=d[e]; 9 | if(c){for(e=0;8>e;e++)a[e+8]=a[7-e];for(e=0;8>e;e++)a[e+16]=a[7-e]}else{for(e=0;8>e;e++)a[e+8]=a[e];for(e=0;8>e;e++)a[e+16]=a[e]}for(e=0;8>e;e++)a[e+24]=a[7-e];return a}function ga(b,c){for(var a=new Int32Array(32),d=new Int32Array(q(b)),e=0;8>e;e++)a[e]=D(d[e]);if(c){for(e=0;8>e;e++)a[e+8]=a[7-e];for(e=0;8>e;e++)a[e+16]=a[7-e]}else{for(e=0;8>e;e++)a[e+8]=a[e];for(e=0;8>e;e++)a[e+16]=a[e]}for(e=0;8>e;e++)a[e+24]=a[7-e];return a}function x(b,c){for(var a=this.pad(s(c)),d=this.blockSize,e=a.byteLength/ 10 | d,f=this.keySchedule(b),g=0;g>3,g=c.length,h=g%f,g=(g-h)/f,l=this.keySchedule(b),k=0;k>3,g=c.length,h=g%f,g=(g-h)/f,l=this.keySchedule(b),k=0;k>3,g=new Uint8Array(f),h=c.length,l=h%f,h=(h-l)/f,k=this.keySchedule(b),m=0;mm?m:m-4294967295);for(m=0;mm?m:m-4294967295),this.process(h,l),k=0;k>3,f=c.length,g=f%e,f=(f-g)/e,h=new Uint8Array(d),l=new Int32Array(d);b=this.keySchedule(b);h.set(a||this.iv);for(a=0;al;l++)K(f,g,b[l])}} 17 | function V(b){for(var c=0,a=b.length,d=a-1;0<=d;--d){var e=b[d]>>>7;b[d]=b[d]<<1&255|c;c=e}0!==c&&(16===a?b[15]^=135:b[7]^=27)}function ma(b,c,a){var d=this.blockSize,e=s(a),f=new Uint8Array(d);this.process(b,f);V(f);0!==a.byteLength%d&&(e=W.call(this,s(a)),V(f));a=0;for(var g=e.length/d;a>3)||this.blockSize>> 18 | 1;this.processMAC(b,a,c);c=new Uint8Array(d);c.set(new Uint8Array(a.buffer,0,d));return c.buffer}function A(b,c,a,d){b=new Uint8Array(z.call(this,b,a,d));c=s(c);if(b.length!==c.length)return!1;a=0;for(d=b.length;a>1);if(!this.ukm)throw new p("UKM must be defined");var e=new Uint8Array(this.ukm),e=z.call(this,b,c,e),f=x.call(this,b,c),d=new Uint8Array(d);d.set(new Uint8Array(f),0);d.set(new Uint8Array(e), 19 | a);return d.buffer}function oa(b,c){var a=this.blockSize,d=this.keySize,e=d+(a>>1),f=q(c);if(f.byteLength!==e)throw new p("Wrapping key size must be "+e+" bytes");if(!this.ukm)throw new p("UKM must be defined");var e=new Uint8Array(this.ukm),g=new Uint8Array(f,0,d),a=new Uint8Array(f,d,a>>1),d=F.call(this,b,g);if(!A.call(this,b,a,d,e))throw new p("Error verify MAC of wrapping key");return d}function X(b,c){for(var a=this.blockSize,d=new Int32Array(q(b)),e=[],f=0;fg;g++)e[f][g]= 20 | c[f]>>>g&1}for(f=0;fg;g++)e[f][g]?h[0]=h[0]+d[g]&4294967295:h[1]=h[1]+d[g]&4294967295;g=new Uint8Array(h.buffer);d=new Int32Array(S.call(this,d,d,g))}return d}function pa(b,c){var a=this.keySize,d=a+(this.blockSize>>1);if(!this.ukm)throw new p("UKM must be defined");var e=new Uint8Array(this.ukm),f=X.call(this,b,e),e=z.call(this,f,c,e),f=x.call(this,f,c),d=new Uint8Array(d);d.set(new Uint8Array(f),0);d.set(new Uint8Array(e),a);return d.buffer}function qa(b, 21 | c){var a=this.blockSize,d=this.keySize,e=d+(a>>1),f=q(c);if(f.byteLength!==e)throw new p("Wrapping key size must be "+e+" bytes");if(!this.ukm)throw new p("UKM must be defined");var e=new Uint8Array(this.ukm),g=new Uint8Array(f,0,d),a=new Uint8Array(f,d,a>>1),d=X.call(this,b,e),g=F.call(this,d,g);if(!A.call(this,d,a,g,e))throw new p("Error verify MAC of wrapping key");return g}function Y(b){var c=this.blockSize>>1,a=this.keySize,d=q(b);if(34!==(new Uint8Array(d,0,1))[0])throw new p("Invalid magic number"); 22 | var e=(new Uint8Array(d,1,1))[0];b=new Uint8Array(d,2,c);for(var f=new Uint8Array(a),g=0;g>1,d=this.keySize,e=q(b),f=q(c);e.byteLength!==d&&(e=Y.call(this,e));var g=x.call(this,e,f),e= 23 | z.call(this,e,f),a=new Uint8Array(a+d);a.set(new Uint8Array(g),0);a.set(new Uint8Array(e),d);return a.buffer}function sa(b,c){var a=this.blockSize>>1,d=this.keySize,e=q(b),f=q(c);e.byteLength!==d&&(e=Y.call(this,e));var g=new Uint8Array(f,0,d),a=new Uint8Array(f,d,a),g=F.call(this,e,g);if(!A.call(this,e,a,g))throw new p("Invalid key MAC");return g}function ta(){var b=y.call(this),c=void 0,a=this.blockSize>>1,d=this.keySize,e=8,b=new Uint8Array(q(b));if(b.byteLength!==d)throw new p("Wrong cleartext size "+ 24 | b.byteLength+" bytes");if(c=c||this.ukm)if(c=new Uint8Array(q(c)),0this.blockSize)throw p("Invalid padding");a=new Uint8Array(c);0a;a++){c[a]=[];for(var d=0;256>d;d++){for(var e=c[a],f=d,g=b[a],h=d,l=0,k=void 0,m=void 0,k=0;8>k;k++)h&1&&(l^=g),m=g&128,g=g<<1&255,m&&(g^=195),h>>=1;e[f]=l&255}}return c}(),Q=[4,2,3,1,6,5,0,7,0,5,6,1,3,2,4,0],J=[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, 36 | 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, 37 | 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],ca=function(){for(var b=[],c=0,a=J.length;ch;h++)f[h]=b[(f[h-1]+f[h-a])%256];f[128-e]=b[f[128-e]&d];for(h=127-e;0<=h;--h)f[h]=b[f[h+1]^ 40 | f[h+e]];return g}}(),Ga=function(){function b(a){if(h){var b=f[a],c=g[a];f[a]=(b>>>c|b<<16-c)&65535;f[a]=f[a]-d[e]-(f[(a+3)%4]&f[(a+2)%4])-(~f[(a+3)%4]&f[(a+1)%4]);--e}else f[a]=f[a]+d[e]+(f[(a+3)%4]&f[(a+2)%4])+(~f[(a+3)%4]&f[(a+1)%4]),e+=1,b=f[a],c=g[a],f[a]=(b<>>16-c)&65535}function c(a){f[a]=h?f[a]-d[f[(a+3)%4]&63]:f[a]+d[f[(a+3)%4]&63]}function a(a,b){b=b||1;for(var c=0;cd;d++)a(d)}var d,e,f=new Uint16Array(4),g=new Uint16Array([1,2,3, 41 | 5]),h;return function(g,k,m,n){h=n;f=new Uint16Array(k.buffer,m||k.byteOffset,4);d=g;e=n?63:0;a(b,5);a(c);a(b,6);a(c);a(b,5)}}();return function(b){if(!Ca)throw new C("Big endian platform not supported");b=b||{};this.keySize=32;this.blockLength=b.length||64;this.blockSize=this.blockLength>>3;this.name=(b.name||(1===b.version?"RC2":1989===b.version?"GOST 28147":"GOST R 34.12"))+(4>1):"KW"===b.mode||b.keyWrapping?("NO"!==(b.keyWrapping||"NO")?b.keyWrapping:"")+"KW":(b.block||"ECB")+(("CFB"===b.block||"OFB"===b.block||"CTR"===b.block&&2015===b.version)&&b.shiftBits&&b.shiftBits!==this.blockLength?"-"+b.shiftBits:"")+(b.padding?"-"+(b.padding||("CTR"===b.block||"CFB"===b.block||"OFB"===b.block?"NO":"ZERO"))+"PADDING":"")+("NO"!==(b.keyMeshing||"NO")?"-CPKEYMESHING":""))+(b.procreator?"/"+b.procreator:"")+("string"===typeof b.sBox?"/"+b.sBox:"");this.procreator= 43 | b.procreator;switch(b.version||1989){case 1:this.process=Ga;this.keySchedule=Fa;this.blockLength=64;this.effectiveLength=b.length||32;this.keySize=8*Math.ceil(this.effectiveLength/8);this.blockSize=this.blockLength>>3;break;case 2015:this.version=2015;if(64===this.blockLength)this.process=ea,this.keySchedule=ga;else if(128===this.blockLength)this.process=ba,this.keySchedule=aa;else throw new p("Invalid block length");this.processMAC=ma;break;case 1989:this.version=1989;this.process=da;this.processMAC= 44 | la;this.keySchedule=fa;if(64!==this.blockLength)throw new p("Invalid block length");break;default:throw new C("Algorithm version "+b.version+" not supported");}switch(b.mode||b.keyWrapping&&"KW"||"ES"){case "ES":switch(b.block||"ECB"){case "ECB":this.encrypt=x;this.decrypt=F;break;case "CTR":1989===this.version?this.decrypt=this.encrypt=ja:(this.decrypt=this.encrypt=L,this.shiftBits=b.shiftBits||this.blockLength);break;case "CBC":this.encrypt=T;this.decrypt=ka;break;case "CFB":this.encrypt=S;this.decrypt= 45 | ha;this.shiftBits=b.shiftBits||this.blockLength;break;case "OFB":this.decrypt=this.encrypt=ia;this.shiftBits=b.shiftBits||this.blockLength;break;default:throw new C("Block mode "+b.block+" not supported");}switch(b.keyMeshing){case "CP":this.keyMeshing=wa;break;default:this.keyMeshing=M}if(this.encrypt===x||this.encrypt===T)switch(b.padding){case "PKCS5P":this.pad=ya;this.unpad=za;break;case "RANDOM":this.pad=Ba;this.unpad=G;break;case "BIT":this.pad=W;this.unpad=Aa;break;default:this.pad=U,this.unpad= 46 | G}else this.unpad=this.pad=G;this.generateKey=y;break;case "MAC":this.sign=z;this.verify=A;this.generateKey=y;this.macLength=b.macLength||this.blockLength>>1;this.unpad=this.pad=G;this.keyMeshing=M;break;case "KW":this.unpad=this.pad=G;this.keyMeshing=M;switch(b.keyWrapping){case "CP":this.wrapKey=pa;this.unwrapKey=qa;this.generateKey=y;this.shiftBits=b.shiftBits||this.blockLength;break;case "SC":this.wrapKey=ra;this.unwrapKey=sa;this.generateKey=ta;break;default:this.wrapKey=na,this.unwrapKey=oa, 47 | this.generateKey=y}break;case "MASK":this.wrapKey=ua;this.unwrapKey=va;this.generateKey=y;break;default:throw new C("Mode "+b.mode+" not supported");}var c=b.sBox;if(!c)c=2015===this.version?u["E-Z"]:"SC"===this.procreator?u["E-SC"]:u["E-A"];else if("string"===typeof c){if(c=c.toUpperCase(),c=u[c],!c)throw new B("Unknown sBox name: "+b.sBox);}else if(!c.length||c.length!==u["E-Z"].length)throw new B("Length of sBox must be "+u["E-Z"].length);this.sBox=c;if(b.iv){this.iv=new Uint8Array(b.iv);if(this.iv.byteLength!== 48 | this.blockSize&&1989===this.version)throw new B("Length of iv must be "+this.blockLength+" bits");if(this.iv.byteLength!==this.blockSize>>1&&this.encrypt===L)throw new B("Length of iv must be "+this.blockLength>>NaN);if(0!==this.iv.byteLength%this.blockSize&&this.encrypt!==L)throw new B("Length of iv must be a multiple of "+this.blockLength+" bits");}else this.iv=128===this.blockLength?Ea:Da;if(b.ukm&&(this.ukm=new Uint8Array(b.ukm),8*this.ukm.byteLength!==this.blockLength))throw new B("Length of ukm must be "+ 49 | this.blockLength+" bits");}}); 50 | -------------------------------------------------------------------------------- /gostCipher.test.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015, Rudolf Nickolaev. 3 | * All rights reserved. 4 | * 5 | * GOST 28147-89 Encryption Algorithm 6 | * 7 | */ 8 | 9 | /* 10 | * Licensed under the Apache License, Version 2.0 (the "License"); 11 | * you may not use this file except in compliance with the License. 12 | * You may obtain a copy of the License at 13 | * 14 | * http://www.apache.org/licenses/LICENSE-2.0 15 | * 16 | * Unless required by applicable law or agreed to in writing, software 17 | * distributed under the License is distributed on an "AS IS" BASIS, 18 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 19 | * See the License for the specific language governing permissions and 20 | * limitations under the License. 21 | * 22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 24 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 25 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 28 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 29 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | * 33 | */ 34 | 35 | (function (root, factory) { 36 | 37 | if (typeof define === 'function' && define.amd) { 38 | define(['gostCoding', 'gostCipher'], factory); 39 | } else if (typeof exports === 'object') { 40 | module.exports = factory(require('gostCoding'), require('gostCipher')); 41 | } else { 42 | if (typeof importScripts !== 'undefined') { 43 | if (!root.onmessage) 44 | root.onmessage = function (event) { 45 | postMessage((root[event.data.object] || root)[event.data.method].apply(event.data.object || root, event.data.args)); 46 | }; 47 | importScripts('gostCoding.js', 'gostCipher.js'); 48 | } 49 | root.GostCipher_test = factory(root.GostCoding, root.GostCipher); 50 | } 51 | 52 | }(this, function (GostCoding, GostCipher) { 53 | 54 | var root = this, gostCoding; 55 | 56 | function println(s, h) { 57 | if (typeof importScripts !== 'undefined') { 58 | var tag = h ? 'h3' : 'div'; 59 | postMessage({log: '<' + tag + '>' + (s || ' ') + ''}); 60 | } else { 61 | if (typeof document !== 'undefined') { 62 | var el = document.createElement(h ? 'h3' : 'div'); 63 | el.innerHTML = s || ' '; 64 | (document.getElementById('output') || document.body).appendChild(el); 65 | } 66 | if (typeof console !== 'undefined') 67 | console.log((s || '') + (h ? '' : '\n')); 68 | } 69 | } 70 | 71 | function perform(id, algorithm, key, input, output) { 72 | var Hex = gostCoding.Hex; 73 | if (algorithm.iv) 74 | (algorithm.iv = Hex.decode(algorithm.iv)); 75 | 76 | var cipher = new GostCipher(algorithm); 77 | var result = 'Test ' + ' ' + ('0' + id).slice(-2) + ' ' + (cipher.name + ' ' + new Array(61).join('.')).substring(0, 60) + ' '; 78 | try { 79 | var out = Hex.encode(cipher.encrypt(Hex.decode(key), Hex.decode(input))); 80 | var test = 0 + (output && out.replace(/[^\-A-Fa-f0-9]/g, '').toLowerCase() !== output.toLowerCase()); 81 | if (!test) { 82 | var out = Hex.encode(cipher.decrypt(Hex.decode(key), Hex.decode(out))); 83 | test = 0 + (out.replace(/[^\-A-Fa-f0-9]/g, '').toLowerCase() !== input.toLowerCase()); 84 | if (!test) 85 | result += 'PASSED'; 86 | else 87 | result += 'FAILED - Decrypt expected ' + input + " got " + out; 88 | } else 89 | result += 'FAILED - Encrypt expected ' + output + " got " + out; 90 | } catch (e) { 91 | result += 'FAILED - Throw error: ' + e.message; 92 | } 93 | println(result); 94 | return test; 95 | } 96 | 97 | function performMac(id, algorithm, key, input, output) { 98 | var Hex = gostCoding.Hex; 99 | if (algorithm.iv) 100 | (algorithm.iv = Hex.decode(algorithm.iv)); 101 | 102 | var cipher = new GostCipher(algorithm); 103 | var result = 'Test ' + ' ' + ('0' + id).slice(-2) + ' ' + (cipher.name + ' ' + new Array(61).join('.')).substring(0, 60) + ' '; 104 | try { 105 | var out = Hex.encode(cipher.sign(Hex.decode(key), Hex.decode(input))); 106 | var test = 0 + (output && out.replace(/[^\-A-Fa-f0-9]/g, '').toLowerCase() !== output.toLowerCase()); 107 | if (!test) { 108 | var res = cipher.verify(Hex.decode(key), Hex.decode(out), Hex.decode(input)); 109 | test = 0 + (!res); 110 | if (!test) 111 | result += 'PASSED'; 112 | else 113 | result += 'FAILED - Verify return (false)'; 114 | } else 115 | result += 'FAILED - Sign expected ' + output + " got " + out; 116 | } catch (e) { 117 | result += 'FAILED - Throw error: ' + e.message; 118 | } 119 | println(result); 120 | return test; 121 | } 122 | 123 | function performWrap(id, algorithm, key, input, output) { 124 | var Hex = gostCoding.Hex; 125 | if (algorithm.ukm) 126 | (algorithm.ukm = Hex.decode(algorithm.ukm)); 127 | 128 | var cipher = new GostCipher(algorithm); 129 | var result = 'Test ' + ' ' + ('0' + id).slice(-2) + ' ' + (cipher.name + ' ' + new Array(61).join('.')).substring(0, 60) + ' '; 130 | try { 131 | var out = Hex.encode(cipher.wrapKey(Hex.decode(key), Hex.decode(input))); 132 | var test = 0 + (output && out.replace(/[^\-A-Fa-f0-9]/g, '').toLowerCase() !== output.toLowerCase()); 133 | if (!test) { 134 | var out = Hex.encode(cipher.unwrapKey(Hex.decode(key), Hex.decode(out))); 135 | test = 0 + (out.replace(/[^\-A-Fa-f0-9]/g, '').toLowerCase() !== input.toLowerCase()); 136 | if (!test) 137 | result += 'PASSED'; 138 | else 139 | result += 'FAILED - Unwrap key expected ' + input + " got " + out; 140 | } else 141 | result += 'FAILED - Wrap key expected ' + output + " got " + out; 142 | } catch (e) { 143 | result += 'FAILED - Throw error: ' + e.message; 144 | } 145 | println(result); 146 | return test; 147 | } 148 | 149 | /** 150 | * Test cases 151 | * 152 | * @returns {unresolved} 153 | */ 154 | return function () { 155 | 156 | GostCoding = GostCoding || root.GostCoding; 157 | gostCoding = new GostCoding(); 158 | GostCipher = GostCipher || root.GostCipher; 159 | 160 | var input1 = "0000000000000000"; 161 | var output1 = "1b0bbc32cebcab42"; 162 | var input2 = "bc350e71aac5f5c2"; 163 | var output2 = "d35ab653493b49f5"; 164 | var input3 = "bc350e71aa11345709acde"; 165 | var output3 = "8824c124c4fd14301fb1e8"; 166 | var input4 = "000102030405060708090a0b0c0d0e0fff0102030405060708090a0b0c0d0e0f"; 167 | var output4 = "29b7083e0a6d955ca0ec5b04fdb4ea41949f1dd2efdf17baffc1780b031f3934"; 168 | 169 | var TestSBox = new Uint8Array([ 170 | 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 171 | 0xF, 0xE, 0xD, 0xC, 0xB, 0xA, 0x9, 0x8, 0x7, 0x6, 0x5, 0x4, 0x3, 0x2, 0x1, 0x0, 172 | 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 173 | 0xF, 0xE, 0xD, 0xC, 0xB, 0xA, 0x9, 0x8, 0x7, 0x6, 0x5, 0x4, 0x3, 0x2, 0x1, 0x0, 174 | 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 175 | 0xF, 0xE, 0xD, 0xC, 0xB, 0xA, 0x9, 0x8, 0x7, 0x6, 0x5, 0x4, 0x3, 0x2, 0x1, 0x0, 176 | 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 177 | 0xF, 0xE, 0xD, 0xC, 0xB, 0xA, 0x9, 0x8, 0x7, 0x6, 0x5, 0x4, 0x3, 0x2, 0x1, 0x0 178 | ]); 179 | 180 | 181 | // Basic chiper mode tests 182 | var tests = 0, i = 0; 183 | println('GOST 28147-89/GOST R 34.12-2015 TEST', true); 184 | 185 | tests += perform(++i, {name: 'GOST 28147', sBox: 'D-TEST'}, 186 | '546d203368656c326973652073736e62206167796967747473656865202c3d73', input1, output1); 187 | tests += perform(++i, {name: 'GOST 28147', block: 'CBC', iv: '1234567890abcdef', sBox: 'D-TEST'}, 188 | '00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF', input2, output2); 189 | tests += perform(++i, {name: 'GOST 28147', block: 'CTR', iv: '1234567890abcdef', sBox: 'D-TEST'}, 190 | '0011223344556677889900112233445566778899001122334455667788990011', input3, output3); 191 | tests += perform(++i, {name: 'GOST 28147', block: 'CFB', iv: 'aafd12f659cae634', sBox: 'D-TEST'}, 192 | 'aafd12f659cae63489b479e5076ddec2f06cb58faafd12f659cae63489b479e5', input4, output4); 193 | 194 | // Tests with parameters, set S-box. 195 | tests += perform(++i, {name: 'GOST 28147', sBox: 'D-TEST'}, 196 | '546d203368656c326973652073736e62206167796967747473656865202c3d73', input1, output1); // default parameter S-box set to D-TEST 197 | tests += perform(++i, {name: 'GOST 28147', block: 'CFB', iv: '1234567890abcdef', sBox: 'D-TEST'}, 198 | '546d203368656c326973652073736e62206167796967747473656865202c3d73', '0000000000000000', 'b587f7a0814c911d'); //type S-box 199 | tests += perform(++i, {name: 'GOST 28147', block: 'CFB', iv: '1234567890abcdef', sBox: 'E-TEST'}, 200 | '546d203368656c326973652073736e62206167796967747473656865202c3d73', '0000000000000000', 'e8287f53f991d52b'); 201 | tests += perform(++i, {name: 'GOST 28147', block: 'CFB', shiftBits: 64, iv: '1234567890abcdef', sBox: 'E-A'}, 202 | '546d203368656c326973652073736e62206167796967747473656865202c3d73', '0000000000000000', 'c41009dba22ebe35'); 203 | tests += perform(++i, {name: 'GOST 28147', block: 'CFB', iv: '1234567890abcdef', sBox: 'E-B', shiftBits: 8}, 204 | '546d203368656c326973652073736e62206167796967747473656865202c3d73', '0000000000000000', '80d8723fcd3aba28'); 205 | tests += perform(++i, {name: 'GOST 28147', block: 'CFB', shiftBits: 8, iv: '1234567890abcdef', sBox: 'E-C'}, 206 | '546d203368656c326973652073736e62206167796967747473656865202c3d73', '0000000000000000', '739f6f95068499b5'); 207 | tests += perform(++i, {name: 'GOST 28147', block: 'CFB', shiftBits: 8, iv: '1234567890abcdef', sBox: 'E-D'}, 208 | '546d203368656c326973652073736e62206167796967747473656865202c3d73', '0000000000000000', '4663f720f4340f57'); 209 | tests += perform(++i, {name: 'GOST 28147', block: 'CFB', shiftBits: 8, iv: '1234567890abcdef', sBox: 'D-A'}, 210 | '546d203368656c326973652073736e62206167796967747473656865202c3d73', '0000000000000000', '5bb0a31d218ed564'); 211 | tests += perform(++i, {name: 'GOST 28147', block: 'CFB', shiftBits: 8, iv: '1234567890abcdef', sBox: TestSBox}, 212 | '546d203368656c326973652073736e62206167796967747473656865202c3d73', '0000000000000000', 'c3af96ef788667c5'); 213 | tests += perform(++i, {name: 'GOST 28147', block: 'CTR', iv: '1234567890abcdef', sBox: 'E-A'}, 214 | '4ef72b778f0b0bebeef4f077551cb74a927b470ad7d7f2513454569a247e989d', 'bc350e71aa11345709acde', '1bcc2282707c676fb656dc'); 215 | tests += perform(++i, {name: 'GOST 28147', block: 'ECB', sBox: 'E-Z'}, 216 | '8182838485868788898a8b8c8d8e8f80d1d2d3d4d5d6d7d8d9dadbdcdddedfd0', 217 | '0102030405060708f1f2f3f4f5f6f7f8', 'ce5a5ed7e0577a5fd0cc85ce31635b8b'); 218 | 219 | var gkeyBytes5 = "6d145dc993f4019e104280df6fcd8cd8e01e101e4c113d7ec4f469ce6dcd9e49"; 220 | var gkeyBytes6 = "6d145dc993f4019e104280df6fcd8cd8e01e101e4c113d7ec4f469ce6dcd9e49"; 221 | 222 | var input5 = "7768617420646f2079612077616e7420666f72206e6f7468696e673f"; 223 | var input6 = "7768617420646f2079612077616e7420666f72206e6f7468696e673f"; 224 | 225 | var output5 = "93468a46"; 226 | var output6 = "93468a46"; 227 | 228 | // MAC 229 | println(); 230 | println('MAC sing/verify'); 231 | tests += performMac(++i, {name: 'GOST 28147', mode: 'MAC', sBox: 'E-A'}, gkeyBytes5, input5, output5); 232 | tests += performMac(++i, {name: 'GOST 28147', mode: 'MAC', sBox: 'E-A'}, gkeyBytes6, input6, output6); 233 | 234 | // Padding 235 | println(); 236 | println('Padding'); 237 | tests += perform(++i, {name: 'GOST 28147', sBox: 'D-TEST', padding: 'BIT'}, 238 | '546d203368656c326973652073736e62206167796967747473656865202c3d73', 'fedcba98765432'); 239 | tests += perform(++i, {name: 'GOST 28147', sBox: 'D-TEST', padding: 'BIT'}, 240 | '546d203368656c326973652073736e62206167796967747473656865202c3d73', 'fedcba9876543210'); 241 | tests += perform(++i, {name: 'GOST 28147', sBox: 'D-TEST', padding: 'PKCS5P'}, 242 | '546d203368656c326973652073736e62206167796967747473656865202c3d73', 'fedcba98765432'); 243 | tests += perform(++i, {name: 'GOST 28147', sBox: 'D-TEST', padding: 'PKCS5P'}, 244 | '546d203368656c326973652073736e62206167796967747473656865202c3d73', 'fedcba9876543210'); 245 | tests += perform(++i, {name: 'GOST 28147', sBox: 'D-TEST', padding: 'ZERO'}, 246 | '546d203368656c326973652073736e62206167796967747473656865202c3d73', 'fedcba9876543210'); 247 | 248 | // Key meshing 249 | println(); 250 | println('Key meshing'); 251 | var input = new Array(10001).join('61'); // hex(a) 252 | tests += perform(++i, {name: 'GOST 28147', block: 'CFB', keyMeshing: 'CP', iv: '1234567890abcdef', sBox: 'E-A'}, 253 | '4ef72b778f0b0bebeef4f077551cb74a927b470ad7d7f2513454569a247e989d', input); 254 | tests += perform(++i, {name: 'GOST 28147', block: 'CBC', keyMeshing: 'CP', iv: '1234567890abcdef', sBox: 'E-A'}, 255 | '4ef72b778f0b0bebeef4f077551cb74a927b470ad7d7f2513454569a247e989d', input); 256 | tests += perform(++i, {name: 'GOST 28147', block: 'CTR', keyMeshing: 'CP', iv: '1234567890abcdef', sBox: 'E-A'}, 257 | '4ef72b778f0b0bebeef4f077551cb74a927b470ad7d7f2513454569a247e989d', input); 258 | tests += performMac(++i, {name: 'GOST 28147', mode: 'MAC', keyMeshing: 'CP', iv: '1234567890abcdef', sBox: 'E-A'}, 259 | '4ef72b778f0b0bebeef4f077551cb74a927b470ad7d7f2513454569a247e989d', input); 260 | 261 | println(); 262 | println('Key wrapping'); 263 | var input = new Array(10001).join('61'); // hex(a) 264 | tests += performWrap(++i, {name: 'GOST 28147', mode: 'KW', ukm: '1234567890abcdef', sBox: 'D-TEST'}, // Initial UKM seed 265 | 'aafd12f659cae63489b479e5076ddec2f06cb58faafd12f659cae63489b479e5', 266 | '6d145dc993f4019e104280df6fcd8cd8e01e101e4c113d7ec4f469ce6dcd9e49', 267 | 'af502015229a831dc82b4d32dc00173f5d43d921e5e09cc09ce947c777414397022a90c7'); 268 | tests += performWrap(++i, {name: 'GOST 28147', mode: 'KW', ukm: '1234567890abcdef', sBox: 'E-A'}, // E-A 269 | 'aafd12f659cae63489b479e5076ddec2f06cb58faafd12f659cae63489b479e5', 270 | '6d145dc993f4019e104280df6fcd8cd8e01e101e4c113d7ec4f469ce6dcd9e49'); 271 | 272 | tests += performWrap(++i, {name: 'GOST 28147', sBox: 'D-TEST', ukm: '1234567890abcdef', keyWrapping: 'CP'}, // CryptoPro. 273 | 'aafd12f659cae63489b479e5076ddec2f06cb58faafd12f659cae63489b479e5', 274 | '6d145dc993f4019e104280df6fcd8cd8e01e101e4c113d7ec4f469ce6dcd9e49', 275 | '16256f060dd3b3d8734a9fcc9ab4c3d04e777dc5c46a2f4c3e411e3597a5bfc32b41e492'); 276 | 277 | tests += performWrap(++i, {name: 'GOST 28147', mode: 'KW', keyWrapping: 'CP', ukm: '1234567890abcdef', sBox: 'E-A'}, // CryptoPro E-A 278 | 'aafd12f659cae63489b479e5076ddec2f06cb58faafd12f659cae63489b479e5', 279 | '6d145dc993f4019e104280df6fcd8cd8e01e101e4c113d7ec4f469ce6dcd9e49'); 280 | 281 | tests += performWrap(++i, {name: 'GOST 28147', mode: 'KW', keyWrapping: 'SC', sBox: 'E-SC'}, 282 | '2208cd6bc96a' + 283 | '009f05175f635bee6cc09c78260b9b7eee1e070d346462e6881bbf572f436df5' + 284 | '716b1212a9fba3d022db4aed0a18530ae6c62d9bdd206479805ce652c17bc9cc' + 285 | '07dcdce25cba19276285f6c54dfa940ab55473bde2d8338eaaedc59cdd808619' + 286 | 'f75296db91e016b588c0650686ff6929258a76d5ca7ba91b7fa87f41b2deb535' + 287 | 'a66b489a5485ac68971e00658836ce358dcda04b358621ebf08ce062b671d84a' + 288 | '30706495ee2ed7d0f0a6a3e171a9daba04b582c3b7113905053a5b9254c7e08b' + 289 | 'ea27cb66e19699db55444f1e1f1b5a3b7db7cbcc04728e225e67ab8099dc82b1' + // mk.db3 290 | '5d6f4f794c0f584718252fb2d9ffffe6d2adc4c86616466fe032ed28790e6af6', // masks.db3 291 | '5a7145b0ee4c080e0fcf689e5222c25876ac9d2b25a68fb3357eea8f849d6272', 292 | '7c34bf4e03d0bc120768164f355cf6180b32851e2ad6fc22b386bbea17fa1d5f1789eb95'); // kek.opq 293 | 294 | // Tests for new GOST 2015 295 | println(); 296 | println('GOST R 34.12-2015/64bits'); 297 | var key64 = 'ffeeddccbbaa99887766554433221100f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff'; 298 | var inp64 = '92def06b3c130a59db54c704f8189d204a98fb2e67a8024c8912409b17b57e41'; 299 | tests += perform(++i, {name: 'GOST R 34.12', version: 2015}, key64, 'fedcba9876543210', '4ee901e5c2d8ca3d'); 300 | tests += perform(++i, {name: 'GOST R 34.12', version: 2015, block: 'ECB'}, key64, inp64, 301 | '2b073f0494f372a0de70e715d3556e4811d8d9e9eacfbc1e7c68260996c67efb'); 302 | tests += perform(++i, {name: 'GOST R 34.12', version: 2015, block: 'CTR', iv: '12345678'}, key64, inp64, 303 | '4e98110c97b7b93c3e250d93d6e85d69136d868807b2dbef568eb680ab52a12d'); 304 | tests += perform(++i, {name: 'GOST R 34.12', version: 2015, block: 'CBC', iv: '1234567890abcdef234567890abcdef134567890abcdef12'}, 305 | key64, inp64, '96d1b05eea683919aff76129abb937b95058b4a1c4bc001920b78b1a7cd7e667'); 306 | tests += perform(++i, {name: 'GOST R 34.12', version: 2015, block: 'CFB', iv: '1234567890abcdef234567890abcdef1'}, 307 | key64, inp64, 'db37e0e266903c830d46644c1f9a089c24bdd2035315d38bbcc0321421075505'); 308 | tests += perform(++i, {name: 'GOST R 34.12', version: 2015, block: 'OFB', iv: '1234567890abcdef234567890abcdef1'}, 309 | key64, inp64, 'db37e0e266903c830d46644c1f9a089ca0f83062430e327ec824efb8bd4fdb05'); 310 | tests += performMac(++i, {name: 'GOST R 34.12', version: 2015, mode: 'MAC'}, 311 | key64, inp64, '154e7210'); 312 | 313 | println(); 314 | println('GOST R 34.12-2015/128bits'); 315 | var key128 = '8899aabbccddeeff0011223344556677fedcba98765432100123456789abcdef'; 316 | var inp128 = '1122334455667700ffeeddccbbaa998800112233445566778899aabbcceeff0a112233445566778899aabbcceeff0a002233445566778899aabbcceeff0a0011'; 317 | tests += perform(++i, {name: 'GOST R 34.12', version: 2015, length: 128}, key128, 318 | '1122334455667700ffeeddccbbaa9988', '7f679d90bebc24305a468d42b9d4edcd'); 319 | tests += perform(++i, {name: 'GOST R 34.12', version: 2015, length: 128}, key128, inp128, 320 | '7f679d90bebc24305a468d42b9d4edcdb429912c6e0032f9285452d76718d08bf0ca33549d247ceef3f5a5313bd4b157d0b09ccde830b9eb3a02c4c5aa8ada98'); 321 | tests += perform(++i, {name: 'GOST R 34.12', version: 2015, length: 128, block: 'CTR', iv: '1234567890abcef0'}, key128, inp128, 322 | 'f195d8bec10ed1dbd57b5fa240bda1b885eee733f6a13e5df33ce4b33c45dee4a5eae88be6356ed3d5e877f13564a3a5cb91fab1f20cbab6d1c6d15820bdba73'); 323 | tests += perform(++i, {name: 'GOST R 34.12', version: 2015, length: 128, block: 'OFB', 324 | iv: '1234567890abcef0a1b2c3d4e5f0011223344556677889901213141516171819'}, key128, inp128, 325 | '81800a59b1842b24ff1f795e897abd95ed5b47a7048cfab48fb521369d9326bf66a257ac3ca0b8b1c80fe7fc10288a13203ebbc066138660a0292243f6903150'); 326 | tests += perform(++i, {name: 'GOST R 34.12', version: 2015, length: 128, block: 'CBC', 327 | iv: '1234567890abcef0a1b2c3d4e5f0011223344556677889901213141516171819'}, key128, inp128, 328 | '689972d4a085fa4d90e52e3d6d7dcc272826e661b478eca6af1e8e448d5ea5acfe7babf1e91999e85640e8b0f49d90d0167688065a895c631a2d9a1560b63970'); 329 | tests += perform(++i, {name: 'GOST R 34.12', version: 2015, length: 128, block: 'CFB', 330 | iv: '1234567890abcef0a1b2c3d4e5f0011223344556677889901213141516171819'}, key128, inp128, 331 | '81800a59b1842b24ff1f795e897abd95ed5b47a7048cfab48fb521369d9326bf79f2a8eb5cc68d38842d264e97a238b54ffebecd4e922de6c75bd9dd44fbf4d1'); 332 | tests += performMac(++i, {name: 'GOST R 34.12', version: 2015, length: 128, mode: 'MAC'}, key128, inp128, 333 | '336f4d296059fbe3'); 334 | 335 | println(); 336 | println('RC2'); 337 | tests += perform(++i, {name: 'RC2', version: 1, length: 63}, '0000000000000000', '0000000000000000', 'ebb773f993278eff'); 338 | tests += perform(++i, {name: 'RC2', version: 1, length: 64}, 'ffffffffffffffff', 'ffffffffffffffff', '278b27e42e2f0d49'); 339 | tests += perform(++i, {name: 'RC2', version: 1, length: 64}, '3000000000000000', '1000000000000001', '30649edf9be7d2c2'); 340 | tests += perform(++i, {name: 'RC2', version: 1, length: 64}, '88', '0000000000000000', '61a8a244adacccf0'); 341 | tests += perform(++i, {name: 'RC2', version: 1, length: 64}, '88bca90e90875a', '0000000000000000', '6ccf4308974c267f'); 342 | tests += perform(++i, {name: 'RC2', version: 1, length: 64}, '88bca90e90875a7f0f79c384627bafb2', '0000000000000000', '1a807d272bbe5db1'); 343 | tests += perform(++i, {name: 'RC2', version: 1, length: 128}, '88bca90e90875a7f0f79c384627bafb2', '0000000000000000', '2269552ab0f85ca6'); 344 | tests += perform(++i, {name: 'RC2', version: 1, length: 129}, '88bca90e90875a7f0f79c384627bafb216f80a6f85920584c42fceb0be255daf1e', '0000000000000000', '5b78d3a43dfff1f1'); 345 | println(); 346 | 347 | println('TOTAL ' + (tests ? tests + ' ERRORS' : 'OK')); 348 | println(); 349 | 350 | return tests; 351 | }; 352 | 353 | })); 354 | 355 | -------------------------------------------------------------------------------- /gostDigest.test.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Rudolf Nickolaev. 3 | * All rights reserved. 4 | * 5 | * Tests for GOST R 34.11-2012 hash function with 512/256 bits digest. 6 | * 7 | */ 8 | 9 | /* 10 | * Licensed under the Apache License, Version 2.0 (the "License"); 11 | * you may not use this file except in compliance with the License. 12 | * You may obtain a copy of the License at 13 | * 14 | * http://www.apache.org/licenses/LICENSE-2.0 15 | * 16 | * Unless required by applicable law or agreed to in writing, software 17 | * distributed under the License is distributed on an "AS IS" BASIS, 18 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 19 | * See the License for the specific language governing permissions and 20 | * limitations under the License. 21 | * 22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 24 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 25 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 28 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 29 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | * 33 | */ 34 | 35 | (function (root, factory) { 36 | if (typeof define === 'function' && define.amd) { 37 | define(['gostCoding', 'gostDigest'], factory); 38 | } else if (typeof exports === 'object') { 39 | module.exports = factory(require('gostCoding'), require('gostCipher'), require('gostDigest')); 40 | } else { 41 | if (typeof importScripts !== 'undefined') { 42 | if (!root.onmessage) 43 | root.onmessage = function (event) { 44 | postMessage((root[event.data.object] || root)[event.data.method].apply(event.data.object || root, event.data.args)); 45 | }; 46 | importScripts('gostCoding.js', 'gostCipher.js', 'gostDigest.js'); 47 | } 48 | root.GostDigest_test = factory(root.GostCoding, root.GostCipher, root.GostDigest); 49 | } 50 | }(this, function (GostCoding, GostCipher, GostDigest) { 51 | 52 | var root = this, gostCoding; 53 | 54 | /* ========== Tests ========== */ 55 | 56 | function println(s, h) { 57 | if (typeof importScripts !== 'undefined') { 58 | var tag = h ? 'h3' : 'div'; 59 | postMessage({log: '<' + tag + '>' + (s || ' ') + ''}); 60 | } else { 61 | if (typeof document !== 'undefined') { 62 | var el = document.createElement(h ? 'h3' : 'div'); 63 | el.innerHTML = s || ' '; 64 | (document.getElementById('output') || document.body).appendChild(el); 65 | } 66 | if (typeof console !== 'undefined') 67 | console.log((s || '') + (h ? '' : '\n')); 68 | } 69 | } 70 | 71 | function perform(cipher, id, array, digest, method, param) { 72 | var start, finish, out, r, test; 73 | 74 | start = (new Date).getTime(); 75 | r = 'Test ' + ' ' + ('0' + id).slice(-2) + ' ' + (cipher.name + ' ' + new Array(61).join('.')).substring(0, 60) + ' '; 76 | try { 77 | method = method || 'digest'; 78 | out = gostCoding.Hex.encode(cipher[method](array, param)); 79 | finish = (new Date).getTime(); 80 | out = out.replace(/[^\-A-Fa-f0-9]/g, '').toLowerCase(); 81 | test = 0 + (out !== digest.toLowerCase()); 82 | if (test) 83 | r += 'FAILED: Expected ' + digest + " got " + out; 84 | else 85 | r += 'PASSED ' + (finish - start) / 1000 + ' sec'; 86 | } catch (e) { 87 | r += 'FAILED - Throw error: ' + e.message; 88 | } 89 | 90 | println(r); 91 | return test; 92 | } 93 | 94 | return function (performance) { 95 | 96 | GostCoding = GostCoding || root.GostCoding; 97 | gostCoding = new GostCoding(); 98 | GostDigest = GostDigest || root.GostDigest; 99 | 100 | // GOST R 34.11-94 tests 101 | var tests = 0, i = 0; 102 | println('GOST R 34.11-94 TEST', true); 103 | 104 | var cipher = new GostDigest({name: 'GOST R 34.11', version: 1994}); 105 | 106 | tests += perform(cipher, ++i, 107 | gostCoding.Chars.decode(''), 108 | '981e5f3ca30c841487830f84fb433e13ac1101569b9c13584ac483234cd656c0'); 109 | tests += perform(cipher, ++i, 110 | gostCoding.Chars.decode('This is message, length=32 bytes'), 111 | '2cefc2f7b7bdc514e18ea57fa74ff357e7fa17d652c75f69cb1be7893ede48eb'); 112 | tests += perform(cipher, ++i, 113 | gostCoding.Chars.decode('Suppose the original message has length = 50 bytes'), 114 | 'c3730c5cbccacf915ac292676f21e8bd4ef75331d9405e5f1a61dc3130a65011'); 115 | tests += perform(cipher, ++i, 116 | gostCoding.Chars.decode('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'), 117 | '73b70a39497de53a6e08c67b6d4db853540f03e9389299d9b0156ef7e85d0f61'); 118 | println(); 119 | 120 | cipher = new GostDigest({name: 'GOST R 34.11', version: 1994, sBox: 'D-TEST'}); 121 | 122 | tests += perform(cipher, ++i, 123 | gostCoding.Chars.decode(''), 124 | 'ce85b99cc46752fffee35cab9a7b0278abb4c2d2055cff685af4912c49490f8d'); 125 | tests += perform(cipher, ++i, 126 | gostCoding.Chars.decode('This is message, length=32 bytes'), 127 | 'b1c466d37519b82e8319819ff32595e047a28cb6f83eff1c6916a815a637fffa'); 128 | tests += perform(cipher, ++i, 129 | gostCoding.Chars.decode('Suppose the original message has length = 50 bytes'), 130 | '471aba57a60a770d3a76130635c1fbea4ef14de51f78b4ae57dd893b62f55208'); 131 | tests += perform(cipher, ++i, 132 | gostCoding.Chars.decode('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'), 133 | '95c1af627c356496d80274330b2cff6a10c67b5f597087202f94d06d2338cf8e'); 134 | println(); 135 | 136 | println('PBKDF2 tests'); 137 | cipher = new GostDigest({name: 'GOST R 34.11', version: 1994, mode: 'PBKDF2', salt: gostCoding.Chars.decode('salt'), iterations: 1}); 138 | tests += perform(cipher, ++i, 139 | gostCoding.Chars.decode('password'), 140 | '7314e7c04fb2e662c543674253f68bd0b73445d07f241bed872882da21662d58', 'deriveKey'); 141 | cipher = new GostDigest({name: 'GOST R 34.11', version: 1994, mode: 'PBKDF2', salt: gostCoding.Chars.decode('salt'), iterations: 2}); 142 | tests += perform(cipher, ++i, 143 | gostCoding.Chars.decode('password'), 144 | '990dfa2bd965639ba48b07b792775df79f2db34fef25f274378872fed7ed1bb3', 'deriveKey'); 145 | cipher = new GostDigest({name: 'GOST R 34.11', version: 1994, mode: 'PBKDF2', salt: gostCoding.Chars.decode('salt'), iterations: 1000}); 146 | tests += perform(cipher, ++i, 147 | gostCoding.Chars.decode('password'), 148 | '2b6e0a5cc2103274dd3353fb86e4983c6451f8025a51cd9ddfd33361c6cb572b', 'deriveKey'); 149 | println(); 150 | 151 | if (performance) { 152 | 153 | println('PBKDF2 4096 iterations tests'); 154 | cipher = new GostDigest({name: 'GOST R 34.11', version: 1994, mode: 'PBKDF2', salt: gostCoding.Chars.decode('salt'), iterations: 4096}); 155 | tests += perform(cipher, ++i, 156 | gostCoding.Chars.decode('password'), 157 | '1f1829a94bdff5be10d0aeb36af498e7a97467f3b31116a5a7c1afff9deadafe', 'deriveKey'); 158 | 159 | cipher = new GostDigest({name: 'GOST R 34.11', version: 1994, mode: 'PBKDF2', salt: gostCoding.Chars.decode('saltSALTsaltSALTsaltSALTsaltSALTsalt'), iterations: 4096}); 160 | tests += perform(cipher, ++i, 161 | gostCoding.Chars.decode('passwordPASSWORDpassword'), 162 | '788358c69cb2dbe251a7bb17d5f4241f265a792a35becde8d56f326b49c85047b7638acb4764b1fd', 'deriveBits', 320); 163 | 164 | cipher = new GostDigest({name: 'GOST R 34.11', version: 1994, mode: 'PBKDF2', salt: gostCoding.Chars.decode('sa\0lt'), iterations: 4096}); 165 | tests += perform(cipher, ++i, 166 | gostCoding.Chars.decode('pass\0word'), 167 | '43e06c5590b08c0225242373127edf9c8e9c3291', 'deriveBits', 160); 168 | 169 | println(); 170 | 171 | 172 | cipher = new GostDigest({name: 'GOST R 34.11', version: 1994}); 173 | println('Million "a" TEST'); 174 | var million_a = new Array(1000001).join('a'); 175 | tests += perform(cipher, ++i, 176 | gostCoding.Chars.decode(million_a), 177 | '8693287aa62f9478f7cb312ec0866b6c4e4a0f11160441e8f4ffcd2715dd554f'); 178 | println(); 179 | } 180 | println('TOTAL ' + (tests ? tests + ' ERRORS' : 'OK')); 181 | println(); 182 | 183 | // GOST R 34.11-2012 tests 184 | var tests2 = 0; 185 | i = 0; 186 | println('GOST R 34.11-2012 TEST', true); 187 | 188 | cipher = new GostDigest(); 189 | tests2 += perform(cipher, ++i, 190 | gostCoding.Chars.decode('012345678901234567890123456789012345678901234567890123456789012'), 191 | '9d151eefd8590b89daa6ba6cb74af9275dd051026bb149a452fd84e5e57b5500'); 192 | tests2 += perform(cipher, ++i, 193 | gostCoding.Chars.decode('Се ветри, Стрибожи внуци, веютъ с моря стрелами на храбрыя плъкы Игоревы'), 194 | '9dd2fe4e90409e5da87f53976d7405b0c0cac628fc669a741d50063c557e8f50'); 195 | tests2 += perform(cipher, ++i, new Uint8Array(0), 196 | '3f539a213e97c802cc229d474c6aa32a825a360b2a933a949fd925208d9ce1bb'); 197 | tests2 += perform(cipher, ++i, new Uint8Array([ 198 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 199 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]), 200 | 'df1fda9ce83191390537358031db2ecaa6aa54cd0eda241dc107105e13636b95'); 201 | println(); 202 | 203 | cipher = new GostDigest({name: 'GOST R 34.11', version: 2012, mode: 'KDF', context: gostCoding.Hex.decode('af21434145656378'), 204 | label: gostCoding.Hex.decode('26bdb878')}); 205 | tests += perform(cipher, ++i, 206 | gostCoding.Hex.decode('000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f'), 207 | 'a1aa5f7de402d7b3d323f2991c8d4534013137010a83754fd0af6d7cd4922ed9', 'deriveKey'); 208 | cipher = new GostDigest({name: 'GOST R 34.11', version: 2012, mode: 'KDF', context: gostCoding.Hex.decode('af21434145656378'), 209 | label: gostCoding.Hex.decode('26bdb878')}); 210 | tests += perform(cipher, ++i, 211 | gostCoding.Hex.decode('000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f'), 212 | '22b6837845c6bef65ea71672b265831086d3c76aebe6dae91cad51d83f79d16b074c9330599d7f8d712fca54392f4ddde93751206b3584c8f43f9e6dc51531f9', 'deriveBits', 512); 213 | println(); 214 | 215 | println('HMAC/PBKDF2 tests'); 216 | cipher = new GostDigest({name: 'GOST R 34.11', mode: 'HMAC'}); 217 | tests += perform(cipher, ++i, gostCoding.Hex.decode('000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f'), 218 | 'a1aa5f7de402d7b3d323f2991c8d4534013137010a83754fd0af6d7cd4922ed9', 'sign', gostCoding.Hex.decode('0126bdb87800af214341456563780100')); 219 | cipher = new GostDigest({name: 'GOST R 34.11', length: 512, mode: 'HMAC'}); 220 | tests += perform(cipher, ++i, gostCoding.Hex.decode('000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f'), 221 | 'a59bab22ecae19c65fbde6e5f4e9f5d8549d31f037f9df9b905500e171923a773d5f1530f2ed7e964cb2eedc29e9ad2f3afe93b2814f79f5000ffc0366c251e6', 222 | 'sign', gostCoding.Hex.decode('0126bdb87800af214341456563780100')); 223 | cipher = new GostDigest({name: 'GOST R 34.11', mode: 'PBKDF2', salt: gostCoding.Chars.decode('salt'), iterations: 1000}); 224 | tests += perform(cipher, ++i, gostCoding.Chars.decode('password'), 225 | 'c5f66589be62e183038e5dee22ea3d7a32afb314abd9970dc8f66858d1a924f4', 'deriveKey'); 226 | cipher = new GostDigest({name: 'GOST R 34.11', length: 512, procreator: 'VN', mode: 'PBKDF2', salt: gostCoding.Chars.decode('salt'), iterations: 1}); 227 | tests += perform(cipher, ++i, gostCoding.Chars.decode('password'), 228 | 'bcd19a1c423a63e72e47ef0f56566c726745d96ac1a1c127b2edadb45fb45b307aca15999e91f640f4818f68af716e30fd543c52026bbb295d100eb471339f46', 'deriveBits', 512); 229 | cipher = new GostDigest({name: 'GOST R 34.11', length: 512, procreator: 'VN', mode: 'PBKDF2', salt: gostCoding.Chars.decode('salt'), iterations: 2}); 230 | tests += perform(cipher, ++i, gostCoding.Chars.decode('password'), 231 | '088fec3b0f1ffaf0615eb267de92907fd4e0bb89d2f5ef9d4111a80e3cbf231af07ba3ce96065395f8f1a7505f9781f97e99a26b8314907dbf3510bc3ca2000c', 'deriveBits', 512); 232 | println(); 233 | 234 | cipher = new GostDigest({name: 'GOST R 34.11', length: 512}); 235 | 236 | tests2 += perform(cipher, ++i, gostCoding.Chars.decode('012345678901234567890123456789012345678901234567890123456789012'), 237 | '1b54d01a4af5b9d5cc3d86d68d285462b19abc2475222f35c085122be4ba1ffa00ad30f8767b3a82384c6574f024c311e2a481332b08ef7f41797891c1646f48'); 238 | tests2 += perform(cipher, ++i, gostCoding.Chars.decode('Се ветри, Стрибожи внуци, веютъ с моря стрелами на храбрыя плъкы Игоревы'), 239 | '1e88e62226bfca6f9994f1f2d51569e0daf8475a3b0fe61a5300eee46d961376035fe83549ada2b8620fcd7c496ce5b33f0cb9dddc2b6460143b03dabac9fb28'); 240 | tests2 += perform(cipher, ++i, new Uint8Array(0), 241 | '8e945da209aa869f0455928529bcae4679e9873ab707b55315f56ceb98bef0a7362f715528356ee83cda5f2aac4c6ad2ba3a715c1bcd81cb8e9f90bf4c1c1a8a'); 242 | tests2 += perform(cipher, ++i, new Uint8Array([ 243 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 244 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]), 245 | 'b0fd29ac1b0df441769ff3fdb8dc564df67721d6ac06fb28ceffb7bbaa7948c6c014ac999235b58cb26fb60fb112a145d7b4ade9ae566bf2611402c552d20db7'); 246 | println(); 247 | 248 | if (performance) { 249 | 250 | println('PBKDF2 4096 iterations tests'); 251 | cipher = new GostDigest({name: 'GOST R 34.11', mode: 'PBKDF2', salt: gostCoding.Chars.decode('salt'), iterations: 4096}); 252 | tests += perform(cipher, ++i, 253 | gostCoding.Chars.decode('password'), 254 | 'd744dc35ddfe10c7679af205ceb6492fb3680f861db598ee8110b30e3a0f3cb4', 'deriveKey'); 255 | 256 | cipher = new GostDigest({name: 'GOST R 34.11', mode: 'PBKDF2', salt: gostCoding.Chars.decode('saltSALTsaltSALTsaltSALTsaltSALTsalt'), iterations: 4096}); 257 | tests += perform(cipher, ++i, 258 | gostCoding.Chars.decode('passwordPASSWORDpassword'), 259 | '8452d34400e6404864f12206a2ac3f932fe7fe55026b1dd8f21a645cf340cbf0cca377e603024e82', 'deriveBits', 320); 260 | 261 | cipher = new GostDigest({name: 'GOST R 34.11', mode: 'PBKDF2', salt: gostCoding.Chars.decode('sa\0lt'), iterations: 4096}); 262 | tests += perform(cipher, ++i, 263 | gostCoding.Chars.decode('pass\0word'), 264 | '5023f9b3cc41e5aa491ea3e9eb65b6c01ffbeb63', 'deriveBits', 160); 265 | 266 | cipher = new GostDigest({name: 'GOST R 34.11', length: 512, procreator: 'VN', mode: 'PBKDF2', salt: gostCoding.Chars.decode('salt'), iterations: 4096}); 267 | tests += perform(cipher, ++i, gostCoding.Chars.decode('password'), 268 | '596f63971eae970a4eac9c18bff42ec52b936c1ccac6d17caa308afe12d4ff31943180ce02e42956524e991392c4bddeb7077edc1d2abf52eaf72b9e32a8c605', 'deriveBits', 512); 269 | 270 | cipher = new GostDigest({name: 'GOST R 34.11', length: 512, procreator: 'VN', mode: 'PBKDF2', salt: gostCoding.Chars.decode('saltSALTsaltSALTsaltSALTsaltSALTsalt'), iterations: 4096}); 271 | tests += perform(cipher, ++i, gostCoding.Chars.decode('passwordPASSWORDpassword'), 272 | 'e457ee6126f07c09be004ba512adc90c611c2b3fa11141c21196dae5a48a50d83ccf163233f014fb6ade71695bf37159e9062443b75dac911fa7a181d24c4ed2a910499d72aba93284c78dbc1acba2789bd8ef50b5052f33ec6e2491f4f74eda05723864', 'deriveBits', 800); 273 | 274 | cipher = new GostDigest({name: 'GOST R 34.11', length: 512, procreator: 'VN', mode: 'PBKDF2', salt: gostCoding.Chars.decode('sa\0lt'), iterations: 4096}); 275 | tests += perform(cipher, ++i, gostCoding.Chars.decode('pass\0word'), 276 | 'eed92e8d76e18d6a632f2da65c9b2859af555c3335ea30095989dea14d9d093114668e329deb034cc1565c3d731de0b5ca11acbdf85ab9eaab15295df05b9805', 'deriveBits', 512); 277 | 278 | println(); 279 | 280 | cipher = new GostDigest(); 281 | println('Million "a" TEST'); 282 | var million_a = gostCoding.Chars.decode(new Array(1000001).join('a')); 283 | tests += perform(cipher, ++i, million_a, 284 | '841af1a0b2f92a800fb1b7e4aabc8e48763153c448a0fc57c90ba830e130f152'); 285 | cipher = new GostDigest({name: 'GOST R 34.11', length: '512'}); 286 | tests += perform(cipher, ++i, million_a, 287 | 'd396a40b126b1f324465bfa7aa159859ab33fac02dcdd4515ad231206396a266d0102367e4c544ef47d2294064e1a25342d0cd25ae3d904b45abb1425ae41095'); 288 | println(); 289 | } 290 | 291 | println('TOTAL ' + (tests2 ? tests2 + ' ERRORS' : 'OK')); 292 | println(); 293 | 294 | // SHA-1 tests 295 | var tests3 = 0; 296 | i = 0; 297 | println('SHA-1 TEST', true); 298 | 299 | var cipher = new GostDigest({name: 'SHA', version: 1}); 300 | tests3 += perform(cipher, ++i, 301 | gostCoding.Chars.decode('abc'), 302 | 'a9993e364706816aba3e25717850C26c9cd0d89d'); 303 | tests3 += perform(cipher, ++i, 304 | gostCoding.Chars.decode('abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq'), 305 | '84983e441c3bd26ebaae4aa1f95129e5e54670f1'); 306 | 307 | tests3 += perform(cipher, ++i, 308 | gostCoding.Chars.decode(new Array(11).join('0123456701234567012345670123456701234567012345670123456701234567')), 309 | 'dea356a2cddd90c7a7ecedc5ebb563934f460452'); 310 | 311 | println(); 312 | 313 | println('PBKDF2 tests'); 314 | cipher = new GostDigest({name: 'SHA', version: 1, mode: 'PBKDF2', salt: gostCoding.Chars.decode('salt'), iterations: 1}); 315 | tests3 += perform(cipher, ++i, 316 | gostCoding.Chars.decode('password'), 317 | '0c60c80f961f0e71f3a9b524af6012062fe037a6', 'deriveKey'); 318 | cipher = new GostDigest({name: 'SHA', version: 1, mode: 'PBKDF2', salt: gostCoding.Chars.decode('salt'), iterations: 2}); 319 | tests3 += perform(cipher, ++i, 320 | gostCoding.Chars.decode('password'), 321 | 'ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957', 'deriveKey'); 322 | cipher = new GostDigest({name: 'SHA', version: 1, mode: 'PFXKDF', salt: gostCoding.Hex.decode('0A58CF64530D823F'), iterations: 1}); 323 | tests3 += perform(cipher, ++i, 324 | gostCoding.Hex.decode('0073006D006500670000'), 325 | '8aaae6297b6cb04642ab5b077851284eb7128f1a2a7fbca3', 'deriveBits', 192); 326 | cipher = new GostDigest({name: 'SHA', version: 1, mode: 'PFXKDF', salt: gostCoding.Hex.decode('0A58CF64530D823F'), iterations: 1, diversifier: 2}); 327 | tests3 += perform(cipher, ++i, 328 | gostCoding.Hex.decode('0073006D006500670000'), 329 | '79993dfe048d3b76', 'deriveBits', 64); 330 | cipher = new GostDigest({name: 'SHA', version: 1, mode: 'PFXKDF', salt: gostCoding.Hex.decode('3D83C0E4546AC140'), iterations: 1, diversifier: 3}); 331 | tests3 += perform(cipher, ++i, 332 | gostCoding.Hex.decode('0073006D006500670000'), 333 | '8D967D88F6CAA9D714800AB3D48051D63F73A312', 'deriveBits', 160); 334 | cipher = new GostDigest({name: 'SHA', version: 1, mode: 'PFXKDF', salt: gostCoding.Hex.decode('05DEC959ACFF72F7'), iterations: 1000, diversifier: 1}); 335 | tests3 += perform(cipher, ++i, 336 | gostCoding.Hex.decode('007100750065006500670000'), 337 | 'ED2034E36328830FF09DF1E1A07DD357185DAC0D4F9EB3D4', 'deriveBits', 192); 338 | println(); 339 | 340 | if (performance) { 341 | println('PBKDF2 4096 iterations tests'); 342 | cipher = new GostDigest({name: 'SHA', version: 1, mode: 'PBKDF2', salt: gostCoding.Chars.decode('salt'), iterations: 4096}); 343 | tests3 += perform(cipher, ++i, 344 | gostCoding.Chars.decode('password'), 345 | '4b007901b765489abead49d926f721d065a429c1', 'deriveKey'); 346 | cipher = new GostDigest({name: 'SHA', version: 1, mode: 'PBKDF2', salt: gostCoding.Chars.decode('saltSALTsaltSALTsaltSALTsaltSALTsalt'), iterations: 4096}); 347 | tests3 += perform(cipher, ++i, 348 | gostCoding.Chars.decode('passwordPASSWORDpassword'), 349 | '3d2eec4fe41c849b80c8d83662c0e44a8b291a964cf2f07038', 'deriveBits', 200); 350 | cipher = new GostDigest({name: 'SHA', version: 1, mode: 'PBKDF2', salt: gostCoding.Chars.decode('sa\0lt'), iterations: 4096}); 351 | tests3 += perform(cipher, ++i, 352 | gostCoding.Chars.decode('pass\0word'), 353 | '56fa6aa75548099dcc37d7f03425e0c3', 'deriveBits', 128); 354 | println(); 355 | 356 | println('Million "a" TEST'); 357 | var million_a = new Array(1000001).join('a'); 358 | tests3 += perform(cipher, ++i, 359 | gostCoding.Chars.decode(million_a), 360 | '34aa973cd4c4daa4f61eeb2bdbad27316534016f'); 361 | println(); 362 | } 363 | 364 | println('TOTAL ' + (tests3 ? tests3 + ' ERRORS' : 'OK')); 365 | println(); 366 | 367 | 368 | 369 | return tests + tests2; 370 | }; 371 | })); 372 | -------------------------------------------------------------------------------- /min/gostSign.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | 2014-2016, Rudolf Nickolaev. All rights reserved. 3 | */ 4 | (function(K,F){"function"===typeof define&&define.amd?define(["gostRandom","gostDigest"],F):"object"===typeof exports?module.exports=F(require("gostRandom"),require("gostDigest")):K.GostSign=F(K.GostRandom,K.GostDigest)})(this,function(K,F){function B(a,b,c,d,e,f,g){var h=c&16383;for(c>>=14;0<=--g;){var k=a[b]&16383,l=a[b++]>>14,n=c*k+l*h,k=h*k+((n&16383)<<14)+d[e]+f;f=(k>>28)+(n>>14)+c*l;d[e++]=k&268435455}return f}function n(a){a=Array(Math.ceil(a));a.s=0;a.t=0;return a}function G(a,b){for(var c= 5 | a.t-1;0<=c;--c)b[c]=a[c];b.t=a.t;b.s=a.s;return b}function ua(a,b){a.t=1;a.s=0>b?-1:0;0b?a[0]=b+268435456:a.t=0;return a}function C(a){var b=n(1);ua(b,a);return b}function u(a){for(var b=a.s&268435455;0>=28;if(b.t>=28;e+=a.s}else{for(e+=a.s;d>=28;e-=b.s}c.s=0>e?-1:0;-1>e? 6 | c[d++]=268435456+e:0>=28;if(b.t>=28;e+=a.s}else{for(e+=a.s;d>=28;e+=b.s}c.s=0>e?-1:0;0e&&(c[d++]=268435456+e);c.t=d;return u(c)}function M(a){if(0>a.s){var b=n(a.t);a=p(t,a,b)}return a}function s(a,b){var c=a.s-b.s;if(0!==c)return c;var d= 7 | a.t,c=d-b.t;if(0!==c)return 0>a.s?-c:c;for(;0<=--d;)if(0!==(c=a[d]-b[d]))return c;return 0}function ga(a){var b=1,c;0!==(c=a>>>16)&&(a=c,b+=16);0!==(c=a>>8)&&(a=c,b+=8);0!==(c=a>>4)&&(a=c,b+=4);0!==(c=a>>2)&&(a=c,b+=2);0!==a>>1&&(b+=1);return b}function U(a,b,c){var d;for(d=a.t-1;0<=d;--d)c[d+b]=a[d];for(d=b-1;0<=d;--d)c[d]=0;c.t=a.t+b;c.s=a.s;return c}function Y(a,b,c){for(var d=b;d>e|g,g=(a[h]&f)<=a.t)c.t=0;else{b%=28;var e=28-b,f=(1<>b;for(var g=d+1;g>b;0=a.t?0:28*(a.t-1)+ga(a[a.t-1]^a.s&268435455)}function Z(a,b,c){var d=M(a),e=M(b),f=d.t;for(c.t=f+e.t;0<=--f;)c[f]= 9 | 0;for(f=0;f=c.DV&&(b[d+c.t]-=c.DV,b[d+c.t+1]=1)}0=e.t)throw new Ea("Division by zero");var f=M(a);if(f.t>4:0),q=Fa/m,m=16777216/m,N=d.t,r=N-e;a=c?c:n(Math.max(a.t-b.t,1));U(g,r,a);0<=s(d,a)&&(d[d.t++]=1,p(d,a,d));U(R,e,a);for(p(a,g,g);g.th&&p(t,d,d);return c}function va(a,b,c){ia(M(a),b,null,c);0>a.s&&0a.s?-1:0>=a.t||1===a.t&&0>=a[0]?0:1}function aa(a,b){var c=y(b);if(y(a)&&c||0===S(b))return t;for(var d=G(b,n(b.t)),e=G(a,n(a.t)),f=C(1),g=C(0),h=C(0),k=C(1);0!==S(d);){for(;y(d);)H(d,1,d),c?(y(f)&&y(g)||(L(f,a,f),p(g,b,g)),H(f,1,f)):y(g)||p(g,b,g),H(g,1,g);for(;y(e);)H(e, 12 | 1,e),c?(y(h)&&y(k)||(L(h,a,h),p(k,b,k)),H(h,1,h)):y(k)||p(k,b,k),H(k,1,k);0<=s(d,e)?(p(d,e,d),c&&p(f,h,f),p(g,k,g)):(p(e,d,e),c&&p(h,f,h),p(k,g,k))}if(0!==s(e,R))return t;if(0<=s(k,b))return subtract(k,b);if(0>S(k))L(k,b,k);else return k;return 0>S(k)?L(k,b,n(k.t)):k}function V(a,b){var c=Math.floor(b/28);return c>=a.t?0!==a.s:0!==(a[c]&1<=d)return f;e=18>d?1:48>d?3:144>d?4:768>d?5:6;g=8>d?new wa(c):y(c)?new ka(c):new xa(c);var h=[],k=3,l=e-1,m=(1<=l?c=b[a]>>d-l&m:(c=(b[a]&(1<>28+d-l));for(k=e;0==(c&1);)c>>=1,--k;0>(d-=k)&&(d+=28,--a);if(p)G(h[c],f),p=!1;else{for(;1--d&&(d=27,--a)}return g.revert(f)}function w(a,b){a.r.reduce(b);b.q=a.q;b.r=a.r;return b}function ca(a,b){b.q=a.q;b.r=a.r;return b}function ya(a,b){var c=L(a,b,n(a.t));0c.s&&L(a.q,c,c);return ca(a,c)}function l(a,b){return w(a,v(a,b))}function O(a){return w(a,$(a,n(2*a.t)))}function T(a,b){var c=n(a.t);0>b? 15 | H(a,-b,c):ha(a,b,c);return w(a,c)}function za(a){return ca(a,aa(a,a.q))}function P(a,b,c,d){return{curve:a,x:b,y:c,z:d||w(a,R)}}function da(a){a.zinv||(a.zinv=za(a.z));return l(a.x,a.zinv)}function Aa(a){a.zinv||(a.zinv=za(a.z));return l(a.y,a.zinv)}function W(a){return a.x||a.y?z(a.z)&&!z(a.y):!0}function X(a,b){if(W(a))return b;if(W(b))return a;var c=D(l(b.y,a.z),l(a.y,b.z)),d=D(l(b.x,a.z),l(a.x,b.z));if(z(d))return z(c)?la(a):a.curve.infinity;var e=a.x,f=a.y,g=O(d),h=l(g,d),e=l(e,g),g=l(O(c),a.z), 16 | d=l(D(l(D(g,T(e,1)),b.z),h),d),c=ya(l(D(D(l(l(e,ea),c),l(f,h)),l(g,c)),b.z),l(c,h)),h=l(l(h,a.z),b.z);return P(a.curve,d,c,h)}function la(a){if(W(a))return a;if(0===S(a.y))return a.curve.infinity;var b=a.x,c=a.y,d=l(c,a.z),e=l(d,c),c=a.curve.a,f=l(O(b),ea);z(c)||(f=ya(f,l(O(a.z),c)));c=l(T(D(O(f),l(T(b,3),e)),1),d);b=D(l(T(D(l(l(f,ea),b),T(e,1)),2),e),l(O(f),f));d=T(l(O(d),d),3);return P(a.curve,c,b,d)}function ma(a,b){if(W(a))return a;if(0===S(b))return a.curve.infinity;var c=v(b,ea),d;d=a.curve; 17 | var e=a.x,f;f=a.y;f=ca(f,fa(f.q,f));d=P(d,e,f,a.z);e=a;for(f=I(c)-2;0>28-c):b[b.t-1]|=f<g&&0<(c=a[f]>>g)&&(d=!0,e.push(c));0<=f;)8>g?(c=(a[f]&(1<>(g+=20)):(c=a[f]>>(g-=8)&255,0>=g&&(g+=28,--f)),0>28-e):b[b.t-1]|=f<a.s){var b=n(a.t);a=p(t,a,b);return"-"+na(a)}var c=!1,d="",e=a.t,f=28-28*e%4;if(0f&&0<(b=a[e]>>f)&&(c=!0,d=b.toString(16));0<=e;)4>f?(b=(a[e]&(1<>(f+=24)):(b=a[e]>>(f-=4)&15,0>=f&&(f+=28,--e)),0I(c)?I(b)-1:I(c)-1,h=a.curve.infinity,k=X(a,f);0<=g;)h=la(h),V(b,g)?h=V(c,g)?X(h,k):X(h,a):V(c,g)&&(h=X(h,f)),--g;d=m(da(h),d)}else g=this.p,h=this.a,f=q(a),d=m(m(v(ba(h,b,g),ba(f,c,g)),g),d);return 0===s(d,e)}function Ca(){var a=this.curve;if(a){for(a=a.infinity;W(a);){var b=t;if(this.ukm)b=q(this.ukm); 24 | else for(;z(b);)b=m(q(ta(this.bitLength)),this.q);var a=ma(this.P,b),c=da(a),d=Aa(a)}return{privateKey:Q(b,this.bitLength),publicKey:sa(c,d,this.bitLength)}}throw new J("Key generation for GOST R 34.10-94 not supported");}function Ja(){if(this.curve){for(var a=t;z(a);)a=m(q(ta(this.bitLength)),this.q);return Q(a,this.bitLength)}throw new J("Key generation for GOST R 34.10-94 not supported");}function Ka(a,b){if(this.curve){var c=this.q,d=m(q(E(b)),c),e=m(q(E(a)),c),c="VN"===this.procreator?m(v(d, 25 | e),c):m(v(d,aa(e,c)),c);return Q(c)}throw new J("Key wrapping GOST R 34.10-94 not supported");}function La(a,b){if(this.curve){var c=this.q,d=m(q(E(b)),c),e=m(q(E(a)),c),c="VN"===this.procreator?m(v(d,aa(e,c)),c):m(v(d,e),c);return Q(c)}throw new J("Key wrapping GOST R 34.10-94 not supported");}function Da(a){var b;b=q(this.ukm);var c=this.q;a=m(q(E(a)),c);this.curve?(b=ma(this.peer_Q,m(v(b,a),c)),b=sa(da(b),Aa(b),this.bitLength)):b=Q(ba(this.peer_y,a,this.p));return pa.call(this,b)}function Ma(a, 26 | b){if(8>b||b>this.bitLength||0a.s||0<=s(a,this.m)?m(a,this.m):a},revert:function(a){return a}, 42 | reduce:function(a){va(a,this.m,a)},sqrTo:function(a,b){$(a,b);this.reduce(b)},mulTo:function(a,b,c){Z(a,b,c);this.reduce(c)}});var xa=function(a){this.m=a;var b;if(1>a.t)b=0;else if(b=a[0],0===(b&1))b=0;else{var c=b&3,c=c*(2-(b&15)*c)&15,c=c*(2-(b&255)*c)&255,c=c*(2-((b&65535)*c&65535))&65535,c=c*(2-b*c%268435456)%268435456;b=0>15;this.um=8191;this.mt2=2*a.t};ja(xa,{convert:function(a){var b=n(a.t);U(M(a),this.m.t,b);ia(b,this.m, 43 | null,b);0>a.s&&0>15)*this.mpl&this.um)<<15)&268435455,c=b+this.m.t;for(a[c]+=B(this.m,0,d,a,b,0,this.m.t);268435456<=a[c];)a[c]-=268435456,a[++c]++}u(a);Y(a,this.m.t,a);0<=s(a,this.m)&&p(a,this.m,a)},sqrTo:function(a,b){$(a,b);this.reduce(b)},mulTo:function(a,b,c){Z(a,b,c);this.reduce(c)}}); 44 | ja(ka,{convert:function(a){if(0>a.s||a.t>2*this.m.t)return m(a,this.m);if(0>s(a,this.m))return a;var b=n(a.t);G(a,b);this.reduce(b);return b},revert:function(a){return a},reduce:function(a){Y(a,this.m.t-1,this.r2);a.t>this.m.t+1&&(a.t=this.m.t+1,u(a));var b=this.mu,c=this.r2,d=this.m.t+1,e=this.q3;--d;var f=e.t=b.t+c.t-d;for(e.s=0;0<=--f;)e[f]=0;for(f=Math.max(d-b.t,0);fs(a,this.r2);){b=a;for(c=this.m.t+1;b.t<=c;)b[b.t++]=0;for(b[c]+=1;268435456<=b[c];)b[c]-=268435456,++c>=b.t&&(b[b.t++]=0),++b[c]}for(p(a,this.r2,a);0<=s(a,this.m);)p(a,this.m,a)},sqrTo:function(a,b){$(a,b);this.reduce(b)},mulTo:function(a,b,c){Z(a,b,c);this.reduce(c)}});return function(a){a=a||{};this.name=(a.name||"GOST R 34.10")+"-"+(a.version||2012)% 46 | 100+"-"+(a.length||256)+("SIGN"!==(a.mode||"SIGN")?"-"+a.mode:"")+("string"===typeof a.namedParam?"/"+a.namedParam:"")+("string"===typeof a.namedCurve?"/"+a.namedCurve:"")+("string"===typeof a.sBox?"/"+a.sBox:"");var b=a.version||2012;switch(a.mode||"SIGN"){case "SIGN":this.sign=Ha;this.verify=Ia;this.generateKey=Ca;break;case "DH":this.deriveBits=Ma;this.deriveKey=Na;this.generateKey=Ca;break;case "MASK":this.wrapKey=La,this.unwrapKey=Ka,this.generateKey=Ja}if(1994===b)b=a.param,b||(b=Oa[this.namedParam= 47 | (a.namedParam||"S-A").toUpperCase()]),this.modulusLength=a.modulusLength||b.modulusLength||1024,this.p=A(b.p),this.q=A(b.q),this.a=A(b.a),a["public"]&&(this.peer_y=q(a["public"]));else{b=a.curve;b||(b=r[this.namedCurve=(a.namedCurve||"S-256-A").toUpperCase()]);var c=A(b.p),d=A(b.a),e=A(b.b),f={};f.q=c;f.r=new ka(c);f.a=w(f,d);f.b=w(f,e);f.infinity=P(f);c=this.curve=f;this.P=P(c,w(c,A(b.x)),w(c,A(b.y)));this.q=A(b.q);a["public"]&&(b=ra(a["public"]),this.peer_Q=new P(this.curve,w(this.curve,b[0]),w(this.curve, 48 | b[1])))}if(this.curve){c=a.length||I(this.q);if(508=c)c=512;else if(254=c)c=256;else throw new J("Support keys only 256 or 512 bits length");b=c}else{c=a.modulusLength||I(this.p);if(1016=c)c=1024;else if(508=c)c=512;else throw new J("Support keys only 512 or 1024 bits length");b=256}this.bitLength=b;this.keyLength=c;this.procreator=a.procreator;if(c=a.hash){if("string"===typeof c||c instanceof String)c={name:c};1994===a.version||2001===a.version?(c.version=1994,c.length= 49 | 256,c.sBox=a.sBox||c.sBox):(c.version=2012,c.length=b);c.procreator=c.procreator||a.procreator;F||(F=x.GostDigest);if(!F)throw new J("Object GostDigest not found");this.hash=new F(c)}a.ukm&&(this.ukm=a.ukm)}}); 50 | -------------------------------------------------------------------------------- /gostEngine.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @file GOST 34.10-2012 signature function with 1024/512 bits digest 3 | * @version 1.76 4 | * @copyright 2014-2016, Rudolf Nickolaev. All rights reserved. 5 | */ 6 | 7 | /* 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 21 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | * 31 | */ 32 | 33 | (function (root, factory) { 34 | 35 | /* 36 | * Module imports and exports 37 | * 38 | */ // 39 | if (typeof define === 'function' && define.amd) { 40 | define(['gostRandom', 'gostCipher', 'gostDigest', 'gostSign'], factory); 41 | } else if (typeof exports === 'object') { 42 | module.exports = factory(require('gostRandom'), require('gostCipher'), require('gostDigest'), require('gostSign')); 43 | } else { 44 | if (typeof importScripts !== 'undefined') { 45 | if (!(root.GostRandom && root.GostCipher && root.GostDigest && root.GostSign)) 46 | importScripts('gostRandom.js', 'gostCipher.js', 'gostDigest.js', 'gostSign.js'); 47 | } 48 | root.gostEngine = factory(root.GostRandom, root.GostCipher, root.GostDigest, root.GostSign); 49 | } 50 | // 51 | 52 | }(this, function (GostRandom, GostCipher, GostDigest, GostSign) { 53 | 54 | /* 55 | * Engine definition base on normalized algorithm identifier 56 | * 57 | */ // 58 | 59 | var root = this; 60 | 61 | // Define engine 62 | function defineEngine(method, algorithm) { 63 | if (!algorithm) 64 | throw new (root.SyntaxError || Error)('Algorithm not defined'); 65 | 66 | if (!algorithm.name) 67 | throw new (root.SyntaxError || Error)('Algorithm name not defined'); 68 | 69 | var name = algorithm.name, mode = algorithm.mode; 70 | if ((name === 'GOST 28147' || name === 'GOST R 34.12' || name === 'RC2') && (method === 'generateKey' || 71 | (mode === 'MAC' && (method === 'sign' || method === 'verify')) || 72 | ((mode === 'KW' || mode === 'MASK') && (method === 'wrapKey' || method === 'unwrapKey')) || 73 | ((!mode || mode === 'ES') && (method === 'encrypt' || method === 'decrypt')))) { 74 | return 'GostCipher'; 75 | 76 | } else if ((name === 'GOST R 34.11' || name === 'SHA') && (method === 'digest' || 77 | (mode === 'HMAC' && (method === 'sign' || method === 'verify' || method === 'generateKey')) || 78 | ((mode === 'KDF' || mode === 'PBKDF2' || mode === 'PFXKDF' || mode === 'CPKDF') && 79 | (method === 'deriveKey' || method === 'deriveBits' || method === 'generateKey')))) { 80 | return 'GostDigest'; 81 | 82 | } else if (name === 'GOST R 34.10' && (method === 'generateKey' || 83 | ((!mode || mode === 'SIGN') && (method === 'sign' || method === 'verify')) || 84 | (mode === 'MASK' && (method === 'wrapKey' || method === 'unwrapKey')) || 85 | (mode === 'DH' && (method === 'deriveKey' || method === 'deriveBits')))) { 86 | return 'GostSign'; 87 | } else 88 | throw new (root.NotSupportedError || Error)('Algorithm ' + name + '-' + mode + ' is not valid for ' + method); 89 | } // 90 | 91 | /** 92 | * Object implements dedicated Web Workers and provide a simple way to create 93 | * and run GOST cryptographic algorithms in background thread. 94 | * 95 | * Object provide interface to GOST low-level cryptogric classes: 96 | *
    97 | *
  • GostCipher - implementation of GOST 28147, GOST R 34.12, GOST R 34.13 Encryption algorithms. Reference {@link http://tools.ietf.org/html/rfc5830}
  • 98 | *
  • 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}
  • 99 | *
  • 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}
  • 100 | *
101 | * @namespace gostEngine 102 | */ 103 | var gostEngine = { 104 | /** 105 | * gostEngine.execute(algorithm, method, args) Entry point to execution 106 | * all low-level GOST cryptographic methods 107 | * 108 | *
    109 | *
  • Determine the appropriate engine for a given execution method
  • 110 | *
  • Create cipher object for determineted engine
  • 111 | *
  • Execute method of cipher with given args
  • 112 | *
113 | * 114 | * @memberOf gostEngine 115 | * @param {AlgorithmIndentifier} algorithm Algorithm identifier 116 | * @param {string} method Crypto method for execution 117 | * @param {Array} args Method arguments (keys, data, additional parameters) 118 | * @returns {(CryptoOperationData|Key|KeyPair|boolean)} Result of method execution 119 | */ 120 | execute: function (algorithm, method, args) // 121 | { 122 | // Define engine for GOST algorithms 123 | var engine = defineEngine(method, algorithm); 124 | // Create cipher 125 | var cipher = this['get' + engine](algorithm); 126 | // Execute method 127 | return cipher[method].apply(cipher, args); 128 | }, // 129 | /** 130 | * gostEngine.getGostCipher(algorithm) returns GOST 28147 / GOST R 34.12 cipher instance

131 | * 132 | * GOST 28147-89 / GOST R 34.12-15 Encryption Algorithm

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

135 | * 136 | * Normalized algorithm identifier common parameters: 137 | * 138 | *
    139 | *
  • name Algorithm name 'GOST 28147' or 'GOST R 34.12'
  • 140 | *
  • version Algorithm version, number 141 | *
      142 | *
    • 1989 Current version of standard
    • 143 | *
    • 2015 New draft version of standard
    • 144 | *
    145 | *
  • 146 | *
  • length Block length 147 | *
      148 | *
    • 64 64 bits length (default)
    • 149 | *
    • 128 128 bits length (only for version 2015)
    • 150 | *
    151 | *
  • 152 | *
  • mode Algorithm mode, string 153 | *
      154 | *
    • ES Encryption mode (default)
    • 155 | *
    • MAC "imitovstavka" (MAC) mode
    • 156 | *
    • KW Key wrapping mode
    • 157 | *
    • MASK Key mask mode
    • 158 | *
    159 | *
  • 160 | *
  • sBox Paramset sBox for GOST 28147-89, string. Used only if version = 1989
  • 161 | *
162 | * 163 | * Supported algorithms, modes and parameters: 164 | * 165 | *
    166 | *
  • Encript/Decrypt mode (ES) 167 | *
      168 | *
    • block Block mode, string. Default ECB
    • 169 | *
    • keyMeshing Key meshing mode, string. Default NO
    • 170 | *
    • padding Padding mode, string. Default NO for CFB and CTR modes, or ZERO for others
    • 171 | *
    • iv {@link CryptoOperationData} Initial vector with length of block. Default - zero block
    • 172 | *
    173 | *
  • 174 | *
  • Sign/Verify mode (MAC) 175 | *
      176 | *
    • macLength Length of mac in bits (default - 32 bits)
    • 177 | *
    • iv {@link CryptoOperationData} Initial vector with length of block. Default - zero block
    • 178 | *
    179 | *
  • 180 | *
  • Wrap/Unwrap key mode (KW) 181 | *
      182 | *
    • keyWrapping Mode of keywrapping, string. Default NO - standard GOST key wrapping
    • 183 | *
    • ukm {@link CryptoOperationData} User key material. Default - random generated value
    • 184 | *
    185 | *
  • 186 | *
  • Wrap/Unwrap key mode (MASK)
  • 187 | *
188 | * 189 | * Supported paramters values: 190 | * 191 | *
    192 | *
  • Block modes (parameter 'block') 193 | *
      194 | *
    • ECB "prostaya zamena" (ECB) mode (default)
    • 195 | *
    • CFB "gammirovanie s obratnoj svyaziyu" (64-bit CFB) mode
    • 196 | *
    • CTR "gammirovanie" (counter) mode
    • 197 | *
    • CBC Cipher-Block-Chaining (CBC) mode
    • 198 | *
    199 | *
  • 200 | *
  • Key meshing modes (parameter 'keyMeshing') 201 | *
      202 | *
    • NO No key wrapping (default)
    • 203 | *
    • CP CryptoPor Key key meshing
    • 204 | *
    205 | *
  • 206 | *
  • Padding modes (parameter 'padding') 207 | *
      208 | *
    • NO No padding only for CFB and CTR modes
    • 209 | *
    • PKCS5 PKCS#5 padding mode
    • 210 | *
    • ZERO Zero bits padding mode
    • 211 | *
    • RANDOM Random bits padding mode
    • 212 | *
    213 | *
  • 214 | *
  • Wrapping key modes (parameter 'keyWrapping') 215 | *
      216 | *
    • NO Ref. rfc4357 6.1 GOST 28147-89 Key wrapping
    • 217 | *
    • CP CryptoPro Key wrapping mode
    • 218 | *
    • SC SignalCom Key wrapping mode
    • 219 | *
    220 | *
  • 221 | *
222 | * 223 | * @memberOf gostEngine 224 | * @param {AlgorithmIndentifier} algorithm Algorithm identifier 225 | * @returns {GostCipher} Instance of GostCipher 226 | */ 227 | getGostCipher: function (algorithm) // 228 | { 229 | return new (GostCipher || (GostCipher = root.GostCipher))(algorithm); 230 | }, // 231 | /** 232 | * gostEngine.getGostDigest(algorithm) returns GOST R 34.11 cipher instance

233 | * 234 | * Normalized algorithm identifier common parameters: 235 | * 236 | *
    237 | *
  • name Algorithm name 'GOST R 34.11'
  • 238 | *
  • version Algorithm version 239 | *
      240 | *
    • 1994 old-style 256 bits digest based on GOST 28147-89
    • 241 | *
    • 2012 256 ro 512 bits digest algorithm "Streebog" GOST R 34.11-2012 (default)
    • 242 | *
    243 | *
  • 244 | *
  • length Digest length 245 | *
      246 | *
    • 256 256 bits digest
    • 247 | *
    • 512 512 bits digest, valid only for algorithm "Streebog"
    • 248 | *
    249 | *
  • 250 | *
  • mode Algorithm mode 251 | *
      252 | *
    • HASH simple digest mode (default)
    • 253 | *
    • HMAC HMAC algorithm based on GOST R 34.11
    • 254 | *
    • KDF Derive bits for KEK deversification
    • 255 | *
    • PBKDF2 Password based key dirivation algorithms PBKDF2 (based on HMAC)
    • 256 | *
    • PFXKDF PFX key dirivation algorithms PFXKDF
    • 257 | *
    • CPKDF CryptoPro Password based key dirivation algorithms
    • 258 | *
    259 | *
  • 260 | *
  • sBox Paramset sBox for GOST 28147-89. Used only if version = 1994
  • 261 | *
262 | * 263 | * Supported algorithms, modes and parameters: 264 | * 265 | *
    266 | *
  • Digest HASH mode (default)
  • 267 | *
  • Sign/Verify HMAC modes parameters depends on version and length 268 | *
      269 | *
    • version: 1994 HMAC parameters (B = 32, L = 32)
    • 270 | *
    • version: 2012, length: 256 HMAC parameters (B = 64, L = 32)
    • 271 | *
    • version: 2012, length: 512 HMAC parameters (B = 64, L = 64)
    • 272 | *
    273 | *
  • 274 | *
  • DeriveBits/DeriveKey KDF mode 275 | *
      276 | *
    • context {@link CryptoOperationData} Context of the key derivation
    • 277 | *
    • label {@link CryptoOperationData} Label that identifies the purpose for the derived keying material
    • 278 | *
    279 | *
  • 280 | *
  • DeriveBits/DeriveKey PBKDF2 mode 281 | *
      282 | *
    • salt {@link CryptoOperationData} Random salt as input for HMAC algorithm
    • 283 | *
    • iterations Iteration count. GOST recomended value 1000 (default) or 2000
    • 284 | *
    285 | *
  • 286 | *
  • DeriveBits/DeriveKey PFXKDF mode 287 | *
      288 | *
    • salt {@link CryptoOperationData} Random salt as input for HMAC algorithm
    • 289 | *
    • iterations Iteration count. GOST recomended value 1000 (default) or 2000
    • 290 | *
    • diversifier Deversifier, ID=1 - key material for performing encryption or decryption, 291 | * ID=2 - IV (Initial Value) for encryption or decryption, ID=3 - integrity key for MACing
    • 292 | *
    293 | *
  • 294 | *
  • DeriveBits/DeriveKey CPKDF mode 295 | *
      296 | *
    • salt {@link CryptoOperationData} Random salt as input for HMAC algorithm
    • 297 | *
    • iterations Iteration count. GOST recomended value 1000 (default) or 2000
    • 298 | *
    299 | *
  • 300 | *
301 | * 302 | * @memberOf gostEngine 303 | * @param {AlgorithmIndentifier} algorithm Algorithm identifier 304 | * @returns {GostDigest} Instance of GostDigest 305 | */ 306 | getGostDigest: function (algorithm) // 307 | { 308 | return new (GostDigest || (GostDigest = root.GostDigest))(algorithm); 309 | }, // 310 | /** 311 | * gostEngine.getGostSign(algorithm) returns GOST R 34.10 cipher instance

312 | * 313 | * Normalized algorithm identifier common parameters: 314 | * 315 | *
    316 | *
  • name Algorithm name 'GOST R 34.10'
  • 317 | *
  • version Algorithm version 318 | *
      319 | *
    • 1994 - Old-style GOST R 34.10-94 ExpMod algorithm with GOST R 34.11-94 hash
    • 320 | *
    • 2001 - GOST R 34.10-2001 Eliptic curve algorithm with old GOST R 34.11-94 hash
    • 321 | *
    • 2012 - GOST R 34.10-2012 Eliptic curve algorithm with GOST R 34.11-12 hash, default mode
    • 322 | *
    323 | *
  • 324 | *
  • length Length of hash and signature. Key length == hash length for EC algorithms and 2 * hash length for ExpMod algorithm 325 | *
      326 | *
    • GOST R 34.10-256 - 256 bits digest, default mode
    • 327 | *
    • GOST R 34.10-512 - 512 bits digest only for GOST R 34.11-2012 hash
    • 328 | *
    329 | *
  • 330 | *
  • mode Algorithm mode 331 | *
      332 | *
    • SIGN Digital signature mode (default)
    • 333 | *
    • DH Diffie-Hellman key generation and key agreement mode
    • 334 | *
    • MASK Key mask mode
    • 335 | *
    336 | *
  • 337 | *
  • sBox Paramset sBox for GOST 34.11-94. Used only if version = 1994 or 2001
  • 338 | *
339 | * 340 | * Supported algorithms, modes and parameters: 341 | * 342 | *
    343 | *
  • Sign/Verify mode (SIGN)
  • 344 | *
  • Wrap/Unwrap mode (MASK)
  • 345 | *
  • DeriveKey/DeriveBits mode (DH) 346 | *
      347 | *
    • {@link CryptoOperationData} ukm User key material. Default - random generated value
    • 348 | *
    • {@link CryptoOperationData} public The peer's EC public key data
    • 349 | *
    350 | *
  • 351 | *
  • GenerateKey mode (SIGN and DH and MASK) version = 1994 352 | *
      353 | *
    • namedParam Paramset for key generation algorithm. If specified no additianal parameters required
    • 354 | *
    355 | * Additional parameters, if namedParam not specified 356 | *
      357 | *
    • modulusLength Bit length of p (512 or 1024 bits). Default = 1024
    • 358 | *
    • p {@link CryptoOperationData} Modulus, prime number, 2^(t-1) 359 | *
    • q {@link CryptoOperationData} Order of cyclic group, prime number, 2^254 360 | *
    • a {@link CryptoOperationData} Generator, integer, 1 361 | *
    362 | *
  • 363 | *
  • GenerateKey mode (SIGN and DH and MASK) version = 2001 or 2012 364 | *
      365 | *
    • namedCurve Paramset for key generation algorithm. If specified no additianal parameters required
    • 366 | *
    367 | * Additional EC parameters, if namedCurve not specified 368 | *
      369 | *
    • p {@link CryptoOperationData} Prime number - elliptic curve modulus
    • 370 | *
    • a {@link CryptoOperationData} Coefficients a of the elliptic curve E
    • 371 | *
    • b {@link CryptoOperationData} Coefficients b of the elliptic curve E
    • 372 | *
    • q {@link CryptoOperationData} Prime number - order of cyclic group
    • 373 | *
    • x {@link CryptoOperationData} Base point p x-coordinate
    • 374 | *
    • y {@link CryptoOperationData} Base point p y-coordinate
    • 375 | *
    376 | *
  • 377 | *
378 | * 379 | * @memberOf gostEngine 380 | * @param {AlgorithmIndentifier} algorithm Algorithm identifier 381 | * @returns {GostSign} Instance of GostSign 382 | */ 383 | getGostSign: function (algorithm) // 384 | { 385 | return new (GostSign || (GostSign = root.GostSign))(algorithm); 386 | } // 387 | }; 388 | 389 | /* 390 | * Worker method execution 391 | * 392 | */ // 393 | 394 | // Worker for gostCripto method execution 395 | if (root.importScripts) { 396 | 397 | /** 398 | * Method called when {@link SubtleCrypto} calls its own postMessage() 399 | * method with data parameter: algorithm, method and arg.
400 | * Call method execute and postMessage() results to onmessage event handler 401 | * in the main process.
402 | * If error occured onerror event handler executed in main process. 403 | * 404 | * @memberOf gostEngine 405 | * @name onmessage 406 | * @param {MessageEvent} event Message event with data {algorithm, method, args} 407 | */ 408 | root.onmessage = function (event) { 409 | try { 410 | postMessage({ 411 | id: event.data.id, 412 | result: gostEngine.execute(event.data.algorithm, 413 | event.data.method, event.data.args)}); 414 | } catch (e) { 415 | postMessage({ 416 | id: event.data.id, 417 | error: e.message 418 | }); 419 | } 420 | }; 421 | } else { 422 | 423 | // Load dependens 424 | var baseUrl = '', nameSuffix = ''; 425 | // Try to define from DOM model 426 | if (typeof document !== 'undefined') { 427 | (function () { 428 | var regs = /^(.*)gostCrypto(.*)\.js$/i; 429 | var list = document.querySelectorAll('script'); 430 | for (var i = 0, n = list.length; i < n; i++) { 431 | var value = list[i].getAttribute('src'); 432 | var test = regs.exec(value); 433 | if (test) { 434 | baseUrl = test[1]; 435 | nameSuffix = test[2]; 436 | } 437 | } 438 | })(); 439 | } 440 | 441 | // Local importScripts procedure for include dependens 442 | var importScripts = function () { 443 | for (var i = 0, n = arguments.length; i < n; i++) { 444 | var name = arguments[i].split('.'), 445 | src = baseUrl + name[0] + nameSuffix + '.' + name[1]; 446 | var el = document.querySelector('script[src="' + src + '"]'); 447 | if (!el) { 448 | el = document.createElement('script'); 449 | el.setAttribute('src', src); 450 | document.head.appendChild(el); 451 | } 452 | } 453 | }; 454 | 455 | // Import engines 456 | if (!GostRandom) 457 | importScripts('gostRandom.js'); 458 | if (!GostCipher) 459 | importScripts('gostCipher.js'); 460 | if (!GostDigest) 461 | importScripts('gostDigest.js'); 462 | if (!GostSign) 463 | importScripts('gostSign.js'); 464 | } //
465 | 466 | return gostEngine; 467 | 468 | })); 469 | 470 | --------------------------------------------------------------------------------