From 7b60d2ffc2996f31e001715b9cd02a8530ee5620 Mon Sep 17 00:00:00 2001 From: Sing Painter Date: Fri, 28 Sep 2018 10:17:27 +0300 Subject: [PATCH] + new version (add createTx) --- README.md | 47 +- example.html | 31 +- metahash.js | 128 ++- metahash.min.js | 36 + source/asn1-1.0.js | 1658 +++++++++++++++++++++++++++++ source/asn1hex-1.1.js | 709 +++++++++++++ source/base64x-1.1.js | 1173 +++++++++++++++++++++ source/build.md | 17 + source/crypto-1.1.js | 1466 ++++++++++++++++++++++++++ source/cryptojs-312-core-fix.js | 711 +++++++++++++ source/ec.js | 318 ++++++ source/ecdsa-modified-1.0.js | 839 +++++++++++++++ source/ecparam-1.0.js | 248 +++++ source/jsbn.js | 561 ++++++++++ source/jsbn2.js | 658 ++++++++++++ source/keyutil-1.0.js | 1756 +++++++++++++++++++++++++++++++ source/pack.js | 384 +++++++ source/prng4.js | 47 + source/rng.js | 81 ++ source/rsa.js | 212 ++++ source/sha256.js | 185 ++++ source/yahoo.js | 72 ++ 22 files changed, 11327 insertions(+), 10 deletions(-) create mode 100644 metahash.min.js create mode 100644 source/asn1-1.0.js create mode 100644 source/asn1hex-1.1.js create mode 100644 source/base64x-1.1.js create mode 100644 source/build.md create mode 100644 source/crypto-1.1.js create mode 100644 source/cryptojs-312-core-fix.js create mode 100644 source/ec.js create mode 100644 source/ecdsa-modified-1.0.js create mode 100644 source/ecparam-1.0.js create mode 100644 source/jsbn.js create mode 100644 source/jsbn2.js create mode 100644 source/keyutil-1.0.js create mode 100644 source/pack.js create mode 100644 source/prng4.js create mode 100644 source/rng.js create mode 100644 source/rsa.js create mode 100644 source/sha256.js create mode 100644 source/yahoo.js diff --git a/README.md b/README.md index 43a15b0..32f381f 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ ![logo_en](https://user-images.githubusercontent.com/2198826/46068471-e44d1900-c181-11e8-99cf-0234839623f5.png) # [MetaHash](https://metahash.org/) JavaScript library -### Версия 0.1.0 +### Версия 0.2.0 ------------ @@ -13,7 +13,9 @@ ## Использование 1. Подключить MetaHash JavaScript библиотеку: ```html - + +или через CDN: + ``` 2. Если нужно изменить конфигурацию: адрес ноды, и т.д.: ```js @@ -104,6 +106,45 @@ metahash.getTx('23fb8f98f1faecf04c23112ad47bba7b42ff7bcec0cdf22ce231061d02e9ad2c }); ``` +- ### createTx +Создание транзакции. + +Параметры: +***to*** +***value*** +***fee*** +***nonce*** +***data*** +***publicKeyHex*** +***privateKey*** +***youHashAddress*** + +Пример использования: +```js +metahash.apiUrl = 'http://139.162.42.43:9999'; +let publicKeyBase64 = 'MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE8gBrTLUQxXDZQ4f/OpiFWe4dhNbEo11PtFkq/0NgXt+AxGwmiWUhojtI56Hj2H3QpxGZCqrjxldDC4IHzpyVfw=='; // from key.pub +let to = '0x0003f6441039b7f944c82ac62f7c124918e02c203b5820f5ed'; +let value = 1000; +let fee = 0; +let nonce = null; +let data = ''; +let publicKeyHex = metahash.base64toHex(publicKeyBase64); // convert from base64 to hex +/* + 1. openssl ec -in key.pem -noout -text + 2. copy "priv" value: + 42:d1:ae:22:4c:27:fc:02:a4:bc:43:b9:ec:47:6b: + bd:21:b4:51:69:db:97:35:f9:c6:1d:31:a0:87:21: + 04:4f + 3. remove symbol ":" +*/ +let privateKey = '42d1ae224c27fc02a4bc43b9ec476bbd21b45169db9735f9c61d31a08721044f'; +let youHashAddress = '0x009b84f533aa2192456a7e944eb471183abbceafe678a98984'; +metahash.createTx(to, value, fee, nonce, data, publicKeyHex, privateKey, youHashAddress, (res, err) => { + if (res) console.log('createTx', res, 'http://mhscan.com/?page=tx&id=' + res.params); + else console.error('createTx', err) +}); +``` + - ### balanceFormatter Форматирование баланса в правильный вид. @@ -123,6 +164,8 @@ BTC: [3LPVbQ8fu4um4aY16tpeie62kznGJywrai](bitcoin:3LPVbQ8fu4um4aY16tpeie62kznGJy ETH: [0x230D2C5aE86fFB69C8e6d575aB634f345aE497e5](ethereum:0x230D2C5aE86fFB69C8e6d575aB634f345aE497e5) +MHC: [0x00a1d0f653dd39c33255acac2f5ea4fb3c3ea5795908c3bf05](mhc:0x00a1d0f653dd39c33255acac2f5ea4fb3c3ea5795908c3bf05) + ------------ ## Контакты: diff --git a/example.html b/example.html index 0927ff7..46619ea 100644 --- a/example.html +++ b/example.html @@ -1,7 +1,9 @@ - + \ No newline at end of file diff --git a/metahash.js b/metahash.js index 9ef7bcc..a23faf1 100644 --- a/metahash.js +++ b/metahash.js @@ -7,7 +7,7 @@ class MetaHash { request(method, callback, params) { const query = { - id: 1, + //id: 1, method: method, params: params }; @@ -17,7 +17,11 @@ class MetaHash { }) .then((response) => { return response.json(); }) .then((data) => { - if (data.result) callback(data.result); else callback(null, data.error); + if ( ! data.error) { + if ( ! data.params) data = data.result; + callback(data); + } + else callback(null, data.error); }); } @@ -33,7 +37,7 @@ class MetaHash { } callback(res, err); }, { - address: address + address }); } @@ -48,7 +52,7 @@ class MetaHash { } callback(res, err); }, { - address: address + address }); } @@ -60,10 +64,122 @@ class MetaHash { } callback(res, err); }, { - hash: hash + hash }); } + intToHexHandler(firstFormat, firstValue, secondFormat, SecondValue) { + return this.binToHex(pack(firstFormat, firstValue)) + (secondFormat ? this.binToHex(pack(secondFormat, SecondValue)) : ''); + } + + intToHex(value) { + if (value < 250) return this.intToHexHandler('C', value); + else if (value < 65536) return this.intToHexHandler('C', 250, 'v', value); + else if (value < 4294967296) return this.intToHexHandler('C', 251, 'V', value); + else return this.intToHexHandler('C', 252, '@', value); + } + + strToHex(value) { + let str = ''; + for (let i = 0 ; i < value.length ; i++ ) { + if (value.charCodeAt(i) < 256) str += '\\x' + value.charCodeAt(i).toString(16) + ''; + else if (value.charCodeAt(i) < 4096) str += '\\u0' + value.charCodeAt(i).toString(16) + ''; + else str += '\\u' + value.charCodeAt(i).toString(16) + ''; + } + return str; + } + + binToHex(value) { + let i, l, o = '', n; + value += ''; + for (i = 0, l = value.length; i < l; i++) { + n = value.charCodeAt(i).toString(16); + o += n.length < 2 ? '0' + n : n; + } + return o; + } + + base64toHex(base64) { + let raw = atob(base64); + let hex = ''; + for (let i = 0; i < raw.length; i++ ) { + let _hex = raw.charCodeAt(i).toString(16); + hex += (_hex.length==2?_hex:'0'+_hex); + } + return hex; + } + + createTx(to, value, fee, nonce, data, pubkey, privateKey, youHashAddress, callback) { + value = value.toString(); + fee = fee.toString(); + // need refactoring! + if ( ! nonce) { + this.apiUrl = 'http://172.104.224.65:5795'; + const address = youHashAddress; + this.fetchBalance(address, (res, err) => { + this.apiUrl = 'http://139.162.42.43:9999'; + res.count_spent++; + this.createTxHandler(to, value, fee, res.count_spent, data, pubkey, privateKey, callback) + }); + } + else this.createTxHandler(to, value, fee, nonce, data, pubkey, privateKey, callback); + } + + createTxHandler(to, value, fee, nonce, data, pubkey, privateKey, callback) { + nonce = nonce.toString(); + const message = to.substr(2) + this.intToHex(value) + this.intToHex(fee) + this.intToHex(nonce) + '00'; + const sig = new KJUR.crypto.Signature({'alg': 'SHA256withECDSA'}); + sig.init({d: privateKey, curve: 'secp256k1'}); + sig.updateHex(message); + const sign = sig.sign(); + this.request('mhc_send', (res, err) => { + callback(res, err); + }, { + to, + value, + fee, + nonce, + data, + pubkey, + sign + }); + } + } -const metahash = new MetaHash(); \ No newline at end of file +const metahash = new MetaHash(); + +// Copyright (c) 2011, Yahoo! Inc. All rights reserved. +if(void 0===YAHOO)var YAHOO={};YAHOO.lang={extend:function(t,o,e){if(!o||!t)throw new Error("YAHOO.lang.extend failed, please check that all dependencies are included.");var r=function(){};if(r.prototype=o.prototype,t.prototype=new r,t.prototype.constructor=t,t.superclass=o.prototype,o.prototype.constructor==Object.prototype.constructor&&(o.prototype.constructor=o),e){var n;for(n in e)t.prototype[n]=e[n];var p=function(){},c=["toString","valueOf"];try{/MSIE/.test(navigator.userAgent)&&(p=function(t,o){for(n=0;n>>2]>>>24-s%4*8&255;n[r+s>>>2]|=o<<24-(r+s)%4*8}else for(s=0;s>>2]=i[s>>>2];return this.sigBytes+=e,this},clamp:function(){var n=this.words,i=this.sigBytes;n[i>>>2]&=4294967295<<32-i%4*8,n.length=t.ceil(i/4)},clone:function(){var t=e.clone.call(this);return t.words=this.words.slice(0),t},random:function(n){for(var i=[],r=0;r>>2]>>>24-e%4*8&255;r.push((s>>>4).toString(16)),r.push((15&s).toString(16))}return r.join("")},parse:function(t){for(var n=t.length,i=[],r=0;r>>3]|=parseInt(t.substr(r,2),16)<<24-r%8*4;return new s.init(i,n/2)}},c=o.Latin1={stringify:function(t){for(var n=t.words,i=t.sigBytes,r=[],e=0;e>>2]>>>24-e%4*8&255;r.push(String.fromCharCode(s))}return r.join("")},parse:function(t){for(var n=t.length,i=[],r=0;r>>2]|=(255&t.charCodeAt(r))<<24-r%4*8;return new s.init(i,n)}},u=o.Utf8={stringify:function(t){try{return decodeURIComponent(escape(c.stringify(t)))}catch(t){throw new Error("Malformed UTF-8 data")}},parse:function(t){return c.parse(unescape(encodeURIComponent(t)))}},f=r.BufferedBlockAlgorithm=e.extend({reset:function(){this._data=new s.init,this._nDataBytes=0},_append:function(t){"string"==typeof t&&(t=u.parse(t)),this._data.concat(t),this._nDataBytes+=t.sigBytes},_process:function(n){var i=this._data,r=i.words,e=i.sigBytes,o=this.blockSize,a=e/(4*o),c=(a=n?t.ceil(a):t.max((0|a)-this._minBufferSize,0))*o,u=t.min(4*c,e);if(c){for(var f=0;f=0;){var s=i*this[t++]+r[o]+n;n=Math.floor(s/67108864),r[o++]=67108863&s}return n}function am2(t,i,r,o,n,e){for(var s=32767&i,h=i>>15;--e>=0;){var p=32767&this[t],a=this[t++]>>15,f=h*p+a*s;n=((p=s*p+((32767&f)<<15)+r[o]+(1073741823&n))>>>30)+(f>>>15)+h*a+(n>>>30),r[o++]=1073741823&p}return n}function am3(t,i,r,o,n,e){for(var s=16383&i,h=i>>14;--e>=0;){var p=16383&this[t],a=this[t++]>>14,f=h*p+a*s;n=((p=s*p+((16383&f)<<14)+r[o]+n)>>28)+(f>>14)+h*a,r[o++]=268435455&p}return n}j_lm&&"Microsoft Internet Explorer"==navigator.appName?(BigInteger.prototype.am=am2,dbits=30):j_lm&&"Netscape"!=navigator.appName?(BigInteger.prototype.am=am1,dbits=26):(BigInteger.prototype.am=am3,dbits=28),BigInteger.prototype.DB=dbits,BigInteger.prototype.DM=(1<=0;--i)t[i]=this[i];t.t=this.t,t.s=this.s}function bnpFromInt(t){this.t=1,this.s=t<0?-1:0,t>0?this[0]=t:t<-1?this[0]=t+this.DV:this.t=0}function nbv(t){var i=nbi();return i.fromInt(t),i}function bnpFromString(t,i){var r;if(16==i)r=4;else if(8==i)r=3;else if(256==i)r=8;else if(2==i)r=1;else if(32==i)r=5;else{if(4!=i)return void this.fromRadix(t,i);r=2}this.t=0,this.s=0;for(var o=t.length,n=!1,e=0;--o>=0;){var s=8==r?255&t[o]:intAt(t,o);s<0?"-"==t.charAt(o)&&(n=!0):(n=!1,0==e?this[this.t++]=s:e+r>this.DB?(this[this.t-1]|=(s&(1<>this.DB-e):this[this.t-1]|=s<=this.DB&&(e-=this.DB))}8==r&&0!=(128&t[0])&&(this.s=-1,e>0&&(this[this.t-1]|=(1<0&&this[this.t-1]==t;)--this.t}function bnToString(t){if(this.s<0)return"-"+this.negate().toString(t);var i;if(16==t)i=4;else if(8==t)i=3;else if(2==t)i=1;else if(32==t)i=5;else{if(4!=t)return this.toRadix(t);i=2}var r,o=(1<0)for(h>h)>0&&(n=!0,e=int2char(r));s>=0;)h>(h+=this.DB-i)):(r=this[s]>>(h-=i)&o,h<=0&&(h+=this.DB,--s)),r>0&&(n=!0),n&&(e+=int2char(r));return n?e:"0"}function bnNegate(){var t=nbi();return BigInteger.ZERO.subTo(this,t),t}function bnAbs(){return this.s<0?this.negate():this}function bnCompareTo(t){var i=this.s-t.s;if(0!=i)return i;var r=this.t;if(0!=(i=r-t.t))return this.s<0?-i:i;for(;--r>=0;)if(0!=(i=this[r]-t[r]))return i;return 0}function nbits(t){var i,r=1;return 0!=(i=t>>>16)&&(t=i,r+=16),0!=(i=t>>8)&&(t=i,r+=8),0!=(i=t>>4)&&(t=i,r+=4),0!=(i=t>>2)&&(t=i,r+=2),0!=(i=t>>1)&&(t=i,r+=1),r}function bnBitLength(){return this.t<=0?0:this.DB*(this.t-1)+nbits(this[this.t-1]^this.s&this.DM)}function bnpDLShiftTo(t,i){var r;for(r=this.t-1;r>=0;--r)i[r+t]=this[r];for(r=t-1;r>=0;--r)i[r]=0;i.t=this.t+t,i.s=this.s}function bnpDRShiftTo(t,i){for(var r=t;r=0;--r)i[r+s+1]=this[r]>>n|h,h=(this[r]&e)<=0;--r)i[r]=0;i[s]=h,i.t=this.t+s+1,i.s=this.s,i.clamp()}function bnpRShiftTo(t,i){i.s=this.s;var r=Math.floor(t/this.DB);if(r>=this.t)i.t=0;else{var o=t%this.DB,n=this.DB-o,e=(1<>o;for(var s=r+1;s>o;o>0&&(i[this.t-r-1]|=(this.s&e)<>=this.DB;if(t.t>=this.DB;o+=this.s}else{for(o+=this.s;r>=this.DB;o-=t.s}i.s=o<0?-1:0,o<-1?i[r++]=this.DV+o:o>0&&(i[r++]=o),i.t=r,i.clamp()}function bnpMultiplyTo(t,i){var r=this.abs(),o=t.abs(),n=r.t;for(i.t=n+o.t;--n>=0;)i[n]=0;for(n=0;n=0;)t[r]=0;for(r=0;r=i.DV&&(t[r+i.t]-=i.DV,t[r+i.t+1]=1)}t.t>0&&(t[t.t-1]+=i.am(r,i[r],t,2*r,0,1)),t.s=0,t.clamp()}function bnpDivRemTo(t,i,r){var o=t.abs();if(!(o.t<=0)){var n=this.abs();if(n.t0?(o.lShiftTo(p,e),n.lShiftTo(p,r)):(o.copyTo(e),n.copyTo(r));var a=e.t,f=e[a-1];if(0!=f){var u=f*(1<1?e[a-2]>>this.F2:0),g=this.FV/u,m=(1<=0&&(r[r.t++]=1,r.subTo(l,r)),BigInteger.ONE.dlShiftTo(a,l),l.subTo(e,e);e.t=0;){var T=r[--v]==f?this.DM:Math.floor(r[v]*g+(r[v-1]+c)*m);if((r[v]+=e.am(0,T,r,b,0,a))0&&r.rShiftTo(p,r),s<0&&BigInteger.ZERO.subTo(r,r)}}}function bnMod(t){var i=nbi();return this.abs().divRemTo(t,null,i),this.s<0&&i.compareTo(BigInteger.ZERO)>0&&t.subTo(i,i),i}function Classic(t){this.m=t}function cConvert(t){return t.s<0||t.compareTo(this.m)>=0?t.mod(this.m):t}function cRevert(t){return t}function cReduce(t){t.divRemTo(this.m,null,t)}function cMulTo(t,i,r){t.multiplyTo(i,r),this.reduce(r)}function cSqrTo(t,i){t.squareTo(i),this.reduce(i)}function bnpInvDigit(){if(this.t<1)return 0;var t=this[0];if(0==(1&t))return 0;var i=3&t;return(i=(i=(i=(i=i*(2-(15&t)*i)&15)*(2-(255&t)*i)&255)*(2-((65535&t)*i&65535))&65535)*(2-t*i%this.DV)%this.DV)>0?this.DV-i:-i}function Montgomery(t){this.m=t,this.mp=t.invDigit(),this.mpl=32767&this.mp,this.mph=this.mp>>15,this.um=(1<0&&this.m.subTo(i,i),i}function montRevert(t){var i=nbi();return t.copyTo(i),this.reduce(i),i}function montReduce(t){for(;t.t<=this.mt2;)t[t.t++]=0;for(var i=0;i>15)*this.mpl&this.um)<<15)&t.DM;for(t[r=i+this.m.t]+=this.m.am(0,o,t,i,0,this.m.t);t[r]>=t.DV;)t[r]-=t.DV,t[++r]++}t.clamp(),t.drShiftTo(this.m.t,t),t.compareTo(this.m)>=0&&t.subTo(this.m,t)}function montSqrTo(t,i){t.squareTo(i),this.reduce(i)}function montMulTo(t,i,r){t.multiplyTo(i,r),this.reduce(r)}function bnpIsEven(){return 0==(this.t>0?1&this[0]:this.s)}function bnpExp(t,i){if(t>4294967295||t<1)return BigInteger.ONE;var r=nbi(),o=nbi(),n=i.convert(this),e=nbits(t)-1;for(n.copyTo(r);--e>=0;)if(i.sqrTo(r,o),(t&1<0)i.mulTo(o,n,r);else{var s=r;r=o,o=s}return i.revert(r)}function bnModPowInt(t,i){var r;return r=t<256||i.isEven()?new Classic(i):new Montgomery(i),this.exp(t,r)}Classic.prototype.convert=cConvert,Classic.prototype.revert=cRevert,Classic.prototype.reduce=cReduce,Classic.prototype.mulTo=cMulTo,Classic.prototype.sqrTo=cSqrTo,Montgomery.prototype.convert=montConvert,Montgomery.prototype.revert=montRevert,Montgomery.prototype.reduce=montReduce,Montgomery.prototype.mulTo=montMulTo,Montgomery.prototype.sqrTo=montSqrTo,BigInteger.prototype.copyTo=bnpCopyTo,BigInteger.prototype.fromInt=bnpFromInt,BigInteger.prototype.fromString=bnpFromString,BigInteger.prototype.clamp=bnpClamp,BigInteger.prototype.dlShiftTo=bnpDLShiftTo,BigInteger.prototype.drShiftTo=bnpDRShiftTo,BigInteger.prototype.lShiftTo=bnpLShiftTo,BigInteger.prototype.rShiftTo=bnpRShiftTo,BigInteger.prototype.subTo=bnpSubTo,BigInteger.prototype.multiplyTo=bnpMultiplyTo,BigInteger.prototype.squareTo=bnpSquareTo,BigInteger.prototype.divRemTo=bnpDivRemTo,BigInteger.prototype.invDigit=bnpInvDigit,BigInteger.prototype.isEven=bnpIsEven,BigInteger.prototype.exp=bnpExp,BigInteger.prototype.toString=bnToString,BigInteger.prototype.negate=bnNegate,BigInteger.prototype.abs=bnAbs,BigInteger.prototype.compareTo=bnCompareTo,BigInteger.prototype.bitLength=bnBitLength,BigInteger.prototype.mod=bnMod,BigInteger.prototype.modPowInt=bnModPowInt,BigInteger.ZERO=nbv(0),BigInteger.ONE=nbv(1); +// (c) Tom Wu | http://www-cs-students.stanford.edu/~tjw/jsbn/ +function bnClone(){var t=nbi();return this.copyTo(t),t}function bnIntValue(){if(this.s<0){if(1==this.t)return this[0]-this.DV;if(0==this.t)return-1}else{if(1==this.t)return this[0];if(0==this.t)return 0}return(this[1]&(1<<32-this.DB)-1)<>24}function bnShortValue(){return 0==this.t?this.s:this[0]<<16>>16}function bnpChunkSize(t){return Math.floor(Math.LN2*this.DB/Math.log(t))}function bnSigNum(){return this.s<0?-1:this.t<=0||1==this.t&&this[0]<=0?0:1}function bnpToRadix(t){if(null==t&&(t=10),0==this.signum()||t<2||t>36)return"0";var i=this.chunkSize(t),r=Math.pow(t,i),e=nbv(r),n=nbi(),o=nbi(),s="";for(this.divRemTo(e,n,o);n.signum()>0;)s=(r+o.intValue()).toString(t).substr(1)+s,n.divRemTo(e,n,o);return o.intValue().toString(t)+s}function bnpFromRadix(t,i){this.fromInt(0),null==i&&(i=10);for(var r=this.chunkSize(i),e=Math.pow(i,r),n=!1,o=0,s=0,h=0;h=r&&(this.dMultiply(e),this.dAddOffset(s,0),o=0,s=0))}o>0&&(this.dMultiply(Math.pow(i,o)),this.dAddOffset(s,0)),n&&BigInteger.ZERO.subTo(this,this)}function bnpFromNumber(t,i,r){if("number"==typeof i)if(t<2)this.fromInt(1);else for(this.fromNumber(t,r),this.testBit(t-1)||this.bitwiseTo(BigInteger.ONE.shiftLeft(t-1),op_or,this),this.isEven()&&this.dAddOffset(1,0);!this.isProbablePrime(i);)this.dAddOffset(2,0),this.bitLength()>t&&this.subTo(BigInteger.ONE.shiftLeft(t-1),this);else{var e=new Array,n=7&t;e.length=1+(t>>3),i.nextBytes(e),n>0?e[0]&=(1<0)for(e>e)!=(this.s&this.DM)>>e&&(i[n++]=r|this.s<=0;)e<8?(r=(this[t]&(1<>(e+=this.DB-8)):(r=this[t]>>(e-=8)&255,e<=0&&(e+=this.DB,--t)),0!=(128&r)&&(r|=-256),0==n&&(128&this.s)!=(128&r)&&++n,(n>0||r!=this.s)&&(i[n++]=r);return i}function bnEquals(t){return 0==this.compareTo(t)}function bnMin(t){return this.compareTo(t)<0?this:t}function bnMax(t){return this.compareTo(t)>0?this:t}function bnpBitwiseTo(t,i,r){var e,n,o=Math.min(t.t,this.t);for(e=0;e>=16,i+=16),0==(255&t)&&(t>>=8,i+=8),0==(15&t)&&(t>>=4,i+=4),0==(3&t)&&(t>>=2,i+=2),0==(1&t)&&++i,i}function bnGetLowestSetBit(){for(var t=0;t=this.t?0!=this.s:0!=(this[i]&1<>=this.DB;if(t.t>=this.DB;e+=this.s}else{for(e+=this.s;r>=this.DB;e+=t.s}i.s=e<0?-1:0,e>0?i[r++]=e:e<-1&&(i[r++]=this.DV+e),i.t=r,i.clamp()}function bnAdd(t){var i=nbi();return this.addTo(t,i),i}function bnSubtract(t){var i=nbi();return this.subTo(t,i),i}function bnMultiply(t){var i=nbi();return this.multiplyTo(t,i),i}function bnSquare(){var t=nbi();return this.squareTo(t),t}function bnDivide(t){var i=nbi();return this.divRemTo(t,i,null),i}function bnRemainder(t){var i=nbi();return this.divRemTo(t,null,i),i}function bnDivideAndRemainder(t){var i=nbi(),r=nbi();return this.divRemTo(t,i,r),new Array(i,r)}function bnpDMultiply(t){this[this.t]=this.am(0,t-1,this,0,0,this.t),++this.t,this.clamp()}function bnpDAddOffset(t,i){if(0!=t){for(;this.t<=i;)this[this.t++]=0;for(this[i]+=t;this[i]>=this.DV;)this[i]-=this.DV,++i>=this.t&&(this[this.t++]=0),++this[i]}}function NullExp(){}function nNop(t){return t}function nMulTo(t,i,r){t.multiplyTo(i,r)}function nSqrTo(t,i){t.squareTo(i)}function bnPow(t){return this.exp(t,new NullExp)}function bnpMultiplyLowerTo(t,i,r){var e,n=Math.min(this.t+t.t,i);for(r.s=0,r.t=n;n>0;)r[--n]=0;for(e=r.t-this.t;n=0;)r[e]=0;for(e=Math.max(i-this.t,0);e2*this.m.t)return t.mod(this.m);if(t.compareTo(this.m)<0)return t;var i=nbi();return t.copyTo(i),this.reduce(i),i}function barrettRevert(t){return t}function barrettReduce(t){for(t.drShiftTo(this.m.t-1,this.r2),t.t>this.m.t+1&&(t.t=this.m.t+1,t.clamp()),this.mu.multiplyUpperTo(this.r2,this.m.t+1,this.q3),this.m.multiplyLowerTo(this.q3,this.m.t+1,this.r2);t.compareTo(this.r2)<0;)t.dAddOffset(1,this.m.t+1);for(t.subTo(this.r2,t);t.compareTo(this.m)>=0;)t.subTo(this.m,t)}function barrettSqrTo(t,i){t.squareTo(i),this.reduce(i)}function barrettMulTo(t,i,r){t.multiplyTo(i,r),this.reduce(r)}function bnModPow(t,i){var r,e,n=t.bitLength(),o=nbv(1);if(n<=0)return o;r=n<18?1:n<48?3:n<144?4:n<768?5:6,e=n<8?new Classic(i):i.isEven()?new Barrett(i):new Montgomery(i);var s=new Array,h=3,u=r-1,p=(1<1){var f=nbi();for(e.sqrTo(s[1],f);h<=p;)s[h]=nbi(),e.mulTo(f,s[h-2],s[h]),h+=2}var a,b,g=t.t-1,l=!0,m=nbi();for(n=nbits(t[g])-1;g>=0;){for(n>=u?a=t[g]>>n-u&p:(a=(t[g]&(1<0&&(a|=t[g-1]>>this.DB+n-u)),h=r;0==(1&a);)a>>=1,--h;if((n-=h)<0&&(n+=this.DB,--g),l)s[a].copyTo(o),l=!1;else{for(;h>1;)e.sqrTo(o,m),e.sqrTo(m,o),h-=2;h>0?e.sqrTo(o,m):(b=o,o=m,m=b),e.mulTo(m,s[a],o)}for(;g>=0&&0==(t[g]&1<0&&(i.rShiftTo(o,i),r.rShiftTo(o,r));i.signum()>0;)(n=i.getLowestSetBit())>0&&i.rShiftTo(n,i),(n=r.getLowestSetBit())>0&&r.rShiftTo(n,r),i.compareTo(r)>=0?(i.subTo(r,i),i.rShiftTo(1,i)):(r.subTo(i,r),r.rShiftTo(1,r));return o>0&&r.lShiftTo(o,r),r}function bnpModInt(t){if(t<=0)return 0;var i=this.DV%t,r=this.s<0?t-1:0;if(this.t>0)if(0==i)r=this[0]%t;else for(var e=this.t-1;e>=0;--e)r=(i*r+this[e])%t;return r}function bnModInverse(t){var i=t.isEven();if(this.isEven()&&i||0==t.signum())return BigInteger.ZERO;for(var r=t.clone(),e=this.clone(),n=nbv(1),o=nbv(0),s=nbv(0),h=nbv(1);0!=r.signum();){for(;r.isEven();)r.rShiftTo(1,r),i?(n.isEven()&&o.isEven()||(n.addTo(this,n),o.subTo(t,o)),n.rShiftTo(1,n)):o.isEven()||o.subTo(t,o),o.rShiftTo(1,o);for(;e.isEven();)e.rShiftTo(1,e),i?(s.isEven()&&h.isEven()||(s.addTo(this,s),h.subTo(t,h)),s.rShiftTo(1,s)):h.isEven()||h.subTo(t,h),h.rShiftTo(1,h);r.compareTo(e)>=0?(r.subTo(e,r),i&&n.subTo(s,n),o.subTo(h,o)):(e.subTo(r,e),i&&s.subTo(n,s),h.subTo(o,h))}return 0!=e.compareTo(BigInteger.ONE)?BigInteger.ZERO:h.compareTo(t)>=0?h.subtract(t):h.signum()<0?(h.addTo(t,h),h.signum()<0?h.add(t):h):h}NullExp.prototype.convert=nNop,NullExp.prototype.revert=nNop,NullExp.prototype.mulTo=nMulTo,NullExp.prototype.sqrTo=nSqrTo,Barrett.prototype.convert=barrettConvert,Barrett.prototype.revert=barrettRevert,Barrett.prototype.reduce=barrettReduce,Barrett.prototype.mulTo=barrettMulTo,Barrett.prototype.sqrTo=barrettSqrTo;var lowprimes=[2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509,521,523,541,547,557,563,569,571,577,587,593,599,601,607,613,617,619,631,641,643,647,653,659,661,673,677,683,691,701,709,719,727,733,739,743,751,757,761,769,773,787,797,809,811,821,823,827,829,839,853,857,859,863,877,881,883,887,907,911,919,929,937,941,947,953,967,971,977,983,991,997],lplim=(1<<26)/lowprimes[lowprimes.length-1];function bnIsProbablePrime(t){var i,r=this.abs();if(1==r.t&&r[0]<=lowprimes[lowprimes.length-1]){for(i=0;i>1)>lowprimes.length&&(t=lowprimes.length);for(var n=nbi(),o=0;o0;--e){u=u.twice();var s=n.testBit(e);s!=i.testBit(e)&&(u=u.add(s?this:r))}return u}function pointFpMultiplyTwo(t,e,i){var n;n=t.bitLength()>i.bitLength()?t.bitLength()-1:i.bitLength()-1;for(var r=this.curve.getInfinity(),u=this.add(e);n>=0;)r=r.twice(),t.testBit(n)?r=i.testBit(n)?r.add(u):r.add(this):i.testBit(n)&&(r=r.add(e)),--n;return r}function ECCurveFp(t,e,i){this.q=t,this.a=this.fromBigInteger(e),this.b=this.fromBigInteger(i),this.infinity=new ECPointFp(this,null,null)}function curveFpGetQ(){return this.q}function curveFpGetA(){return this.a}function curveFpGetB(){return this.b}function curveFpEquals(t){return t==this||this.q.equals(t.q)&&this.a.equals(t.a)&&this.b.equals(t.b)}function curveFpGetInfinity(){return this.infinity}function curveFpFromBigInteger(t){return new ECFieldElementFp(this.q,t)}function curveFpDecodePointHex(t){switch(parseInt(t.substr(0,2),16)){case 0:return this.infinity;case 2:case 3:return null;case 4:case 6:case 7:var e=(t.length-2)/2,i=t.substr(2,e),n=t.substr(e+2,e);return new ECPointFp(this,this.fromBigInteger(new BigInteger(i,16)),this.fromBigInteger(new BigInteger(n,16)));default:return null}}ECFieldElementFp.prototype.equals=feFpEquals,ECFieldElementFp.prototype.toBigInteger=feFpToBigInteger,ECFieldElementFp.prototype.negate=feFpNegate,ECFieldElementFp.prototype.add=feFpAdd,ECFieldElementFp.prototype.subtract=feFpSubtract,ECFieldElementFp.prototype.multiply=feFpMultiply,ECFieldElementFp.prototype.square=feFpSquare,ECFieldElementFp.prototype.divide=feFpDivide,ECPointFp.prototype.getX=pointFpGetX,ECPointFp.prototype.getY=pointFpGetY,ECPointFp.prototype.equals=pointFpEquals,ECPointFp.prototype.isInfinity=pointFpIsInfinity,ECPointFp.prototype.negate=pointFpNegate,ECPointFp.prototype.add=pointFpAdd,ECPointFp.prototype.twice=pointFpTwice,ECPointFp.prototype.multiply=pointFpMultiply,ECPointFp.prototype.multiplyTwo=pointFpMultiplyTwo,ECCurveFp.prototype.getQ=curveFpGetQ,ECCurveFp.prototype.getA=curveFpGetA,ECCurveFp.prototype.getB=curveFpGetB,ECCurveFp.prototype.equals=curveFpEquals,ECCurveFp.prototype.getInfinity=curveFpGetInfinity,ECCurveFp.prototype.fromBigInteger=curveFpFromBigInteger,ECCurveFp.prototype.decodePointHex=curveFpDecodePointHex; +// ! (c) Tom Wu | http://www-cs-students.stanford.edu/~tjw/jsbn/ +function Arcfour(){this.i=0,this.j=0,this.S=new Array}function ARC4init(i){var t,s,h;for(t=0;t<256;++t)this.S[t]=t;for(s=0,t=0;t<256;++t)s=s+this.S[t]+i[t%i.length]&255,h=this.S[t],this.S[t]=this.S[s],this.S[s]=h;this.i=0,this.j=0}function ARC4next(){var i;return this.i=this.i+1&255,this.j=this.j+this.S[this.i]&255,i=this.S[this.i],this.S[this.i]=this.S[this.j],this.S[this.j]=i,this.S[i+this.S[this.i]&255]}function prng_newstate(){return new Arcfour}Arcfour.prototype.init=ARC4init,Arcfour.prototype.next=ARC4next;var rng_psize=256; +// (c) Tom Wu | http://www-cs-students.stanford.edu/~tjw/jsbn/ +var rng_state,rng_pool,rng_pptr;function rng_seed_int(r){rng_pool[rng_pptr++]^=255&r,rng_pool[rng_pptr++]^=r>>8&255,rng_pool[rng_pptr++]^=r>>16&255,rng_pool[rng_pptr++]^=r>>24&255,rng_pptr>=rng_psize&&(rng_pptr-=rng_psize)}function rng_seed_time(){rng_seed_int((new Date).getTime())}if(null==rng_pool){var t;if(rng_pool=new Array,rng_pptr=0,void 0!==window&&(void 0!==window.crypto||void 0!==window.msCrypto)){var crypto=window.crypto||window.msCrypto;if(crypto.getRandomValues){var ua=new Uint8Array(32);for(crypto.getRandomValues(ua),t=0;t<32;++t)rng_pool[rng_pptr++]=ua[t]}else if("Netscape"==navigator.appName&&navigator.appVersion<"5"){var z=window.crypto.random(32);for(t=0;t>>8,rng_pool[rng_pptr++]=255&t;rng_pptr=0,rng_seed_time()}function rng_get_byte(){if(null==rng_state){for(rng_seed_time(),(rng_state=prng_newstate()).init(rng_pool),rng_pptr=0;rng_pptr=0&&n>0;){var i=t.charCodeAt(e--);i<128?r[--n]=i:i>127&&i<2048?(r[--n]=63&i|128,r[--n]=i>>6|192):(r[--n]=63&i|128,r[--n]=i>>6&63|128,r[--n]=i>>12|224)}r[--n]=0;for(var o=new SecureRandom,l=new Array;n>2;){for(l[0]=0;0==l[0];)o.nextBytes(l);r[--n]=l[0]}return r[--n]=2,r[--n]=0,new BigInteger(r)}function oaep_mgf1_arr(t,n,r){for(var e="",i=0;e.length>24,(16711680&i)>>16,(65280&i)>>8,255&i]))),i+=1;return e}function oaep_pad(t,n,r,e){var i=KJUR.crypto.MessageDigest,o=KJUR.crypto.Util,l=null;if(r||(r="sha1"),"string"==typeof r&&(l=i.getCanonicalAlgName(r),e=i.getHashLength(l),r=function(t){return hextorstr(o.hashHex(rstrtohex(t),l))}),t.length+2*e+2>n)throw"Message too long for RSA";var u,a="";for(u=0;u0&&n.length>0))throw"Invalid RSA public key";this.n=parseBigInt(t,16),this.e=parseInt(n,16)}}function RSADoPublic(t){return t.modPowInt(this.e,this.n)}function RSAEncrypt(t){var n=pkcs1pad2(t,this.n.bitLength()+7>>3);if(null==n)return null;var r=this.doPublic(n);if(null==r)return null;var e=r.toString(16);return 0==(1&e.length)?e:"0"+e}function RSAEncryptOAEP(t,n,r){var e=oaep_pad(t,this.n.bitLength()+7>>3,n,r);if(null==e)return null;var i=this.doPublic(e);if(null==i)return null;var o=i.toString(16);return 0==(1&o.length)?o:"0"+o}RSAKey.prototype.doPublic=RSADoPublic,RSAKey.prototype.setPublic=RSASetPublic,RSAKey.prototype.encrypt=RSAEncrypt,RSAKey.prototype.encryptOAEP=RSAEncryptOAEP,RSAKey.prototype.type="RSA"; +// CryptoJS v3.1.2 +!function(r){var t=CryptoJS,e=t.lib,n=e.WordArray,o=e.Hasher,s=t.algo,a=[],i=[];!function(){function t(t){for(var e=r.sqrt(t),n=2;n<=e;n++)if(!(t%n))return!1;return!0}function e(r){return 4294967296*(r-(0|r))|0}for(var n=2,o=0;o<64;)t(n)&&(o<8&&(a[o]=e(r.pow(n,.5))),i[o]=e(r.pow(n,1/3)),o++),n++}();var h=[],c=s.SHA256=o.extend({_doReset:function(){this._hash=new n.init(a.slice(0))},_doProcessBlock:function(r,t){for(var e=this._hash.words,n=e[0],o=e[1],s=e[2],a=e[3],c=e[4],l=e[5],f=e[6],u=e[7],_=0;_<64;_++){if(_<16)h[_]=0|r[t+_];else{var v=h[_-15],d=(v<<25|v>>>7)^(v<<14|v>>>18)^v>>>3,H=h[_-2],p=(H<<15|H>>>17)^(H<<13|H>>>19)^H>>>10;h[_]=d+h[_-7]+p+h[_-16]}var w=n&o^n&s^o&s,y=(n<<30|n>>>2)^(n<<19|n>>>13)^(n<<10|n>>>22),g=u+((c<<26|c>>>6)^(c<<21|c>>>11)^(c<<7|c>>>25))+(c&l^~c&f)+i[_]+h[_];u=f,f=l,l=c,c=a+g|0,a=s,s=o,o=n,n=g+(y+w)|0}e[0]=e[0]+n|0,e[1]=e[1]+o|0,e[2]=e[2]+s|0,e[3]=e[3]+a|0,e[4]=e[4]+c|0,e[5]=e[5]+l|0,e[6]=e[6]+f|0,e[7]=e[7]+u|0},_doFinalize:function(){var t=this._data,e=t.words,n=8*this._nDataBytes,o=8*t.sigBytes;return e[o>>>5]|=128<<24-o%32,e[14+(o+64>>>9<<4)]=r.floor(n/4294967296),e[15+(o+64>>>9<<4)]=n,t.sigBytes=4*e.length,this._process(),this._hash},clone:function(){var r=o.clone.call(this);return r._hash=this._hash.clone(),r}});t.SHA256=o._createHelper(c),t.HmacSHA256=o._createHmacHelper(c)}(Math); +// asn1-1.0.14.js (c) 2013-2018 Kenji Urushima | kjur.github.com/jsrsasign/license +"undefined"!=typeof KJUR&&KJUR||(KJUR={}),void 0!==KJUR.asn1&&KJUR.asn1||(KJUR.asn1={}),KJUR.asn1.ASN1Util=new function(){this.integerToByteHex=function(t){var e=t.toString(16);return e.length%2==1&&(e="0"+e),e},this.bigIntToMinTwosComplementsHex=function(t){var e=t.toString(16);if("-"!=e.substr(0,1))e.length%2==1?e="0"+e:e.match(/^[0-7]/)||(e="00"+e);else{var i=e.substr(1).length;i%2==1?i+=1:e.match(/^[0-7]/)||(i+=2);for(var n="",s=0;s15)throw"ASN.1 length too long to represent by 8x: n = "+t.toString(16);return(128+i).toString(16)+e},this.getEncodedHex=function(){return(null==this.hTLV||this.isModified)&&(this.hV=this.getFreshValueHex(),this.hL=this.getLengthHexFromValue(),this.hTLV=this.hT+this.hL+this.hV,this.isModified=!1),this.hTLV},this.getValueHex=function(){return this.getEncodedHex(),this.hV},this.getFreshValueHex=function(){return""}},KJUR.asn1.DERAbstractString=function(t){KJUR.asn1.DERAbstractString.superclass.constructor.call(this);this.getString=function(){return this.s},this.setString=function(t){this.hTLV=null,this.isModified=!0,this.s=t,this.hV=utf8tohex(this.s).toLowerCase()},this.setStringHex=function(t){this.hTLV=null,this.isModified=!0,this.s=null,this.hV=t},this.getFreshValueHex=function(){return this.hV},void 0!==t&&("string"==typeof t?this.setString(t):void 0!==t.str?this.setString(t.str):void 0!==t.hex&&this.setStringHex(t.hex))},YAHOO.lang.extend(KJUR.asn1.DERAbstractString,KJUR.asn1.ASN1Object),KJUR.asn1.DERAbstractTime=function(t){KJUR.asn1.DERAbstractTime.superclass.constructor.call(this);this.localDateToUTC=function(t){return utc=t.getTime()+6e4*t.getTimezoneOffset(),new Date(utc)},this.formatDate=function(t,e,i){var n=this.zeroPadding,s=this.localDateToUTC(t),r=String(s.getFullYear());"utc"==e&&(r=r.substr(2,2));var h=r+n(String(s.getMonth()+1),2)+n(String(s.getDate()),2)+n(String(s.getHours()),2)+n(String(s.getMinutes()),2)+n(String(s.getSeconds()),2);if(!0===i){var a=s.getMilliseconds();if(0!=a){var o=n(String(a),3);h=h+"."+(o=o.replace(/[0]+$/,""))}}return h+"Z"},this.zeroPadding=function(t,e){return t.length>=e?t:new Array(e-t.length+1).join("0")+t},this.getString=function(){return this.s},this.setString=function(t){this.hTLV=null,this.isModified=!0,this.s=t,this.hV=stohex(t)},this.setByDateValue=function(t,e,i,n,s,r){var h=new Date(Date.UTC(t,e-1,i,n,s,r,0));this.setByDate(h)},this.getFreshValueHex=function(){return this.hV}},YAHOO.lang.extend(KJUR.asn1.DERAbstractTime,KJUR.asn1.ASN1Object),KJUR.asn1.DERAbstractStructured=function(t){KJUR.asn1.DERAbstractString.superclass.constructor.call(this);this.setByASN1ObjectArray=function(t){this.hTLV=null,this.isModified=!0,this.asn1Array=t},this.appendASN1Object=function(t){this.hTLV=null,this.isModified=!0,this.asn1Array.push(t)},this.asn1Array=new Array,void 0!==t&&void 0!==t.array&&(this.asn1Array=t.array)},YAHOO.lang.extend(KJUR.asn1.DERAbstractStructured,KJUR.asn1.ASN1Object),KJUR.asn1.DERBoolean=function(){KJUR.asn1.DERBoolean.superclass.constructor.call(this),this.hT="01",this.hTLV="0101ff"},YAHOO.lang.extend(KJUR.asn1.DERBoolean,KJUR.asn1.ASN1Object),KJUR.asn1.DERInteger=function(t){KJUR.asn1.DERInteger.superclass.constructor.call(this),this.hT="02",this.setByBigInteger=function(t){this.hTLV=null,this.isModified=!0,this.hV=KJUR.asn1.ASN1Util.bigIntToMinTwosComplementsHex(t)},this.setByInteger=function(t){var e=new BigInteger(String(t),10);this.setByBigInteger(e)},this.setValueHex=function(t){this.hV=t},this.getFreshValueHex=function(){return this.hV},void 0!==t&&(void 0!==t.bigint?this.setByBigInteger(t.bigint):void 0!==t.int?this.setByInteger(t.int):"number"==typeof t?this.setByInteger(t):void 0!==t.hex&&this.setValueHex(t.hex))},YAHOO.lang.extend(KJUR.asn1.DERInteger,KJUR.asn1.ASN1Object),KJUR.asn1.DERBitString=function(t){if(void 0!==t&&void 0!==t.obj){var e=KJUR.asn1.ASN1Util.newObject(t.obj);t.hex="00"+e.getEncodedHex()}KJUR.asn1.DERBitString.superclass.constructor.call(this),this.hT="03",this.setHexValueIncludingUnusedBits=function(t){this.hTLV=null,this.isModified=!0,this.hV=t},this.setUnusedBitsAndHexValue=function(t,e){if(t<0||7=2*u)break;if(g>=200)break;e.push(o),s=o,g++}return e},ASN1HEX.getNthChildIdx=function(t,r,n){return ASN1HEX.getChildIdx(t,r)[n]},ASN1HEX.getIdxbyList=function(t,r,n,e){var i,u,s=ASN1HEX;if(0==n.length){if(void 0!==e&&t.substr(r,2)!==e)throw"checking tag doesn't match: "+t.substr(r,2)+"!="+e;return r}return i=n.shift(),u=s.getChildIdx(t,r),s.getIdxbyList(t,u[i],n,e)},ASN1HEX.getTLVbyList=function(t,r,n,e){var i=ASN1HEX,u=i.getIdxbyList(t,r,n);if(void 0===u)throw"can't find nthList object";if(void 0!==e&&t.substr(u,2)!=e)throw"checking tag doesn't match: "+t.substr(u,2)+"!="+e;return i.getTLV(t,u)},ASN1HEX.getVbyList=function(t,r,n,e,i){var u,s,g=ASN1HEX;if(void 0===(u=g.getIdxbyList(t,r,n,e)))throw"can't find nthList object";return s=g.getV(t,u),!0===i&&(s=s.substr(2)),s},ASN1HEX.hextooidstr=function(t){var r=function(t,r){return t.length>=r?t:new Array(r-t.length+1).join("0")+t},n=[],e=t.substr(0,2),i=parseInt(e,16);n[0]=new String(Math.floor(i/40)),n[1]=new String(i%40);for(var u=t.substr(2),s=[],g=0;g0&&(f=f+"."+o.join(".")),f},ASN1HEX.dump=function(t,r,n,e){var i=ASN1HEX,u=i.getV,s=i.dump,g=i.getChildIdx,o=t;t instanceof KJUR.asn1.ASN1Object&&(o=t.getEncodedHex());var a=function(t,r){return t.length<=2*r?t:t.substr(0,r)+"..(total "+t.length/2+"bytes).."+t.substr(t.length-r,r)};void 0===r&&(r={ommit_long_octet:32}),void 0===n&&(n=0),void 0===e&&(e="");var f=r.ommit_long_octet;if("01"==o.substr(n,2))return"00"==(b=u(o,n))?e+"BOOLEAN FALSE\n":e+"BOOLEAN TRUE\n";if("02"==o.substr(n,2))return e+"INTEGER "+a(b=u(o,n),f)+"\n";if("03"==o.substr(n,2))return e+"BITSTRING "+a(b=u(o,n),f)+"\n";if("04"==o.substr(n,2)){var b=u(o,n);if(i.isASN1HEX(b)){var S=e+"OCTETSTRING, encapsulates\n";return S+=s(b,r,0,e+" ")}return e+"OCTETSTRING "+a(b,f)+"\n"}if("05"==o.substr(n,2))return e+"NULL\n";if("06"==o.substr(n,2)){var N=u(o,n),E=KJUR.asn1.ASN1Util.oidHexToInt(N),h=KJUR.asn1.x509.OID.oid2name(E),l=E.replace(/\./g," ");return""!=h?e+"ObjectIdentifier "+h+" ("+l+")\n":e+"ObjectIdentifier ("+l+")\n"}if("0c"==o.substr(n,2))return e+"UTF8String '"+hextoutf8(u(o,n))+"'\n";if("13"==o.substr(n,2))return e+"PrintableString '"+hextoutf8(u(o,n))+"'\n";if("14"==o.substr(n,2))return e+"TeletexString '"+hextoutf8(u(o,n))+"'\n";if("16"==o.substr(n,2))return e+"IA5String '"+hextoutf8(u(o,n))+"'\n";if("17"==o.substr(n,2))return e+"UTCTime "+hextoutf8(u(o,n))+"\n";if("18"==o.substr(n,2))return e+"GeneralizedTime "+hextoutf8(u(o,n))+"\n";if("30"==o.substr(n,2)){if("3000"==o.substr(n,4))return e+"SEQUENCE {}\n";S=e+"SEQUENCE\n";var d=r;if((2==(v=g(o,n)).length||3==v.length)&&"06"==o.substr(v[0],2)&&"04"==o.substr(v[v.length-1],2)){h=i.oidname(u(o,v[0]));var A=JSON.parse(JSON.stringify(r));A.x509ExtName=h,d=A}for(var c=0;co.length&&(o=n[r]);return(t=t.replace(o,"::")).slice(1,-1)}function hextoip(t){var e="malformed hex value";if(!t.match(/^([0-9A-Fa-f][0-9A-Fa-f]){1,}$/))throw e;if(8!=t.length)return 32==t.length?hextoipv6(t):t;try{return parseInt(t.substr(0,2),16)+"."+parseInt(t.substr(2,2),16)+"."+parseInt(t.substr(4,2),16)+"."+parseInt(t.substr(6,2),16)}catch(t){throw e}}function iptohex(t){var e="malformed IP address";if(!(t=t.toLowerCase(t)).match(/^[0-9.]+$/)){if(t.match(/^[0-9a-f:]+$/)&&-1!==t.indexOf(":"))return ipv6tohex(t);throw e}var r=t.split(".");if(4!==r.length)throw e;var n="";try{for(var o=0;o<4;o++){n+=("0"+parseInt(r[o]).toString(16)).slice(-2)}return n}catch(t){throw e}}function encodeURIComponentAll(t){for(var e=encodeURIComponent(t),r="",n=0;n"7"?"00"+t:t}function intarystrtohex(t){t=(t=(t=t.replace(/^\s*\[\s*/,"")).replace(/\s*\]\s*$/,"")).replace(/\s*/g,"");try{return t.split(/,/).map(function(t,e,r){var n=parseInt(t);if(n<0||255e.length&&(r=e.length);for(var n=0;nr)throw"key is too short for SigAlg: keylen="+e+","+s;for(var o="0001",a="00"+i,h="",n=r-o.length-a.length,p=0;p=0)return!1;if(r.compareTo(BigInteger.ONE)<0||r.compareTo(s)>=0)return!1;var a=r.modInverse(s),o=e.multiply(a).mod(s),u=t.multiply(a).mod(s);return n.multiply(o).add(i.multiply(u)).getX().toBigInteger().mod(s).equals(t)},this.serializeSig=function(e,t){var r=e.toByteArraySigned(),i=t.toByteArraySigned(),s=[];return s.push(2),s.push(r.length),(s=s.concat(r)).push(2),s.push(i.length),(s=s.concat(i)).unshift(s.length),s.unshift(48),s},this.parseSig=function(e){var t;if(48!=e[0])throw new Error("Signature not a valid DERSequence");if(2!=e[t=2])throw new Error("First element in signature must be a DERInteger");var r=e.slice(t+2,t+2+e[t+1]);if(2!=e[t+=2+e[t+1]])throw new Error("Second element in signature must be a DERInteger");var i=e.slice(t+2,t+2+e[t+1]);return t+=2+e[t+1],{r:BigInteger.fromByteArrayUnsigned(r),s:BigInteger.fromByteArrayUnsigned(i)}},this.parseSigCompact=function(e){if(65!==e.length)throw"Signature has the wrong length";var t=e[0]-27;if(t<0||t>7)throw"Invalid signature type";var r=this.ecparams.n;return{r:BigInteger.fromByteArrayUnsigned(e.slice(1,33)).mod(r),s:BigInteger.fromByteArrayUnsigned(e.slice(33,65)).mod(r),i:t}},this.readPKCS5PrvKeyHex=function(e){var t,r,i,s=ASN1HEX,n=KJUR.crypto.ECDSA.getName,a=s.getVbyList;if(!1===s.isASN1HEX(e))throw"not ASN.1 hex string";try{t=a(e,0,[2,0],"06"),r=a(e,0,[1],"04");try{i=a(e,0,[3,0],"03").substr(2)}catch(e){}}catch(e){throw"malformed PKCS#1/5 plain ECC private key"}if(this.curveName=n(t),void 0===this.curveName)throw"unsupported curve name";this.setNamedCurve(this.curveName),this.setPublicKeyHex(i),this.setPrivateKeyHex(r),this.isPublic=!1},this.readPKCS8PrvKeyHex=function(e){var t,r,i,s=ASN1HEX,n=KJUR.crypto.ECDSA.getName,a=s.getVbyList;if(!1===s.isASN1HEX(e))throw"not ASN.1 hex string";try{a(e,0,[1,0],"06"),t=a(e,0,[1,1],"06"),r=a(e,0,[2,0,1],"04");try{i=a(e,0,[2,0,2,0],"03").substr(2)}catch(e){}}catch(e){throw"malformed PKCS#8 plain ECC private key"}if(this.curveName=n(t),void 0===this.curveName)throw"unsupported curve name";this.setNamedCurve(this.curveName),this.setPublicKeyHex(i),this.setPrivateKeyHex(r),this.isPublic=!1},this.readPKCS8PubKeyHex=function(e){var t,r,i=ASN1HEX,s=KJUR.crypto.ECDSA.getName,n=i.getVbyList;if(!1===i.isASN1HEX(e))throw"not ASN.1 hex string";try{n(e,0,[0,0],"06"),t=n(e,0,[0,1],"06"),r=n(e,0,[1],"03").substr(2)}catch(e){throw"malformed PKCS#8 ECC public key"}if(this.curveName=s(t),null===this.curveName)throw"unsupported curve name";this.setNamedCurve(this.curveName),this.setPublicKeyHex(r)},this.readCertPubKeyHex=function(e,t){5!==t&&(t=6);var r,i,s=ASN1HEX,n=KJUR.crypto.ECDSA.getName,a=s.getVbyList;if(!1===s.isASN1HEX(e))throw"not ASN.1 hex string";try{r=a(e,0,[0,t,0,1],"06"),i=a(e,0,[0,t,1],"03").substr(2)}catch(e){throw"malformed X.509 certificate ECC public key"}if(this.curveName=n(r),null===this.curveName)throw"unsupported curve name";this.setNamedCurve(this.curveName),this.setPublicKeyHex(i)},void 0!==e&&void 0!==e.curve&&(this.curveName=e.curve),void 0===this.curveName&&(this.curveName="secp256r1"),this.setNamedCurve(this.curveName),void 0!==e&&(void 0!==e.prv&&this.setPrivateKeyHex(e.prv),void 0!==e.pub&&this.setPublicKeyHex(e.pub))},KJUR.crypto.ECDSA.parseSigHex=function(e){var t=KJUR.crypto.ECDSA.parseSigHexInHexRS(e);return{r:new BigInteger(t.r,16),s:new BigInteger(t.s,16)}},KJUR.crypto.ECDSA.parseSigHexInHexRS=function(e){var t=ASN1HEX,r=t.getChildIdx,i=t.getV;if("30"!=e.substr(0,2))throw"signature is not a ASN.1 sequence";var s=r(e,0);if(2!=s.length)throw"number of signature ASN.1 sequence elements seem wrong";var n=s[0],a=s[1];if("02"!=e.substr(n,2))throw"1st item of sequene of signature is not ASN.1 integer";if("02"!=e.substr(a,2))throw"2nd item of sequene of signature is not ASN.1 integer";return{r:i(e,n),s:i(e,a)}},KJUR.crypto.ECDSA.asn1SigToConcatSig=function(e){var t=KJUR.crypto.ECDSA.parseSigHexInHexRS(e),r=t.r,i=t.s;if("00"==r.substr(0,2)&&r.length%32==2&&(r=r.substr(2)),"00"==i.substr(0,2)&&i.length%32==2&&(i=i.substr(2)),r.length%32==30&&(r="00"+r),i.length%32==30&&(i="00"+i),r.length%32!=0)throw"unknown ECDSA sig r length error";if(i.length%32!=0)throw"unknown ECDSA sig s length error";return r+i},KJUR.crypto.ECDSA.concatSigToASN1Sig=function(e){if(e.length/2*8%128!=0)throw"unknown ECDSA concatinated r-s sig length error";var t=e.substr(0,e.length/2),r=e.substr(e.length/2);return KJUR.crypto.ECDSA.hexRSSigToASN1Sig(t,r)},KJUR.crypto.ECDSA.hexRSSigToASN1Sig=function(e,t){var r=new BigInteger(e,16),i=new BigInteger(t,16);return KJUR.crypto.ECDSA.biRSSigToASN1Sig(r,i)},KJUR.crypto.ECDSA.biRSSigToASN1Sig=function(e,t){var r=KJUR.asn1,i=new r.DERInteger({bigint:e}),s=new r.DERInteger({bigint:t});return new r.DERSequence({array:[i,s]}).getEncodedHex()},KJUR.crypto.ECDSA.getName=function(e){return"2a8648ce3d030107"===e?"secp256r1":"2b8104000a"===e?"secp256k1":"2b81040022"===e?"secp384r1":-1!=="|secp256r1|NIST P-256|P-256|prime256v1|".indexOf(e)?"secp256r1":-1!=="|secp256k1|".indexOf(e)?"secp256k1":-1!=="|secp384r1|NIST P-384|P-384|".indexOf(e)?"secp384r1":null}; +// ecparam-1.0.0.js (c) 2013 Kenji Urushima | kjur.github.com/jsrsasign/license +"undefined"!=typeof KJUR&&KJUR||(KJUR={}),void 0!==KJUR.crypto&&KJUR.crypto||(KJUR.crypto={}),KJUR.crypto.ECParameterDB=new function(){var F={},B={};function E(F){return new BigInteger(F,16)}this.getByName=function(E){var C=E;if(void 0!==B[C]&&(C=B[E]),void 0!==F[C])return F[C];throw"unregistered EC curve name: "+C},this.regist=function(C,D,A,e,r,t,c,a,i,p,o,s){F[C]={};var d=E(A),f=E(e),n=E(r),m=E(t),P=E(c),v=new ECCurveFp(d,f,n),y=v.decodePointHex("04"+a+i);F[C].name=C,F[C].keylen=D,F[C].curve=v,F[C].G=y,F[C].n=m,F[C].h=P,F[C].oid=o,F[C].info=s;for(var J=0;J=2*d)break}var v={};return v.keyhex=c.substr(0,2*n[e].keylen),v.ivhex=c.substr(2*n[e].keylen,2*n[e].ivlen),v},d=function(e,t,r,i){var o=CryptoJS.enc.Base64.parse(e),a=CryptoJS.enc.Hex.stringify(o);return(0,n[t].proc)(a,r,i)};return{version:"1.0.0",parsePKCS5PEM:function(e){return o(e)},getKeyAndUnusedIvByPasscodeAndIvsalt:function(e,t,r){return a(e,t,r)},decryptKeyB64:function(e,t,r,i){return d(e,t,r,i)},getDecryptedKeyHex:function(e,t){var r=o(e),i=(r.type,r.cipher),n=r.ivsalt,c=r.data,u=a(i,t,n).keyhex;return d(c,i,u,n)},getEncryptedPKCS5PEMFromPrvKeyHex:function(e,t,r,i,o){var d,c,u="";if(void 0!==i&&null!=i||(i="AES-256-CBC"),void 0===n[i])throw"KEYUTIL unsupported algorithm: "+i;if(void 0===o||null==o){var p=n[i].ivlen;o=(d=p,c=CryptoJS.lib.WordArray.random(d),CryptoJS.enc.Hex.stringify(c)).toUpperCase()}var v,s,f,E=a(i,r,o).keyhex;u="-----BEGIN "+e+" PRIVATE KEY-----\r\n";return u+="Proc-Type: 4,ENCRYPTED\r\n",u+="DEK-Info: "+i+","+o+"\r\n",u+="\r\n",u+=(v=t,s=E,f=o,(0,n[i].eproc)(v,s,f)).replace(/(.{64})/g,"$1\r\n"),u+="\r\n-----END "+e+" PRIVATE KEY-----\r\n"},parseHexOfEncryptedPKCS8:function(e){var t=ASN1HEX,r=t.getChildIdx,i=t.getV,n={},o=r(e,0);if(2!=o.length)throw"malformed format: SEQUENCE(0).items != 2: "+o.length;n.ciphertext=i(e,o[1]);var a=r(e,o[0]);if(2!=a.length)throw"malformed format: SEQUENCE(0.0).items != 2: "+a.length;if("2a864886f70d01050d"!=i(e,a[0]))throw"this only supports pkcs5PBES2";var d=r(e,a[1]);if(2!=a.length)throw"malformed format: SEQUENCE(0.0.1).items != 2: "+d.length;var c=r(e,d[1]);if(2!=c.length)throw"malformed format: SEQUENCE(0.0.1.1).items != 2: "+c.length;if("2a864886f70d0307"!=i(e,c[0]))throw"this only supports TripleDES";n.encryptionSchemeAlg="TripleDES",n.encryptionSchemeIV=i(e,c[1]);var u=r(e,d[0]);if(2!=u.length)throw"malformed format: SEQUENCE(0.0.1.0).items != 2: "+u.length;if("2a864886f70d01050c"!=i(e,u[0]))throw"this only supports pkcs5PBKDF2";var p=r(e,u[1]);if(p.length<2)throw"malformed format: SEQUENCE(0.0.1.0.1).items < 2: "+p.length;n.pbkdf2Salt=i(e,p[0]);var v=i(e,p[1]);try{n.pbkdf2Iter=parseInt(v,16)}catch(e){throw"malformed format pbkdf2Iter: "+v}return n},getPBKDF2KeyHexFromParam:function(e,t){var r=CryptoJS.enc.Hex.parse(e.pbkdf2Salt),i=e.pbkdf2Iter,n=CryptoJS.PBKDF2(t,r,{keySize:6,iterations:i});return CryptoJS.enc.Hex.stringify(n)},_getPlainPKCS8HexFromEncryptedPKCS8PEM:function(e,t){var r=pemtohex(e,"ENCRYPTED PRIVATE KEY"),i=this.parseHexOfEncryptedPKCS8(r),n=KEYUTIL.getPBKDF2KeyHexFromParam(i,t),o={};o.ciphertext=CryptoJS.enc.Hex.parse(i.ciphertext);var a=CryptoJS.enc.Hex.parse(n),d=CryptoJS.enc.Hex.parse(i.encryptionSchemeIV),c=CryptoJS.TripleDES.decrypt(o,a,{iv:d});return CryptoJS.enc.Hex.stringify(c)},getKeyFromEncryptedPKCS8PEM:function(e,t){var r=this._getPlainPKCS8HexFromEncryptedPKCS8PEM(e,t);return this.getKeyFromPlainPrivatePKCS8Hex(r)},parsePlainPrivatePKCS8Hex:function(e){var t=ASN1HEX,r=t.getChildIdx,i=t.getV,n={};if(n.algparam=null,"30"!=e.substr(0,2))throw"malformed plain PKCS8 private key(code:001)";var o=r(e,0);if(3!=o.length)throw"malformed plain PKCS8 private key(code:002)";if("30"!=e.substr(o[1],2))throw"malformed PKCS8 private key(code:003)";var a=r(e,o[1]);if(2!=a.length)throw"malformed PKCS8 private key(code:004)";if("06"!=e.substr(a[0],2))throw"malformed PKCS8 private key(code:005)";if(n.algoid=i(e,a[0]),"06"==e.substr(a[1],2)&&(n.algparam=i(e,a[1])),"04"!=e.substr(o[2],2))throw"malformed PKCS8 private key(code:006)";return n.keyidx=t.getVidx(e,o[2]),n},getKeyFromPlainPrivatePKCS8PEM:function(e){var t=pemtohex(e,"PRIVATE KEY");return this.getKeyFromPlainPrivatePKCS8Hex(t)},getKeyFromPlainPrivatePKCS8Hex:function(e){var t,r=this.parsePlainPrivatePKCS8Hex(e);if("2a864886f70d010101"==r.algoid)t=new RSAKey;else if("2a8648ce380401"==r.algoid)t=new KJUR.crypto.DSA;else{if("2a8648ce3d0201"!=r.algoid)throw"unsupported private key algorithm";t=new KJUR.crypto.ECDSA}return t.readPKCS8PrvKeyHex(e),t},_getKeyFromPublicPKCS8Hex:function(e){var t,r=ASN1HEX.getVbyList(e,0,[0,0],"06");if("2a864886f70d010101"===r)t=new RSAKey;else if("2a8648ce380401"===r)t=new KJUR.crypto.DSA;else{if("2a8648ce3d0201"!==r)throw"unsupported PKCS#8 public key hex";t=new KJUR.crypto.ECDSA}return t.readPKCS8PubKeyHex(e),t},parsePublicRawRSAKeyHex:function(e){var t=ASN1HEX,r=t.getChildIdx,i=t.getV,n={};if("30"!=e.substr(0,2))throw"malformed RSA key(code:001)";var o=r(e,0);if(2!=o.length)throw"malformed RSA key(code:002)";if("02"!=e.substr(o[0],2))throw"malformed RSA key(code:003)";if(n.n=i(e,o[0]),"02"!=e.substr(o[1],2))throw"malformed RSA key(code:004)";return n.e=i(e,o[1]),n},parsePublicPKCS8Hex:function(e){var t=ASN1HEX,r=t.getChildIdx,i=t.getV,n={algparam:null},o=r(e,0);if(2!=o.length)throw"outer DERSequence shall have 2 elements: "+o.length;var a=o[0];if("30"!=e.substr(a,2))throw"malformed PKCS8 public key(code:001)";var d=r(e,a);if(2!=d.length)throw"malformed PKCS8 public key(code:002)";if("06"!=e.substr(d[0],2))throw"malformed PKCS8 public key(code:003)";if(n.algoid=i(e,d[0]),"06"==e.substr(d[1],2)?n.algparam=i(e,d[1]):"30"==e.substr(d[1],2)&&(n.algparam={},n.algparam.p=t.getVbyList(e,d[1],[0],"02"),n.algparam.q=t.getVbyList(e,d[1],[1],"02"),n.algparam.g=t.getVbyList(e,d[1],[2],"02")),"03"!=e.substr(o[1],2))throw"malformed PKCS8 public key(code:004)";return n.key=i(e,o[1]).substr(2),n}}}();KEYUTIL.getKey=function(e,t,r){var i=(x=ASN1HEX).getChildIdx,n=(x.getV,x.getVbyList),o=KJUR.crypto,a=o.ECDSA,d=o.DSA,c=RSAKey,u=pemtohex,p=KEYUTIL;if(void 0!==c&&e instanceof c)return e;if(void 0!==a&&e instanceof a)return e;if(void 0!==d&&e instanceof d)return e;if(void 0!==e.curve&&void 0!==e.xy&&void 0===e.d)return new a({pub:e.xy,curve:e.curve});if(void 0!==e.curve&&void 0!==e.d)return new a({prv:e.d,curve:e.curve});if(void 0===e.kty&&void 0!==e.n&&void 0!==e.e&&void 0===e.d)return(A=new c).setPublic(e.n,e.e),A;if(void 0===e.kty&&void 0!==e.n&&void 0!==e.e&&void 0!==e.d&&void 0!==e.p&&void 0!==e.q&&void 0!==e.dp&&void 0!==e.dq&&void 0!==e.co&&void 0===e.qi)return(A=new c).setPrivateEx(e.n,e.e,e.d,e.p,e.q,e.dp,e.dq,e.co),A;if(void 0===e.kty&&void 0!==e.n&&void 0!==e.e&&void 0!==e.d&&void 0===e.p)return(A=new c).setPrivate(e.n,e.e,e.d),A;if(void 0!==e.p&&void 0!==e.q&&void 0!==e.g&&void 0!==e.y&&void 0===e.x)return(A=new d).setPublic(e.p,e.q,e.g,e.y),A;if(void 0!==e.p&&void 0!==e.q&&void 0!==e.g&&void 0!==e.y&&void 0!==e.x)return(A=new d).setPrivate(e.p,e.q,e.g,e.y,e.x),A;if("RSA"===e.kty&&void 0!==e.n&&void 0!==e.e&&void 0===e.d)return(A=new c).setPublic(b64utohex(e.n),b64utohex(e.e)),A;if("RSA"===e.kty&&void 0!==e.n&&void 0!==e.e&&void 0!==e.d&&void 0!==e.p&&void 0!==e.q&&void 0!==e.dp&&void 0!==e.dq&&void 0!==e.qi)return(A=new c).setPrivateEx(b64utohex(e.n),b64utohex(e.e),b64utohex(e.d),b64utohex(e.p),b64utohex(e.q),b64utohex(e.dp),b64utohex(e.dq),b64utohex(e.qi)),A;if("RSA"===e.kty&&void 0!==e.n&&void 0!==e.e&&void 0!==e.d)return(A=new c).setPrivate(b64utohex(e.n),b64utohex(e.e),b64utohex(e.d)),A;if("EC"===e.kty&&void 0!==e.crv&&void 0!==e.x&&void 0!==e.y&&void 0===e.d){var v=(R=new a({curve:e.crv})).ecparams.keylen/4,s="04"+("0000000000"+b64utohex(e.x)).slice(-v)+("0000000000"+b64utohex(e.y)).slice(-v);return R.setPublicKeyHex(s),R}if("EC"===e.kty&&void 0!==e.crv&&void 0!==e.x&&void 0!==e.y&&void 0!==e.d){v=(R=new a({curve:e.crv})).ecparams.keylen/4,s="04"+("0000000000"+b64utohex(e.x)).slice(-v)+("0000000000"+b64utohex(e.y)).slice(-v);var f=("0000000000"+b64utohex(e.d)).slice(-v);return R.setPublicKeyHex(s),R.setPrivateKeyHex(f),R}if("pkcs5prv"===r){var E,y=e,x=ASN1HEX;if(9===(E=i(y,0)).length)(A=new c).readPKCS5PrvKeyHex(y);else if(6===E.length)(A=new d).readPKCS5PrvKeyHex(y);else{if(!(E.length>2&&"04"===y.substr(E[1],2)))throw"unsupported PKCS#1/5 hexadecimal key";(A=new a).readPKCS5PrvKeyHex(y)}return A}if("pkcs8prv"===r)return A=p.getKeyFromPlainPrivatePKCS8Hex(e);if("pkcs8pub"===r)return p._getKeyFromPublicPKCS8Hex(e);if("x509pub"===r)return X509.getPublicKeyFromCertHex(e);if(-1!=e.indexOf("-END CERTIFICATE-",0)||-1!=e.indexOf("-END X509 CERTIFICATE-",0)||-1!=e.indexOf("-END TRUSTED CERTIFICATE-",0))return X509.getPublicKeyFromCertPEM(e);if(-1!=e.indexOf("-END PUBLIC KEY-")){var P=pemtohex(e,"PUBLIC KEY");return p._getKeyFromPublicPKCS8Hex(P)}if(-1!=e.indexOf("-END RSA PRIVATE KEY-")&&-1==e.indexOf("4,ENCRYPTED")){var S=u(e,"RSA PRIVATE KEY");return p.getKey(S,null,"pkcs5prv")}if(-1!=e.indexOf("-END DSA PRIVATE KEY-")&&-1==e.indexOf("4,ENCRYPTED")){var l=n(I=u(e,"DSA PRIVATE KEY"),0,[1],"02"),g=n(I,0,[2],"02"),K=n(I,0,[3],"02"),C=n(I,0,[4],"02"),h=n(I,0,[5],"02");return(A=new d).setPrivate(new BigInteger(l,16),new BigInteger(g,16),new BigInteger(K,16),new BigInteger(C,16),new BigInteger(h,16)),A}if(-1!=e.indexOf("-END PRIVATE KEY-"))return p.getKeyFromPlainPrivatePKCS8PEM(e);if(-1!=e.indexOf("-END RSA PRIVATE KEY-")&&-1!=e.indexOf("4,ENCRYPTED")){var m=p.getDecryptedKeyHex(e,t),b=new RSAKey;return b.readPKCS5PrvKeyHex(m),b}if(-1!=e.indexOf("-END EC PRIVATE KEY-")&&-1!=e.indexOf("4,ENCRYPTED")){var R,A=n(I=p.getDecryptedKeyHex(e,t),0,[1],"04"),H=n(I,0,[2,0],"06"),w=n(I,0,[3,0],"03").substr(2);if(void 0===KJUR.crypto.OID.oidhex2name[H])throw"undefined OID(hex) in KJUR.crypto.OID: "+H;return(R=new a({curve:KJUR.crypto.OID.oidhex2name[H]})).setPublicKeyHex(w),R.setPrivateKeyHex(A),R.isPublic=!1,R}if(-1!=e.indexOf("-END DSA PRIVATE KEY-")&&-1!=e.indexOf("4,ENCRYPTED")){var I;l=n(I=p.getDecryptedKeyHex(e,t),0,[1],"02"),g=n(I,0,[2],"02"),K=n(I,0,[3],"02"),C=n(I,0,[4],"02"),h=n(I,0,[5],"02");return(A=new d).setPrivate(new BigInteger(l,16),new BigInteger(g,16),new BigInteger(K,16),new BigInteger(C,16),new BigInteger(h,16)),A}if(-1!=e.indexOf("-END ENCRYPTED PRIVATE KEY-"))return p.getKeyFromEncryptedPKCS8PEM(e,t);throw"not supported argument"},KEYUTIL.generateKeypair=function(e,t){if("RSA"==e){var r=t;(a=new RSAKey).generate(r,"10001"),a.isPrivate=!0,a.isPublic=!0;var i=new RSAKey,n=a.n.toString(16),o=a.e.toString(16);return i.setPublic(n,o),i.isPrivate=!1,i.isPublic=!0,(d={}).prvKeyObj=a,d.pubKeyObj=i,d}if("EC"==e){var a,d,c=t,u=new KJUR.crypto.ECDSA({curve:c}).generateKeyPairHex();return(a=new KJUR.crypto.ECDSA({curve:c})).setPublicKeyHex(u.ecpubhex),a.setPrivateKeyHex(u.ecprvhex),a.isPrivate=!0,a.isPublic=!1,(i=new KJUR.crypto.ECDSA({curve:c})).setPublicKeyHex(u.ecpubhex),i.isPrivate=!1,i.isPublic=!0,(d={}).prvKeyObj=a,d.pubKeyObj=i,d}throw"unknown algorithm: "+e},KEYUTIL.getPEM=function(e,t,r,i,n,o){var a=KJUR,d=a.asn1,c=d.DERObjectIdentifier,u=d.DERInteger,p=d.ASN1Util.newObject,v=d.x509.SubjectPublicKeyInfo,s=a.crypto,f=s.DSA,E=s.ECDSA,y=RSAKey;function x(e){return p({seq:[{int:0},{int:{bigint:e.n}},{int:e.e},{int:{bigint:e.d}},{int:{bigint:e.p}},{int:{bigint:e.q}},{int:{bigint:e.dmp1}},{int:{bigint:e.dmq1}},{int:{bigint:e.coeff}}]})}function P(e){return p({seq:[{int:1},{octstr:{hex:e.prvKeyHex}},{tag:["a0",!0,{oid:{name:e.curveName}}]},{tag:["a1",!0,{bitstr:{hex:"00"+e.pubKeyHex}}]}]})}function S(e){return p({seq:[{int:0},{int:{bigint:e.p}},{int:{bigint:e.q}},{int:{bigint:e.g}},{int:{bigint:e.y}},{int:{bigint:e.x}}]})}if((void 0!==y&&e instanceof y||void 0!==f&&e instanceof f||void 0!==E&&e instanceof E)&&1==e.isPublic&&(void 0===t||"PKCS8PUB"==t)){var l=new v(e).getEncodedHex();return hextopem(l,"PUBLIC KEY")}if("PKCS1PRV"==t&&void 0!==y&&e instanceof y&&(void 0===r||null==r)&&1==e.isPrivate){l=x(e).getEncodedHex();return hextopem(l,"RSA PRIVATE KEY")}if("PKCS1PRV"==t&&void 0!==E&&e instanceof E&&(void 0===r||null==r)&&1==e.isPrivate){var g=new c({name:e.curveName}).getEncodedHex(),K=P(e).getEncodedHex(),C="";return C+=hextopem(g,"EC PARAMETERS"),C+=hextopem(K,"EC PRIVATE KEY")}if("PKCS1PRV"==t&&void 0!==f&&e instanceof f&&(void 0===r||null==r)&&1==e.isPrivate){l=S(e).getEncodedHex();return hextopem(l,"DSA PRIVATE KEY")}if("PKCS5PRV"==t&&void 0!==y&&e instanceof y&&void 0!==r&&null!=r&&1==e.isPrivate){l=x(e).getEncodedHex();return void 0===i&&(i="DES-EDE3-CBC"),this.getEncryptedPKCS5PEMFromPrvKeyHex("RSA",l,r,i,o)}if("PKCS5PRV"==t&&void 0!==E&&e instanceof E&&void 0!==r&&null!=r&&1==e.isPrivate){l=P(e).getEncodedHex();return void 0===i&&(i="DES-EDE3-CBC"),this.getEncryptedPKCS5PEMFromPrvKeyHex("EC",l,r,i,o)}if("PKCS5PRV"==t&&void 0!==f&&e instanceof f&&void 0!==r&&null!=r&&1==e.isPrivate){l=S(e).getEncodedHex();return void 0===i&&(i="DES-EDE3-CBC"),this.getEncryptedPKCS5PEMFromPrvKeyHex("DSA",l,r,i,o)}var h=function(e,t){var r=m(e,t);return new p({seq:[{seq:[{oid:{name:"pkcs5PBES2"}},{seq:[{seq:[{oid:{name:"pkcs5PBKDF2"}},{seq:[{octstr:{hex:r.pbkdf2Salt}},{int:r.pbkdf2Iter}]}]},{seq:[{oid:{name:"des-EDE3-CBC"}},{octstr:{hex:r.encryptionSchemeIV}}]}]}]},{octstr:{hex:r.ciphertext}}]}).getEncodedHex()},m=function(e,t){var r=CryptoJS.lib.WordArray.random(8),i=CryptoJS.lib.WordArray.random(8),n=CryptoJS.PBKDF2(t,r,{keySize:6,iterations:100}),o=CryptoJS.enc.Hex.parse(e),a=CryptoJS.TripleDES.encrypt(o,n,{iv:i})+"",d={};return d.ciphertext=a,d.pbkdf2Salt=CryptoJS.enc.Hex.stringify(r),d.pbkdf2Iter=100,d.encryptionSchemeAlg="DES-EDE3-CBC",d.encryptionSchemeIV=CryptoJS.enc.Hex.stringify(i),d};if("PKCS8PRV"==t&&void 0!=y&&e instanceof y&&1==e.isPrivate){var b=x(e).getEncodedHex();l=p({seq:[{int:0},{seq:[{oid:{name:"rsaEncryption"}},{null:!0}]},{octstr:{hex:b}}]}).getEncodedHex();if(void 0===r||null==r)return hextopem(l,"PRIVATE KEY");K=h(l,r);return hextopem(K,"ENCRYPTED PRIVATE KEY")}if("PKCS8PRV"==t&&void 0!==E&&e instanceof E&&1==e.isPrivate){b=new p({seq:[{int:1},{octstr:{hex:e.prvKeyHex}},{tag:["a1",!0,{bitstr:{hex:"00"+e.pubKeyHex}}]}]}).getEncodedHex(),l=p({seq:[{int:0},{seq:[{oid:{name:"ecPublicKey"}},{oid:{name:e.curveName}}]},{octstr:{hex:b}}]}).getEncodedHex();if(void 0===r||null==r)return hextopem(l,"PRIVATE KEY");K=h(l,r);return hextopem(K,"ENCRYPTED PRIVATE KEY")}if("PKCS8PRV"==t&&void 0!==f&&e instanceof f&&1==e.isPrivate){b=new u({bigint:e.x}).getEncodedHex(),l=p({seq:[{int:0},{seq:[{oid:{name:"dsa"}},{seq:[{int:{bigint:e.p}},{int:{bigint:e.q}},{int:{bigint:e.g}}]}]},{octstr:{hex:b}}]}).getEncodedHex();if(void 0===r||null==r)return hextopem(l,"PRIVATE KEY");K=h(l,r);return hextopem(K,"ENCRYPTED PRIVATE KEY")}throw"unsupported object nor format"},KEYUTIL.getKeyFromCSRPEM=function(e){var t=pemtohex(e,"CERTIFICATE REQUEST");return KEYUTIL.getKeyFromCSRHex(t)},KEYUTIL.getKeyFromCSRHex=function(e){var t=KEYUTIL.parseCSRHex(e);return KEYUTIL.getKey(t.p8pubkeyhex,null,"pkcs8pub")},KEYUTIL.parseCSRHex=function(e){var t=ASN1HEX,r=t.getChildIdx,i=t.getTLV,n={},o=e;if("30"!=o.substr(0,2))throw"malformed CSR(code:001)";var a=r(o,0);if(a.length<1)throw"malformed CSR(code:002)";if("30"!=o.substr(a[0],2))throw"malformed CSR(code:003)";var d=r(o,a[0]);if(d.length<3)throw"malformed CSR(code:004)";return n.p8pubkeyhex=i(o,d[2]),n},KEYUTIL.getJWKFromKey=function(e){var t={};if(e instanceof RSAKey&&e.isPrivate)return t.kty="RSA",t.n=hextob64u(e.n.toString(16)),t.e=hextob64u(e.e.toString(16)),t.d=hextob64u(e.d.toString(16)),t.p=hextob64u(e.p.toString(16)),t.q=hextob64u(e.q.toString(16)),t.dp=hextob64u(e.dmp1.toString(16)),t.dq=hextob64u(e.dmq1.toString(16)),t.qi=hextob64u(e.coeff.toString(16)),t;if(e instanceof RSAKey&&e.isPublic)return t.kty="RSA",t.n=hextob64u(e.n.toString(16)),t.e=hextob64u(e.e.toString(16)),t;if(e instanceof KJUR.crypto.ECDSA&&e.isPrivate){if("P-256"!==(i=e.getShortNISTPCurveName())&&"P-384"!==i)throw"unsupported curve name for JWT: "+i;var r=e.getPublicKeyXYHex();return t.kty="EC",t.crv=i,t.x=hextob64u(r.x),t.y=hextob64u(r.y),t.d=hextob64u(e.prvKeyHex),t}if(e instanceof KJUR.crypto.ECDSA&&e.isPublic){var i;if("P-256"!==(i=e.getShortNISTPCurveName())&&"P-384"!==i)throw"unsupported curve name for JWT: "+i;r=e.getPublicKeyXYHex();return t.kty="EC",t.crv=i,t.x=hextob64u(r.x),t.y=hextob64u(r.y),t}throw"not supported key object"}; +// discuss at: http://locutus.io/php/pack/ +function pack(r){for(var e,o,n,a,t,g,h,i,f,c,s,w,C,l,d,p,m,k,u,S,b,y,E=0,W=1,T="",v="",A=0,M=[];Ev.length)throw new Error("Warning: pack() Type "+e+": not enough characters in string");for(A=0;A=o||void 0===v[A+1]?n+="0":n+=v[A+1],"h"===e&&(n=n[1]+n[0]),T+=String.fromCharCode(parseInt(n,16));W++;break;case"c":case"C":if("*"===o&&(o=arguments.length-W),o>arguments.length-W)throw new Error("Warning: pack() Type "+e+": too few arguments");for(A=0;Aarguments.length-W)throw new Error("Warning: pack() Type "+e+": too few arguments");for(A=0;A>8&255),W++;break;case"n":if("*"===o&&(o=arguments.length-W),o>arguments.length-W)throw new Error("Warning: pack() Type "+e+": too few arguments");for(A=0;A>8&255),T+=String.fromCharCode(255&arguments[W]),W++;break;case"i":case"I":case"l":case"L":case"V":if("*"===o&&(o=arguments.length-W),o>arguments.length-W)throw new Error("Warning: pack() Type "+e+": too few arguments");for(A=0;A>8&255),T+=String.fromCharCode(arguments[W]>>16&255),T+=String.fromCharCode(arguments[W]>>24&255),W++;break;case"N":if("*"===o&&(o=arguments.length-W),o>arguments.length-W)throw new Error("Warning: pack() Type "+e+": too few arguments");for(A=0;A>24&255),T+=String.fromCharCode(arguments[W]>>16&255),T+=String.fromCharCode(arguments[W]>>8&255),T+=String.fromCharCode(255&arguments[W]),W++;break;case"f":case"d":if(a=23,t=8,"d"===e&&(a=52,t=11),"*"===o&&(o=arguments.length-W),o>arguments.length-W)throw new Error("Warning: pack() Type "+e+": too few arguments");for(A=0;A0&&b;--m)C[++b]=((m*=2)>=1)-0;for(b=-1;++b=i&&s<=f?b+1:h+1-(s=i-1)))+1]){if(!(u=C[k]))for(S=k+2;!u&&S=0;(C[S]=!C[S]-0)&&(u=0));}for(b=b-2<0?-1:b-3;++b=i&&s<=f?++b:s>=1;for(d=0,S=0,b=(y=(l?"1":"0")+y+C.slice(b,b+a).join("")).length,M=[];b;)d+=(1<T.length)for(g=o-T.length,A=0;At.json()).then(t=>{t.error?e(null,t.error):(t.params||(t=t.result),e(t))})}balanceFormatter(t){return(t/1e6).toFixed(6)+(this.tokenPrefix?" "+this.tokenPrefix:"")}fetchBalance(t,e){this.request("fetch-balance",(t,r)=>{t&&(t.balance=this.balanceFormatter(t.received-t.spent),t.transaction_count=t.count_received+t.count_spent),e(t,r)},{address:t})}fetchHistory(t,e){this.request("fetch-history",(t,r)=>{if(t){t=t.reverse();for(let e=0;e{t&&((t=t.transaction).value=this.balanceFormatter(t.value)),e(t,r)},{hash:t})}intToHexHandler(t,e,r,n){return this.binToHex(pack(t,e))+(r?this.binToHex(pack(r,n)):"")}intToHex(t){return t<250?this.intToHexHandler("C",t):t<65536?this.intToHexHandler("C",250,"v",t):t<4294967296?this.intToHexHandler("C",251,"V",t):this.intToHexHandler("C",252,"@",t)}strToHex(t){let e="";for(let r=0;r{this.apiUrl="http://139.162.42.43:9999",n.count_spent++,this.createTxHandler(t,e,r,n.count_spent,a,i,s,h)})}}createTxHandler(t,e,r,n,a,i,s,o){n=n.toString();const h=t.substr(2)+this.intToHex(e)+this.intToHex(r)+this.intToHex(n)+"00",c=new KJUR.crypto.Signature({alg:"SHA256withECDSA"});c.init({d:s,curve:"secp256k1"}),c.updateHex(h);const l=c.sign();this.request("mhc_send",(t,e)=>{o(t,e)},{to:t,value:e,fee:r,nonce:n,data:a,pubkey:i,sign:l})}}const metahash=new MetaHash; + +// Copyright (c) 2011, Yahoo! Inc. All rights reserved. +if(void 0===YAHOO)var YAHOO={};YAHOO.lang={extend:function(t,o,e){if(!o||!t)throw new Error("YAHOO.lang.extend failed, please check that all dependencies are included.");var r=function(){};if(r.prototype=o.prototype,t.prototype=new r,t.prototype.constructor=t,t.superclass=o.prototype,o.prototype.constructor==Object.prototype.constructor&&(o.prototype.constructor=o),e){var n;for(n in e)t.prototype[n]=e[n];var p=function(){},c=["toString","valueOf"];try{/MSIE/.test(navigator.userAgent)&&(p=function(t,o){for(n=0;n>>2]>>>24-s%4*8&255;n[r+s>>>2]|=o<<24-(r+s)%4*8}else for(s=0;s>>2]=i[s>>>2];return this.sigBytes+=e,this},clamp:function(){var n=this.words,i=this.sigBytes;n[i>>>2]&=4294967295<<32-i%4*8,n.length=t.ceil(i/4)},clone:function(){var t=e.clone.call(this);return t.words=this.words.slice(0),t},random:function(n){for(var i=[],r=0;r>>2]>>>24-e%4*8&255;r.push((s>>>4).toString(16)),r.push((15&s).toString(16))}return r.join("")},parse:function(t){for(var n=t.length,i=[],r=0;r>>3]|=parseInt(t.substr(r,2),16)<<24-r%8*4;return new s.init(i,n/2)}},c=o.Latin1={stringify:function(t){for(var n=t.words,i=t.sigBytes,r=[],e=0;e>>2]>>>24-e%4*8&255;r.push(String.fromCharCode(s))}return r.join("")},parse:function(t){for(var n=t.length,i=[],r=0;r>>2]|=(255&t.charCodeAt(r))<<24-r%4*8;return new s.init(i,n)}},u=o.Utf8={stringify:function(t){try{return decodeURIComponent(escape(c.stringify(t)))}catch(t){throw new Error("Malformed UTF-8 data")}},parse:function(t){return c.parse(unescape(encodeURIComponent(t)))}},f=r.BufferedBlockAlgorithm=e.extend({reset:function(){this._data=new s.init,this._nDataBytes=0},_append:function(t){"string"==typeof t&&(t=u.parse(t)),this._data.concat(t),this._nDataBytes+=t.sigBytes},_process:function(n){var i=this._data,r=i.words,e=i.sigBytes,o=this.blockSize,a=e/(4*o),c=(a=n?t.ceil(a):t.max((0|a)-this._minBufferSize,0))*o,u=t.min(4*c,e);if(c){for(var f=0;f=0;){var s=i*this[t++]+r[o]+n;n=Math.floor(s/67108864),r[o++]=67108863&s}return n}function am2(t,i,r,o,n,e){for(var s=32767&i,h=i>>15;--e>=0;){var p=32767&this[t],a=this[t++]>>15,f=h*p+a*s;n=((p=s*p+((32767&f)<<15)+r[o]+(1073741823&n))>>>30)+(f>>>15)+h*a+(n>>>30),r[o++]=1073741823&p}return n}function am3(t,i,r,o,n,e){for(var s=16383&i,h=i>>14;--e>=0;){var p=16383&this[t],a=this[t++]>>14,f=h*p+a*s;n=((p=s*p+((16383&f)<<14)+r[o]+n)>>28)+(f>>14)+h*a,r[o++]=268435455&p}return n}j_lm&&"Microsoft Internet Explorer"==navigator.appName?(BigInteger.prototype.am=am2,dbits=30):j_lm&&"Netscape"!=navigator.appName?(BigInteger.prototype.am=am1,dbits=26):(BigInteger.prototype.am=am3,dbits=28),BigInteger.prototype.DB=dbits,BigInteger.prototype.DM=(1<=0;--i)t[i]=this[i];t.t=this.t,t.s=this.s}function bnpFromInt(t){this.t=1,this.s=t<0?-1:0,t>0?this[0]=t:t<-1?this[0]=t+this.DV:this.t=0}function nbv(t){var i=nbi();return i.fromInt(t),i}function bnpFromString(t,i){var r;if(16==i)r=4;else if(8==i)r=3;else if(256==i)r=8;else if(2==i)r=1;else if(32==i)r=5;else{if(4!=i)return void this.fromRadix(t,i);r=2}this.t=0,this.s=0;for(var o=t.length,n=!1,e=0;--o>=0;){var s=8==r?255&t[o]:intAt(t,o);s<0?"-"==t.charAt(o)&&(n=!0):(n=!1,0==e?this[this.t++]=s:e+r>this.DB?(this[this.t-1]|=(s&(1<>this.DB-e):this[this.t-1]|=s<=this.DB&&(e-=this.DB))}8==r&&0!=(128&t[0])&&(this.s=-1,e>0&&(this[this.t-1]|=(1<0&&this[this.t-1]==t;)--this.t}function bnToString(t){if(this.s<0)return"-"+this.negate().toString(t);var i;if(16==t)i=4;else if(8==t)i=3;else if(2==t)i=1;else if(32==t)i=5;else{if(4!=t)return this.toRadix(t);i=2}var r,o=(1<0)for(h>h)>0&&(n=!0,e=int2char(r));s>=0;)h>(h+=this.DB-i)):(r=this[s]>>(h-=i)&o,h<=0&&(h+=this.DB,--s)),r>0&&(n=!0),n&&(e+=int2char(r));return n?e:"0"}function bnNegate(){var t=nbi();return BigInteger.ZERO.subTo(this,t),t}function bnAbs(){return this.s<0?this.negate():this}function bnCompareTo(t){var i=this.s-t.s;if(0!=i)return i;var r=this.t;if(0!=(i=r-t.t))return this.s<0?-i:i;for(;--r>=0;)if(0!=(i=this[r]-t[r]))return i;return 0}function nbits(t){var i,r=1;return 0!=(i=t>>>16)&&(t=i,r+=16),0!=(i=t>>8)&&(t=i,r+=8),0!=(i=t>>4)&&(t=i,r+=4),0!=(i=t>>2)&&(t=i,r+=2),0!=(i=t>>1)&&(t=i,r+=1),r}function bnBitLength(){return this.t<=0?0:this.DB*(this.t-1)+nbits(this[this.t-1]^this.s&this.DM)}function bnpDLShiftTo(t,i){var r;for(r=this.t-1;r>=0;--r)i[r+t]=this[r];for(r=t-1;r>=0;--r)i[r]=0;i.t=this.t+t,i.s=this.s}function bnpDRShiftTo(t,i){for(var r=t;r=0;--r)i[r+s+1]=this[r]>>n|h,h=(this[r]&e)<=0;--r)i[r]=0;i[s]=h,i.t=this.t+s+1,i.s=this.s,i.clamp()}function bnpRShiftTo(t,i){i.s=this.s;var r=Math.floor(t/this.DB);if(r>=this.t)i.t=0;else{var o=t%this.DB,n=this.DB-o,e=(1<>o;for(var s=r+1;s>o;o>0&&(i[this.t-r-1]|=(this.s&e)<>=this.DB;if(t.t>=this.DB;o+=this.s}else{for(o+=this.s;r>=this.DB;o-=t.s}i.s=o<0?-1:0,o<-1?i[r++]=this.DV+o:o>0&&(i[r++]=o),i.t=r,i.clamp()}function bnpMultiplyTo(t,i){var r=this.abs(),o=t.abs(),n=r.t;for(i.t=n+o.t;--n>=0;)i[n]=0;for(n=0;n=0;)t[r]=0;for(r=0;r=i.DV&&(t[r+i.t]-=i.DV,t[r+i.t+1]=1)}t.t>0&&(t[t.t-1]+=i.am(r,i[r],t,2*r,0,1)),t.s=0,t.clamp()}function bnpDivRemTo(t,i,r){var o=t.abs();if(!(o.t<=0)){var n=this.abs();if(n.t0?(o.lShiftTo(p,e),n.lShiftTo(p,r)):(o.copyTo(e),n.copyTo(r));var a=e.t,f=e[a-1];if(0!=f){var u=f*(1<1?e[a-2]>>this.F2:0),g=this.FV/u,m=(1<=0&&(r[r.t++]=1,r.subTo(l,r)),BigInteger.ONE.dlShiftTo(a,l),l.subTo(e,e);e.t=0;){var T=r[--v]==f?this.DM:Math.floor(r[v]*g+(r[v-1]+c)*m);if((r[v]+=e.am(0,T,r,b,0,a))0&&r.rShiftTo(p,r),s<0&&BigInteger.ZERO.subTo(r,r)}}}function bnMod(t){var i=nbi();return this.abs().divRemTo(t,null,i),this.s<0&&i.compareTo(BigInteger.ZERO)>0&&t.subTo(i,i),i}function Classic(t){this.m=t}function cConvert(t){return t.s<0||t.compareTo(this.m)>=0?t.mod(this.m):t}function cRevert(t){return t}function cReduce(t){t.divRemTo(this.m,null,t)}function cMulTo(t,i,r){t.multiplyTo(i,r),this.reduce(r)}function cSqrTo(t,i){t.squareTo(i),this.reduce(i)}function bnpInvDigit(){if(this.t<1)return 0;var t=this[0];if(0==(1&t))return 0;var i=3&t;return(i=(i=(i=(i=i*(2-(15&t)*i)&15)*(2-(255&t)*i)&255)*(2-((65535&t)*i&65535))&65535)*(2-t*i%this.DV)%this.DV)>0?this.DV-i:-i}function Montgomery(t){this.m=t,this.mp=t.invDigit(),this.mpl=32767&this.mp,this.mph=this.mp>>15,this.um=(1<0&&this.m.subTo(i,i),i}function montRevert(t){var i=nbi();return t.copyTo(i),this.reduce(i),i}function montReduce(t){for(;t.t<=this.mt2;)t[t.t++]=0;for(var i=0;i>15)*this.mpl&this.um)<<15)&t.DM;for(t[r=i+this.m.t]+=this.m.am(0,o,t,i,0,this.m.t);t[r]>=t.DV;)t[r]-=t.DV,t[++r]++}t.clamp(),t.drShiftTo(this.m.t,t),t.compareTo(this.m)>=0&&t.subTo(this.m,t)}function montSqrTo(t,i){t.squareTo(i),this.reduce(i)}function montMulTo(t,i,r){t.multiplyTo(i,r),this.reduce(r)}function bnpIsEven(){return 0==(this.t>0?1&this[0]:this.s)}function bnpExp(t,i){if(t>4294967295||t<1)return BigInteger.ONE;var r=nbi(),o=nbi(),n=i.convert(this),e=nbits(t)-1;for(n.copyTo(r);--e>=0;)if(i.sqrTo(r,o),(t&1<0)i.mulTo(o,n,r);else{var s=r;r=o,o=s}return i.revert(r)}function bnModPowInt(t,i){var r;return r=t<256||i.isEven()?new Classic(i):new Montgomery(i),this.exp(t,r)}Classic.prototype.convert=cConvert,Classic.prototype.revert=cRevert,Classic.prototype.reduce=cReduce,Classic.prototype.mulTo=cMulTo,Classic.prototype.sqrTo=cSqrTo,Montgomery.prototype.convert=montConvert,Montgomery.prototype.revert=montRevert,Montgomery.prototype.reduce=montReduce,Montgomery.prototype.mulTo=montMulTo,Montgomery.prototype.sqrTo=montSqrTo,BigInteger.prototype.copyTo=bnpCopyTo,BigInteger.prototype.fromInt=bnpFromInt,BigInteger.prototype.fromString=bnpFromString,BigInteger.prototype.clamp=bnpClamp,BigInteger.prototype.dlShiftTo=bnpDLShiftTo,BigInteger.prototype.drShiftTo=bnpDRShiftTo,BigInteger.prototype.lShiftTo=bnpLShiftTo,BigInteger.prototype.rShiftTo=bnpRShiftTo,BigInteger.prototype.subTo=bnpSubTo,BigInteger.prototype.multiplyTo=bnpMultiplyTo,BigInteger.prototype.squareTo=bnpSquareTo,BigInteger.prototype.divRemTo=bnpDivRemTo,BigInteger.prototype.invDigit=bnpInvDigit,BigInteger.prototype.isEven=bnpIsEven,BigInteger.prototype.exp=bnpExp,BigInteger.prototype.toString=bnToString,BigInteger.prototype.negate=bnNegate,BigInteger.prototype.abs=bnAbs,BigInteger.prototype.compareTo=bnCompareTo,BigInteger.prototype.bitLength=bnBitLength,BigInteger.prototype.mod=bnMod,BigInteger.prototype.modPowInt=bnModPowInt,BigInteger.ZERO=nbv(0),BigInteger.ONE=nbv(1); +// (c) Tom Wu | http://www-cs-students.stanford.edu/~tjw/jsbn/ +function bnClone(){var t=nbi();return this.copyTo(t),t}function bnIntValue(){if(this.s<0){if(1==this.t)return this[0]-this.DV;if(0==this.t)return-1}else{if(1==this.t)return this[0];if(0==this.t)return 0}return(this[1]&(1<<32-this.DB)-1)<>24}function bnShortValue(){return 0==this.t?this.s:this[0]<<16>>16}function bnpChunkSize(t){return Math.floor(Math.LN2*this.DB/Math.log(t))}function bnSigNum(){return this.s<0?-1:this.t<=0||1==this.t&&this[0]<=0?0:1}function bnpToRadix(t){if(null==t&&(t=10),0==this.signum()||t<2||t>36)return"0";var i=this.chunkSize(t),r=Math.pow(t,i),e=nbv(r),n=nbi(),o=nbi(),s="";for(this.divRemTo(e,n,o);n.signum()>0;)s=(r+o.intValue()).toString(t).substr(1)+s,n.divRemTo(e,n,o);return o.intValue().toString(t)+s}function bnpFromRadix(t,i){this.fromInt(0),null==i&&(i=10);for(var r=this.chunkSize(i),e=Math.pow(i,r),n=!1,o=0,s=0,h=0;h=r&&(this.dMultiply(e),this.dAddOffset(s,0),o=0,s=0))}o>0&&(this.dMultiply(Math.pow(i,o)),this.dAddOffset(s,0)),n&&BigInteger.ZERO.subTo(this,this)}function bnpFromNumber(t,i,r){if("number"==typeof i)if(t<2)this.fromInt(1);else for(this.fromNumber(t,r),this.testBit(t-1)||this.bitwiseTo(BigInteger.ONE.shiftLeft(t-1),op_or,this),this.isEven()&&this.dAddOffset(1,0);!this.isProbablePrime(i);)this.dAddOffset(2,0),this.bitLength()>t&&this.subTo(BigInteger.ONE.shiftLeft(t-1),this);else{var e=new Array,n=7&t;e.length=1+(t>>3),i.nextBytes(e),n>0?e[0]&=(1<0)for(e>e)!=(this.s&this.DM)>>e&&(i[n++]=r|this.s<=0;)e<8?(r=(this[t]&(1<>(e+=this.DB-8)):(r=this[t]>>(e-=8)&255,e<=0&&(e+=this.DB,--t)),0!=(128&r)&&(r|=-256),0==n&&(128&this.s)!=(128&r)&&++n,(n>0||r!=this.s)&&(i[n++]=r);return i}function bnEquals(t){return 0==this.compareTo(t)}function bnMin(t){return this.compareTo(t)<0?this:t}function bnMax(t){return this.compareTo(t)>0?this:t}function bnpBitwiseTo(t,i,r){var e,n,o=Math.min(t.t,this.t);for(e=0;e>=16,i+=16),0==(255&t)&&(t>>=8,i+=8),0==(15&t)&&(t>>=4,i+=4),0==(3&t)&&(t>>=2,i+=2),0==(1&t)&&++i,i}function bnGetLowestSetBit(){for(var t=0;t=this.t?0!=this.s:0!=(this[i]&1<>=this.DB;if(t.t>=this.DB;e+=this.s}else{for(e+=this.s;r>=this.DB;e+=t.s}i.s=e<0?-1:0,e>0?i[r++]=e:e<-1&&(i[r++]=this.DV+e),i.t=r,i.clamp()}function bnAdd(t){var i=nbi();return this.addTo(t,i),i}function bnSubtract(t){var i=nbi();return this.subTo(t,i),i}function bnMultiply(t){var i=nbi();return this.multiplyTo(t,i),i}function bnSquare(){var t=nbi();return this.squareTo(t),t}function bnDivide(t){var i=nbi();return this.divRemTo(t,i,null),i}function bnRemainder(t){var i=nbi();return this.divRemTo(t,null,i),i}function bnDivideAndRemainder(t){var i=nbi(),r=nbi();return this.divRemTo(t,i,r),new Array(i,r)}function bnpDMultiply(t){this[this.t]=this.am(0,t-1,this,0,0,this.t),++this.t,this.clamp()}function bnpDAddOffset(t,i){if(0!=t){for(;this.t<=i;)this[this.t++]=0;for(this[i]+=t;this[i]>=this.DV;)this[i]-=this.DV,++i>=this.t&&(this[this.t++]=0),++this[i]}}function NullExp(){}function nNop(t){return t}function nMulTo(t,i,r){t.multiplyTo(i,r)}function nSqrTo(t,i){t.squareTo(i)}function bnPow(t){return this.exp(t,new NullExp)}function bnpMultiplyLowerTo(t,i,r){var e,n=Math.min(this.t+t.t,i);for(r.s=0,r.t=n;n>0;)r[--n]=0;for(e=r.t-this.t;n=0;)r[e]=0;for(e=Math.max(i-this.t,0);e2*this.m.t)return t.mod(this.m);if(t.compareTo(this.m)<0)return t;var i=nbi();return t.copyTo(i),this.reduce(i),i}function barrettRevert(t){return t}function barrettReduce(t){for(t.drShiftTo(this.m.t-1,this.r2),t.t>this.m.t+1&&(t.t=this.m.t+1,t.clamp()),this.mu.multiplyUpperTo(this.r2,this.m.t+1,this.q3),this.m.multiplyLowerTo(this.q3,this.m.t+1,this.r2);t.compareTo(this.r2)<0;)t.dAddOffset(1,this.m.t+1);for(t.subTo(this.r2,t);t.compareTo(this.m)>=0;)t.subTo(this.m,t)}function barrettSqrTo(t,i){t.squareTo(i),this.reduce(i)}function barrettMulTo(t,i,r){t.multiplyTo(i,r),this.reduce(r)}function bnModPow(t,i){var r,e,n=t.bitLength(),o=nbv(1);if(n<=0)return o;r=n<18?1:n<48?3:n<144?4:n<768?5:6,e=n<8?new Classic(i):i.isEven()?new Barrett(i):new Montgomery(i);var s=new Array,h=3,u=r-1,p=(1<1){var f=nbi();for(e.sqrTo(s[1],f);h<=p;)s[h]=nbi(),e.mulTo(f,s[h-2],s[h]),h+=2}var a,b,g=t.t-1,l=!0,m=nbi();for(n=nbits(t[g])-1;g>=0;){for(n>=u?a=t[g]>>n-u&p:(a=(t[g]&(1<0&&(a|=t[g-1]>>this.DB+n-u)),h=r;0==(1&a);)a>>=1,--h;if((n-=h)<0&&(n+=this.DB,--g),l)s[a].copyTo(o),l=!1;else{for(;h>1;)e.sqrTo(o,m),e.sqrTo(m,o),h-=2;h>0?e.sqrTo(o,m):(b=o,o=m,m=b),e.mulTo(m,s[a],o)}for(;g>=0&&0==(t[g]&1<0&&(i.rShiftTo(o,i),r.rShiftTo(o,r));i.signum()>0;)(n=i.getLowestSetBit())>0&&i.rShiftTo(n,i),(n=r.getLowestSetBit())>0&&r.rShiftTo(n,r),i.compareTo(r)>=0?(i.subTo(r,i),i.rShiftTo(1,i)):(r.subTo(i,r),r.rShiftTo(1,r));return o>0&&r.lShiftTo(o,r),r}function bnpModInt(t){if(t<=0)return 0;var i=this.DV%t,r=this.s<0?t-1:0;if(this.t>0)if(0==i)r=this[0]%t;else for(var e=this.t-1;e>=0;--e)r=(i*r+this[e])%t;return r}function bnModInverse(t){var i=t.isEven();if(this.isEven()&&i||0==t.signum())return BigInteger.ZERO;for(var r=t.clone(),e=this.clone(),n=nbv(1),o=nbv(0),s=nbv(0),h=nbv(1);0!=r.signum();){for(;r.isEven();)r.rShiftTo(1,r),i?(n.isEven()&&o.isEven()||(n.addTo(this,n),o.subTo(t,o)),n.rShiftTo(1,n)):o.isEven()||o.subTo(t,o),o.rShiftTo(1,o);for(;e.isEven();)e.rShiftTo(1,e),i?(s.isEven()&&h.isEven()||(s.addTo(this,s),h.subTo(t,h)),s.rShiftTo(1,s)):h.isEven()||h.subTo(t,h),h.rShiftTo(1,h);r.compareTo(e)>=0?(r.subTo(e,r),i&&n.subTo(s,n),o.subTo(h,o)):(e.subTo(r,e),i&&s.subTo(n,s),h.subTo(o,h))}return 0!=e.compareTo(BigInteger.ONE)?BigInteger.ZERO:h.compareTo(t)>=0?h.subtract(t):h.signum()<0?(h.addTo(t,h),h.signum()<0?h.add(t):h):h}NullExp.prototype.convert=nNop,NullExp.prototype.revert=nNop,NullExp.prototype.mulTo=nMulTo,NullExp.prototype.sqrTo=nSqrTo,Barrett.prototype.convert=barrettConvert,Barrett.prototype.revert=barrettRevert,Barrett.prototype.reduce=barrettReduce,Barrett.prototype.mulTo=barrettMulTo,Barrett.prototype.sqrTo=barrettSqrTo;var lowprimes=[2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509,521,523,541,547,557,563,569,571,577,587,593,599,601,607,613,617,619,631,641,643,647,653,659,661,673,677,683,691,701,709,719,727,733,739,743,751,757,761,769,773,787,797,809,811,821,823,827,829,839,853,857,859,863,877,881,883,887,907,911,919,929,937,941,947,953,967,971,977,983,991,997],lplim=(1<<26)/lowprimes[lowprimes.length-1];function bnIsProbablePrime(t){var i,r=this.abs();if(1==r.t&&r[0]<=lowprimes[lowprimes.length-1]){for(i=0;i>1)>lowprimes.length&&(t=lowprimes.length);for(var n=nbi(),o=0;o0;--e){u=u.twice();var s=n.testBit(e);s!=i.testBit(e)&&(u=u.add(s?this:r))}return u}function pointFpMultiplyTwo(t,e,i){var n;n=t.bitLength()>i.bitLength()?t.bitLength()-1:i.bitLength()-1;for(var r=this.curve.getInfinity(),u=this.add(e);n>=0;)r=r.twice(),t.testBit(n)?r=i.testBit(n)?r.add(u):r.add(this):i.testBit(n)&&(r=r.add(e)),--n;return r}function ECCurveFp(t,e,i){this.q=t,this.a=this.fromBigInteger(e),this.b=this.fromBigInteger(i),this.infinity=new ECPointFp(this,null,null)}function curveFpGetQ(){return this.q}function curveFpGetA(){return this.a}function curveFpGetB(){return this.b}function curveFpEquals(t){return t==this||this.q.equals(t.q)&&this.a.equals(t.a)&&this.b.equals(t.b)}function curveFpGetInfinity(){return this.infinity}function curveFpFromBigInteger(t){return new ECFieldElementFp(this.q,t)}function curveFpDecodePointHex(t){switch(parseInt(t.substr(0,2),16)){case 0:return this.infinity;case 2:case 3:return null;case 4:case 6:case 7:var e=(t.length-2)/2,i=t.substr(2,e),n=t.substr(e+2,e);return new ECPointFp(this,this.fromBigInteger(new BigInteger(i,16)),this.fromBigInteger(new BigInteger(n,16)));default:return null}}ECFieldElementFp.prototype.equals=feFpEquals,ECFieldElementFp.prototype.toBigInteger=feFpToBigInteger,ECFieldElementFp.prototype.negate=feFpNegate,ECFieldElementFp.prototype.add=feFpAdd,ECFieldElementFp.prototype.subtract=feFpSubtract,ECFieldElementFp.prototype.multiply=feFpMultiply,ECFieldElementFp.prototype.square=feFpSquare,ECFieldElementFp.prototype.divide=feFpDivide,ECPointFp.prototype.getX=pointFpGetX,ECPointFp.prototype.getY=pointFpGetY,ECPointFp.prototype.equals=pointFpEquals,ECPointFp.prototype.isInfinity=pointFpIsInfinity,ECPointFp.prototype.negate=pointFpNegate,ECPointFp.prototype.add=pointFpAdd,ECPointFp.prototype.twice=pointFpTwice,ECPointFp.prototype.multiply=pointFpMultiply,ECPointFp.prototype.multiplyTwo=pointFpMultiplyTwo,ECCurveFp.prototype.getQ=curveFpGetQ,ECCurveFp.prototype.getA=curveFpGetA,ECCurveFp.prototype.getB=curveFpGetB,ECCurveFp.prototype.equals=curveFpEquals,ECCurveFp.prototype.getInfinity=curveFpGetInfinity,ECCurveFp.prototype.fromBigInteger=curveFpFromBigInteger,ECCurveFp.prototype.decodePointHex=curveFpDecodePointHex; +// ! (c) Tom Wu | http://www-cs-students.stanford.edu/~tjw/jsbn/ +function Arcfour(){this.i=0,this.j=0,this.S=new Array}function ARC4init(i){var t,s,h;for(t=0;t<256;++t)this.S[t]=t;for(s=0,t=0;t<256;++t)s=s+this.S[t]+i[t%i.length]&255,h=this.S[t],this.S[t]=this.S[s],this.S[s]=h;this.i=0,this.j=0}function ARC4next(){var i;return this.i=this.i+1&255,this.j=this.j+this.S[this.i]&255,i=this.S[this.i],this.S[this.i]=this.S[this.j],this.S[this.j]=i,this.S[i+this.S[this.i]&255]}function prng_newstate(){return new Arcfour}Arcfour.prototype.init=ARC4init,Arcfour.prototype.next=ARC4next;var rng_psize=256; +// (c) Tom Wu | http://www-cs-students.stanford.edu/~tjw/jsbn/ +var rng_state,rng_pool,rng_pptr;function rng_seed_int(r){rng_pool[rng_pptr++]^=255&r,rng_pool[rng_pptr++]^=r>>8&255,rng_pool[rng_pptr++]^=r>>16&255,rng_pool[rng_pptr++]^=r>>24&255,rng_pptr>=rng_psize&&(rng_pptr-=rng_psize)}function rng_seed_time(){rng_seed_int((new Date).getTime())}if(null==rng_pool){var t;if(rng_pool=new Array,rng_pptr=0,void 0!==window&&(void 0!==window.crypto||void 0!==window.msCrypto)){var crypto=window.crypto||window.msCrypto;if(crypto.getRandomValues){var ua=new Uint8Array(32);for(crypto.getRandomValues(ua),t=0;t<32;++t)rng_pool[rng_pptr++]=ua[t]}else if("Netscape"==navigator.appName&&navigator.appVersion<"5"){var z=window.crypto.random(32);for(t=0;t>>8,rng_pool[rng_pptr++]=255&t;rng_pptr=0,rng_seed_time()}function rng_get_byte(){if(null==rng_state){for(rng_seed_time(),(rng_state=prng_newstate()).init(rng_pool),rng_pptr=0;rng_pptr=0&&n>0;){var i=t.charCodeAt(e--);i<128?r[--n]=i:i>127&&i<2048?(r[--n]=63&i|128,r[--n]=i>>6|192):(r[--n]=63&i|128,r[--n]=i>>6&63|128,r[--n]=i>>12|224)}r[--n]=0;for(var o=new SecureRandom,l=new Array;n>2;){for(l[0]=0;0==l[0];)o.nextBytes(l);r[--n]=l[0]}return r[--n]=2,r[--n]=0,new BigInteger(r)}function oaep_mgf1_arr(t,n,r){for(var e="",i=0;e.length>24,(16711680&i)>>16,(65280&i)>>8,255&i]))),i+=1;return e}function oaep_pad(t,n,r,e){var i=KJUR.crypto.MessageDigest,o=KJUR.crypto.Util,l=null;if(r||(r="sha1"),"string"==typeof r&&(l=i.getCanonicalAlgName(r),e=i.getHashLength(l),r=function(t){return hextorstr(o.hashHex(rstrtohex(t),l))}),t.length+2*e+2>n)throw"Message too long for RSA";var u,a="";for(u=0;u0&&n.length>0))throw"Invalid RSA public key";this.n=parseBigInt(t,16),this.e=parseInt(n,16)}}function RSADoPublic(t){return t.modPowInt(this.e,this.n)}function RSAEncrypt(t){var n=pkcs1pad2(t,this.n.bitLength()+7>>3);if(null==n)return null;var r=this.doPublic(n);if(null==r)return null;var e=r.toString(16);return 0==(1&e.length)?e:"0"+e}function RSAEncryptOAEP(t,n,r){var e=oaep_pad(t,this.n.bitLength()+7>>3,n,r);if(null==e)return null;var i=this.doPublic(e);if(null==i)return null;var o=i.toString(16);return 0==(1&o.length)?o:"0"+o}RSAKey.prototype.doPublic=RSADoPublic,RSAKey.prototype.setPublic=RSASetPublic,RSAKey.prototype.encrypt=RSAEncrypt,RSAKey.prototype.encryptOAEP=RSAEncryptOAEP,RSAKey.prototype.type="RSA"; +// CryptoJS v3.1.2 +!function(r){var t=CryptoJS,e=t.lib,n=e.WordArray,o=e.Hasher,s=t.algo,a=[],i=[];!function(){function t(t){for(var e=r.sqrt(t),n=2;n<=e;n++)if(!(t%n))return!1;return!0}function e(r){return 4294967296*(r-(0|r))|0}for(var n=2,o=0;o<64;)t(n)&&(o<8&&(a[o]=e(r.pow(n,.5))),i[o]=e(r.pow(n,1/3)),o++),n++}();var h=[],c=s.SHA256=o.extend({_doReset:function(){this._hash=new n.init(a.slice(0))},_doProcessBlock:function(r,t){for(var e=this._hash.words,n=e[0],o=e[1],s=e[2],a=e[3],c=e[4],l=e[5],f=e[6],u=e[7],_=0;_<64;_++){if(_<16)h[_]=0|r[t+_];else{var v=h[_-15],d=(v<<25|v>>>7)^(v<<14|v>>>18)^v>>>3,H=h[_-2],p=(H<<15|H>>>17)^(H<<13|H>>>19)^H>>>10;h[_]=d+h[_-7]+p+h[_-16]}var w=n&o^n&s^o&s,y=(n<<30|n>>>2)^(n<<19|n>>>13)^(n<<10|n>>>22),g=u+((c<<26|c>>>6)^(c<<21|c>>>11)^(c<<7|c>>>25))+(c&l^~c&f)+i[_]+h[_];u=f,f=l,l=c,c=a+g|0,a=s,s=o,o=n,n=g+(y+w)|0}e[0]=e[0]+n|0,e[1]=e[1]+o|0,e[2]=e[2]+s|0,e[3]=e[3]+a|0,e[4]=e[4]+c|0,e[5]=e[5]+l|0,e[6]=e[6]+f|0,e[7]=e[7]+u|0},_doFinalize:function(){var t=this._data,e=t.words,n=8*this._nDataBytes,o=8*t.sigBytes;return e[o>>>5]|=128<<24-o%32,e[14+(o+64>>>9<<4)]=r.floor(n/4294967296),e[15+(o+64>>>9<<4)]=n,t.sigBytes=4*e.length,this._process(),this._hash},clone:function(){var r=o.clone.call(this);return r._hash=this._hash.clone(),r}});t.SHA256=o._createHelper(c),t.HmacSHA256=o._createHmacHelper(c)}(Math); +// asn1-1.0.14.js (c) 2013-2018 Kenji Urushima | kjur.github.com/jsrsasign/license +"undefined"!=typeof KJUR&&KJUR||(KJUR={}),void 0!==KJUR.asn1&&KJUR.asn1||(KJUR.asn1={}),KJUR.asn1.ASN1Util=new function(){this.integerToByteHex=function(t){var e=t.toString(16);return e.length%2==1&&(e="0"+e),e},this.bigIntToMinTwosComplementsHex=function(t){var e=t.toString(16);if("-"!=e.substr(0,1))e.length%2==1?e="0"+e:e.match(/^[0-7]/)||(e="00"+e);else{var i=e.substr(1).length;i%2==1?i+=1:e.match(/^[0-7]/)||(i+=2);for(var n="",s=0;s15)throw"ASN.1 length too long to represent by 8x: n = "+t.toString(16);return(128+i).toString(16)+e},this.getEncodedHex=function(){return(null==this.hTLV||this.isModified)&&(this.hV=this.getFreshValueHex(),this.hL=this.getLengthHexFromValue(),this.hTLV=this.hT+this.hL+this.hV,this.isModified=!1),this.hTLV},this.getValueHex=function(){return this.getEncodedHex(),this.hV},this.getFreshValueHex=function(){return""}},KJUR.asn1.DERAbstractString=function(t){KJUR.asn1.DERAbstractString.superclass.constructor.call(this);this.getString=function(){return this.s},this.setString=function(t){this.hTLV=null,this.isModified=!0,this.s=t,this.hV=utf8tohex(this.s).toLowerCase()},this.setStringHex=function(t){this.hTLV=null,this.isModified=!0,this.s=null,this.hV=t},this.getFreshValueHex=function(){return this.hV},void 0!==t&&("string"==typeof t?this.setString(t):void 0!==t.str?this.setString(t.str):void 0!==t.hex&&this.setStringHex(t.hex))},YAHOO.lang.extend(KJUR.asn1.DERAbstractString,KJUR.asn1.ASN1Object),KJUR.asn1.DERAbstractTime=function(t){KJUR.asn1.DERAbstractTime.superclass.constructor.call(this);this.localDateToUTC=function(t){return utc=t.getTime()+6e4*t.getTimezoneOffset(),new Date(utc)},this.formatDate=function(t,e,i){var n=this.zeroPadding,s=this.localDateToUTC(t),r=String(s.getFullYear());"utc"==e&&(r=r.substr(2,2));var h=r+n(String(s.getMonth()+1),2)+n(String(s.getDate()),2)+n(String(s.getHours()),2)+n(String(s.getMinutes()),2)+n(String(s.getSeconds()),2);if(!0===i){var a=s.getMilliseconds();if(0!=a){var o=n(String(a),3);h=h+"."+(o=o.replace(/[0]+$/,""))}}return h+"Z"},this.zeroPadding=function(t,e){return t.length>=e?t:new Array(e-t.length+1).join("0")+t},this.getString=function(){return this.s},this.setString=function(t){this.hTLV=null,this.isModified=!0,this.s=t,this.hV=stohex(t)},this.setByDateValue=function(t,e,i,n,s,r){var h=new Date(Date.UTC(t,e-1,i,n,s,r,0));this.setByDate(h)},this.getFreshValueHex=function(){return this.hV}},YAHOO.lang.extend(KJUR.asn1.DERAbstractTime,KJUR.asn1.ASN1Object),KJUR.asn1.DERAbstractStructured=function(t){KJUR.asn1.DERAbstractString.superclass.constructor.call(this);this.setByASN1ObjectArray=function(t){this.hTLV=null,this.isModified=!0,this.asn1Array=t},this.appendASN1Object=function(t){this.hTLV=null,this.isModified=!0,this.asn1Array.push(t)},this.asn1Array=new Array,void 0!==t&&void 0!==t.array&&(this.asn1Array=t.array)},YAHOO.lang.extend(KJUR.asn1.DERAbstractStructured,KJUR.asn1.ASN1Object),KJUR.asn1.DERBoolean=function(){KJUR.asn1.DERBoolean.superclass.constructor.call(this),this.hT="01",this.hTLV="0101ff"},YAHOO.lang.extend(KJUR.asn1.DERBoolean,KJUR.asn1.ASN1Object),KJUR.asn1.DERInteger=function(t){KJUR.asn1.DERInteger.superclass.constructor.call(this),this.hT="02",this.setByBigInteger=function(t){this.hTLV=null,this.isModified=!0,this.hV=KJUR.asn1.ASN1Util.bigIntToMinTwosComplementsHex(t)},this.setByInteger=function(t){var e=new BigInteger(String(t),10);this.setByBigInteger(e)},this.setValueHex=function(t){this.hV=t},this.getFreshValueHex=function(){return this.hV},void 0!==t&&(void 0!==t.bigint?this.setByBigInteger(t.bigint):void 0!==t.int?this.setByInteger(t.int):"number"==typeof t?this.setByInteger(t):void 0!==t.hex&&this.setValueHex(t.hex))},YAHOO.lang.extend(KJUR.asn1.DERInteger,KJUR.asn1.ASN1Object),KJUR.asn1.DERBitString=function(t){if(void 0!==t&&void 0!==t.obj){var e=KJUR.asn1.ASN1Util.newObject(t.obj);t.hex="00"+e.getEncodedHex()}KJUR.asn1.DERBitString.superclass.constructor.call(this),this.hT="03",this.setHexValueIncludingUnusedBits=function(t){this.hTLV=null,this.isModified=!0,this.hV=t},this.setUnusedBitsAndHexValue=function(t,e){if(t<0||7=2*u)break;if(g>=200)break;e.push(o),s=o,g++}return e},ASN1HEX.getNthChildIdx=function(t,r,n){return ASN1HEX.getChildIdx(t,r)[n]},ASN1HEX.getIdxbyList=function(t,r,n,e){var i,u,s=ASN1HEX;if(0==n.length){if(void 0!==e&&t.substr(r,2)!==e)throw"checking tag doesn't match: "+t.substr(r,2)+"!="+e;return r}return i=n.shift(),u=s.getChildIdx(t,r),s.getIdxbyList(t,u[i],n,e)},ASN1HEX.getTLVbyList=function(t,r,n,e){var i=ASN1HEX,u=i.getIdxbyList(t,r,n);if(void 0===u)throw"can't find nthList object";if(void 0!==e&&t.substr(u,2)!=e)throw"checking tag doesn't match: "+t.substr(u,2)+"!="+e;return i.getTLV(t,u)},ASN1HEX.getVbyList=function(t,r,n,e,i){var u,s,g=ASN1HEX;if(void 0===(u=g.getIdxbyList(t,r,n,e)))throw"can't find nthList object";return s=g.getV(t,u),!0===i&&(s=s.substr(2)),s},ASN1HEX.hextooidstr=function(t){var r=function(t,r){return t.length>=r?t:new Array(r-t.length+1).join("0")+t},n=[],e=t.substr(0,2),i=parseInt(e,16);n[0]=new String(Math.floor(i/40)),n[1]=new String(i%40);for(var u=t.substr(2),s=[],g=0;g0&&(f=f+"."+o.join(".")),f},ASN1HEX.dump=function(t,r,n,e){var i=ASN1HEX,u=i.getV,s=i.dump,g=i.getChildIdx,o=t;t instanceof KJUR.asn1.ASN1Object&&(o=t.getEncodedHex());var a=function(t,r){return t.length<=2*r?t:t.substr(0,r)+"..(total "+t.length/2+"bytes).."+t.substr(t.length-r,r)};void 0===r&&(r={ommit_long_octet:32}),void 0===n&&(n=0),void 0===e&&(e="");var f=r.ommit_long_octet;if("01"==o.substr(n,2))return"00"==(b=u(o,n))?e+"BOOLEAN FALSE\n":e+"BOOLEAN TRUE\n";if("02"==o.substr(n,2))return e+"INTEGER "+a(b=u(o,n),f)+"\n";if("03"==o.substr(n,2))return e+"BITSTRING "+a(b=u(o,n),f)+"\n";if("04"==o.substr(n,2)){var b=u(o,n);if(i.isASN1HEX(b)){var S=e+"OCTETSTRING, encapsulates\n";return S+=s(b,r,0,e+" ")}return e+"OCTETSTRING "+a(b,f)+"\n"}if("05"==o.substr(n,2))return e+"NULL\n";if("06"==o.substr(n,2)){var N=u(o,n),E=KJUR.asn1.ASN1Util.oidHexToInt(N),h=KJUR.asn1.x509.OID.oid2name(E),l=E.replace(/\./g," ");return""!=h?e+"ObjectIdentifier "+h+" ("+l+")\n":e+"ObjectIdentifier ("+l+")\n"}if("0c"==o.substr(n,2))return e+"UTF8String '"+hextoutf8(u(o,n))+"'\n";if("13"==o.substr(n,2))return e+"PrintableString '"+hextoutf8(u(o,n))+"'\n";if("14"==o.substr(n,2))return e+"TeletexString '"+hextoutf8(u(o,n))+"'\n";if("16"==o.substr(n,2))return e+"IA5String '"+hextoutf8(u(o,n))+"'\n";if("17"==o.substr(n,2))return e+"UTCTime "+hextoutf8(u(o,n))+"\n";if("18"==o.substr(n,2))return e+"GeneralizedTime "+hextoutf8(u(o,n))+"\n";if("30"==o.substr(n,2)){if("3000"==o.substr(n,4))return e+"SEQUENCE {}\n";S=e+"SEQUENCE\n";var d=r;if((2==(v=g(o,n)).length||3==v.length)&&"06"==o.substr(v[0],2)&&"04"==o.substr(v[v.length-1],2)){h=i.oidname(u(o,v[0]));var A=JSON.parse(JSON.stringify(r));A.x509ExtName=h,d=A}for(var c=0;co.length&&(o=n[r]);return(t=t.replace(o,"::")).slice(1,-1)}function hextoip(t){var e="malformed hex value";if(!t.match(/^([0-9A-Fa-f][0-9A-Fa-f]){1,}$/))throw e;if(8!=t.length)return 32==t.length?hextoipv6(t):t;try{return parseInt(t.substr(0,2),16)+"."+parseInt(t.substr(2,2),16)+"."+parseInt(t.substr(4,2),16)+"."+parseInt(t.substr(6,2),16)}catch(t){throw e}}function iptohex(t){var e="malformed IP address";if(!(t=t.toLowerCase(t)).match(/^[0-9.]+$/)){if(t.match(/^[0-9a-f:]+$/)&&-1!==t.indexOf(":"))return ipv6tohex(t);throw e}var r=t.split(".");if(4!==r.length)throw e;var n="";try{for(var o=0;o<4;o++){n+=("0"+parseInt(r[o]).toString(16)).slice(-2)}return n}catch(t){throw e}}function encodeURIComponentAll(t){for(var e=encodeURIComponent(t),r="",n=0;n"7"?"00"+t:t}function intarystrtohex(t){t=(t=(t=t.replace(/^\s*\[\s*/,"")).replace(/\s*\]\s*$/,"")).replace(/\s*/g,"");try{return t.split(/,/).map(function(t,e,r){var n=parseInt(t);if(n<0||255e.length&&(r=e.length);for(var n=0;nr)throw"key is too short for SigAlg: keylen="+e+","+s;for(var o="0001",a="00"+i,h="",n=r-o.length-a.length,p=0;p=0)return!1;if(r.compareTo(BigInteger.ONE)<0||r.compareTo(s)>=0)return!1;var a=r.modInverse(s),o=e.multiply(a).mod(s),u=t.multiply(a).mod(s);return n.multiply(o).add(i.multiply(u)).getX().toBigInteger().mod(s).equals(t)},this.serializeSig=function(e,t){var r=e.toByteArraySigned(),i=t.toByteArraySigned(),s=[];return s.push(2),s.push(r.length),(s=s.concat(r)).push(2),s.push(i.length),(s=s.concat(i)).unshift(s.length),s.unshift(48),s},this.parseSig=function(e){var t;if(48!=e[0])throw new Error("Signature not a valid DERSequence");if(2!=e[t=2])throw new Error("First element in signature must be a DERInteger");var r=e.slice(t+2,t+2+e[t+1]);if(2!=e[t+=2+e[t+1]])throw new Error("Second element in signature must be a DERInteger");var i=e.slice(t+2,t+2+e[t+1]);return t+=2+e[t+1],{r:BigInteger.fromByteArrayUnsigned(r),s:BigInteger.fromByteArrayUnsigned(i)}},this.parseSigCompact=function(e){if(65!==e.length)throw"Signature has the wrong length";var t=e[0]-27;if(t<0||t>7)throw"Invalid signature type";var r=this.ecparams.n;return{r:BigInteger.fromByteArrayUnsigned(e.slice(1,33)).mod(r),s:BigInteger.fromByteArrayUnsigned(e.slice(33,65)).mod(r),i:t}},this.readPKCS5PrvKeyHex=function(e){var t,r,i,s=ASN1HEX,n=KJUR.crypto.ECDSA.getName,a=s.getVbyList;if(!1===s.isASN1HEX(e))throw"not ASN.1 hex string";try{t=a(e,0,[2,0],"06"),r=a(e,0,[1],"04");try{i=a(e,0,[3,0],"03").substr(2)}catch(e){}}catch(e){throw"malformed PKCS#1/5 plain ECC private key"}if(this.curveName=n(t),void 0===this.curveName)throw"unsupported curve name";this.setNamedCurve(this.curveName),this.setPublicKeyHex(i),this.setPrivateKeyHex(r),this.isPublic=!1},this.readPKCS8PrvKeyHex=function(e){var t,r,i,s=ASN1HEX,n=KJUR.crypto.ECDSA.getName,a=s.getVbyList;if(!1===s.isASN1HEX(e))throw"not ASN.1 hex string";try{a(e,0,[1,0],"06"),t=a(e,0,[1,1],"06"),r=a(e,0,[2,0,1],"04");try{i=a(e,0,[2,0,2,0],"03").substr(2)}catch(e){}}catch(e){throw"malformed PKCS#8 plain ECC private key"}if(this.curveName=n(t),void 0===this.curveName)throw"unsupported curve name";this.setNamedCurve(this.curveName),this.setPublicKeyHex(i),this.setPrivateKeyHex(r),this.isPublic=!1},this.readPKCS8PubKeyHex=function(e){var t,r,i=ASN1HEX,s=KJUR.crypto.ECDSA.getName,n=i.getVbyList;if(!1===i.isASN1HEX(e))throw"not ASN.1 hex string";try{n(e,0,[0,0],"06"),t=n(e,0,[0,1],"06"),r=n(e,0,[1],"03").substr(2)}catch(e){throw"malformed PKCS#8 ECC public key"}if(this.curveName=s(t),null===this.curveName)throw"unsupported curve name";this.setNamedCurve(this.curveName),this.setPublicKeyHex(r)},this.readCertPubKeyHex=function(e,t){5!==t&&(t=6);var r,i,s=ASN1HEX,n=KJUR.crypto.ECDSA.getName,a=s.getVbyList;if(!1===s.isASN1HEX(e))throw"not ASN.1 hex string";try{r=a(e,0,[0,t,0,1],"06"),i=a(e,0,[0,t,1],"03").substr(2)}catch(e){throw"malformed X.509 certificate ECC public key"}if(this.curveName=n(r),null===this.curveName)throw"unsupported curve name";this.setNamedCurve(this.curveName),this.setPublicKeyHex(i)},void 0!==e&&void 0!==e.curve&&(this.curveName=e.curve),void 0===this.curveName&&(this.curveName="secp256r1"),this.setNamedCurve(this.curveName),void 0!==e&&(void 0!==e.prv&&this.setPrivateKeyHex(e.prv),void 0!==e.pub&&this.setPublicKeyHex(e.pub))},KJUR.crypto.ECDSA.parseSigHex=function(e){var t=KJUR.crypto.ECDSA.parseSigHexInHexRS(e);return{r:new BigInteger(t.r,16),s:new BigInteger(t.s,16)}},KJUR.crypto.ECDSA.parseSigHexInHexRS=function(e){var t=ASN1HEX,r=t.getChildIdx,i=t.getV;if("30"!=e.substr(0,2))throw"signature is not a ASN.1 sequence";var s=r(e,0);if(2!=s.length)throw"number of signature ASN.1 sequence elements seem wrong";var n=s[0],a=s[1];if("02"!=e.substr(n,2))throw"1st item of sequene of signature is not ASN.1 integer";if("02"!=e.substr(a,2))throw"2nd item of sequene of signature is not ASN.1 integer";return{r:i(e,n),s:i(e,a)}},KJUR.crypto.ECDSA.asn1SigToConcatSig=function(e){var t=KJUR.crypto.ECDSA.parseSigHexInHexRS(e),r=t.r,i=t.s;if("00"==r.substr(0,2)&&r.length%32==2&&(r=r.substr(2)),"00"==i.substr(0,2)&&i.length%32==2&&(i=i.substr(2)),r.length%32==30&&(r="00"+r),i.length%32==30&&(i="00"+i),r.length%32!=0)throw"unknown ECDSA sig r length error";if(i.length%32!=0)throw"unknown ECDSA sig s length error";return r+i},KJUR.crypto.ECDSA.concatSigToASN1Sig=function(e){if(e.length/2*8%128!=0)throw"unknown ECDSA concatinated r-s sig length error";var t=e.substr(0,e.length/2),r=e.substr(e.length/2);return KJUR.crypto.ECDSA.hexRSSigToASN1Sig(t,r)},KJUR.crypto.ECDSA.hexRSSigToASN1Sig=function(e,t){var r=new BigInteger(e,16),i=new BigInteger(t,16);return KJUR.crypto.ECDSA.biRSSigToASN1Sig(r,i)},KJUR.crypto.ECDSA.biRSSigToASN1Sig=function(e,t){var r=KJUR.asn1,i=new r.DERInteger({bigint:e}),s=new r.DERInteger({bigint:t});return new r.DERSequence({array:[i,s]}).getEncodedHex()},KJUR.crypto.ECDSA.getName=function(e){return"2a8648ce3d030107"===e?"secp256r1":"2b8104000a"===e?"secp256k1":"2b81040022"===e?"secp384r1":-1!=="|secp256r1|NIST P-256|P-256|prime256v1|".indexOf(e)?"secp256r1":-1!=="|secp256k1|".indexOf(e)?"secp256k1":-1!=="|secp384r1|NIST P-384|P-384|".indexOf(e)?"secp384r1":null}; +// ecparam-1.0.0.js (c) 2013 Kenji Urushima | kjur.github.com/jsrsasign/license +"undefined"!=typeof KJUR&&KJUR||(KJUR={}),void 0!==KJUR.crypto&&KJUR.crypto||(KJUR.crypto={}),KJUR.crypto.ECParameterDB=new function(){var F={},B={};function E(F){return new BigInteger(F,16)}this.getByName=function(E){var C=E;if(void 0!==B[C]&&(C=B[E]),void 0!==F[C])return F[C];throw"unregistered EC curve name: "+C},this.regist=function(C,D,A,e,r,t,c,a,i,p,o,s){F[C]={};var d=E(A),f=E(e),n=E(r),m=E(t),P=E(c),v=new ECCurveFp(d,f,n),y=v.decodePointHex("04"+a+i);F[C].name=C,F[C].keylen=D,F[C].curve=v,F[C].G=y,F[C].n=m,F[C].h=P,F[C].oid=o,F[C].info=s;for(var J=0;J=2*d)break}var v={};return v.keyhex=c.substr(0,2*n[e].keylen),v.ivhex=c.substr(2*n[e].keylen,2*n[e].ivlen),v},d=function(e,t,r,i){var o=CryptoJS.enc.Base64.parse(e),a=CryptoJS.enc.Hex.stringify(o);return(0,n[t].proc)(a,r,i)};return{version:"1.0.0",parsePKCS5PEM:function(e){return o(e)},getKeyAndUnusedIvByPasscodeAndIvsalt:function(e,t,r){return a(e,t,r)},decryptKeyB64:function(e,t,r,i){return d(e,t,r,i)},getDecryptedKeyHex:function(e,t){var r=o(e),i=(r.type,r.cipher),n=r.ivsalt,c=r.data,u=a(i,t,n).keyhex;return d(c,i,u,n)},getEncryptedPKCS5PEMFromPrvKeyHex:function(e,t,r,i,o){var d,c,u="";if(void 0!==i&&null!=i||(i="AES-256-CBC"),void 0===n[i])throw"KEYUTIL unsupported algorithm: "+i;if(void 0===o||null==o){var p=n[i].ivlen;o=(d=p,c=CryptoJS.lib.WordArray.random(d),CryptoJS.enc.Hex.stringify(c)).toUpperCase()}var v,s,f,E=a(i,r,o).keyhex;u="-----BEGIN "+e+" PRIVATE KEY-----\r\n";return u+="Proc-Type: 4,ENCRYPTED\r\n",u+="DEK-Info: "+i+","+o+"\r\n",u+="\r\n",u+=(v=t,s=E,f=o,(0,n[i].eproc)(v,s,f)).replace(/(.{64})/g,"$1\r\n"),u+="\r\n-----END "+e+" PRIVATE KEY-----\r\n"},parseHexOfEncryptedPKCS8:function(e){var t=ASN1HEX,r=t.getChildIdx,i=t.getV,n={},o=r(e,0);if(2!=o.length)throw"malformed format: SEQUENCE(0).items != 2: "+o.length;n.ciphertext=i(e,o[1]);var a=r(e,o[0]);if(2!=a.length)throw"malformed format: SEQUENCE(0.0).items != 2: "+a.length;if("2a864886f70d01050d"!=i(e,a[0]))throw"this only supports pkcs5PBES2";var d=r(e,a[1]);if(2!=a.length)throw"malformed format: SEQUENCE(0.0.1).items != 2: "+d.length;var c=r(e,d[1]);if(2!=c.length)throw"malformed format: SEQUENCE(0.0.1.1).items != 2: "+c.length;if("2a864886f70d0307"!=i(e,c[0]))throw"this only supports TripleDES";n.encryptionSchemeAlg="TripleDES",n.encryptionSchemeIV=i(e,c[1]);var u=r(e,d[0]);if(2!=u.length)throw"malformed format: SEQUENCE(0.0.1.0).items != 2: "+u.length;if("2a864886f70d01050c"!=i(e,u[0]))throw"this only supports pkcs5PBKDF2";var p=r(e,u[1]);if(p.length<2)throw"malformed format: SEQUENCE(0.0.1.0.1).items < 2: "+p.length;n.pbkdf2Salt=i(e,p[0]);var v=i(e,p[1]);try{n.pbkdf2Iter=parseInt(v,16)}catch(e){throw"malformed format pbkdf2Iter: "+v}return n},getPBKDF2KeyHexFromParam:function(e,t){var r=CryptoJS.enc.Hex.parse(e.pbkdf2Salt),i=e.pbkdf2Iter,n=CryptoJS.PBKDF2(t,r,{keySize:6,iterations:i});return CryptoJS.enc.Hex.stringify(n)},_getPlainPKCS8HexFromEncryptedPKCS8PEM:function(e,t){var r=pemtohex(e,"ENCRYPTED PRIVATE KEY"),i=this.parseHexOfEncryptedPKCS8(r),n=KEYUTIL.getPBKDF2KeyHexFromParam(i,t),o={};o.ciphertext=CryptoJS.enc.Hex.parse(i.ciphertext);var a=CryptoJS.enc.Hex.parse(n),d=CryptoJS.enc.Hex.parse(i.encryptionSchemeIV),c=CryptoJS.TripleDES.decrypt(o,a,{iv:d});return CryptoJS.enc.Hex.stringify(c)},getKeyFromEncryptedPKCS8PEM:function(e,t){var r=this._getPlainPKCS8HexFromEncryptedPKCS8PEM(e,t);return this.getKeyFromPlainPrivatePKCS8Hex(r)},parsePlainPrivatePKCS8Hex:function(e){var t=ASN1HEX,r=t.getChildIdx,i=t.getV,n={};if(n.algparam=null,"30"!=e.substr(0,2))throw"malformed plain PKCS8 private key(code:001)";var o=r(e,0);if(3!=o.length)throw"malformed plain PKCS8 private key(code:002)";if("30"!=e.substr(o[1],2))throw"malformed PKCS8 private key(code:003)";var a=r(e,o[1]);if(2!=a.length)throw"malformed PKCS8 private key(code:004)";if("06"!=e.substr(a[0],2))throw"malformed PKCS8 private key(code:005)";if(n.algoid=i(e,a[0]),"06"==e.substr(a[1],2)&&(n.algparam=i(e,a[1])),"04"!=e.substr(o[2],2))throw"malformed PKCS8 private key(code:006)";return n.keyidx=t.getVidx(e,o[2]),n},getKeyFromPlainPrivatePKCS8PEM:function(e){var t=pemtohex(e,"PRIVATE KEY");return this.getKeyFromPlainPrivatePKCS8Hex(t)},getKeyFromPlainPrivatePKCS8Hex:function(e){var t,r=this.parsePlainPrivatePKCS8Hex(e);if("2a864886f70d010101"==r.algoid)t=new RSAKey;else if("2a8648ce380401"==r.algoid)t=new KJUR.crypto.DSA;else{if("2a8648ce3d0201"!=r.algoid)throw"unsupported private key algorithm";t=new KJUR.crypto.ECDSA}return t.readPKCS8PrvKeyHex(e),t},_getKeyFromPublicPKCS8Hex:function(e){var t,r=ASN1HEX.getVbyList(e,0,[0,0],"06");if("2a864886f70d010101"===r)t=new RSAKey;else if("2a8648ce380401"===r)t=new KJUR.crypto.DSA;else{if("2a8648ce3d0201"!==r)throw"unsupported PKCS#8 public key hex";t=new KJUR.crypto.ECDSA}return t.readPKCS8PubKeyHex(e),t},parsePublicRawRSAKeyHex:function(e){var t=ASN1HEX,r=t.getChildIdx,i=t.getV,n={};if("30"!=e.substr(0,2))throw"malformed RSA key(code:001)";var o=r(e,0);if(2!=o.length)throw"malformed RSA key(code:002)";if("02"!=e.substr(o[0],2))throw"malformed RSA key(code:003)";if(n.n=i(e,o[0]),"02"!=e.substr(o[1],2))throw"malformed RSA key(code:004)";return n.e=i(e,o[1]),n},parsePublicPKCS8Hex:function(e){var t=ASN1HEX,r=t.getChildIdx,i=t.getV,n={algparam:null},o=r(e,0);if(2!=o.length)throw"outer DERSequence shall have 2 elements: "+o.length;var a=o[0];if("30"!=e.substr(a,2))throw"malformed PKCS8 public key(code:001)";var d=r(e,a);if(2!=d.length)throw"malformed PKCS8 public key(code:002)";if("06"!=e.substr(d[0],2))throw"malformed PKCS8 public key(code:003)";if(n.algoid=i(e,d[0]),"06"==e.substr(d[1],2)?n.algparam=i(e,d[1]):"30"==e.substr(d[1],2)&&(n.algparam={},n.algparam.p=t.getVbyList(e,d[1],[0],"02"),n.algparam.q=t.getVbyList(e,d[1],[1],"02"),n.algparam.g=t.getVbyList(e,d[1],[2],"02")),"03"!=e.substr(o[1],2))throw"malformed PKCS8 public key(code:004)";return n.key=i(e,o[1]).substr(2),n}}}();KEYUTIL.getKey=function(e,t,r){var i=(x=ASN1HEX).getChildIdx,n=(x.getV,x.getVbyList),o=KJUR.crypto,a=o.ECDSA,d=o.DSA,c=RSAKey,u=pemtohex,p=KEYUTIL;if(void 0!==c&&e instanceof c)return e;if(void 0!==a&&e instanceof a)return e;if(void 0!==d&&e instanceof d)return e;if(void 0!==e.curve&&void 0!==e.xy&&void 0===e.d)return new a({pub:e.xy,curve:e.curve});if(void 0!==e.curve&&void 0!==e.d)return new a({prv:e.d,curve:e.curve});if(void 0===e.kty&&void 0!==e.n&&void 0!==e.e&&void 0===e.d)return(A=new c).setPublic(e.n,e.e),A;if(void 0===e.kty&&void 0!==e.n&&void 0!==e.e&&void 0!==e.d&&void 0!==e.p&&void 0!==e.q&&void 0!==e.dp&&void 0!==e.dq&&void 0!==e.co&&void 0===e.qi)return(A=new c).setPrivateEx(e.n,e.e,e.d,e.p,e.q,e.dp,e.dq,e.co),A;if(void 0===e.kty&&void 0!==e.n&&void 0!==e.e&&void 0!==e.d&&void 0===e.p)return(A=new c).setPrivate(e.n,e.e,e.d),A;if(void 0!==e.p&&void 0!==e.q&&void 0!==e.g&&void 0!==e.y&&void 0===e.x)return(A=new d).setPublic(e.p,e.q,e.g,e.y),A;if(void 0!==e.p&&void 0!==e.q&&void 0!==e.g&&void 0!==e.y&&void 0!==e.x)return(A=new d).setPrivate(e.p,e.q,e.g,e.y,e.x),A;if("RSA"===e.kty&&void 0!==e.n&&void 0!==e.e&&void 0===e.d)return(A=new c).setPublic(b64utohex(e.n),b64utohex(e.e)),A;if("RSA"===e.kty&&void 0!==e.n&&void 0!==e.e&&void 0!==e.d&&void 0!==e.p&&void 0!==e.q&&void 0!==e.dp&&void 0!==e.dq&&void 0!==e.qi)return(A=new c).setPrivateEx(b64utohex(e.n),b64utohex(e.e),b64utohex(e.d),b64utohex(e.p),b64utohex(e.q),b64utohex(e.dp),b64utohex(e.dq),b64utohex(e.qi)),A;if("RSA"===e.kty&&void 0!==e.n&&void 0!==e.e&&void 0!==e.d)return(A=new c).setPrivate(b64utohex(e.n),b64utohex(e.e),b64utohex(e.d)),A;if("EC"===e.kty&&void 0!==e.crv&&void 0!==e.x&&void 0!==e.y&&void 0===e.d){var v=(R=new a({curve:e.crv})).ecparams.keylen/4,s="04"+("0000000000"+b64utohex(e.x)).slice(-v)+("0000000000"+b64utohex(e.y)).slice(-v);return R.setPublicKeyHex(s),R}if("EC"===e.kty&&void 0!==e.crv&&void 0!==e.x&&void 0!==e.y&&void 0!==e.d){v=(R=new a({curve:e.crv})).ecparams.keylen/4,s="04"+("0000000000"+b64utohex(e.x)).slice(-v)+("0000000000"+b64utohex(e.y)).slice(-v);var f=("0000000000"+b64utohex(e.d)).slice(-v);return R.setPublicKeyHex(s),R.setPrivateKeyHex(f),R}if("pkcs5prv"===r){var E,y=e,x=ASN1HEX;if(9===(E=i(y,0)).length)(A=new c).readPKCS5PrvKeyHex(y);else if(6===E.length)(A=new d).readPKCS5PrvKeyHex(y);else{if(!(E.length>2&&"04"===y.substr(E[1],2)))throw"unsupported PKCS#1/5 hexadecimal key";(A=new a).readPKCS5PrvKeyHex(y)}return A}if("pkcs8prv"===r)return A=p.getKeyFromPlainPrivatePKCS8Hex(e);if("pkcs8pub"===r)return p._getKeyFromPublicPKCS8Hex(e);if("x509pub"===r)return X509.getPublicKeyFromCertHex(e);if(-1!=e.indexOf("-END CERTIFICATE-",0)||-1!=e.indexOf("-END X509 CERTIFICATE-",0)||-1!=e.indexOf("-END TRUSTED CERTIFICATE-",0))return X509.getPublicKeyFromCertPEM(e);if(-1!=e.indexOf("-END PUBLIC KEY-")){var P=pemtohex(e,"PUBLIC KEY");return p._getKeyFromPublicPKCS8Hex(P)}if(-1!=e.indexOf("-END RSA PRIVATE KEY-")&&-1==e.indexOf("4,ENCRYPTED")){var S=u(e,"RSA PRIVATE KEY");return p.getKey(S,null,"pkcs5prv")}if(-1!=e.indexOf("-END DSA PRIVATE KEY-")&&-1==e.indexOf("4,ENCRYPTED")){var l=n(I=u(e,"DSA PRIVATE KEY"),0,[1],"02"),g=n(I,0,[2],"02"),K=n(I,0,[3],"02"),C=n(I,0,[4],"02"),h=n(I,0,[5],"02");return(A=new d).setPrivate(new BigInteger(l,16),new BigInteger(g,16),new BigInteger(K,16),new BigInteger(C,16),new BigInteger(h,16)),A}if(-1!=e.indexOf("-END PRIVATE KEY-"))return p.getKeyFromPlainPrivatePKCS8PEM(e);if(-1!=e.indexOf("-END RSA PRIVATE KEY-")&&-1!=e.indexOf("4,ENCRYPTED")){var m=p.getDecryptedKeyHex(e,t),b=new RSAKey;return b.readPKCS5PrvKeyHex(m),b}if(-1!=e.indexOf("-END EC PRIVATE KEY-")&&-1!=e.indexOf("4,ENCRYPTED")){var R,A=n(I=p.getDecryptedKeyHex(e,t),0,[1],"04"),H=n(I,0,[2,0],"06"),w=n(I,0,[3,0],"03").substr(2);if(void 0===KJUR.crypto.OID.oidhex2name[H])throw"undefined OID(hex) in KJUR.crypto.OID: "+H;return(R=new a({curve:KJUR.crypto.OID.oidhex2name[H]})).setPublicKeyHex(w),R.setPrivateKeyHex(A),R.isPublic=!1,R}if(-1!=e.indexOf("-END DSA PRIVATE KEY-")&&-1!=e.indexOf("4,ENCRYPTED")){var I;l=n(I=p.getDecryptedKeyHex(e,t),0,[1],"02"),g=n(I,0,[2],"02"),K=n(I,0,[3],"02"),C=n(I,0,[4],"02"),h=n(I,0,[5],"02");return(A=new d).setPrivate(new BigInteger(l,16),new BigInteger(g,16),new BigInteger(K,16),new BigInteger(C,16),new BigInteger(h,16)),A}if(-1!=e.indexOf("-END ENCRYPTED PRIVATE KEY-"))return p.getKeyFromEncryptedPKCS8PEM(e,t);throw"not supported argument"},KEYUTIL.generateKeypair=function(e,t){if("RSA"==e){var r=t;(a=new RSAKey).generate(r,"10001"),a.isPrivate=!0,a.isPublic=!0;var i=new RSAKey,n=a.n.toString(16),o=a.e.toString(16);return i.setPublic(n,o),i.isPrivate=!1,i.isPublic=!0,(d={}).prvKeyObj=a,d.pubKeyObj=i,d}if("EC"==e){var a,d,c=t,u=new KJUR.crypto.ECDSA({curve:c}).generateKeyPairHex();return(a=new KJUR.crypto.ECDSA({curve:c})).setPublicKeyHex(u.ecpubhex),a.setPrivateKeyHex(u.ecprvhex),a.isPrivate=!0,a.isPublic=!1,(i=new KJUR.crypto.ECDSA({curve:c})).setPublicKeyHex(u.ecpubhex),i.isPrivate=!1,i.isPublic=!0,(d={}).prvKeyObj=a,d.pubKeyObj=i,d}throw"unknown algorithm: "+e},KEYUTIL.getPEM=function(e,t,r,i,n,o){var a=KJUR,d=a.asn1,c=d.DERObjectIdentifier,u=d.DERInteger,p=d.ASN1Util.newObject,v=d.x509.SubjectPublicKeyInfo,s=a.crypto,f=s.DSA,E=s.ECDSA,y=RSAKey;function x(e){return p({seq:[{int:0},{int:{bigint:e.n}},{int:e.e},{int:{bigint:e.d}},{int:{bigint:e.p}},{int:{bigint:e.q}},{int:{bigint:e.dmp1}},{int:{bigint:e.dmq1}},{int:{bigint:e.coeff}}]})}function P(e){return p({seq:[{int:1},{octstr:{hex:e.prvKeyHex}},{tag:["a0",!0,{oid:{name:e.curveName}}]},{tag:["a1",!0,{bitstr:{hex:"00"+e.pubKeyHex}}]}]})}function S(e){return p({seq:[{int:0},{int:{bigint:e.p}},{int:{bigint:e.q}},{int:{bigint:e.g}},{int:{bigint:e.y}},{int:{bigint:e.x}}]})}if((void 0!==y&&e instanceof y||void 0!==f&&e instanceof f||void 0!==E&&e instanceof E)&&1==e.isPublic&&(void 0===t||"PKCS8PUB"==t)){var l=new v(e).getEncodedHex();return hextopem(l,"PUBLIC KEY")}if("PKCS1PRV"==t&&void 0!==y&&e instanceof y&&(void 0===r||null==r)&&1==e.isPrivate){l=x(e).getEncodedHex();return hextopem(l,"RSA PRIVATE KEY")}if("PKCS1PRV"==t&&void 0!==E&&e instanceof E&&(void 0===r||null==r)&&1==e.isPrivate){var g=new c({name:e.curveName}).getEncodedHex(),K=P(e).getEncodedHex(),C="";return C+=hextopem(g,"EC PARAMETERS"),C+=hextopem(K,"EC PRIVATE KEY")}if("PKCS1PRV"==t&&void 0!==f&&e instanceof f&&(void 0===r||null==r)&&1==e.isPrivate){l=S(e).getEncodedHex();return hextopem(l,"DSA PRIVATE KEY")}if("PKCS5PRV"==t&&void 0!==y&&e instanceof y&&void 0!==r&&null!=r&&1==e.isPrivate){l=x(e).getEncodedHex();return void 0===i&&(i="DES-EDE3-CBC"),this.getEncryptedPKCS5PEMFromPrvKeyHex("RSA",l,r,i,o)}if("PKCS5PRV"==t&&void 0!==E&&e instanceof E&&void 0!==r&&null!=r&&1==e.isPrivate){l=P(e).getEncodedHex();return void 0===i&&(i="DES-EDE3-CBC"),this.getEncryptedPKCS5PEMFromPrvKeyHex("EC",l,r,i,o)}if("PKCS5PRV"==t&&void 0!==f&&e instanceof f&&void 0!==r&&null!=r&&1==e.isPrivate){l=S(e).getEncodedHex();return void 0===i&&(i="DES-EDE3-CBC"),this.getEncryptedPKCS5PEMFromPrvKeyHex("DSA",l,r,i,o)}var h=function(e,t){var r=m(e,t);return new p({seq:[{seq:[{oid:{name:"pkcs5PBES2"}},{seq:[{seq:[{oid:{name:"pkcs5PBKDF2"}},{seq:[{octstr:{hex:r.pbkdf2Salt}},{int:r.pbkdf2Iter}]}]},{seq:[{oid:{name:"des-EDE3-CBC"}},{octstr:{hex:r.encryptionSchemeIV}}]}]}]},{octstr:{hex:r.ciphertext}}]}).getEncodedHex()},m=function(e,t){var r=CryptoJS.lib.WordArray.random(8),i=CryptoJS.lib.WordArray.random(8),n=CryptoJS.PBKDF2(t,r,{keySize:6,iterations:100}),o=CryptoJS.enc.Hex.parse(e),a=CryptoJS.TripleDES.encrypt(o,n,{iv:i})+"",d={};return d.ciphertext=a,d.pbkdf2Salt=CryptoJS.enc.Hex.stringify(r),d.pbkdf2Iter=100,d.encryptionSchemeAlg="DES-EDE3-CBC",d.encryptionSchemeIV=CryptoJS.enc.Hex.stringify(i),d};if("PKCS8PRV"==t&&void 0!=y&&e instanceof y&&1==e.isPrivate){var b=x(e).getEncodedHex();l=p({seq:[{int:0},{seq:[{oid:{name:"rsaEncryption"}},{null:!0}]},{octstr:{hex:b}}]}).getEncodedHex();if(void 0===r||null==r)return hextopem(l,"PRIVATE KEY");K=h(l,r);return hextopem(K,"ENCRYPTED PRIVATE KEY")}if("PKCS8PRV"==t&&void 0!==E&&e instanceof E&&1==e.isPrivate){b=new p({seq:[{int:1},{octstr:{hex:e.prvKeyHex}},{tag:["a1",!0,{bitstr:{hex:"00"+e.pubKeyHex}}]}]}).getEncodedHex(),l=p({seq:[{int:0},{seq:[{oid:{name:"ecPublicKey"}},{oid:{name:e.curveName}}]},{octstr:{hex:b}}]}).getEncodedHex();if(void 0===r||null==r)return hextopem(l,"PRIVATE KEY");K=h(l,r);return hextopem(K,"ENCRYPTED PRIVATE KEY")}if("PKCS8PRV"==t&&void 0!==f&&e instanceof f&&1==e.isPrivate){b=new u({bigint:e.x}).getEncodedHex(),l=p({seq:[{int:0},{seq:[{oid:{name:"dsa"}},{seq:[{int:{bigint:e.p}},{int:{bigint:e.q}},{int:{bigint:e.g}}]}]},{octstr:{hex:b}}]}).getEncodedHex();if(void 0===r||null==r)return hextopem(l,"PRIVATE KEY");K=h(l,r);return hextopem(K,"ENCRYPTED PRIVATE KEY")}throw"unsupported object nor format"},KEYUTIL.getKeyFromCSRPEM=function(e){var t=pemtohex(e,"CERTIFICATE REQUEST");return KEYUTIL.getKeyFromCSRHex(t)},KEYUTIL.getKeyFromCSRHex=function(e){var t=KEYUTIL.parseCSRHex(e);return KEYUTIL.getKey(t.p8pubkeyhex,null,"pkcs8pub")},KEYUTIL.parseCSRHex=function(e){var t=ASN1HEX,r=t.getChildIdx,i=t.getTLV,n={},o=e;if("30"!=o.substr(0,2))throw"malformed CSR(code:001)";var a=r(o,0);if(a.length<1)throw"malformed CSR(code:002)";if("30"!=o.substr(a[0],2))throw"malformed CSR(code:003)";var d=r(o,a[0]);if(d.length<3)throw"malformed CSR(code:004)";return n.p8pubkeyhex=i(o,d[2]),n},KEYUTIL.getJWKFromKey=function(e){var t={};if(e instanceof RSAKey&&e.isPrivate)return t.kty="RSA",t.n=hextob64u(e.n.toString(16)),t.e=hextob64u(e.e.toString(16)),t.d=hextob64u(e.d.toString(16)),t.p=hextob64u(e.p.toString(16)),t.q=hextob64u(e.q.toString(16)),t.dp=hextob64u(e.dmp1.toString(16)),t.dq=hextob64u(e.dmq1.toString(16)),t.qi=hextob64u(e.coeff.toString(16)),t;if(e instanceof RSAKey&&e.isPublic)return t.kty="RSA",t.n=hextob64u(e.n.toString(16)),t.e=hextob64u(e.e.toString(16)),t;if(e instanceof KJUR.crypto.ECDSA&&e.isPrivate){if("P-256"!==(i=e.getShortNISTPCurveName())&&"P-384"!==i)throw"unsupported curve name for JWT: "+i;var r=e.getPublicKeyXYHex();return t.kty="EC",t.crv=i,t.x=hextob64u(r.x),t.y=hextob64u(r.y),t.d=hextob64u(e.prvKeyHex),t}if(e instanceof KJUR.crypto.ECDSA&&e.isPublic){var i;if("P-256"!==(i=e.getShortNISTPCurveName())&&"P-384"!==i)throw"unsupported curve name for JWT: "+i;r=e.getPublicKeyXYHex();return t.kty="EC",t.crv=i,t.x=hextob64u(r.x),t.y=hextob64u(r.y),t}throw"not supported key object"}; +// discuss at: http://locutus.io/php/pack/ +function pack(r){for(var e,o,n,a,t,g,h,i,f,c,s,w,C,l,d,p,m,k,u,S,b,y,E=0,W=1,T="",v="",A=0,M=[];Ev.length)throw new Error("Warning: pack() Type "+e+": not enough characters in string");for(A=0;A=o||void 0===v[A+1]?n+="0":n+=v[A+1],"h"===e&&(n=n[1]+n[0]),T+=String.fromCharCode(parseInt(n,16));W++;break;case"c":case"C":if("*"===o&&(o=arguments.length-W),o>arguments.length-W)throw new Error("Warning: pack() Type "+e+": too few arguments");for(A=0;Aarguments.length-W)throw new Error("Warning: pack() Type "+e+": too few arguments");for(A=0;A>8&255),W++;break;case"n":if("*"===o&&(o=arguments.length-W),o>arguments.length-W)throw new Error("Warning: pack() Type "+e+": too few arguments");for(A=0;A>8&255),T+=String.fromCharCode(255&arguments[W]),W++;break;case"i":case"I":case"l":case"L":case"V":if("*"===o&&(o=arguments.length-W),o>arguments.length-W)throw new Error("Warning: pack() Type "+e+": too few arguments");for(A=0;A>8&255),T+=String.fromCharCode(arguments[W]>>16&255),T+=String.fromCharCode(arguments[W]>>24&255),W++;break;case"N":if("*"===o&&(o=arguments.length-W),o>arguments.length-W)throw new Error("Warning: pack() Type "+e+": too few arguments");for(A=0;A>24&255),T+=String.fromCharCode(arguments[W]>>16&255),T+=String.fromCharCode(arguments[W]>>8&255),T+=String.fromCharCode(255&arguments[W]),W++;break;case"f":case"d":if(a=23,t=8,"d"===e&&(a=52,t=11),"*"===o&&(o=arguments.length-W),o>arguments.length-W)throw new Error("Warning: pack() Type "+e+": too few arguments");for(A=0;A0&&b;--m)C[++b]=((m*=2)>=1)-0;for(b=-1;++b=i&&s<=f?b+1:h+1-(s=i-1)))+1]){if(!(u=C[k]))for(S=k+2;!u&&S=0;(C[S]=!C[S]-0)&&(u=0));}for(b=b-2<0?-1:b-3;++b=i&&s<=f?++b:s>=1;for(d=0,S=0,b=(y=(l?"1":"0")+y+C.slice(b,b+a).join("")).length,M=[];b;)d+=(1<T.length)for(g=o-T.length,A=0;AMIT License + */ + +/** + * kjur's class library name space + *

+ * This name space provides following name spaces: + *

    + *
  • {@link KJUR.asn1} - ASN.1 primitive hexadecimal encoder
  • + *
  • {@link KJUR.asn1.x509} - ASN.1 structure for X.509 certificate and CRL
  • + *
  • {@link KJUR.crypto} - Java Cryptographic Extension(JCE) style MessageDigest/Signature + * class and utilities
  • + *
+ *

+ * NOTE: Please ignore method summary and document of this namespace. This caused by a bug of jsdoc2. + * @name KJUR + * @namespace kjur's class library name space + */ +if (typeof KJUR == "undefined" || !KJUR) KJUR = {}; + +/** + * kjur's ASN.1 class library name space + *

+ * This is ITU-T X.690 ASN.1 DER encoder class library and + * class structure and methods is very similar to + * org.bouncycastle.asn1 package of + * well known BouncyCaslte Cryptography Library. + *

PROVIDING ASN.1 PRIMITIVES

+ * Here are ASN.1 DER primitive classes. + *
    + *
  • 0x01 {@link KJUR.asn1.DERBoolean}
  • + *
  • 0x02 {@link KJUR.asn1.DERInteger}
  • + *
  • 0x03 {@link KJUR.asn1.DERBitString}
  • + *
  • 0x04 {@link KJUR.asn1.DEROctetString}
  • + *
  • 0x05 {@link KJUR.asn1.DERNull}
  • + *
  • 0x06 {@link KJUR.asn1.DERObjectIdentifier}
  • + *
  • 0x0a {@link KJUR.asn1.DEREnumerated}
  • + *
  • 0x0c {@link KJUR.asn1.DERUTF8String}
  • + *
  • 0x12 {@link KJUR.asn1.DERNumericString}
  • + *
  • 0x13 {@link KJUR.asn1.DERPrintableString}
  • + *
  • 0x14 {@link KJUR.asn1.DERTeletexString}
  • + *
  • 0x16 {@link KJUR.asn1.DERIA5String}
  • + *
  • 0x17 {@link KJUR.asn1.DERUTCTime}
  • + *
  • 0x18 {@link KJUR.asn1.DERGeneralizedTime}
  • + *
  • 0x30 {@link KJUR.asn1.DERSequence}
  • + *
  • 0x31 {@link KJUR.asn1.DERSet}
  • + *
+ *

OTHER ASN.1 CLASSES

+ *
    + *
  • {@link KJUR.asn1.ASN1Object}
  • + *
  • {@link KJUR.asn1.DERAbstractString}
  • + *
  • {@link KJUR.asn1.DERAbstractTime}
  • + *
  • {@link KJUR.asn1.DERAbstractStructured}
  • + *
  • {@link KJUR.asn1.DERTaggedObject}
  • + *
+ *

SUB NAME SPACES

+ *
    + *
  • {@link KJUR.asn1.cades} - CAdES long term signature format
  • + *
  • {@link KJUR.asn1.cms} - Cryptographic Message Syntax
  • + *
  • {@link KJUR.asn1.csr} - Certificate Signing Request (CSR/PKCS#10)
  • + *
  • {@link KJUR.asn1.tsp} - RFC 3161 Timestamping Protocol Format
  • + *
  • {@link KJUR.asn1.x509} - RFC 5280 X.509 certificate and CRL
  • + *
+ *

+ * NOTE: Please ignore method summary and document of this namespace. + * This caused by a bug of jsdoc2. + * @name KJUR.asn1 + * @namespace + */ +if (typeof KJUR.asn1 == "undefined" || !KJUR.asn1) KJUR.asn1 = {}; + +/** + * ASN1 utilities class + * @name KJUR.asn1.ASN1Util + * @class ASN1 utilities class + * @since asn1 1.0.2 + */ +KJUR.asn1.ASN1Util = new function() { + this.integerToByteHex = function(i) { + var h = i.toString(16); + if ((h.length % 2) == 1) h = '0' + h; + return h; + }; + this.bigIntToMinTwosComplementsHex = function(bigIntegerValue) { + var h = bigIntegerValue.toString(16); + if (h.substr(0, 1) != '-') { + if (h.length % 2 == 1) { + h = '0' + h; + } else { + if (! h.match(/^[0-7]/)) { + h = '00' + h; + } + } + } else { + var hPos = h.substr(1); + var xorLen = hPos.length; + if (xorLen % 2 == 1) { + xorLen += 1; + } else { + if (! h.match(/^[0-7]/)) { + xorLen += 2; + } + } + var hMask = ''; + for (var i = 0; i < xorLen; i++) { + hMask += 'f'; + } + var biMask = new BigInteger(hMask, 16); + var biNeg = biMask.xor(bigIntegerValue).add(BigInteger.ONE); + h = biNeg.toString(16).replace(/^-/, ''); + } + return h; + }; + /** + * get PEM string from hexadecimal data and header string + * @name getPEMStringFromHex + * @memberOf KJUR.asn1.ASN1Util + * @function + * @param {String} dataHex hexadecimal string of PEM body + * @param {String} pemHeader PEM header string (ex. 'RSA PRIVATE KEY') + * @return {String} PEM formatted string of input data + * @description + * This method converts a hexadecimal string to a PEM string with + * a specified header. Its line break will be CRLF("\r\n"). + * @example + * var pem = KJUR.asn1.ASN1Util.getPEMStringFromHex('616161', 'RSA PRIVATE KEY'); + * // value of pem will be: + * -----BEGIN PRIVATE KEY----- + * YWFh + * -----END PRIVATE KEY----- + */ + this.getPEMStringFromHex = function(dataHex, pemHeader) { + return hextopem(dataHex, pemHeader); + }; + + /** + * generate ASN1Object specifed by JSON parameters + * @name newObject + * @memberOf KJUR.asn1.ASN1Util + * @function + * @param {Array} param JSON parameter to generate ASN1Object + * @return {KJUR.asn1.ASN1Object} generated object + * @since asn1 1.0.3 + * @description + * generate any ASN1Object specified by JSON param + * including ASN.1 primitive or structured. + * Generally 'param' can be described as follows: + *
+ * {TYPE-OF-ASNOBJ: ASN1OBJ-PARAMETER} + *
+ * 'TYPE-OF-ASN1OBJ' can be one of following symbols: + *
    + *
  • 'bool' - DERBoolean
  • + *
  • 'int' - DERInteger
  • + *
  • 'bitstr' - DERBitString
  • + *
  • 'octstr' - DEROctetString
  • + *
  • 'null' - DERNull
  • + *
  • 'oid' - DERObjectIdentifier
  • + *
  • 'enum' - DEREnumerated
  • + *
  • 'utf8str' - DERUTF8String
  • + *
  • 'numstr' - DERNumericString
  • + *
  • 'prnstr' - DERPrintableString
  • + *
  • 'telstr' - DERTeletexString
  • + *
  • 'ia5str' - DERIA5String
  • + *
  • 'utctime' - DERUTCTime
  • + *
  • 'gentime' - DERGeneralizedTime
  • + *
  • 'seq' - DERSequence
  • + *
  • 'set' - DERSet
  • + *
  • 'tag' - DERTaggedObject
  • + *
+ * @example + * newObject({'prnstr': 'aaa'}); + * newObject({'seq': [{'int': 3}, {'prnstr': 'aaa'}]}) + * // ASN.1 Tagged Object + * newObject({'tag': {'tag': 'a1', + * 'explicit': true, + * 'obj': {'seq': [{'int': 3}, {'prnstr': 'aaa'}]}}}); + * // more simple representation of ASN.1 Tagged Object + * newObject({'tag': ['a1', + * true, + * {'seq': [ + * {'int': 3}, + * {'prnstr': 'aaa'}]} + * ]}); + */ + this.newObject = function(param) { + var _KJUR = KJUR, + _KJUR_asn1 = _KJUR.asn1, + _DERBoolean = _KJUR_asn1.DERBoolean, + _DERInteger = _KJUR_asn1.DERInteger, + _DERBitString = _KJUR_asn1.DERBitString, + _DEROctetString = _KJUR_asn1.DEROctetString, + _DERNull = _KJUR_asn1.DERNull, + _DERObjectIdentifier = _KJUR_asn1.DERObjectIdentifier, + _DEREnumerated = _KJUR_asn1.DEREnumerated, + _DERUTF8String = _KJUR_asn1.DERUTF8String, + _DERNumericString = _KJUR_asn1.DERNumericString, + _DERPrintableString = _KJUR_asn1.DERPrintableString, + _DERTeletexString = _KJUR_asn1.DERTeletexString, + _DERIA5String = _KJUR_asn1.DERIA5String, + _DERUTCTime = _KJUR_asn1.DERUTCTime, + _DERGeneralizedTime = _KJUR_asn1.DERGeneralizedTime, + _DERSequence = _KJUR_asn1.DERSequence, + _DERSet = _KJUR_asn1.DERSet, + _DERTaggedObject = _KJUR_asn1.DERTaggedObject, + _newObject = _KJUR_asn1.ASN1Util.newObject; + + var keys = Object.keys(param); + if (keys.length != 1) + throw "key of param shall be only one."; + var key = keys[0]; + + if (":bool:int:bitstr:octstr:null:oid:enum:utf8str:numstr:prnstr:telstr:ia5str:utctime:gentime:seq:set:tag:".indexOf(":" + key + ":") == -1) + throw "undefined key: " + key; + + if (key == "bool") return new _DERBoolean(param[key]); + if (key == "int") return new _DERInteger(param[key]); + if (key == "bitstr") return new _DERBitString(param[key]); + if (key == "octstr") return new _DEROctetString(param[key]); + if (key == "null") return new _DERNull(param[key]); + if (key == "oid") return new _DERObjectIdentifier(param[key]); + if (key == "enum") return new _DEREnumerated(param[key]); + if (key == "utf8str") return new _DERUTF8String(param[key]); + if (key == "numstr") return new _DERNumericString(param[key]); + if (key == "prnstr") return new _DERPrintableString(param[key]); + if (key == "telstr") return new _DERTeletexString(param[key]); + if (key == "ia5str") return new _DERIA5String(param[key]); + if (key == "utctime") return new _DERUTCTime(param[key]); + if (key == "gentime") return new _DERGeneralizedTime(param[key]); + + if (key == "seq") { + var paramList = param[key]; + var a = []; + for (var i = 0; i < paramList.length; i++) { + var asn1Obj = _newObject(paramList[i]); + a.push(asn1Obj); + } + return new _DERSequence({'array': a}); + } + + if (key == "set") { + var paramList = param[key]; + var a = []; + for (var i = 0; i < paramList.length; i++) { + var asn1Obj = _newObject(paramList[i]); + a.push(asn1Obj); + } + return new _DERSet({'array': a}); + } + + if (key == "tag") { + var tagParam = param[key]; + if (Object.prototype.toString.call(tagParam) === '[object Array]' && + tagParam.length == 3) { + var obj = _newObject(tagParam[2]); + return new _DERTaggedObject({tag: tagParam[0], + explicit: tagParam[1], + obj: obj}); + } else { + var newParam = {}; + if (tagParam.explicit !== undefined) + newParam.explicit = tagParam.explicit; + if (tagParam.tag !== undefined) + newParam.tag = tagParam.tag; + if (tagParam.obj === undefined) + throw "obj shall be specified for 'tag'."; + newParam.obj = _newObject(tagParam.obj); + return new _DERTaggedObject(newParam); + } + } + }; + + /** + * get encoded hexadecimal string of ASN1Object specifed by JSON parameters + * @name jsonToASN1HEX + * @memberOf KJUR.asn1.ASN1Util + * @function + * @param {Array} param JSON parameter to generate ASN1Object + * @return hexadecimal string of ASN1Object + * @since asn1 1.0.4 + * @description + * As for ASN.1 object representation of JSON object, + * please see {@link newObject}. + * @example + * jsonToASN1HEX({'prnstr': 'aaa'}); + */ + this.jsonToASN1HEX = function(param) { + var asn1Obj = this.newObject(param); + return asn1Obj.getEncodedHex(); + }; +}; + +/** + * get dot noted oid number string from hexadecimal value of OID + * @name oidHexToInt + * @memberOf KJUR.asn1.ASN1Util + * @function + * @param {String} hex hexadecimal value of object identifier + * @return {String} dot noted string of object identifier + * @since jsrsasign 4.8.3 asn1 1.0.7 + * @description + * This static method converts from hexadecimal string representation of + * ASN.1 value of object identifier to oid number string. + * @example + * KJUR.asn1.ASN1Util.oidHexToInt('550406') → "2.5.4.6" + */ +KJUR.asn1.ASN1Util.oidHexToInt = function(hex) { + var s = ""; + var i01 = parseInt(hex.substr(0, 2), 16); + var i0 = Math.floor(i01 / 40); + var i1 = i01 % 40; + var s = i0 + "." + i1; + + var binbuf = ""; + for (var i = 2; i < hex.length; i += 2) { + var value = parseInt(hex.substr(i, 2), 16); + var bin = ("00000000" + value.toString(2)).slice(- 8); + binbuf = binbuf + bin.substr(1, 7); + if (bin.substr(0, 1) == "0") { + var bi = new BigInteger(binbuf, 2); + s = s + "." + bi.toString(10); + binbuf = ""; + } + }; + + return s; +}; + +/** + * get hexadecimal value of object identifier from dot noted oid value + * @name oidIntToHex + * @memberOf KJUR.asn1.ASN1Util + * @function + * @param {String} oidString dot noted string of object identifier + * @return {String} hexadecimal value of object identifier + * @since jsrsasign 4.8.3 asn1 1.0.7 + * @description + * This static method converts from object identifier value string. + * to hexadecimal string representation of it. + * @example + * KJUR.asn1.ASN1Util.oidIntToHex("2.5.4.6") → "550406" + */ +KJUR.asn1.ASN1Util.oidIntToHex = function(oidString) { + var itox = function(i) { + var h = i.toString(16); + if (h.length == 1) h = '0' + h; + return h; + }; + + var roidtox = function(roid) { + var h = ''; + var bi = new BigInteger(roid, 10); + var b = bi.toString(2); + var padLen = 7 - b.length % 7; + if (padLen == 7) padLen = 0; + var bPad = ''; + for (var i = 0; i < padLen; i++) bPad += '0'; + b = bPad + b; + for (var i = 0; i < b.length - 1; i += 7) { + var b8 = b.substr(i, 7); + if (i != b.length - 7) b8 = '1' + b8; + h += itox(parseInt(b8, 2)); + } + return h; + }; + + if (! oidString.match(/^[0-9.]+$/)) { + throw "malformed oid string: " + oidString; + } + var h = ''; + var a = oidString.split('.'); + var i0 = parseInt(a[0]) * 40 + parseInt(a[1]); + h += itox(i0); + a.splice(0, 2); + for (var i = 0; i < a.length; i++) { + h += roidtox(a[i]); + } + return h; +}; + + +// ******************************************************************** +// Abstract ASN.1 Classes +// ******************************************************************** + +// ******************************************************************** + +/** + * base class for ASN.1 DER encoder object + * @name KJUR.asn1.ASN1Object + * @class base class for ASN.1 DER encoder object + * @property {Boolean} isModified flag whether internal data was changed + * @property {String} hTLV hexadecimal string of ASN.1 TLV + * @property {String} hT hexadecimal string of ASN.1 TLV tag(T) + * @property {String} hL hexadecimal string of ASN.1 TLV length(L) + * @property {String} hV hexadecimal string of ASN.1 TLV value(V) + * @description + */ +KJUR.asn1.ASN1Object = function() { + var isModified = true; + var hTLV = null; + var hT = '00'; + var hL = '00'; + var hV = ''; + + /** + * get hexadecimal ASN.1 TLV length(L) bytes from TLV value(V) + * @name getLengthHexFromValue + * @memberOf KJUR.asn1.ASN1Object# + * @function + * @return {String} hexadecimal string of ASN.1 TLV length(L) + */ + this.getLengthHexFromValue = function() { + if (typeof this.hV == "undefined" || this.hV == null) { + throw "this.hV is null or undefined."; + } + if (this.hV.length % 2 == 1) { + throw "value hex must be even length: n=" + hV.length + ",v=" + this.hV; + } + var n = this.hV.length / 2; + var hN = n.toString(16); + if (hN.length % 2 == 1) { + hN = "0" + hN; + } + if (n < 128) { + return hN; + } else { + var hNlen = hN.length / 2; + if (hNlen > 15) { + throw "ASN.1 length too long to represent by 8x: n = " + n.toString(16); + } + var head = 128 + hNlen; + return head.toString(16) + hN; + } + }; + + /** + * get hexadecimal string of ASN.1 TLV bytes + * @name getEncodedHex + * @memberOf KJUR.asn1.ASN1Object# + * @function + * @return {String} hexadecimal string of ASN.1 TLV + */ + this.getEncodedHex = function() { + if (this.hTLV == null || this.isModified) { + this.hV = this.getFreshValueHex(); + this.hL = this.getLengthHexFromValue(); + this.hTLV = this.hT + this.hL + this.hV; + this.isModified = false; + //alert("first time: " + this.hTLV); + } + return this.hTLV; + }; + + /** + * get hexadecimal string of ASN.1 TLV value(V) bytes + * @name getValueHex + * @memberOf KJUR.asn1.ASN1Object# + * @function + * @return {String} hexadecimal string of ASN.1 TLV value(V) bytes + */ + this.getValueHex = function() { + this.getEncodedHex(); + return this.hV; + } + + this.getFreshValueHex = function() { + return ''; + }; +}; + +// == BEGIN DERAbstractString ================================================ +/** + * base class for ASN.1 DER string classes + * @name KJUR.asn1.DERAbstractString + * @class base class for ASN.1 DER string classes + * @param {Array} params associative array of parameters (ex. {'str': 'aaa'}) + * @property {String} s internal string of value + * @extends KJUR.asn1.ASN1Object + * @description + *
+ * As for argument 'params' for constructor, you can specify one of + * following properties: + *
    + *
  • str - specify initial ASN.1 value(V) by a string
  • + *
  • hex - specify initial ASN.1 value(V) by a hexadecimal string
  • + *
+ * NOTE: 'params' can be omitted. + */ +KJUR.asn1.DERAbstractString = function(params) { + KJUR.asn1.DERAbstractString.superclass.constructor.call(this); + var s = null; + var hV = null; + + /** + * get string value of this string object + * @name getString + * @memberOf KJUR.asn1.DERAbstractString# + * @function + * @return {String} string value of this string object + */ + this.getString = function() { + return this.s; + }; + + /** + * set value by a string + * @name setString + * @memberOf KJUR.asn1.DERAbstractString# + * @function + * @param {String} newS value by a string to set + * @description + * This method set value by string.
+ * NOTE: This method assumes that the argument string is + * UTF-8 encoded even though ASN.1 primitive + * such as IA5String or PrintableString doesn't + * support all of UTF-8 characters. + * @example + * o = new KJUR.asn1.DERIA5String(); + * o.setString("abc"); + * o.setString("あいう"); + */ + this.setString = function(newS) { + this.hTLV = null; + this.isModified = true; + this.s = newS; + this.hV = utf8tohex(this.s).toLowerCase(); + }; + + /** + * set value by a hexadecimal string + * @name setStringHex + * @memberOf KJUR.asn1.DERAbstractString# + * @function + * @param {String} newHexString value by a hexadecimal string to set + */ + this.setStringHex = function(newHexString) { + this.hTLV = null; + this.isModified = true; + this.s = null; + this.hV = newHexString; + }; + + this.getFreshValueHex = function() { + return this.hV; + }; + + if (typeof params != "undefined") { + if (typeof params == "string") { + this.setString(params); + } else if (typeof params['str'] != "undefined") { + this.setString(params['str']); + } else if (typeof params['hex'] != "undefined") { + this.setStringHex(params['hex']); + } + } +}; +YAHOO.lang.extend(KJUR.asn1.DERAbstractString, KJUR.asn1.ASN1Object); +// == END DERAbstractString ================================================ + +// == BEGIN DERAbstractTime ================================================== +/** + * base class for ASN.1 DER Generalized/UTCTime class + * @name KJUR.asn1.DERAbstractTime + * @class base class for ASN.1 DER Generalized/UTCTime class + * @param {Array} params associative array of parameters (ex. {'str': '130430235959Z'}) + * @extends KJUR.asn1.ASN1Object + * @description + * @see KJUR.asn1.ASN1Object - superclass + */ +KJUR.asn1.DERAbstractTime = function(params) { + KJUR.asn1.DERAbstractTime.superclass.constructor.call(this); + var s = null; + var date = null; + + // --- PRIVATE METHODS -------------------- + this.localDateToUTC = function(d) { + utc = d.getTime() + (d.getTimezoneOffset() * 60000); + var utcDate = new Date(utc); + return utcDate; + }; + + /* + * format date string by Data object + * @name formatDate + * @memberOf KJUR.asn1.AbstractTime; + * @param {Date} dateObject + * @param {string} type 'utc' or 'gen' + * @param {boolean} withMillis flag for with millisections or not + * @description + * 'withMillis' flag is supported from asn1 1.0.6. + */ + this.formatDate = function(dateObject, type, withMillis) { + var pad = this.zeroPadding; + var d = this.localDateToUTC(dateObject); + var year = String(d.getFullYear()); + if (type == 'utc') year = year.substr(2, 2); + var month = pad(String(d.getMonth() + 1), 2); + var day = pad(String(d.getDate()), 2); + var hour = pad(String(d.getHours()), 2); + var min = pad(String(d.getMinutes()), 2); + var sec = pad(String(d.getSeconds()), 2); + var s = year + month + day + hour + min + sec; + if (withMillis === true) { + var millis = d.getMilliseconds(); + if (millis != 0) { + var sMillis = pad(String(millis), 3); + sMillis = sMillis.replace(/[0]+$/, ""); + s = s + "." + sMillis; + } + } + return s + "Z"; + }; + + this.zeroPadding = function(s, len) { + if (s.length >= len) return s; + return new Array(len - s.length + 1).join('0') + s; + }; + + // --- PUBLIC METHODS -------------------- + /** + * get string value of this string object + * @name getString + * @memberOf KJUR.asn1.DERAbstractTime# + * @function + * @return {String} string value of this time object + */ + this.getString = function() { + return this.s; + }; + + /** + * set value by a string + * @name setString + * @memberOf KJUR.asn1.DERAbstractTime# + * @function + * @param {String} newS value by a string to set such like "130430235959Z" + */ + this.setString = function(newS) { + this.hTLV = null; + this.isModified = true; + this.s = newS; + this.hV = stohex(newS); + }; + + /** + * set value by a Date object + * @name setByDateValue + * @memberOf KJUR.asn1.DERAbstractTime# + * @function + * @param {Integer} year year of date (ex. 2013) + * @param {Integer} month month of date between 1 and 12 (ex. 12) + * @param {Integer} day day of month + * @param {Integer} hour hours of date + * @param {Integer} min minutes of date + * @param {Integer} sec seconds of date + */ + this.setByDateValue = function(year, month, day, hour, min, sec) { + var dateObject = new Date(Date.UTC(year, month - 1, day, hour, min, sec, 0)); + this.setByDate(dateObject); + }; + + this.getFreshValueHex = function() { + return this.hV; + }; +}; +YAHOO.lang.extend(KJUR.asn1.DERAbstractTime, KJUR.asn1.ASN1Object); +// == END DERAbstractTime ================================================== + +// == BEGIN DERAbstractStructured ============================================ +/** + * base class for ASN.1 DER structured class + * @name KJUR.asn1.DERAbstractStructured + * @class base class for ASN.1 DER structured class + * @property {Array} asn1Array internal array of ASN1Object + * @extends KJUR.asn1.ASN1Object + * @description + * @see KJUR.asn1.ASN1Object - superclass + */ +KJUR.asn1.DERAbstractStructured = function(params) { + KJUR.asn1.DERAbstractString.superclass.constructor.call(this); + var asn1Array = null; + + /** + * set value by array of ASN1Object + * @name setByASN1ObjectArray + * @memberOf KJUR.asn1.DERAbstractStructured# + * @function + * @param {array} asn1ObjectArray array of ASN1Object to set + */ + this.setByASN1ObjectArray = function(asn1ObjectArray) { + this.hTLV = null; + this.isModified = true; + this.asn1Array = asn1ObjectArray; + }; + + /** + * append an ASN1Object to internal array + * @name appendASN1Object + * @memberOf KJUR.asn1.DERAbstractStructured# + * @function + * @param {ASN1Object} asn1Object to add + */ + this.appendASN1Object = function(asn1Object) { + this.hTLV = null; + this.isModified = true; + this.asn1Array.push(asn1Object); + }; + + this.asn1Array = new Array(); + if (typeof params != "undefined") { + if (typeof params['array'] != "undefined") { + this.asn1Array = params['array']; + } + } +}; +YAHOO.lang.extend(KJUR.asn1.DERAbstractStructured, KJUR.asn1.ASN1Object); + + +// ******************************************************************** +// ASN.1 Object Classes +// ******************************************************************** + +// ******************************************************************** +/** + * class for ASN.1 DER Boolean + * @name KJUR.asn1.DERBoolean + * @class class for ASN.1 DER Boolean + * @extends KJUR.asn1.ASN1Object + * @description + * @see KJUR.asn1.ASN1Object - superclass + */ +KJUR.asn1.DERBoolean = function() { + KJUR.asn1.DERBoolean.superclass.constructor.call(this); + this.hT = "01"; + this.hTLV = "0101ff"; +}; +YAHOO.lang.extend(KJUR.asn1.DERBoolean, KJUR.asn1.ASN1Object); + +// ******************************************************************** +/** + * class for ASN.1 DER Integer + * @name KJUR.asn1.DERInteger + * @class class for ASN.1 DER Integer + * @extends KJUR.asn1.ASN1Object + * @description + *
+ * As for argument 'params' for constructor, you can specify one of + * following properties: + *
    + *
  • int - specify initial ASN.1 value(V) by integer value
  • + *
  • bigint - specify initial ASN.1 value(V) by BigInteger object
  • + *
  • hex - specify initial ASN.1 value(V) by a hexadecimal string
  • + *
+ * NOTE: 'params' can be omitted. + */ +KJUR.asn1.DERInteger = function(params) { + KJUR.asn1.DERInteger.superclass.constructor.call(this); + this.hT = "02"; + + /** + * set value by Tom Wu's BigInteger object + * @name setByBigInteger + * @memberOf KJUR.asn1.DERInteger# + * @function + * @param {BigInteger} bigIntegerValue to set + */ + this.setByBigInteger = function(bigIntegerValue) { + this.hTLV = null; + this.isModified = true; + this.hV = KJUR.asn1.ASN1Util.bigIntToMinTwosComplementsHex(bigIntegerValue); + }; + + /** + * set value by integer value + * @name setByInteger + * @memberOf KJUR.asn1.DERInteger + * @function + * @param {Integer} integer value to set + */ + this.setByInteger = function(intValue) { + var bi = new BigInteger(String(intValue), 10); + this.setByBigInteger(bi); + }; + + /** + * set value by integer value + * @name setValueHex + * @memberOf KJUR.asn1.DERInteger# + * @function + * @param {String} hexadecimal string of integer value + * @description + *
+ * NOTE: Value shall be represented by minimum octet length of + * two's complement representation. + * @example + * new KJUR.asn1.DERInteger(123); + * new KJUR.asn1.DERInteger({'int': 123}); + * new KJUR.asn1.DERInteger({'hex': '1fad'}); + */ + this.setValueHex = function(newHexString) { + this.hV = newHexString; + }; + + this.getFreshValueHex = function() { + return this.hV; + }; + + if (typeof params != "undefined") { + if (typeof params['bigint'] != "undefined") { + this.setByBigInteger(params['bigint']); + } else if (typeof params['int'] != "undefined") { + this.setByInteger(params['int']); + } else if (typeof params == "number") { + this.setByInteger(params); + } else if (typeof params['hex'] != "undefined") { + this.setValueHex(params['hex']); + } + } +}; +YAHOO.lang.extend(KJUR.asn1.DERInteger, KJUR.asn1.ASN1Object); + +// ******************************************************************** +/** + * class for ASN.1 DER encoded BitString primitive + * @name KJUR.asn1.DERBitString + * @class class for ASN.1 DER encoded BitString primitive + * @extends KJUR.asn1.ASN1Object + * @description + *
+ * As for argument 'params' for constructor, you can specify one of + * following properties: + *
    + *
  • bin - specify binary string (ex. '10111')
  • + *
  • array - specify array of boolean (ex. [true,false,true,true])
  • + *
  • hex - specify hexadecimal string of ASN.1 value(V) including unused bits
  • + *
  • obj - specify {@link KJUR.asn1.ASN1Util.newObject} + * argument for "BitString encapsulates" structure.
  • + *
+ * NOTE1: 'params' can be omitted.
+ * NOTE2: 'obj' parameter have been supported since + * asn1 1.0.11, jsrsasign 6.1.1 (2016-Sep-25).
+ * @example + * // default constructor + * o = new KJUR.asn1.DERBitString(); + * // initialize with binary string + * o = new KJUR.asn1.DERBitString({bin: "1011"}); + * // initialize with boolean array + * o = new KJUR.asn1.DERBitString({array: [true,false,true,true]}); + * // initialize with hexadecimal string (04 is unused bits) + * o = new KJUR.asn1.DEROctetString({hex: "04bac0"}); + * // initialize with ASN1Util.newObject argument for encapsulated + * o = new KJUR.asn1.DERBitString({obj: {seq: [{int: 3}, {prnstr: 'aaa'}]}}); + * // above generates a ASN.1 data like this: + * // BIT STRING, encapsulates { + * // SEQUENCE { + * // INTEGER 3 + * // PrintableString 'aaa' + * // } + * // } + */ +KJUR.asn1.DERBitString = function(params) { + if (params !== undefined && typeof params.obj !== "undefined") { + var o = KJUR.asn1.ASN1Util.newObject(params.obj); + params.hex = "00" + o.getEncodedHex(); + } + KJUR.asn1.DERBitString.superclass.constructor.call(this); + this.hT = "03"; + + /** + * set ASN.1 value(V) by a hexadecimal string including unused bits + * @name setHexValueIncludingUnusedBits + * @memberOf KJUR.asn1.DERBitString# + * @function + * @param {String} newHexStringIncludingUnusedBits + */ + this.setHexValueIncludingUnusedBits = function(newHexStringIncludingUnusedBits) { + this.hTLV = null; + this.isModified = true; + this.hV = newHexStringIncludingUnusedBits; + }; + + /** + * set ASN.1 value(V) by unused bit and hexadecimal string of value + * @name setUnusedBitsAndHexValue + * @memberOf KJUR.asn1.DERBitString# + * @function + * @param {Integer} unusedBits + * @param {String} hValue + */ + this.setUnusedBitsAndHexValue = function(unusedBits, hValue) { + if (unusedBits < 0 || 7 < unusedBits) { + throw "unused bits shall be from 0 to 7: u = " + unusedBits; + } + var hUnusedBits = "0" + unusedBits; + this.hTLV = null; + this.isModified = true; + this.hV = hUnusedBits + hValue; + }; + + /** + * set ASN.1 DER BitString by binary string
+ * @name setByBinaryString + * @memberOf KJUR.asn1.DERBitString# + * @function + * @param {String} binaryString binary value string (i.e. '10111') + * @description + * Its unused bits will be calculated automatically by length of + * 'binaryValue'.
+ * NOTE: Trailing zeros '0' will be ignored. + * @example + * o = new KJUR.asn1.DERBitString(); + * o.setByBooleanArray("01011"); + */ + this.setByBinaryString = function(binaryString) { + binaryString = binaryString.replace(/0+$/, ''); + var unusedBits = 8 - binaryString.length % 8; + if (unusedBits == 8) unusedBits = 0; + for (var i = 0; i <= unusedBits; i++) { + binaryString += '0'; + } + var h = ''; + for (var i = 0; i < binaryString.length - 1; i += 8) { + var b = binaryString.substr(i, 8); + var x = parseInt(b, 2).toString(16); + if (x.length == 1) x = '0' + x; + h += x; + } + this.hTLV = null; + this.isModified = true; + this.hV = '0' + unusedBits + h; + }; + + /** + * set ASN.1 TLV value(V) by an array of boolean
+ * @name setByBooleanArray + * @memberOf KJUR.asn1.DERBitString# + * @function + * @param {array} booleanArray array of boolean (ex. [true, false, true]) + * @description + * NOTE: Trailing falses will be ignored in the ASN.1 DER Object. + * @example + * o = new KJUR.asn1.DERBitString(); + * o.setByBooleanArray([false, true, false, true, true]); + */ + this.setByBooleanArray = function(booleanArray) { + var s = ''; + for (var i = 0; i < booleanArray.length; i++) { + if (booleanArray[i] == true) { + s += '1'; + } else { + s += '0'; + } + } + this.setByBinaryString(s); + }; + + /** + * generate an array of falses with specified length
+ * @name newFalseArray + * @memberOf KJUR.asn1.DERBitString + * @function + * @param {Integer} nLength length of array to generate + * @return {array} array of boolean falses + * @description + * This static method may be useful to initialize boolean array. + * @example + * o = new KJUR.asn1.DERBitString(); + * o.newFalseArray(3) → [false, false, false] + */ + this.newFalseArray = function(nLength) { + var a = new Array(nLength); + for (var i = 0; i < nLength; i++) { + a[i] = false; + } + return a; + }; + + this.getFreshValueHex = function() { + return this.hV; + }; + + if (typeof params != "undefined") { + if (typeof params == "string" && params.toLowerCase().match(/^[0-9a-f]+$/)) { + this.setHexValueIncludingUnusedBits(params); + } else if (typeof params['hex'] != "undefined") { + this.setHexValueIncludingUnusedBits(params['hex']); + } else if (typeof params['bin'] != "undefined") { + this.setByBinaryString(params['bin']); + } else if (typeof params['array'] != "undefined") { + this.setByBooleanArray(params['array']); + } + } +}; +YAHOO.lang.extend(KJUR.asn1.DERBitString, KJUR.asn1.ASN1Object); + +// ******************************************************************** +/** + * class for ASN.1 DER OctetString
+ * @name KJUR.asn1.DEROctetString + * @class class for ASN.1 DER OctetString + * @param {Array} params associative array of parameters (ex. {'str': 'aaa'}) + * @extends KJUR.asn1.DERAbstractString + * @description + * This class provides ASN.1 OctetString simple type.
+ * Supported "params" attributes are: + *
    + *
  • str - to set a string as a value
  • + *
  • hex - to set a hexadecimal string as a value
  • + *
  • obj - to set a encapsulated ASN.1 value by JSON object + * which is defined in {@link KJUR.asn1.ASN1Util.newObject}
  • + *
+ * NOTE: A parameter 'obj' have been supported + * for "OCTET STRING, encapsulates" structure. + * since asn1 1.0.11, jsrsasign 6.1.1 (2016-Sep-25). + * @see KJUR.asn1.DERAbstractString - superclass + * @example + * // default constructor + * o = new KJUR.asn1.DEROctetString(); + * // initialize with string + * o = new KJUR.asn1.DEROctetString({str: "aaa"}); + * // initialize with hexadecimal string + * o = new KJUR.asn1.DEROctetString({hex: "616161"}); + * // initialize with ASN1Util.newObject argument + * o = new KJUR.asn1.DEROctetString({obj: {seq: [{int: 3}, {prnstr: 'aaa'}]}}); + * // above generates a ASN.1 data like this: + * // OCTET STRING, encapsulates { + * // SEQUENCE { + * // INTEGER 3 + * // PrintableString 'aaa' + * // } + * // } + */ +KJUR.asn1.DEROctetString = function(params) { + if (params !== undefined && typeof params.obj !== "undefined") { + var o = KJUR.asn1.ASN1Util.newObject(params.obj); + params.hex = o.getEncodedHex(); + } + KJUR.asn1.DEROctetString.superclass.constructor.call(this, params); + this.hT = "04"; +}; +YAHOO.lang.extend(KJUR.asn1.DEROctetString, KJUR.asn1.DERAbstractString); + +// ******************************************************************** +/** + * class for ASN.1 DER Null + * @name KJUR.asn1.DERNull + * @class class for ASN.1 DER Null + * @extends KJUR.asn1.ASN1Object + * @description + * @see KJUR.asn1.ASN1Object - superclass + */ +KJUR.asn1.DERNull = function() { + KJUR.asn1.DERNull.superclass.constructor.call(this); + this.hT = "05"; + this.hTLV = "0500"; +}; +YAHOO.lang.extend(KJUR.asn1.DERNull, KJUR.asn1.ASN1Object); + +// ******************************************************************** +/** + * class for ASN.1 DER ObjectIdentifier + * @name KJUR.asn1.DERObjectIdentifier + * @class class for ASN.1 DER ObjectIdentifier + * @param {Array} params associative array of parameters (ex. {'oid': '2.5.4.5'}) + * @extends KJUR.asn1.ASN1Object + * @description + *
+ * As for argument 'params' for constructor, you can specify one of + * following properties: + *
    + *
  • oid - specify initial ASN.1 value(V) by a oid string (ex. 2.5.4.13)
  • + *
  • hex - specify initial ASN.1 value(V) by a hexadecimal string
  • + *
+ * NOTE: 'params' can be omitted. + */ +KJUR.asn1.DERObjectIdentifier = function(params) { + var itox = function(i) { + var h = i.toString(16); + if (h.length == 1) h = '0' + h; + return h; + }; + var roidtox = function(roid) { + var h = ''; + var bi = new BigInteger(roid, 10); + var b = bi.toString(2); + var padLen = 7 - b.length % 7; + if (padLen == 7) padLen = 0; + var bPad = ''; + for (var i = 0; i < padLen; i++) bPad += '0'; + b = bPad + b; + for (var i = 0; i < b.length - 1; i += 7) { + var b8 = b.substr(i, 7); + if (i != b.length - 7) b8 = '1' + b8; + h += itox(parseInt(b8, 2)); + } + return h; + } + + KJUR.asn1.DERObjectIdentifier.superclass.constructor.call(this); + this.hT = "06"; + + /** + * set value by a hexadecimal string + * @name setValueHex + * @memberOf KJUR.asn1.DERObjectIdentifier# + * @function + * @param {String} newHexString hexadecimal value of OID bytes + */ + this.setValueHex = function(newHexString) { + this.hTLV = null; + this.isModified = true; + this.s = null; + this.hV = newHexString; + }; + + /** + * set value by a OID string
+ * @name setValueOidString + * @memberOf KJUR.asn1.DERObjectIdentifier# + * @function + * @param {String} oidString OID string (ex. 2.5.4.13) + * @example + * o = new KJUR.asn1.DERObjectIdentifier(); + * o.setValueOidString("2.5.4.13"); + */ + this.setValueOidString = function(oidString) { + if (! oidString.match(/^[0-9.]+$/)) { + throw "malformed oid string: " + oidString; + } + var h = ''; + var a = oidString.split('.'); + var i0 = parseInt(a[0]) * 40 + parseInt(a[1]); + h += itox(i0); + a.splice(0, 2); + for (var i = 0; i < a.length; i++) { + h += roidtox(a[i]); + } + this.hTLV = null; + this.isModified = true; + this.s = null; + this.hV = h; + }; + + /** + * set value by a OID name + * @name setValueName + * @memberOf KJUR.asn1.DERObjectIdentifier# + * @function + * @param {String} oidName OID name (ex. 'serverAuth') + * @since 1.0.1 + * @description + * OID name shall be defined in 'KJUR.asn1.x509.OID.name2oidList'. + * Otherwise raise error. + * @example + * o = new KJUR.asn1.DERObjectIdentifier(); + * o.setValueName("serverAuth"); + */ + this.setValueName = function(oidName) { + var oid = KJUR.asn1.x509.OID.name2oid(oidName); + if (oid !== '') { + this.setValueOidString(oid); + } else { + throw "DERObjectIdentifier oidName undefined: " + oidName; + } + }; + + this.getFreshValueHex = function() { + return this.hV; + }; + + if (params !== undefined) { + if (typeof params === "string") { + if (params.match(/^[0-2].[0-9.]+$/)) { + this.setValueOidString(params); + } else { + this.setValueName(params); + } + } else if (params.oid !== undefined) { + this.setValueOidString(params.oid); + } else if (params.hex !== undefined) { + this.setValueHex(params.hex); + } else if (params.name !== undefined) { + this.setValueName(params.name); + } + } +}; +YAHOO.lang.extend(KJUR.asn1.DERObjectIdentifier, KJUR.asn1.ASN1Object); + +// ******************************************************************** +/** + * class for ASN.1 DER Enumerated + * @name KJUR.asn1.DEREnumerated + * @class class for ASN.1 DER Enumerated + * @extends KJUR.asn1.ASN1Object + * @description + *
+ * As for argument 'params' for constructor, you can specify one of + * following properties: + *
    + *
  • int - specify initial ASN.1 value(V) by integer value
  • + *
  • hex - specify initial ASN.1 value(V) by a hexadecimal string
  • + *
+ * NOTE: 'params' can be omitted. + * @example + * new KJUR.asn1.DEREnumerated(123); + * new KJUR.asn1.DEREnumerated({int: 123}); + * new KJUR.asn1.DEREnumerated({hex: '1fad'}); + */ +KJUR.asn1.DEREnumerated = function(params) { + KJUR.asn1.DEREnumerated.superclass.constructor.call(this); + this.hT = "0a"; + + /** + * set value by Tom Wu's BigInteger object + * @name setByBigInteger + * @memberOf KJUR.asn1.DEREnumerated# + * @function + * @param {BigInteger} bigIntegerValue to set + */ + this.setByBigInteger = function(bigIntegerValue) { + this.hTLV = null; + this.isModified = true; + this.hV = KJUR.asn1.ASN1Util.bigIntToMinTwosComplementsHex(bigIntegerValue); + }; + + /** + * set value by integer value + * @name setByInteger + * @memberOf KJUR.asn1.DEREnumerated# + * @function + * @param {Integer} integer value to set + */ + this.setByInteger = function(intValue) { + var bi = new BigInteger(String(intValue), 10); + this.setByBigInteger(bi); + }; + + /** + * set value by integer value + * @name setValueHex + * @memberOf KJUR.asn1.DEREnumerated# + * @function + * @param {String} hexadecimal string of integer value + * @description + *
+ * NOTE: Value shall be represented by minimum octet length of + * two's complement representation. + */ + this.setValueHex = function(newHexString) { + this.hV = newHexString; + }; + + this.getFreshValueHex = function() { + return this.hV; + }; + + if (typeof params != "undefined") { + if (typeof params['int'] != "undefined") { + this.setByInteger(params['int']); + } else if (typeof params == "number") { + this.setByInteger(params); + } else if (typeof params['hex'] != "undefined") { + this.setValueHex(params['hex']); + } + } +}; +YAHOO.lang.extend(KJUR.asn1.DEREnumerated, KJUR.asn1.ASN1Object); + +// ******************************************************************** +/** + * class for ASN.1 DER UTF8String + * @name KJUR.asn1.DERUTF8String + * @class class for ASN.1 DER UTF8String + * @param {Array} params associative array of parameters (ex. {'str': 'aaa'}) + * @extends KJUR.asn1.DERAbstractString + * @description + * @see KJUR.asn1.DERAbstractString - superclass + */ +KJUR.asn1.DERUTF8String = function(params) { + KJUR.asn1.DERUTF8String.superclass.constructor.call(this, params); + this.hT = "0c"; +}; +YAHOO.lang.extend(KJUR.asn1.DERUTF8String, KJUR.asn1.DERAbstractString); + +// ******************************************************************** +/** + * class for ASN.1 DER NumericString + * @name KJUR.asn1.DERNumericString + * @class class for ASN.1 DER NumericString + * @param {Array} params associative array of parameters (ex. {'str': 'aaa'}) + * @extends KJUR.asn1.DERAbstractString + * @description + * @see KJUR.asn1.DERAbstractString - superclass + */ +KJUR.asn1.DERNumericString = function(params) { + KJUR.asn1.DERNumericString.superclass.constructor.call(this, params); + this.hT = "12"; +}; +YAHOO.lang.extend(KJUR.asn1.DERNumericString, KJUR.asn1.DERAbstractString); + +// ******************************************************************** +/** + * class for ASN.1 DER PrintableString + * @name KJUR.asn1.DERPrintableString + * @class class for ASN.1 DER PrintableString + * @param {Array} params associative array of parameters (ex. {'str': 'aaa'}) + * @extends KJUR.asn1.DERAbstractString + * @description + * @see KJUR.asn1.DERAbstractString - superclass + */ +KJUR.asn1.DERPrintableString = function(params) { + KJUR.asn1.DERPrintableString.superclass.constructor.call(this, params); + this.hT = "13"; +}; +YAHOO.lang.extend(KJUR.asn1.DERPrintableString, KJUR.asn1.DERAbstractString); + +// ******************************************************************** +/** + * class for ASN.1 DER TeletexString + * @name KJUR.asn1.DERTeletexString + * @class class for ASN.1 DER TeletexString + * @param {Array} params associative array of parameters (ex. {'str': 'aaa'}) + * @extends KJUR.asn1.DERAbstractString + * @description + * @see KJUR.asn1.DERAbstractString - superclass + */ +KJUR.asn1.DERTeletexString = function(params) { + KJUR.asn1.DERTeletexString.superclass.constructor.call(this, params); + this.hT = "14"; +}; +YAHOO.lang.extend(KJUR.asn1.DERTeletexString, KJUR.asn1.DERAbstractString); + +// ******************************************************************** +/** + * class for ASN.1 DER IA5String + * @name KJUR.asn1.DERIA5String + * @class class for ASN.1 DER IA5String + * @param {Array} params associative array of parameters (ex. {'str': 'aaa'}) + * @extends KJUR.asn1.DERAbstractString + * @description + * @see KJUR.asn1.DERAbstractString - superclass + */ +KJUR.asn1.DERIA5String = function(params) { + KJUR.asn1.DERIA5String.superclass.constructor.call(this, params); + this.hT = "16"; +}; +YAHOO.lang.extend(KJUR.asn1.DERIA5String, KJUR.asn1.DERAbstractString); + +// ******************************************************************** +/** + * class for ASN.1 DER UTCTime + * @name KJUR.asn1.DERUTCTime + * @class class for ASN.1 DER UTCTime + * @param {Array} params associative array of parameters (ex. {'str': '130430235959Z'}) + * @extends KJUR.asn1.DERAbstractTime + * @description + *
+ * As for argument 'params' for constructor, you can specify one of + * following properties: + *
    + *
  • str - specify initial ASN.1 value(V) by a string (ex.'130430235959Z')
  • + *
  • hex - specify initial ASN.1 value(V) by a hexadecimal string
  • + *
  • date - specify Date object.
  • + *
+ * NOTE: 'params' can be omitted. + *

EXAMPLES

+ * @example + * d1 = new KJUR.asn1.DERUTCTime(); + * d1.setString('130430125959Z'); + * + * d2 = new KJUR.asn1.DERUTCTime({'str': '130430125959Z'}); + * d3 = new KJUR.asn1.DERUTCTime({'date': new Date(Date.UTC(2015, 0, 31, 0, 0, 0, 0))}); + * d4 = new KJUR.asn1.DERUTCTime('130430125959Z'); + */ +KJUR.asn1.DERUTCTime = function(params) { + KJUR.asn1.DERUTCTime.superclass.constructor.call(this, params); + this.hT = "17"; + + /** + * set value by a Date object
+ * @name setByDate + * @memberOf KJUR.asn1.DERUTCTime# + * @function + * @param {Date} dateObject Date object to set ASN.1 value(V) + * @example + * o = new KJUR.asn1.DERUTCTime(); + * o.setByDate(new Date("2016/12/31")); + */ + this.setByDate = function(dateObject) { + this.hTLV = null; + this.isModified = true; + this.date = dateObject; + this.s = this.formatDate(this.date, 'utc'); + this.hV = stohex(this.s); + }; + + this.getFreshValueHex = function() { + if (typeof this.date == "undefined" && typeof this.s == "undefined") { + this.date = new Date(); + this.s = this.formatDate(this.date, 'utc'); + this.hV = stohex(this.s); + } + return this.hV; + }; + + if (params !== undefined) { + if (params.str !== undefined) { + this.setString(params.str); + } else if (typeof params == "string" && params.match(/^[0-9]{12}Z$/)) { + this.setString(params); + } else if (params.hex !== undefined) { + this.setStringHex(params.hex); + } else if (params.date !== undefined) { + this.setByDate(params.date); + } + } +}; +YAHOO.lang.extend(KJUR.asn1.DERUTCTime, KJUR.asn1.DERAbstractTime); + +// ******************************************************************** +/** + * class for ASN.1 DER GeneralizedTime + * @name KJUR.asn1.DERGeneralizedTime + * @class class for ASN.1 DER GeneralizedTime + * @param {Array} params associative array of parameters (ex. {'str': '20130430235959Z'}) + * @property {Boolean} withMillis flag to show milliseconds or not + * @extends KJUR.asn1.DERAbstractTime + * @description + *
+ * As for argument 'params' for constructor, you can specify one of + * following properties: + *
    + *
  • str - specify initial ASN.1 value(V) by a string (ex.'20130430235959Z')
  • + *
  • hex - specify initial ASN.1 value(V) by a hexadecimal string
  • + *
  • date - specify Date object.
  • + *
  • millis - specify flag to show milliseconds (from 1.0.6)
  • + *
+ * NOTE1: 'params' can be omitted. + * NOTE2: 'withMillis' property is supported from asn1 1.0.6. + */ +KJUR.asn1.DERGeneralizedTime = function(params) { + KJUR.asn1.DERGeneralizedTime.superclass.constructor.call(this, params); + this.hT = "18"; + this.withMillis = false; + + /** + * set value by a Date object + * @name setByDate + * @memberOf KJUR.asn1.DERGeneralizedTime# + * @function + * @param {Date} dateObject Date object to set ASN.1 value(V) + * @example + * When you specify UTC time, use 'Date.UTC' method like this:
+ * o1 = new DERUTCTime(); + * o1.setByDate(date); + * + * date = new Date(Date.UTC(2015, 0, 31, 23, 59, 59, 0)); #2015JAN31 23:59:59 + */ + this.setByDate = function(dateObject) { + this.hTLV = null; + this.isModified = true; + this.date = dateObject; + this.s = this.formatDate(this.date, 'gen', this.withMillis); + this.hV = stohex(this.s); + }; + + this.getFreshValueHex = function() { + if (this.date === undefined && this.s === undefined) { + this.date = new Date(); + this.s = this.formatDate(this.date, 'gen', this.withMillis); + this.hV = stohex(this.s); + } + return this.hV; + }; + + if (params !== undefined) { + if (params.str !== undefined) { + this.setString(params.str); + } else if (typeof params == "string" && params.match(/^[0-9]{14}Z$/)) { + this.setString(params); + } else if (params.hex !== undefined) { + this.setStringHex(params.hex); + } else if (params.date !== undefined) { + this.setByDate(params.date); + } + if (params.millis === true) { + this.withMillis = true; + } + } +}; +YAHOO.lang.extend(KJUR.asn1.DERGeneralizedTime, KJUR.asn1.DERAbstractTime); + +// ******************************************************************** +/** + * class for ASN.1 DER Sequence + * @name KJUR.asn1.DERSequence + * @class class for ASN.1 DER Sequence + * @extends KJUR.asn1.DERAbstractStructured + * @description + *
+ * As for argument 'params' for constructor, you can specify one of + * following properties: + *
    + *
  • array - specify array of ASN1Object to set elements of content
  • + *
+ * NOTE: 'params' can be omitted. + */ +KJUR.asn1.DERSequence = function(params) { + KJUR.asn1.DERSequence.superclass.constructor.call(this, params); + this.hT = "30"; + this.getFreshValueHex = function() { + var h = ''; + for (var i = 0; i < this.asn1Array.length; i++) { + var asn1Obj = this.asn1Array[i]; + h += asn1Obj.getEncodedHex(); + } + this.hV = h; + return this.hV; + }; +}; +YAHOO.lang.extend(KJUR.asn1.DERSequence, KJUR.asn1.DERAbstractStructured); + +// ******************************************************************** +/** + * class for ASN.1 DER Set + * @name KJUR.asn1.DERSet + * @class class for ASN.1 DER Set + * @extends KJUR.asn1.DERAbstractStructured + * @description + *
+ * As for argument 'params' for constructor, you can specify one of + * following properties: + *
    + *
  • array - specify array of ASN1Object to set elements of content
  • + *
  • sortflag - flag for sort (default: true). ASN.1 BER is not sorted in 'SET OF'.
  • + *
+ * NOTE1: 'params' can be omitted.
+ * NOTE2: sortflag is supported since 1.0.5. + */ +KJUR.asn1.DERSet = function(params) { + KJUR.asn1.DERSet.superclass.constructor.call(this, params); + this.hT = "31"; + this.sortFlag = true; // item shall be sorted only in ASN.1 DER + this.getFreshValueHex = function() { + var a = new Array(); + for (var i = 0; i < this.asn1Array.length; i++) { + var asn1Obj = this.asn1Array[i]; + a.push(asn1Obj.getEncodedHex()); + } + if (this.sortFlag == true) a.sort(); + this.hV = a.join(''); + return this.hV; + }; + + if (typeof params != "undefined") { + if (typeof params.sortflag != "undefined" && + params.sortflag == false) + this.sortFlag = false; + } +}; +YAHOO.lang.extend(KJUR.asn1.DERSet, KJUR.asn1.DERAbstractStructured); + +// ******************************************************************** +/** + * class for ASN.1 DER TaggedObject + * @name KJUR.asn1.DERTaggedObject + * @class class for ASN.1 DER TaggedObject + * @extends KJUR.asn1.ASN1Object + * @description + *
+ * Parameter 'tagNoNex' is ASN.1 tag(T) value for this object. + * For example, if you find '[1]' tag in a ASN.1 dump, + * 'tagNoHex' will be 'a1'. + *
+ * As for optional argument 'params' for constructor, you can specify *ANY* of + * following properties: + *
    + *
  • explicit - specify true if this is explicit tag otherwise false + * (default is 'true').
  • + *
  • tag - specify tag (default is 'a0' which means [0])
  • + *
  • obj - specify ASN1Object which is tagged
  • + *
+ * @example + * d1 = new KJUR.asn1.DERUTF8String({'str':'a'}); + * d2 = new KJUR.asn1.DERTaggedObject({'obj': d1}); + * hex = d2.getEncodedHex(); + */ +KJUR.asn1.DERTaggedObject = function(params) { + KJUR.asn1.DERTaggedObject.superclass.constructor.call(this); + this.hT = "a0"; + this.hV = ''; + this.isExplicit = true; + this.asn1Object = null; + + /** + * set value by an ASN1Object + * @name setString + * @memberOf KJUR.asn1.DERTaggedObject# + * @function + * @param {Boolean} isExplicitFlag flag for explicit/implicit tag + * @param {Integer} tagNoHex hexadecimal string of ASN.1 tag + * @param {ASN1Object} asn1Object ASN.1 to encapsulate + */ + this.setASN1Object = function(isExplicitFlag, tagNoHex, asn1Object) { + this.hT = tagNoHex; + this.isExplicit = isExplicitFlag; + this.asn1Object = asn1Object; + if (this.isExplicit) { + this.hV = this.asn1Object.getEncodedHex(); + this.hTLV = null; + this.isModified = true; + } else { + this.hV = null; + this.hTLV = asn1Object.getEncodedHex(); + this.hTLV = this.hTLV.replace(/^../, tagNoHex); + this.isModified = false; + } + }; + + this.getFreshValueHex = function() { + return this.hV; + }; + + if (typeof params != "undefined") { + if (typeof params['tag'] != "undefined") { + this.hT = params['tag']; + } + if (typeof params['explicit'] != "undefined") { + this.isExplicit = params['explicit']; + } + if (typeof params['obj'] != "undefined") { + this.asn1Object = params['obj']; + this.setASN1Object(this.isExplicit, this.hT, this.asn1Object); + } + } +}; +YAHOO.lang.extend(KJUR.asn1.DERTaggedObject, KJUR.asn1.ASN1Object); diff --git a/source/asn1hex-1.1.js b/source/asn1hex-1.1.js new file mode 100644 index 0000000..a2f669c --- /dev/null +++ b/source/asn1hex-1.1.js @@ -0,0 +1,709 @@ +/* asn1hex-1.2.0.js (c) 2012-2017 Kenji Urushima | kjur.github.com/jsrsasign/license + */ +/* + * asn1hex.js - Hexadecimal represented ASN.1 string library + * + * Copyright (c) 2010-2017 Kenji Urushima (kenji.urushima@gmail.com) + * + * This software is licensed under the terms of the MIT License. + * https://kjur.github.io/jsrsasign/license/ + * + * The above copyright and license notice shall be + * included in all copies or substantial portions of the Software. + */ + +/** + * @fileOverview + * @name asn1hex-1.1.js + * @author Kenji Urushima kenji.urushima@gmail.com + * @version asn1hex 1.2.0 (2017-Jun-24) + * @license MIT License + */ + +/* + * MEMO: + * f('3082025b02...', 2) ... 82025b ... 3bytes + * f('020100', 2) ... 01 ... 1byte + * f('0203001...', 2) ... 03 ... 1byte + * f('02818003...', 2) ... 8180 ... 2bytes + * f('3080....0000', 2) ... 80 ... -1 + * + * Requirements: + * - ASN.1 type octet length MUST be 1. + * (i.e. ASN.1 primitives like SET, SEQUENCE, INTEGER, OCTETSTRING ...) + */ + +/** + * ASN.1 DER encoded hexadecimal string utility class + * @name ASN1HEX + * @class ASN.1 DER encoded hexadecimal string utility class + * @since jsrsasign 1.1 + * @description + * This class provides a parser for hexadecimal string of + * DER encoded ASN.1 binary data. + * Here are major methods of this class. + *
    + *
  • ACCESS BY POSITION + *
      + *
    • {@link ASN1HEX.getTLV} - get ASN.1 TLV at specified position
    • + *
    • {@link ASN1HEX.getV} - get ASN.1 V at specified position
    • + *
    • {@link ASN1HEX.getVlen} - get integer ASN.1 L at specified position
    • + *
    • {@link ASN1HEX.getVidx} - get ASN.1 V position from its ASN.1 TLV position
    • + *
    • {@link ASN1HEX.getL} - get hexadecimal ASN.1 L at specified position
    • + *
    • {@link ASN1HEX.getLblen} - get byte length for ASN.1 L(length) bytes
    • + *
    + *
  • + *
  • ACCESS FOR CHILD ITEM + *
      + *
    • {@link ASN1HEX.getNthChildIndex_AtObj} - get nth child index at specified position
    • + *
    • {@link ASN1HEX.getPosArrayOfChildren_AtObj} - get indexes of children
    • + *
    • {@link ASN1HEX.getPosOfNextSibling_AtObj} - get position of next sibling
    • + *
    + *
  • + *
  • ACCESS NESTED ASN.1 STRUCTURE + *
      + *
    • {@link ASN1HEX.getTLVbyList} - get ASN.1 TLV at specified list index
    • + *
    • {@link ASN1HEX.getVbyList} - get ASN.1 V at specified nth list index with checking expected tag
    • + *
    • {@link ASN1HEX.getIdxbyList} - get index at specified list index
    • + *
    + *
  • + *
  • UTILITIES + *
      + *
    • {@link ASN1HEX.dump} - dump ASN.1 structure
    • + *
    • {@link ASN1HEX.isASN1HEX} - check whether ASN.1 hexadecimal string or not
    • + *
    • {@link ASN1HEX.hextooidstr} - convert hexadecimal string of OID to dotted integer list
    • + *
    + *
  • + *
+ */ +var ASN1HEX = new function() { +}; + +/** + * get byte length for ASN.1 L(length) bytes
+ * @name getLblen + * @memberOf ASN1HEX + * @function + * @param {String} s hexadecimal string of ASN.1 DER encoded data + * @param {Number} idx string index + * @return byte length for ASN.1 L(length) bytes + * @since jsrsasign 7.2.0 asn1hex 1.1.11 + * @example + * ASN1HEX.getLblen('020100', 0) → 1 for '01' + * ASN1HEX.getLblen('020200', 0) → 1 for '02' + * ASN1HEX.getLblen('02818003...', 0) → 2 for '8180' + * ASN1HEX.getLblen('0282025b03...', 0) → 3 for '82025b' + * ASN1HEX.getLblen('0280020100...', 0) → -1 for '80' BER indefinite length + * ASN1HEX.getLblen('02ffab...', 0) → -2 for malformed ASN.1 length + */ +ASN1HEX.getLblen = function(s, idx) { + if (s.substr(idx + 2, 1) != '8') return 1; + var i = parseInt(s.substr(idx + 3, 1)); + if (i == 0) return -1; // length octet '80' indefinite length + if (0 < i && i < 10) return i + 1; // including '8?' octet; + return -2; // malformed format +}; + +/** + * get hexadecimal string for ASN.1 L(length) bytes
+ * @name getL + * @memberOf ASN1HEX + * @function + * @param {String} s hexadecimal string of ASN.1 DER encoded data + * @param {Number} idx string index to get L of ASN.1 object + * @return {String} hexadecimal string for ASN.1 L(length) bytes + * @since jsrsasign 7.2.0 asn1hex 1.1.11 + */ +ASN1HEX.getL = function(s, idx) { + var len = ASN1HEX.getLblen(s, idx); + if (len < 1) return ''; + return s.substr(idx + 2, len * 2); +}; + +/** + * get integer value of ASN.1 length for ASN.1 data
+ * @name getVblen + * @memberOf ASN1HEX + * @function + * @param {String} s hexadecimal string of ASN.1 DER encoded data + * @param {Number} idx string index + * @return ASN.1 L(length) integer value + * @since jsrsasign 7.2.0 asn1hex 1.1.11 + */ +/* + getting ASN.1 length value at the position 'idx' of + hexa decimal string 's'. + f('3082025b02...', 0) ... 82025b ... ??? + f('020100', 0) ... 01 ... 1 + f('0203001...', 0) ... 03 ... 3 + f('02818003...', 0) ... 8180 ... 128 + */ +ASN1HEX.getVblen = function(s, idx) { + var hLen, bi; + hLen = ASN1HEX.getL(s, idx); + if (hLen == '') return -1; + if (hLen.substr(0, 1) === '8') { + bi = new BigInteger(hLen.substr(2), 16); + } else { + bi = new BigInteger(hLen, 16); + } + return bi.intValue(); +}; + +/** + * get ASN.1 value starting string position for ASN.1 object refered by index 'idx'. + * @name getVidx + * @memberOf ASN1HEX + * @function + * @param {String} s hexadecimal string of ASN.1 DER encoded data + * @param {Number} idx string index + * @since jsrsasign 7.2.0 asn1hex 1.1.11 + */ +ASN1HEX.getVidx = function(s, idx) { + var l_len = ASN1HEX.getLblen(s, idx); + if (l_len < 0) return l_len; + return idx + (l_len + 1) * 2; +}; + +/** + * get hexadecimal string of ASN.1 V(value)
+ * @name getV + * @memberOf ASN1HEX + * @function + * @param {String} s hexadecimal string of ASN.1 DER encoded data + * @param {Number} idx string index + * @return {String} hexadecimal string of ASN.1 value. + * @since jsrsasign 7.2.0 asn1hex 1.1.11 + */ +ASN1HEX.getV = function(s, idx) { + var idx1 = ASN1HEX.getVidx(s, idx); + var blen = ASN1HEX.getVblen(s, idx); + return s.substr(idx1, blen * 2); +}; + +/** + * get hexadecimal string of ASN.1 TLV at
+ * @name getTLV + * @memberOf ASN1HEX + * @function + * @param {String} s hexadecimal string of ASN.1 DER encoded data + * @param {Number} idx string index + * @return {String} hexadecimal string of ASN.1 TLV. + * @since jsrsasign 7.2.0 asn1hex 1.1.11 + */ +ASN1HEX.getTLV = function(s, idx) { + return s.substr(idx, 2) + ASN1HEX.getL(s, idx) + ASN1HEX.getV(s, idx); +}; + +// ========== sibling methods ================================ + +/** + * get next sibling starting index for ASN.1 object string
+ * @name getNextSiblingIdx + * @memberOf ASN1HEX + * @function + * @param {String} s hexadecimal string of ASN.1 DER encoded data + * @param {Number} idx string index + * @return next sibling starting index for ASN.1 object string + * @since jsrsasign 7.2.0 asn1hex 1.1.11 + * @example + * SEQUENCE { INTEGER 3, INTEGER 4 } + * 3006 + * 020103 :idx=4 + * 020104 :next sibling idx=10 + * getNextSiblingIdx("3006020103020104", 4) & rarr 10 + */ +ASN1HEX.getNextSiblingIdx = function(s, idx) { + var idx1 = ASN1HEX.getVidx(s, idx); + var blen = ASN1HEX.getVblen(s, idx); + return idx1 + blen * 2; +}; + +// ========== children methods =============================== +/** + * get array of string indexes of child ASN.1 objects
+ * @name getChildIdx + * @memberOf ASN1HEX + * @function + * @param {String} h hexadecimal string of ASN.1 DER encoded data + * @param {Number} pos start string index of ASN.1 object + * @return {Array of Number} array of indexes for childen of ASN.1 objects + * @since jsrsasign 7.2.0 asn1hex 1.1.11 + * @description + * This method returns array of integers for a concatination of ASN.1 objects + * in a ASN.1 value. As for BITSTRING, one byte of unusedbits is skipped. + * As for other ASN.1 simple types such as INTEGER, OCTET STRING or PRINTABLE STRING, + * it returns a array of a string index of its ASN.1 value.
+ * NOTE: Since asn1hex 1.1.7 of jsrsasign 6.1.2, Encapsulated BitString is supported. + * @example + * ASN1HEX.getChildIdx("0203012345", 0) ⇒ [4] // INTEGER 012345 + * ASN1HEX.getChildIdx("1303616161", 0) ⇒ [4] // PrintableString aaa + * ASN1HEX.getChildIdx("030300ffff", 0) ⇒ [6] // BITSTRING ffff (unusedbits=00a) + * ASN1HEX.getChildIdx("3006020104020105", 0) ⇒ [4, 10] // SEQUENCE(INT4,INT5) + */ +ASN1HEX.getChildIdx = function(h, pos) { + var _ASN1HEX = ASN1HEX; + var a = new Array(); + var p0 = _ASN1HEX.getVidx(h, pos); + if (h.substr(pos, 2) == "03") { + a.push(p0 + 2); // BITSTRING value without unusedbits + } else { + a.push(p0); + } + + var blen = _ASN1HEX.getVblen(h, pos); + var p = p0; + var k = 0; + while (1) { + var pNext = _ASN1HEX.getNextSiblingIdx(h, p); + if (pNext == null || (pNext - p0 >= (blen * 2))) break; + if (k >= 200) break; + + a.push(pNext); + p = pNext; + + k++; + } + + return a; +}; + +/** + * get string index of nth child object of ASN.1 object refered by h, idx
+ * @name getNthChildIdx + * @memberOf ASN1HEX + * @function + * @param {String} h hexadecimal string of ASN.1 DER encoded data + * @param {Number} idx start string index of ASN.1 object + * @param {Number} nth for child + * @return {Number} string index of nth child. + * @since jsrsasign 7.2.0 asn1hex 1.1.11 + */ +ASN1HEX.getNthChildIdx = function(h, idx, nth) { + var a = ASN1HEX.getChildIdx(h, idx); + return a[nth]; +}; + +// ========== decendant methods ============================== +/** + * get string index of nth child object of ASN.1 object refered by h, idx
+ * @name getIdxbyList + * @memberOf ASN1HEX + * @function + * @param {String} h hexadecimal string of ASN.1 DER encoded data + * @param {Number} currentIndex start string index of ASN.1 object + * @param {Array of Number} nthList array list of nth + * @param {String} checkingTag (OPTIONAL) string of expected ASN.1 tag for nthList + * @return {Number} string index refered by nthList + * @since jsrsasign 7.1.4 asn1hex 1.1.10. + * @description + * @example + * The "nthList" is a index list of structured ASN.1 object + * reference. Here is a sample structure and "nthList"s which + * refers each objects. + * + * SQUENCE - + * SEQUENCE - [0] + * IA5STRING 000 - [0, 0] + * UTF8STRING 001 - [0, 1] + * SET - [1] + * IA5STRING 010 - [1, 0] + * UTF8STRING 011 - [1, 1] + */ +ASN1HEX.getIdxbyList = function(h, currentIndex, nthList, checkingTag) { + var _ASN1HEX = ASN1HEX; + var firstNth, a; + if (nthList.length == 0) { + if (checkingTag !== undefined) { + if (h.substr(currentIndex, 2) !== checkingTag) { + throw "checking tag doesn't match: " + + h.substr(currentIndex, 2) + "!=" + checkingTag; + } + } + return currentIndex; + } + firstNth = nthList.shift(); + a = _ASN1HEX.getChildIdx(h, currentIndex); + return _ASN1HEX.getIdxbyList(h, a[firstNth], nthList, checkingTag); +}; + +/** + * get ASN.1 TLV by nthList
+ * @name getTLVbyList + * @memberOf ASN1HEX + * @function + * @param {String} h hexadecimal string of ASN.1 structure + * @param {Integer} currentIndex string index to start searching in hexadecimal string "h" + * @param {Array} nthList array of nth list index + * @param {String} checkingTag (OPTIONAL) string of expected ASN.1 tag for nthList + * @since jsrsasign 7.1.4 asn1hex 1.1.10 + * @description + * This static method is to get a ASN.1 value which specified "nthList" position + * with checking expected tag "checkingTag". + */ +ASN1HEX.getTLVbyList = function(h, currentIndex, nthList, checkingTag) { + var _ASN1HEX = ASN1HEX; + var idx = _ASN1HEX.getIdxbyList(h, currentIndex, nthList); + if (idx === undefined) { + throw "can't find nthList object"; + } + if (checkingTag !== undefined) { + if (h.substr(idx, 2) != checkingTag) { + throw "checking tag doesn't match: " + + h.substr(idx,2) + "!=" + checkingTag; + } + } + return _ASN1HEX.getTLV(h, idx); +}; + +/** + * get ASN.1 value by nthList
+ * @name getVbyList + * @memberOf ASN1HEX + * @function + * @param {String} h hexadecimal string of ASN.1 structure + * @param {Integer} currentIndex string index to start searching in hexadecimal string "h" + * @param {Array} nthList array of nth list index + * @param {String} checkingTag (OPTIONAL) string of expected ASN.1 tag for nthList + * @param {Boolean} removeUnusedbits (OPTIONAL) flag for remove first byte for value (DEFAULT false) + * @since asn1hex 1.1.4 + * @description + * This static method is to get a ASN.1 value which specified "nthList" position + * with checking expected tag "checkingTag". + * NOTE: 'removeUnusedbits' flag has been supported since + * jsrsasign 7.1.14 asn1hex 1.1.10. + */ +ASN1HEX.getVbyList = function(h, currentIndex, nthList, checkingTag, removeUnusedbits) { + var _ASN1HEX = ASN1HEX; + var idx, v; + idx = _ASN1HEX.getIdxbyList(h, currentIndex, nthList, checkingTag); + + if (idx === undefined) { + throw "can't find nthList object"; + } + + v = _ASN1HEX.getV(h, idx); + if (removeUnusedbits === true) v = v.substr(2); + return v; +}; + +/** + * get OID string from hexadecimal encoded value
+ * @name hextooidstr + * @memberOf ASN1HEX + * @function + * @param {String} hex hexadecmal string of ASN.1 DER encoded OID value + * @return {String} OID string (ex. '1.2.3.4.567') + * @since asn1hex 1.1.5 + */ +ASN1HEX.hextooidstr = function(hex) { + var zeroPadding = function(s, len) { + if (s.length >= len) return s; + return new Array(len - s.length + 1).join('0') + s; + }; + + var a = []; + + // a[0], a[1] + var hex0 = hex.substr(0, 2); + var i0 = parseInt(hex0, 16); + a[0] = new String(Math.floor(i0 / 40)); + a[1] = new String(i0 % 40); + + // a[2]..a[n] + var hex1 = hex.substr(2); + var b = []; + for (var i = 0; i < hex1.length / 2; i++) { + b.push(parseInt(hex1.substr(i * 2, 2), 16)); + } + var c = []; + var cbin = ""; + for (var i = 0; i < b.length; i++) { + if (b[i] & 0x80) { + cbin = cbin + zeroPadding((b[i] & 0x7f).toString(2), 7); + } else { + cbin = cbin + zeroPadding((b[i] & 0x7f).toString(2), 7); + c.push(new String(parseInt(cbin, 2))); + cbin = ""; + } + } + + var s = a.join("."); + if (c.length > 0) s = s + "." + c.join("."); + return s; +}; + +/** + * get string of simple ASN.1 dump from hexadecimal ASN.1 data
+ * @name dump + * @memberOf ASN1HEX + * @function + * @param {Object} hexOrObj hexadecmal string of ASN.1 data or ASN1Object object + * @param {Array} flags associative array of flags for dump (OPTION) + * @param {Number} idx string index for starting dump (OPTION) + * @param {String} indent indent string (OPTION) + * @return {String} string of simple ASN.1 dump + * @since jsrsasign 4.8.3 asn1hex 1.1.6 + * @description + * This method will get an ASN.1 dump from + * hexadecmal string of ASN.1 DER encoded data. + * Here are features: + *
    + *
  • ommit long hexadecimal string
  • + *
  • dump encapsulated OCTET STRING (good for X.509v3 extensions)
  • + *
  • structured/primitive context specific tag support (i.e. [0], [3] ...)
  • + *
  • automatic decode for implicit primitive context specific tag + * (good for X.509v3 extension value) + *
      + *
    • if hex starts '68747470'(i.e. http) it is decoded as utf8 encoded string.
    • + *
    • if it is in 'subjectAltName' extension value and is '[2]'(dNSName) tag + * value will be encoded as utf8 string
    • + *
    • otherwise it shows as hexadecimal string
    • + *
    + *
  • + *
+ * NOTE1: Argument {@link KJUR.asn1.ASN1Object} object is supported since + * jsrsasign 6.2.4 asn1hex 1.0.8 + * @example + * // 1) ASN.1 INTEGER + * ASN1HEX.dump('0203012345') + * ↓ + * INTEGER 012345 + * + * // 2) ASN.1 Object Identifier + * ASN1HEX.dump('06052b0e03021a') + * ↓ + * ObjectIdentifier sha1 (1 3 14 3 2 26) + * + * // 3) ASN.1 SEQUENCE + * ASN1HEX.dump('3006020101020102') + * ↓ + * SEQUENCE + * INTEGER 01 + * INTEGER 02 + * + * // 4) ASN.1 SEQUENCE since jsrsasign 6.2.4 + * o = KJUR.asn1.ASN1Util.newObject({seq: [{int: 1}, {int: 2}]}); + * ASN1HEX.dump(o) + * ↓ + * SEQUENCE + * INTEGER 01 + * INTEGER 02 + * // 5) ASN.1 DUMP FOR X.509 CERTIFICATE + * ASN1HEX.dump(pemtohex(certPEM)) + * ↓ + * SEQUENCE + * SEQUENCE + * [0] + * INTEGER 02 + * INTEGER 0c009310d206dbe337553580118ddc87 + * SEQUENCE + * ObjectIdentifier SHA256withRSA (1 2 840 113549 1 1 11) + * NULL + * SEQUENCE + * SET + * SEQUENCE + * ObjectIdentifier countryName (2 5 4 6) + * PrintableString 'US' + * : + */ +ASN1HEX.dump = function(hexOrObj, flags, idx, indent) { + var _ASN1HEX = ASN1HEX; + var _getV = _ASN1HEX.getV; + var _dump = _ASN1HEX.dump; + var _getChildIdx = _ASN1HEX.getChildIdx; + + var hex = hexOrObj; + if (hexOrObj instanceof KJUR.asn1.ASN1Object) + hex = hexOrObj.getEncodedHex(); + + var _skipLongHex = function(hex, limitNumOctet) { + if (hex.length <= limitNumOctet * 2) { + return hex; + } else { + var s = hex.substr(0, limitNumOctet) + + "..(total " + hex.length / 2 + "bytes).." + + hex.substr(hex.length - limitNumOctet, limitNumOctet); + return s; + }; + }; + + if (flags === undefined) flags = { "ommit_long_octet": 32 }; + if (idx === undefined) idx = 0; + if (indent === undefined) indent = ""; + var skipLongHex = flags.ommit_long_octet; + + if (hex.substr(idx, 2) == "01") { + var v = _getV(hex, idx); + if (v == "00") { + return indent + "BOOLEAN FALSE\n"; + } else { + return indent + "BOOLEAN TRUE\n"; + } + } + if (hex.substr(idx, 2) == "02") { + var v = _getV(hex, idx); + return indent + "INTEGER " + _skipLongHex(v, skipLongHex) + "\n"; + } + if (hex.substr(idx, 2) == "03") { + var v = _getV(hex, idx); + return indent + "BITSTRING " + _skipLongHex(v, skipLongHex) + "\n"; + } + if (hex.substr(idx, 2) == "04") { + var v = _getV(hex, idx); + if (_ASN1HEX.isASN1HEX(v)) { + var s = indent + "OCTETSTRING, encapsulates\n"; + s = s + _dump(v, flags, 0, indent + " "); + return s; + } else { + return indent + "OCTETSTRING " + _skipLongHex(v, skipLongHex) + "\n"; + } + } + if (hex.substr(idx, 2) == "05") { + return indent + "NULL\n"; + } + if (hex.substr(idx, 2) == "06") { + var hV = _getV(hex, idx); + var oidDot = KJUR.asn1.ASN1Util.oidHexToInt(hV); + var oidName = KJUR.asn1.x509.OID.oid2name(oidDot); + var oidSpc = oidDot.replace(/\./g, ' '); + if (oidName != '') { + return indent + "ObjectIdentifier " + oidName + " (" + oidSpc + ")\n"; + } else { + return indent + "ObjectIdentifier (" + oidSpc + ")\n"; + } + } + if (hex.substr(idx, 2) == "0c") { + return indent + "UTF8String '" + hextoutf8(_getV(hex, idx)) + "'\n"; + } + if (hex.substr(idx, 2) == "13") { + return indent + "PrintableString '" + hextoutf8(_getV(hex, idx)) + "'\n"; + } + if (hex.substr(idx, 2) == "14") { + return indent + "TeletexString '" + hextoutf8(_getV(hex, idx)) + "'\n"; + } + if (hex.substr(idx, 2) == "16") { + return indent + "IA5String '" + hextoutf8(_getV(hex, idx)) + "'\n"; + } + if (hex.substr(idx, 2) == "17") { + return indent + "UTCTime " + hextoutf8(_getV(hex, idx)) + "\n"; + } + if (hex.substr(idx, 2) == "18") { + return indent + "GeneralizedTime " + hextoutf8(_getV(hex, idx)) + "\n"; + } + if (hex.substr(idx, 2) == "30") { + if (hex.substr(idx, 4) == "3000") { + return indent + "SEQUENCE {}\n"; + } + + var s = indent + "SEQUENCE\n"; + var aIdx = _getChildIdx(hex, idx); + + var flagsTemp = flags; + + if ((aIdx.length == 2 || aIdx.length == 3) && + hex.substr(aIdx[0], 2) == "06" && + hex.substr(aIdx[aIdx.length - 1], 2) == "04") { // supposed X.509v3 extension + var oidName = _ASN1HEX.oidname(_getV(hex, aIdx[0])); + var flagsClone = JSON.parse(JSON.stringify(flags)); + flagsClone.x509ExtName = oidName; + flagsTemp = flagsClone; + } + + for (var i = 0; i < aIdx.length; i++) { + s = s + _dump(hex, flagsTemp, aIdx[i], indent + " "); + } + return s; + } + if (hex.substr(idx, 2) == "31") { + var s = indent + "SET\n"; + var aIdx = _getChildIdx(hex, idx); + for (var i = 0; i < aIdx.length; i++) { + s = s + _dump(hex, flags, aIdx[i], indent + " "); + } + return s; + } + var tag = parseInt(hex.substr(idx, 2), 16); + if ((tag & 128) != 0) { // context specific + var tagNumber = tag & 31; + if ((tag & 32) != 0) { // structured tag + var s = indent + "[" + tagNumber + "]\n"; + var aIdx = _getChildIdx(hex, idx); + for (var i = 0; i < aIdx.length; i++) { + s = s + _dump(hex, flags, aIdx[i], indent + " "); + } + return s; + } else { // primitive tag + var v = _getV(hex, idx); + if (v.substr(0, 8) == "68747470") { // http + v = hextoutf8(v); + } + if (flags.x509ExtName === "subjectAltName" && + tagNumber == 2) { + v = hextoutf8(v); + } + + var s = indent + "[" + tagNumber + "] " + v + "\n"; + return s; + } + } + return indent + "UNKNOWN(" + hex.substr(idx, 2) + ") " + + _getV(hex, idx) + "\n"; +}; + +/** + * check wheather the string is ASN.1 hexadecimal string or not + * @name isASN1HEX + * @memberOf ASN1HEX + * @function + * @param {String} hex string to check whether it is hexadecmal string for ASN.1 DER or not + * @return {Boolean} true if it is hexadecimal string of ASN.1 data otherwise false + * @since jsrsasign 4.8.3 asn1hex 1.1.6 + * @description + * This method checks wheather the argument 'hex' is a hexadecimal string of + * ASN.1 data or not. + * @example + * ASN1HEX.isASN1HEX('0203012345') → true // PROPER ASN.1 INTEGER + * ASN1HEX.isASN1HEX('0203012345ff') → false // TOO LONG VALUE + * ASN1HEX.isASN1HEX('02030123') → false // TOO SHORT VALUE + * ASN1HEX.isASN1HEX('fa3bcd') → false // WRONG FOR ASN.1 + */ +ASN1HEX.isASN1HEX = function(hex) { + var _ASN1HEX = ASN1HEX; + if (hex.length % 2 == 1) return false; + + var intL = _ASN1HEX.getVblen(hex, 0); + var tV = hex.substr(0, 2); + var lV = _ASN1HEX.getL(hex, 0); + var hVLength = hex.length - tV.length - lV.length; + if (hVLength == intL * 2) return true; + + return false; +}; + +/** + * get hexacedimal string from PEM format data
+ * @name oidname + * @memberOf ASN1HEX + * @function + * @param {String} oidDotOrHex number dot notation(i.e. 1.2.3) or hexadecimal string for OID + * @return {String} name for OID + * @since jsrsasign 7.2.0 asn1hex 1.1.11 + * @description + * This static method gets a OID name for + * a specified string of number dot notation (i.e. 1.2.3) or + * hexadecimal string. + * @example + * ASN1HEX.oidname("2.5.29.37") → extKeyUsage + * ASN1HEX.oidname("551d25") → extKeyUsage + * ASN1HEX.oidname("0.1.2.3") → 0.1.2.3 // unknown + */ +ASN1HEX.oidname = function(oidDotOrHex) { + var _KJUR_asn1 = KJUR.asn1; + if (KJUR.lang.String.isHex(oidDotOrHex)) + oidDotOrHex = _KJUR_asn1.ASN1Util.oidHexToInt(oidDotOrHex); + var name = _KJUR_asn1.x509.OID.oid2name(oidDotOrHex); + if (name === "") name = oidDotOrHex; + return name; +}; + diff --git a/source/base64x-1.1.js b/source/base64x-1.1.js new file mode 100644 index 0000000..2770cbc --- /dev/null +++ b/source/base64x-1.1.js @@ -0,0 +1,1173 @@ +/* base64x-1.1.14 (c) 2012-2018 Kenji Urushima | kjur.github.com/jsrsasign/license + */ +/* + * base64x.js - Base64url and supplementary functions for Tom Wu's base64.js library + * + * version: 1.1.14 (2018-Apr-21) + * + * Copyright (c) 2012-2018 Kenji Urushima (kenji.urushima@gmail.com) + * + * This software is licensed under the terms of the MIT License. + * https://kjur.github.io/jsrsasign/license + * + * The above copyright and license notice shall be + * included in all copies or substantial portions of the Software. + */ + +/** + * @fileOverview + * @name base64x-1.1.js + * @author Kenji Urushima kenji.urushima@gmail.com + * @version jsrsasign 8.0.12 base64x 1.1.14 (2018-Apr-22) + * @since jsrsasign 2.1 + * @license MIT License + */ + +var KJUR; +if (typeof KJUR == "undefined" || !KJUR) KJUR = {}; +if (typeof KJUR.lang == "undefined" || !KJUR.lang) KJUR.lang = {}; + +/** + * String and its utility class
+ * This class provides some static utility methods for string. + * @class String and its utility class + * @author Kenji Urushima + * @version 1.0 (2016-Aug-05) + * @since base64x 1.1.7 jsrsasign 5.0.13 + * @description + *
+ * This class provides static methods for string utility. + *
+ *
STRING TYPE CHECKERS + *
+ *
    + *
  • {@link KJUR.lang.String.isInteger} - check whether argument is an integer
  • + *
  • {@link KJUR.lang.String.isHex} - check whether argument is a hexadecimal string
  • + *
  • {@link KJUR.lang.String.isBase64} - check whether argument is a Base64 encoded string
  • + *
  • {@link KJUR.lang.String.isBase64URL} - check whether argument is a Base64URL encoded string
  • + *
  • {@link KJUR.lang.String.isIntegerArray} - check whether argument is an array of integers
  • + *
+ *
+ */ +KJUR.lang.String = function() {}; + +/** + * Base64URL and supplementary functions for Tom Wu's base64.js library.
+ * This class is just provide information about global functions + * defined in 'base64x.js'. The 'base64x.js' script file provides + * global functions for converting following data each other. + *
    + *
  • (ASCII) String
  • + *
  • UTF8 String including CJK, Latin and other characters
  • + *
  • byte array
  • + *
  • hexadecimal encoded String
  • + *
  • Full URIComponent encoded String (such like "%69%94")
  • + *
  • Base64 encoded String
  • + *
  • Base64URL encoded String
  • + *
+ * All functions in 'base64x.js' are defined in {@link _global_} and not + * in this class. + * + * @class Base64URL and supplementary functions for Tom Wu's base64.js library + * @author Kenji Urushima + * @version 1.1 (07 May 2012) + * @requires base64.js + * @see 'jwjws'(JWS JavaScript Library) home page https://kjur.github.io/jsjws/ + * @see 'jwrsasign'(RSA Sign JavaScript Library) home page https://kjur.github.io/jsrsasign/ + */ +function Base64x() { +} + +// ==== string / byte array ================================ +/** + * convert a string to an array of character codes + * @name stoBA + * @function + * @param {String} s + * @return {Array of Numbers} + */ +function stoBA(s) { + var a = new Array(); + for (var i = 0; i < s.length; i++) { + a[i] = s.charCodeAt(i); + } + return a; +} + +/** + * convert an array of character codes to a string + * @name BAtos + * @function + * @param {Array of Numbers} a array of character codes + * @return {String} s + */ +function BAtos(a) { + var s = ""; + for (var i = 0; i < a.length; i++) { + s = s + String.fromCharCode(a[i]); + } + return s; +} + +// ==== byte array / hex ================================ +/** + * convert an array of bytes(Number) to hexadecimal string.
+ * @name BAtohex + * @function + * @param {Array of Numbers} a array of bytes + * @return {String} hexadecimal string + */ +function BAtohex(a) { + var s = ""; + for (var i = 0; i < a.length; i++) { + var hex1 = a[i].toString(16); + if (hex1.length == 1) hex1 = "0" + hex1; + s = s + hex1; + } + return s; +} + +// ==== string / hex ================================ +/** + * convert a ASCII string to a hexadecimal string of ASCII codes.
+ * NOTE: This can't be used for non ASCII characters. + * @name stohex + * @function + * @param {s} s ASCII string + * @return {String} hexadecimal string + */ +function stohex(s) { + return BAtohex(stoBA(s)); +} + +// ==== string / base64 ================================ +/** + * convert a ASCII string to a Base64 encoded string.
+ * NOTE: This can't be used for non ASCII characters. + * @name stob64 + * @function + * @param {s} s ASCII string + * @return {String} Base64 encoded string + */ +function stob64(s) { + return hex2b64(stohex(s)); +} + +// ==== string / base64url ================================ +/** + * convert a ASCII string to a Base64URL encoded string.
+ * NOTE: This can't be used for non ASCII characters. + * @name stob64u + * @function + * @param {s} s ASCII string + * @return {String} Base64URL encoded string + */ +function stob64u(s) { + return b64tob64u(hex2b64(stohex(s))); +} + +/** + * convert a Base64URL encoded string to a ASCII string.
+ * NOTE: This can't be used for Base64URL encoded non ASCII characters. + * @name b64utos + * @function + * @param {s} s Base64URL encoded string + * @return {String} ASCII string + */ +function b64utos(s) { + return BAtos(b64toBA(b64utob64(s))); +} + +// ==== base64 / base64url ================================ +/** + * convert a Base64 encoded string to a Base64URL encoded string.
+ * @name b64tob64u + * @function + * @param {String} s Base64 encoded string + * @return {String} Base64URL encoded string + * @example + * b64tob64u("ab+c3f/==") → "ab-c3f_" + */ +function b64tob64u(s) { + s = s.replace(/\=/g, ""); + s = s.replace(/\+/g, "-"); + s = s.replace(/\//g, "_"); + return s; +} + +/** + * convert a Base64URL encoded string to a Base64 encoded string.
+ * @name b64utob64 + * @function + * @param {String} s Base64URL encoded string + * @return {String} Base64 encoded string + * @example + * b64utob64("ab-c3f_") → "ab+c3f/==" + */ +function b64utob64(s) { + if (s.length % 4 == 2) s = s + "=="; + else if (s.length % 4 == 3) s = s + "="; + s = s.replace(/-/g, "+"); + s = s.replace(/_/g, "/"); + return s; +} + +// ==== hex / base64url ================================ +/** + * convert a hexadecimal string to a Base64URL encoded string.
+ * @name hextob64u + * @function + * @param {String} s hexadecimal string + * @return {String} Base64URL encoded string + * @description + * convert a hexadecimal string to a Base64URL encoded string. + * NOTE: If leading "0" is omitted and odd number length for + * hexadecimal leading "0" is automatically added. + */ +function hextob64u(s) { + if (s.length % 2 == 1) s = "0" + s; + return b64tob64u(hex2b64(s)); +} + +/** + * convert a Base64URL encoded string to a hexadecimal string.
+ * @name b64utohex + * @function + * @param {String} s Base64URL encoded string + * @return {String} hexadecimal string + */ +function b64utohex(s) { + return b64tohex(b64utob64(s)); +} + +// ==== utf8 / base64url ================================ + +/** + * convert a UTF-8 encoded string including CJK or Latin to a Base64URL encoded string.
+ * @name utf8tob64u + * @function + * @param {String} s UTF-8 encoded string + * @return {String} Base64URL encoded string + * @since 1.1 + */ + +/** + * convert a Base64URL encoded string to a UTF-8 encoded string including CJK or Latin.
+ * @name b64utoutf8 + * @function + * @param {String} s Base64URL encoded string + * @return {String} UTF-8 encoded string + * @since 1.1 + */ + +var utf8tob64u, b64utoutf8; + +if (typeof Buffer === 'function') { + utf8tob64u = function (s) { + return b64tob64u(new Buffer(s, 'utf8').toString('base64')); + }; + + b64utoutf8 = function (s) { + return new Buffer(b64utob64(s), 'base64').toString('utf8'); + }; +} else { + utf8tob64u = function (s) { + return hextob64u(uricmptohex(encodeURIComponentAll(s))); + }; + + b64utoutf8 = function (s) { + return decodeURIComponent(hextouricmp(b64utohex(s))); + }; +} + +// ==== utf8 / base64url ================================ +/** + * convert a UTF-8 encoded string including CJK or Latin to a Base64 encoded string.
+ * @name utf8tob64 + * @function + * @param {String} s UTF-8 encoded string + * @return {String} Base64 encoded string + * @since 1.1.1 + */ +function utf8tob64(s) { + return hex2b64(uricmptohex(encodeURIComponentAll(s))); +} + +/** + * convert a Base64 encoded string to a UTF-8 encoded string including CJK or Latin.
+ * @name b64toutf8 + * @function + * @param {String} s Base64 encoded string + * @return {String} UTF-8 encoded string + * @since 1.1.1 + */ +function b64toutf8(s) { + return decodeURIComponent(hextouricmp(b64tohex(s))); +} + +// ==== utf8 / hex ================================ +/** + * convert a UTF-8 encoded string including CJK or Latin to a hexadecimal encoded string.
+ * @name utf8tohex + * @function + * @param {String} s UTF-8 encoded string + * @return {String} hexadecimal encoded string + * @since 1.1.1 + */ +function utf8tohex(s) { + return uricmptohex(encodeURIComponentAll(s)); +} + +/** + * convert a hexadecimal encoded string to a UTF-8 encoded string including CJK or Latin.
+ * Note that when input is improper hexadecimal string as UTF-8 string, this function returns + * 'null'. + * @name hextoutf8 + * @function + * @param {String} s hexadecimal encoded string + * @return {String} UTF-8 encoded string or null + * @since 1.1.1 + */ +function hextoutf8(s) { + return decodeURIComponent(hextouricmp(s)); +} + +/** + * convert a hexadecimal encoded string to raw string including non printable characters.
+ * @name hextorstr + * @function + * @param {String} s hexadecimal encoded string + * @return {String} raw string + * @since 1.1.2 + * @example + * hextorstr("610061") → "a\x00a" + */ +function hextorstr(sHex) { + var s = ""; + for (var i = 0; i < sHex.length - 1; i += 2) { + s += String.fromCharCode(parseInt(sHex.substr(i, 2), 16)); + } + return s; +} + +/** + * convert a raw string including non printable characters to hexadecimal encoded string.
+ * @name rstrtohex + * @function + * @param {String} s raw string + * @return {String} hexadecimal encoded string + * @since 1.1.2 + * @example + * rstrtohex("a\x00a") → "610061" + */ +function rstrtohex(s) { + var result = ""; + for (var i = 0; i < s.length; i++) { + result += ("0" + s.charCodeAt(i).toString(16)).slice(-2); + } + return result; +} + +// ==== hex / b64nl ======================================= + +/** + * convert a hexadecimal string to Base64 encoded string
+ * @name hextob64 + * @function + * @param {String} s hexadecimal string + * @return {String} resulted Base64 encoded string + * @since base64x 1.1.3 + * @description + * This function converts from a hexadecimal string to Base64 encoded + * string without new lines. + * @example + * hextob64("616161") → "YWFh" + */ +function hextob64(s) { + return hex2b64(s); +} + +/** + * convert a hexadecimal string to Base64 encoded string with new lines
+ * @name hextob64nl + * @function + * @param {String} s hexadecimal string + * @return {String} resulted Base64 encoded string with new lines + * @since base64x 1.1.3 + * @description + * This function converts from a hexadecimal string to Base64 encoded + * string with new lines for each 64 characters. This is useful for + * PEM encoded file. + * @example + * hextob64nl("123456789012345678901234567890123456789012345678901234567890") + * → + * MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4 // new line + * OTAxMjM0NTY3ODkwCg== + */ +function hextob64nl(s) { + var b64 = hextob64(s); + var b64nl = b64.replace(/(.{64})/g, "$1\r\n"); + b64nl = b64nl.replace(/\r\n$/, ''); + return b64nl; +} + +/** + * convert a Base64 encoded string with new lines to a hexadecimal string
+ * @name b64nltohex + * @function + * @param {String} s Base64 encoded string with new lines + * @return {String} hexadecimal string + * @since base64x 1.1.3 + * @description + * This function converts from a Base64 encoded + * string with new lines to a hexadecimal string. + * This is useful to handle PEM encoded file. + * This function removes any non-Base64 characters (i.e. not 0-9,A-Z,a-z,\,+,=) + * including new line. + * @example + * hextob64nl( + * "MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4\r\n" + + * "OTAxMjM0NTY3ODkwCg==\r\n") + * → + * "123456789012345678901234567890123456789012345678901234567890" + */ +function b64nltohex(s) { + var b64 = s.replace(/[^0-9A-Za-z\/+=]*/g, ''); + var hex = b64tohex(b64); + return hex; +} + +// ==== hex / pem ========================================= + +/** + * get PEM string from hexadecimal data and header string + * @name hextopem + * @function + * @param {String} dataHex hexadecimal string of PEM body + * @param {String} pemHeader PEM header string (ex. 'RSA PRIVATE KEY') + * @return {String} PEM formatted string of input data + * @since jsrasign 7.2.1 base64x 1.1.12 + * @description + * This function converts a hexadecimal string to a PEM string with + * a specified header. Its line break will be CRLF("\r\n"). + * @example + * hextopem('616161', 'RSA PRIVATE KEY') → + * -----BEGIN PRIVATE KEY----- + * YWFh + * -----END PRIVATE KEY----- + */ +function hextopem(dataHex, pemHeader) { + var pemBody = hextob64nl(dataHex); + return "-----BEGIN " + pemHeader + "-----\r\n" + + pemBody + + "\r\n-----END " + pemHeader + "-----\r\n"; +} + +/** + * get hexacedimal string from PEM format data
+ * @name pemtohex + * @function + * @param {String} s PEM formatted string + * @param {String} sHead PEM header string without BEGIN/END(OPTION) + * @return {String} hexadecimal string data of PEM contents + * @since jsrsasign 7.2.1 base64x 1.1.12 + * @description + * This static method gets a hexacedimal string of contents + * from PEM format data. You can explicitly specify PEM header + * by sHead argument. + * Any space characters such as white space or new line + * will be omitted.
+ * NOTE: Now {@link KEYUTIL.getHexFromPEM} and {@link X509.pemToHex} + * have been deprecated since jsrsasign 7.2.1. + * Please use this method instead. + * @example + * pemtohex("-----BEGIN PUBLIC KEY...") → "3082..." + * pemtohex("-----BEGIN CERTIFICATE...", "CERTIFICATE") → "3082..." + * pemtohex(" \r\n-----BEGIN DSA PRIVATE KEY...") → "3082..." + */ +function pemtohex(s, sHead) { + if (s.indexOf("-----BEGIN ") == -1) + throw "can't find PEM header: " + sHead; + + if (sHead !== undefined) { + s = s.replace("-----BEGIN " + sHead + "-----", ""); + s = s.replace("-----END " + sHead + "-----", ""); + } else { + s = s.replace(/-----BEGIN [^-]+-----/, ''); + s = s.replace(/-----END [^-]+-----/, ''); + } + return b64nltohex(s); +} + +// ==== hex / ArrayBuffer ================================= + +/** + * convert a hexadecimal string to an ArrayBuffer
+ * @name hextoArrayBuffer + * @function + * @param {String} hex hexadecimal string + * @return {ArrayBuffer} ArrayBuffer + * @since jsrsasign 6.1.4 base64x 1.1.8 + * @description + * This function converts from a hexadecimal string to an ArrayBuffer. + * @example + * hextoArrayBuffer("fffa01") → ArrayBuffer of [255, 250, 1] + */ +function hextoArrayBuffer(hex) { + if (hex.length % 2 != 0) throw "input is not even length"; + if (hex.match(/^[0-9A-Fa-f]+$/) == null) throw "input is not hexadecimal"; + + var buffer = new ArrayBuffer(hex.length / 2); + var view = new DataView(buffer); + + for (var i = 0; i < hex.length / 2; i++) { + view.setUint8(i, parseInt(hex.substr(i * 2, 2), 16)); + } + + return buffer; +} + +// ==== ArrayBuffer / hex ================================= + +/** + * convert an ArrayBuffer to a hexadecimal string
+ * @name ArrayBuffertohex + * @function + * @param {ArrayBuffer} buffer ArrayBuffer + * @return {String} hexadecimal string + * @since jsrsasign 6.1.4 base64x 1.1.8 + * @description + * This function converts from an ArrayBuffer to a hexadecimal string. + * @example + * var buffer = new ArrayBuffer(3); + * var view = new DataView(buffer); + * view.setUint8(0, 0xfa); + * view.setUint8(1, 0xfb); + * view.setUint8(2, 0x01); + * ArrayBuffertohex(buffer) → "fafb01" + */ +function ArrayBuffertohex(buffer) { + var hex = ""; + var view = new DataView(buffer); + + for (var i = 0; i < buffer.byteLength; i++) { + hex += ("00" + view.getUint8(i).toString(16)).slice(-2); + } + + return hex; +} + +// ==== zulu / int ================================= +/** + * GeneralizedTime or UTCTime string to milliseconds from Unix origin
+ * @name zulutomsec + * @function + * @param {String} s GeneralizedTime or UTCTime string (ex. 20170412235959.384Z) + * @return {Number} milliseconds from Unix origin time (i.e. Jan 1, 1970 0:00:00 UTC) + * @since jsrsasign 7.1.3 base64x 1.1.9 + * @description + * This function converts from GeneralizedTime string (i.e. YYYYMMDDHHmmSSZ) or + * UTCTime string (i.e. YYMMDDHHmmSSZ) to milliseconds from Unix origin time + * (i.e. Jan 1 1970 0:00:00 UTC). + * Argument string may have fraction of seconds and + * its length is one or more digits such as "20170410235959.1234567Z". + * As for UTCTime, if year "YY" is equal or less than 49 then it is 20YY. + * If year "YY" is equal or greater than 50 then it is 19YY. + * @example + * zulutomsec( "071231235959Z") → 1199145599000 #Mon, 31 Dec 2007 23:59:59 GMT + * zulutomsec( "071231235959.1Z") → 1199145599100 #Mon, 31 Dec 2007 23:59:59 GMT + * zulutomsec( "071231235959.12345Z") → 1199145599123 #Mon, 31 Dec 2007 23:59:59 GMT + * zulutomsec("20071231235959Z") → 1199145599000 #Mon, 31 Dec 2007 23:59:59 GMT + * zulutomsec( "931231235959Z") → -410227201000 #Mon, 31 Dec 1956 23:59:59 GMT + */ +function zulutomsec(s) { + var year, month, day, hour, min, sec, msec, d; + var sYear, sFrac, sMsec, matchResult; + + matchResult = s.match(/^(\d{2}|\d{4})(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)(|\.\d+)Z$/); + + if (matchResult) { + sYear = matchResult[1]; + year = parseInt(sYear); + if (sYear.length === 2) { + if (50 <= year && year < 100) { + year = 1900 + year; + } else if (0 <= year && year < 50) { + year = 2000 + year; + } + } + month = parseInt(matchResult[2]) - 1; + day = parseInt(matchResult[3]); + hour = parseInt(matchResult[4]); + min = parseInt(matchResult[5]); + sec = parseInt(matchResult[6]); + msec = 0; + + sFrac = matchResult[7]; + if (sFrac !== "") { + sMsec = (sFrac.substr(1) + "00").substr(0, 3); // .12 -> 012 + msec = parseInt(sMsec); + } + return Date.UTC(year, month, day, hour, min, sec, msec); + } + throw "unsupported zulu format: " + s; +} + +/** + * GeneralizedTime or UTCTime string to seconds from Unix origin
+ * @name zulutosec + * @function + * @param {String} s GeneralizedTime or UTCTime string (ex. 20170412235959.384Z) + * @return {Number} seconds from Unix origin time (i.e. Jan 1, 1970 0:00:00 UTC) + * @since jsrsasign 7.1.3 base64x 1.1.9 + * @description + * This function converts from GeneralizedTime string (i.e. YYYYMMDDHHmmSSZ) or + * UTCTime string (i.e. YYMMDDHHmmSSZ) to seconds from Unix origin time + * (i.e. Jan 1 1970 0:00:00 UTC). Argument string may have fraction of seconds + * however result value will be omitted. + * As for UTCTime, if year "YY" is equal or less than 49 then it is 20YY. + * If year "YY" is equal or greater than 50 then it is 19YY. + * @example + * zulutosec( "071231235959Z") → 1199145599 #Mon, 31 Dec 2007 23:59:59 GMT + * zulutosec( "071231235959.1Z") → 1199145599 #Mon, 31 Dec 2007 23:59:59 GMT + * zulutosec("20071231235959Z") → 1199145599 #Mon, 31 Dec 2007 23:59:59 GMT + */ +function zulutosec(s) { + var msec = zulutomsec(s); + return ~~(msec / 1000); +} + +// ==== zulu / Date ================================= + +/** + * GeneralizedTime or UTCTime string to Date object
+ * @name zulutodate + * @function + * @param {String} s GeneralizedTime or UTCTime string (ex. 20170412235959.384Z) + * @return {Date} Date object for specified time + * @since jsrsasign 7.1.3 base64x 1.1.9 + * @description + * This function converts from GeneralizedTime string (i.e. YYYYMMDDHHmmSSZ) or + * UTCTime string (i.e. YYMMDDHHmmSSZ) to Date object. + * Argument string may have fraction of seconds and + * its length is one or more digits such as "20170410235959.1234567Z". + * As for UTCTime, if year "YY" is equal or less than 49 then it is 20YY. + * If year "YY" is equal or greater than 50 then it is 19YY. + * @example + * zulutodate( "071231235959Z").toUTCString() → "Mon, 31 Dec 2007 23:59:59 GMT" + * zulutodate( "071231235959.1Z").toUTCString() → "Mon, 31 Dec 2007 23:59:59 GMT" + * zulutodate("20071231235959Z").toUTCString() → "Mon, 31 Dec 2007 23:59:59 GMT" + * zulutodate( "071231235959.34").getMilliseconds() → 340 + */ +function zulutodate(s) { + return new Date(zulutomsec(s)); +} + +// ==== Date / zulu ================================= + +/** + * Date object to zulu time string
+ * @name datetozulu + * @function + * @param {Date} d Date object for specified time + * @param {Boolean} flagUTCTime if this is true year will be YY otherwise YYYY + * @param {Boolean} flagMilli if this is true result concludes milliseconds + * @return {String} GeneralizedTime or UTCTime string (ex. 20170412235959.384Z) + * @since jsrsasign 7.2.0 base64x 1.1.11 + * @description + * This function converts from Date object to GeneralizedTime string (i.e. YYYYMMDDHHmmSSZ) or + * UTCTime string (i.e. YYMMDDHHmmSSZ). + * As for UTCTime, if year "YY" is equal or less than 49 then it is 20YY. + * If year "YY" is equal or greater than 50 then it is 19YY. + * If flagMilli is true its result concludes milliseconds such like + * "20170520235959.42Z". + * @example + * d = new Date(Date.UTC(2017,4,20,23,59,59,670)); + * datetozulu(d) → "20170520235959Z" + * datetozulu(d, true) → "170520235959Z" + * datetozulu(d, false, true) → "20170520235959.67Z" + */ +function datetozulu(d, flagUTCTime, flagMilli) { + var s; + var year = d.getUTCFullYear(); + if (flagUTCTime) { + if (year < 1950 || 2049 < year) + throw "not proper year for UTCTime: " + year; + s = ("" + year).slice(-2); + } else { + s = ("000" + year).slice(-4); + } + s += ("0" + (d.getUTCMonth() + 1)).slice(-2); + s += ("0" + d.getUTCDate()).slice(-2); + s += ("0" + d.getUTCHours()).slice(-2); + s += ("0" + d.getUTCMinutes()).slice(-2); + s += ("0" + d.getUTCSeconds()).slice(-2); + if (flagMilli) { + var milli = d.getUTCMilliseconds(); + if (milli !== 0) { + milli = ("00" + milli).slice(-3); + milli = milli.replace(/0+$/g, ""); + s += "." + milli; + } + } + s += "Z"; + return s; +} + +// ==== URIComponent / hex ================================ +/** + * convert a URLComponent string such like "%67%68" to a hexadecimal string.
+ * @name uricmptohex + * @function + * @param {String} s URIComponent string such like "%67%68" + * @return {String} hexadecimal string + * @since 1.1 + */ +function uricmptohex(s) { + return s.replace(/%/g, ""); +} + +/** + * convert a hexadecimal string to a URLComponent string such like "%67%68".
+ * @name hextouricmp + * @function + * @param {String} s hexadecimal string + * @return {String} URIComponent string such like "%67%68" + * @since 1.1 + */ +function hextouricmp(s) { + return s.replace(/(..)/g, "%$1"); +} + +// ==== hex / ipv6 ================================= + +/** + * convert any IPv6 address to a 16 byte hexadecimal string + * @function + * @param s string of IPv6 address + * @return {String} 16 byte hexadecimal string of IPv6 address + * @description + * This function converts any IPv6 address representation string + * to a 16 byte hexadecimal string of address. + * @example + * + */ +function ipv6tohex(s) { + var msgMalformedAddress = "malformed IPv6 address"; + if (! s.match(/^[0-9A-Fa-f:]+$/)) + throw msgMalformedAddress; + + // 1. downcase + s = s.toLowerCase(); + + // 2. expand :: + var num_colon = s.split(':').length - 1; + if (num_colon < 2) throw msgMalformedAddress; + var colon_replacer = ':'.repeat(7 - num_colon + 2); + s = s.replace('::', colon_replacer); + + // 3. fill zero + var a = s.split(':'); + if (a.length != 8) throw msgMalformedAddress; + for (var i = 0; i < 8; i++) { + a[i] = ("0000" + a[i]).slice(-4); + } + return a.join(''); +} + +/** + * convert a 16 byte hexadecimal string to RFC 5952 canonicalized IPv6 address
+ * @name hextoipv6 + * @function + * @param {String} s hexadecimal string of 16 byte IPv6 address + * @return {String} IPv6 address string canonicalized by RFC 5952 + * @since jsrsasign 8.0.10 base64x 1.1.13 + * @description + * This function converts a 16 byte hexadecimal string to + * RFC 5952 + * canonicalized IPv6 address string. + * @example + * hextoip("871020010db8000000000000000000000004") &rarr "2001:db8::4" + * hextoip("871020010db8000000000000000000") &rarr raise exception + * hextoip("xyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyz") &rarr raise exception + */ +function hextoipv6(s) { + if (! s.match(/^[0-9A-Fa-f]{32}$/)) + throw "malformed IPv6 address octet"; + + // 1. downcase + s = s.toLowerCase(); + + // 2. split 4 + var a = s.match(/.{1,4}/g); + + // 3. trim leading 0 + for (var i = 0; i < 8; i++) { + a[i] = a[i].replace(/^0+/, ""); + if (a[i] == '') a[i] = '0'; + } + s = ":" + a.join(":") + ":"; + + // 4. find shrinkables :0:0:... + var aZero = s.match(/:(0:){2,}/g); + + // 5. no shrinkable + if (aZero === null) return s.slice(1, -1); + + // 6. find max length :0:0:... + var item = ''; + for (var i = 0; i < aZero.length; i++) { + if (aZero[i].length > item.length) item = aZero[i]; + } + + // 7. shrink + s = s.replace(item, '::'); + return s.slice(1, -1); +} + +// ==== hex / ip ================================= + +/** + * convert a hexadecimal string to IP addresss
+ * @name hextoip + * @function + * @param {String} s hexadecimal string of IP address + * @return {String} IP address string + * @since jsrsasign 8.0.10 base64x 1.1.13 + * @description + * This function converts a hexadecimal string of IPv4 or + * IPv6 address to IPv4 or IPv6 address string. + * If byte length is not 4 nor 16, this returns a + * hexadecimal string without conversion. + * @see {@link hextoipv6} + * @example + * hextoip("c0a80101") &rarr "192.168.1.1" + * hextoip("871020010db8000000000000000000000004") &rarr "2001:db8::4" + * hextoip("c0a801010203") &rarr "c0a801010203" // 6 bytes + * hextoip("zzz")) &rarr raise exception because of not hexadecimal + */ +function hextoip(s) { + var malformedMsg = "malformed hex value"; + if (! s.match(/^([0-9A-Fa-f][0-9A-Fa-f]){1,}$/)) + throw malformedMsg; + if (s.length == 8) { // ipv4 + var ip; + try { + ip = parseInt(s.substr(0, 2), 16) + "." + + parseInt(s.substr(2, 2), 16) + "." + + parseInt(s.substr(4, 2), 16) + "." + + parseInt(s.substr(6, 2), 16); + return ip; + } catch (ex) { + throw malformedMsg; + } + } else if (s.length == 32) { + return hextoipv6(s); + } else { + return s; + } +} + +/** + * convert IPv4/v6 addresss to a hexadecimal string
+ * @name iptohex + * @function + * @param {String} s IPv4/v6 address string + * @return {String} hexadecimal string of IP address + * @since jsrsasign 8.0.12 base64x 1.1.14 + * @description + * This function converts IPv4 or IPv6 address string to + * a hexadecimal string of IPv4 or IPv6 address. + * @example + * iptohex("192.168.1.1") &rarr "c0a80101" + * iptohex("2001:db8::4") &rarr "871020010db8000000000000000000000004" + * iptohex("zzz")) &rarr raise exception + */ +function iptohex(s) { + var malformedMsg = "malformed IP address"; + s = s.toLowerCase(s); + + if (s.match(/^[0-9.]+$/)) { + var a = s.split("."); + if (a.length !== 4) throw malformedMsg; + var hex = ""; + try { + for (var i = 0; i < 4; i++) { + var d = parseInt(a[i]); + hex += ("0" + d.toString(16)).slice(-2); + } + return hex; + } catch(ex) { + throw malformedMsg; + } + } else if (s.match(/^[0-9a-f:]+$/) && s.indexOf(":") !== -1) { + return ipv6tohex(s); + } else { + throw malformedMsg; + } +} + +// ==== URIComponent ================================ +/** + * convert UTFa hexadecimal string to a URLComponent string such like "%67%68".
+ * Note that these "0-9A-Za-z!'()*-._~" characters will not + * converted to "%xx" format by builtin 'encodeURIComponent()' function. + * However this 'encodeURIComponentAll()' function will convert + * all of characters into "%xx" format. + * @name encodeURIComponentAll + * @function + * @param {String} s hexadecimal string + * @return {String} URIComponent string such like "%67%68" + * @since 1.1 + */ +function encodeURIComponentAll(u8) { + var s = encodeURIComponent(u8); + var s2 = ""; + for (var i = 0; i < s.length; i++) { + if (s[i] == "%") { + s2 = s2 + s.substr(i, 3); + i = i + 2; + } else { + s2 = s2 + "%" + stohex(s[i]); + } + } + return s2; +} + +// ==== new lines ================================ +/** + * convert all DOS new line("\r\n") to UNIX new line("\n") in + * a String "s". + * @name newline_toUnix + * @function + * @param {String} s string + * @return {String} converted string + */ +function newline_toUnix(s) { + s = s.replace(/\r\n/mg, "\n"); + return s; +} + +/** + * convert all UNIX new line("\r\n") to DOS new line("\n") in + * a String "s". + * @name newline_toDos + * @function + * @param {String} s string + * @return {String} converted string + */ +function newline_toDos(s) { + s = s.replace(/\r\n/mg, "\n"); + s = s.replace(/\n/mg, "\r\n"); + return s; +} + +// ==== string type checker =================== + +/** + * check whether a string is an integer string or not
+ * @name isInteger + * @memberOf KJUR.lang.String + * @function + * @static + * @param {String} s input string + * @return {Boolean} true if a string "s" is an integer string otherwise false + * @since base64x 1.1.7 jsrsasign 5.0.13 + * @example + * KJUR.lang.String.isInteger("12345") → true + * KJUR.lang.String.isInteger("123ab") → false + */ +KJUR.lang.String.isInteger = function(s) { + if (s.match(/^[0-9]+$/)) { + return true; + } else if (s.match(/^-[0-9]+$/)) { + return true; + } else { + return false; + } +}; + +/** + * check whether a string is an hexadecimal string or not
+ * @name isHex + * @memberOf KJUR.lang.String + * @function + * @static + * @param {String} s input string + * @return {Boolean} true if a string "s" is an hexadecimal string otherwise false + * @since base64x 1.1.7 jsrsasign 5.0.13 + * @example + * KJUR.lang.String.isHex("1234") → true + * KJUR.lang.String.isHex("12ab") → true + * KJUR.lang.String.isHex("12AB") → true + * KJUR.lang.String.isHex("12ZY") → false + * KJUR.lang.String.isHex("121") → false -- odd length + */ +KJUR.lang.String.isHex = function(s) { + if (s.length % 2 == 0 && + (s.match(/^[0-9a-f]+$/) || s.match(/^[0-9A-F]+$/))) { + return true; + } else { + return false; + } +}; + +/** + * check whether a string is a base64 encoded string or not
+ * Input string can conclude new lines or space characters. + * @name isBase64 + * @memberOf KJUR.lang.String + * @function + * @static + * @param {String} s input string + * @return {Boolean} true if a string "s" is a base64 encoded string otherwise false + * @since base64x 1.1.7 jsrsasign 5.0.13 + * @example + * KJUR.lang.String.isBase64("YWE=") → true + * KJUR.lang.String.isBase64("YW_=") → false + * KJUR.lang.String.isBase64("YWE") → false -- length shall be multiples of 4 + */ +KJUR.lang.String.isBase64 = function(s) { + s = s.replace(/\s+/g, ""); + if (s.match(/^[0-9A-Za-z+\/]+={0,3}$/) && s.length % 4 == 0) { + return true; + } else { + return false; + } +}; + +/** + * check whether a string is a base64url encoded string or not
+ * Input string can conclude new lines or space characters. + * @name isBase64URL + * @memberOf KJUR.lang.String + * @function + * @static + * @param {String} s input string + * @return {Boolean} true if a string "s" is a base64url encoded string otherwise false + * @since base64x 1.1.7 jsrsasign 5.0.13 + * @example + * KJUR.lang.String.isBase64URL("YWE") → true + * KJUR.lang.String.isBase64URL("YW-") → true + * KJUR.lang.String.isBase64URL("YW+") → false + */ +KJUR.lang.String.isBase64URL = function(s) { + if (s.match(/[+/=]/)) return false; + s = b64utob64(s); + return KJUR.lang.String.isBase64(s); +}; + +/** + * check whether a string is a string of integer array or not
+ * Input string can conclude new lines or space characters. + * @name isIntegerArray + * @memberOf KJUR.lang.String + * @function + * @static + * @param {String} s input string + * @return {Boolean} true if a string "s" is a string of integer array otherwise false + * @since base64x 1.1.7 jsrsasign 5.0.13 + * @example + * KJUR.lang.String.isIntegerArray("[1,2,3]") → true + * KJUR.lang.String.isIntegerArray(" [1, 2, 3 ] ") → true + * KJUR.lang.String.isIntegerArray("[a,2]") → false + */ +KJUR.lang.String.isIntegerArray = function(s) { + s = s.replace(/\s+/g, ""); + if (s.match(/^\[[0-9,]+\]$/)) { + return true; + } else { + return false; + } +}; + +// ==== others ================================ + +/** + * canonicalize hexadecimal string of positive integer
+ * @name hextoposhex + * @function + * @param {String} s hexadecimal string + * @return {String} canonicalized hexadecimal string of positive integer + * @since base64x 1.1.10 jsrsasign 7.1.4 + * @description + * This method canonicalize a hexadecimal string of positive integer + * for two's complement representation. + * Canonicalized hexadecimal string of positive integer will be: + *
    + *
  • Its length is always even.
  • + *
  • If odd length it will be padded with leading zero.
  • + *
  • If it is even length and its first character is "8" or greater, + * it will be padded with "00" to make it positive integer.
  • + *
+ * @example + * hextoposhex("abcd") → "00abcd" + * hextoposhex("1234") → "1234" + * hextoposhex("12345") → "012345" + */ +function hextoposhex(s) { + if (s.length % 2 == 1) return "0" + s; + if (s.substr(0, 1) > "7") return "00" + s; + return s; +} + +/** + * convert string of integer array to hexadecimal string.
+ * @name intarystrtohex + * @function + * @param {String} s string of integer array + * @return {String} hexadecimal string + * @since base64x 1.1.6 jsrsasign 5.0.2 + * @throws "malformed integer array string: *" for wrong input + * @description + * This function converts a string of JavaScript integer array to + * a hexadecimal string. Each integer value shall be in a range + * from 0 to 255 otherwise it raise exception. Input string can + * have extra space or newline string so that they will be ignored. + * + * @example + * intarystrtohex(" [123, 34, 101, 34, 58] ") + * → 7b2265223a (i.e. '{"e":' as string) + */ +function intarystrtohex(s) { + s = s.replace(/^\s*\[\s*/, ''); + s = s.replace(/\s*\]\s*$/, ''); + s = s.replace(/\s*/g, ''); + try { + var hex = s.split(/,/).map(function(element, index, array) { + var i = parseInt(element); + if (i < 0 || 255 < i) throw "integer not in range 0-255"; + var hI = ("00" + i.toString(16)).slice(-2); + return hI; + }).join(''); + return hex; + } catch(ex) { + throw "malformed integer array string: " + ex; + } +} + +/** + * find index of string where two string differs + * @name strdiffidx + * @function + * @param {String} s1 string to compare + * @param {String} s2 string to compare + * @return {Number} string index of where character differs. Return -1 if same. + * @since jsrsasign 4.9.0 base64x 1.1.5 + * @example + * strdiffidx("abcdefg", "abcd4fg") -> 4 + * strdiffidx("abcdefg", "abcdefg") -> -1 + * strdiffidx("abcdefg", "abcdef") -> 6 + * strdiffidx("abcdefgh", "abcdef") -> 6 + */ +var strdiffidx = function(s1, s2) { + var n = s1.length; + if (s1.length > s2.length) n = s2.length; + for (var i = 0; i < n; i++) { + if (s1.charCodeAt(i) != s2.charCodeAt(i)) return i; + } + if (s1.length != s2.length) return n; + return -1; // same +}; + + diff --git a/source/build.md b/source/build.md new file mode 100644 index 0000000..91ae12a --- /dev/null +++ b/source/build.md @@ -0,0 +1,17 @@ +yahoo.js +cryptojs-312-core-fix.js +jsbn.js +jsbn2.js +ec.js +prng4.js +rng.js +rsa.js +sha256.js +asn1-1.0.js +asn1hex-1.1.js +base64x-1.1.js +crypto-1.1.js +ecdsa-modified-1.0.js +ecparam-1.0.js +keyutil-1.0.js +pack.js \ No newline at end of file diff --git a/source/crypto-1.1.js b/source/crypto-1.1.js new file mode 100644 index 0000000..ffc3f2e --- /dev/null +++ b/source/crypto-1.1.js @@ -0,0 +1,1466 @@ +/* crypto-1.2.1.js (c) 2013-2017 Kenji Urushima | kjur.github.io/jsrsasign/license + */ +/* + * crypto.js - Cryptographic Algorithm Provider class + * + * Copyright (c) 2013-2017 Kenji Urushima (kenji.urushima@gmail.com) + * + * This software is licensed under the terms of the MIT License. + * https://kjur.github.io/jsrsasign/license + * + * The above copyright and license notice shall be + * included in all copies or substantial portions of the Software. + */ + +/** + * @fileOverview + * @name crypto-1.1.js + * @author Kenji Urushima kenji.urushima@gmail.com + * @version 1.2.1 (2017-Sep-15) + * @since jsrsasign 2.2 + * @license MIT License + */ + +/** + * kjur's class library name space + * @name KJUR + * @namespace kjur's class library name space + */ +if (typeof KJUR == "undefined" || !KJUR) KJUR = {}; +/** + * kjur's cryptographic algorithm provider library name space + *

+ * This namespace privides following crytpgrahic classes. + *

    + *
  • {@link KJUR.crypto.MessageDigest} - Java JCE(cryptograhic extension) style MessageDigest class
  • + *
  • {@link KJUR.crypto.Signature} - Java JCE(cryptograhic extension) style Signature class
  • + *
  • {@link KJUR.crypto.Cipher} - class for encrypting and decrypting data
  • + *
  • {@link KJUR.crypto.Util} - cryptographic utility functions and properties
  • + *
+ * NOTE: Please ignore method summary and document of this namespace. This caused by a bug of jsdoc2. + *

+ * @name KJUR.crypto + * @namespace + */ +if (typeof KJUR.crypto == "undefined" || !KJUR.crypto) KJUR.crypto = {}; + +/** + * static object for cryptographic function utilities + * @name KJUR.crypto.Util + * @class static object for cryptographic function utilities + * @property {Array} DIGESTINFOHEAD PKCS#1 DigestInfo heading hexadecimal bytes for each hash algorithms + * @property {Array} DEFAULTPROVIDER associative array of default provider name for each hash and signature algorithms + * @description + */ +KJUR.crypto.Util = new function() { + this.DIGESTINFOHEAD = { + 'sha1': "3021300906052b0e03021a05000414", + 'sha224': "302d300d06096086480165030402040500041c", + 'sha256': "3031300d060960864801650304020105000420", + 'sha384': "3041300d060960864801650304020205000430", + 'sha512': "3051300d060960864801650304020305000440", + 'md2': "3020300c06082a864886f70d020205000410", + 'md5': "3020300c06082a864886f70d020505000410", + 'ripemd160': "3021300906052b2403020105000414", + }; + + /* + * @since crypto 1.1.1 + */ + this.DEFAULTPROVIDER = { + 'md5': 'cryptojs', + 'sha1': 'cryptojs', + 'sha224': 'cryptojs', + 'sha256': 'cryptojs', + 'sha384': 'cryptojs', + 'sha512': 'cryptojs', + 'ripemd160': 'cryptojs', + 'hmacmd5': 'cryptojs', + 'hmacsha1': 'cryptojs', + 'hmacsha224': 'cryptojs', + 'hmacsha256': 'cryptojs', + 'hmacsha384': 'cryptojs', + 'hmacsha512': 'cryptojs', + 'hmacripemd160': 'cryptojs', + + 'MD5withRSA': 'cryptojs/jsrsa', + 'SHA1withRSA': 'cryptojs/jsrsa', + 'SHA224withRSA': 'cryptojs/jsrsa', + 'SHA256withRSA': 'cryptojs/jsrsa', + 'SHA384withRSA': 'cryptojs/jsrsa', + 'SHA512withRSA': 'cryptojs/jsrsa', + 'RIPEMD160withRSA': 'cryptojs/jsrsa', + + 'MD5withECDSA': 'cryptojs/jsrsa', + 'SHA1withECDSA': 'cryptojs/jsrsa', + 'SHA224withECDSA': 'cryptojs/jsrsa', + 'SHA256withECDSA': 'cryptojs/jsrsa', + 'SHA384withECDSA': 'cryptojs/jsrsa', + 'SHA512withECDSA': 'cryptojs/jsrsa', + 'RIPEMD160withECDSA': 'cryptojs/jsrsa', + + 'SHA1withDSA': 'cryptojs/jsrsa', + 'SHA224withDSA': 'cryptojs/jsrsa', + 'SHA256withDSA': 'cryptojs/jsrsa', + + 'MD5withRSAandMGF1': 'cryptojs/jsrsa', + 'SHA1withRSAandMGF1': 'cryptojs/jsrsa', + 'SHA224withRSAandMGF1': 'cryptojs/jsrsa', + 'SHA256withRSAandMGF1': 'cryptojs/jsrsa', + 'SHA384withRSAandMGF1': 'cryptojs/jsrsa', + 'SHA512withRSAandMGF1': 'cryptojs/jsrsa', + 'RIPEMD160withRSAandMGF1': 'cryptojs/jsrsa', + }; + + /* + * @since crypto 1.1.2 + */ + this.CRYPTOJSMESSAGEDIGESTNAME = { + 'md5': CryptoJS.algo.MD5, + 'sha1': CryptoJS.algo.SHA1, + 'sha224': CryptoJS.algo.SHA224, + 'sha256': CryptoJS.algo.SHA256, + 'sha384': CryptoJS.algo.SHA384, + 'sha512': CryptoJS.algo.SHA512, + 'ripemd160': CryptoJS.algo.RIPEMD160 + }; + + /** + * get hexadecimal DigestInfo + * @name getDigestInfoHex + * @memberOf KJUR.crypto.Util + * @function + * @param {String} hHash hexadecimal hash value + * @param {String} alg hash algorithm name (ex. 'sha1') + * @return {String} hexadecimal string DigestInfo ASN.1 structure + */ + this.getDigestInfoHex = function(hHash, alg) { + if (typeof this.DIGESTINFOHEAD[alg] == "undefined") + throw "alg not supported in Util.DIGESTINFOHEAD: " + alg; + return this.DIGESTINFOHEAD[alg] + hHash; + }; + + /** + * get PKCS#1 padded hexadecimal DigestInfo + * @name getPaddedDigestInfoHex + * @memberOf KJUR.crypto.Util + * @function + * @param {String} hHash hexadecimal hash value of message to be signed + * @param {String} alg hash algorithm name (ex. 'sha1') + * @param {Integer} keySize key bit length (ex. 1024) + * @return {String} hexadecimal string of PKCS#1 padded DigestInfo + */ + this.getPaddedDigestInfoHex = function(hHash, alg, keySize) { + var hDigestInfo = this.getDigestInfoHex(hHash, alg); + var pmStrLen = keySize / 4; // minimum PM length + + if (hDigestInfo.length + 22 > pmStrLen) // len(0001+ff(*8)+00+hDigestInfo)=22 + throw "key is too short for SigAlg: keylen=" + keySize + "," + alg; + + var hHead = "0001"; + var hTail = "00" + hDigestInfo; + var hMid = ""; + var fLen = pmStrLen - hHead.length - hTail.length; + for (var i = 0; i < fLen; i += 2) { + hMid += "ff"; + } + var hPaddedMessage = hHead + hMid + hTail; + return hPaddedMessage; + }; + + /** + * get hexadecimal hash of string with specified algorithm + * @name hashString + * @memberOf KJUR.crypto.Util + * @function + * @param {String} s input string to be hashed + * @param {String} alg hash algorithm name + * @return {String} hexadecimal string of hash value + * @since 1.1.1 + */ + this.hashString = function(s, alg) { + var md = new KJUR.crypto.MessageDigest({'alg': alg}); + return md.digestString(s); + }; + + /** + * get hexadecimal hash of hexadecimal string with specified algorithm + * @name hashHex + * @memberOf KJUR.crypto.Util + * @function + * @param {String} sHex input hexadecimal string to be hashed + * @param {String} alg hash algorithm name + * @return {String} hexadecimal string of hash value + * @since 1.1.1 + */ + this.hashHex = function(sHex, alg) { + var md = new KJUR.crypto.MessageDigest({'alg': alg}); + return md.digestHex(sHex); + }; + + /** + * get hexadecimal SHA1 hash of string + * @name sha1 + * @memberOf KJUR.crypto.Util + * @function + * @param {String} s input string to be hashed + * @return {String} hexadecimal string of hash value + * @since 1.0.3 + */ + this.sha1 = function(s) { + var md = new KJUR.crypto.MessageDigest({'alg':'sha1', 'prov':'cryptojs'}); + return md.digestString(s); + }; + + /** + * get hexadecimal SHA256 hash of string + * @name sha256 + * @memberOf KJUR.crypto.Util + * @function + * @param {String} s input string to be hashed + * @return {String} hexadecimal string of hash value + * @since 1.0.3 + */ + this.sha256 = function(s) { + var md = new KJUR.crypto.MessageDigest({'alg':'sha256', 'prov':'cryptojs'}); + return md.digestString(s); + }; + + this.sha256Hex = function(s) { + var md = new KJUR.crypto.MessageDigest({'alg':'sha256', 'prov':'cryptojs'}); + return md.digestHex(s); + }; + + /** + * get hexadecimal SHA512 hash of string + * @name sha512 + * @memberOf KJUR.crypto.Util + * @function + * @param {String} s input string to be hashed + * @return {String} hexadecimal string of hash value + * @since 1.0.3 + */ + this.sha512 = function(s) { + var md = new KJUR.crypto.MessageDigest({'alg':'sha512', 'prov':'cryptojs'}); + return md.digestString(s); + }; + + this.sha512Hex = function(s) { + var md = new KJUR.crypto.MessageDigest({'alg':'sha512', 'prov':'cryptojs'}); + return md.digestHex(s); + }; + +}; + +/** + * get hexadecimal MD5 hash of string + * @name md5 + * @memberOf KJUR.crypto.Util + * @function + * @param {String} s input string to be hashed + * @return {String} hexadecimal string of hash value + * @since 1.0.3 + * @example + * Util.md5('aaa') → 47bce5c74f589f4867dbd57e9ca9f808 + */ +KJUR.crypto.Util.md5 = function(s) { + var md = new KJUR.crypto.MessageDigest({'alg':'md5', 'prov':'cryptojs'}); + return md.digestString(s); +}; + +/** + * get hexadecimal RIPEMD160 hash of string + * @name ripemd160 + * @memberOf KJUR.crypto.Util + * @function + * @param {String} s input string to be hashed + * @return {String} hexadecimal string of hash value + * @since 1.0.3 + * @example + * KJUR.crypto.Util.ripemd160("aaa") → 08889bd7b151aa174c21f33f59147fa65381edea + */ +KJUR.crypto.Util.ripemd160 = function(s) { + var md = new KJUR.crypto.MessageDigest({'alg':'ripemd160', 'prov':'cryptojs'}); + return md.digestString(s); +}; + +// @since jsrsasign 7.0.0 crypto 1.1.11 +KJUR.crypto.Util.SECURERANDOMGEN = new SecureRandom(); + +/** + * get hexadecimal string of random value from with specified byte length
+ * @name getRandomHexOfNbytes + * @memberOf KJUR.crypto.Util + * @function + * @param {Integer} n length of bytes of random + * @return {String} hexadecimal string of random + * @since jsrsasign 7.0.0 crypto 1.1.11 + * @example + * KJUR.crypto.Util.getRandomHexOfNbytes(3) → "6314af", "000000" or "001fb4" + * KJUR.crypto.Util.getRandomHexOfNbytes(128) → "8fbc..." in 1024bits + */ +KJUR.crypto.Util.getRandomHexOfNbytes = function(n) { + var ba = new Array(n); + KJUR.crypto.Util.SECURERANDOMGEN.nextBytes(ba); + return BAtohex(ba); +}; + +/** + * get BigInteger object of random value from with specified byte length
+ * @name getRandomBigIntegerOfNbytes + * @memberOf KJUR.crypto.Util + * @function + * @param {Integer} n length of bytes of random + * @return {BigInteger} BigInteger object of specified random value + * @since jsrsasign 7.0.0 crypto 1.1.11 + * @example + * KJUR.crypto.Util.getRandomBigIntegerOfNbytes(3) → 6314af of BigInteger + * KJUR.crypto.Util.getRandomBigIntegerOfNbytes(128) → 8fbc... of BigInteger + */ +KJUR.crypto.Util.getRandomBigIntegerOfNbytes = function(n) { + return new BigInteger(KJUR.crypto.Util.getRandomHexOfNbytes(n), 16); +}; + +/** + * get hexadecimal string of random value from with specified bit length
+ * @name getRandomHexOfNbits + * @memberOf KJUR.crypto.Util + * @function + * @param {Integer} n length of bits of random + * @return {String} hexadecimal string of random + * @since jsrsasign 7.0.0 crypto 1.1.11 + * @example + * KJUR.crypto.Util.getRandomHexOfNbits(24) → "6314af", "000000" or "001fb4" + * KJUR.crypto.Util.getRandomHexOfNbits(1024) → "8fbc..." in 1024bits + */ +KJUR.crypto.Util.getRandomHexOfNbits = function(n) { + var n_remainder = n % 8; + var n_quotient = (n - n_remainder) / 8; + var ba = new Array(n_quotient + 1); + KJUR.crypto.Util.SECURERANDOMGEN.nextBytes(ba); + ba[0] = (((255 << n_remainder) & 255) ^ 255) & ba[0]; + return BAtohex(ba); +}; + +/** + * get BigInteger object of random value from with specified bit length
+ * @name getRandomBigIntegerOfNbits + * @memberOf KJUR.crypto.Util + * @function + * @param {Integer} n length of bits of random + * @return {BigInteger} BigInteger object of specified random value + * @since jsrsasign 7.0.0 crypto 1.1.11 + * @example + * KJUR.crypto.Util.getRandomBigIntegerOfNbits(24) → 6314af of BigInteger + * KJUR.crypto.Util.getRandomBigIntegerOfNbits(1024) → 8fbc... of BigInteger + */ +KJUR.crypto.Util.getRandomBigIntegerOfNbits = function(n) { + return new BigInteger(KJUR.crypto.Util.getRandomHexOfNbits(n), 16); +}; + +/** + * get BigInteger object of random value from zero to max value
+ * @name getRandomBigIntegerZeroToMax + * @memberOf KJUR.crypto.Util + * @function + * @param {BigInteger} biMax max value of BigInteger object for random value + * @return {BigInteger} BigInteger object of specified random value + * @since jsrsasign 7.0.0 crypto 1.1.11 + * @description + * This static method generates a BigInteger object with random value + * greater than or equal to zero and smaller than or equal to biMax + * (i.e. 0 ≤ result ≤ biMax). + * @example + * biMax = new BigInteger("3fa411...", 16); + * KJUR.crypto.Util.getRandomBigIntegerZeroToMax(biMax) → 8fbc... of BigInteger + */ +KJUR.crypto.Util.getRandomBigIntegerZeroToMax = function(biMax) { + var bitLenMax = biMax.bitLength(); + while (1) { + var biRand = KJUR.crypto.Util.getRandomBigIntegerOfNbits(bitLenMax); + if (biMax.compareTo(biRand) != -1) return biRand; + } +}; + +/** + * get BigInteger object of random value from min value to max value
+ * @name getRandomBigIntegerMinToMax + * @memberOf KJUR.crypto.Util + * @function + * @param {BigInteger} biMin min value of BigInteger object for random value + * @param {BigInteger} biMax max value of BigInteger object for random value + * @return {BigInteger} BigInteger object of specified random value + * @since jsrsasign 7.0.0 crypto 1.1.11 + * @description + * This static method generates a BigInteger object with random value + * greater than or equal to biMin and smaller than or equal to biMax + * (i.e. biMin ≤ result ≤ biMax). + * @example + * biMin = new BigInteger("2fa411...", 16); + * biMax = new BigInteger("3fa411...", 16); + * KJUR.crypto.Util.getRandomBigIntegerMinToMax(biMin, biMax) → 32f1... of BigInteger + */ +KJUR.crypto.Util.getRandomBigIntegerMinToMax = function(biMin, biMax) { + var flagCompare = biMin.compareTo(biMax); + if (flagCompare == 1) throw "biMin is greater than biMax"; + if (flagCompare == 0) return biMin; + + var biDiff = biMax.subtract(biMin); + var biRand = KJUR.crypto.Util.getRandomBigIntegerZeroToMax(biDiff); + return biRand.add(biMin); +}; + +// === Mac =============================================================== + +/** + * MessageDigest class which is very similar to java.security.MessageDigest class
+ * @name KJUR.crypto.MessageDigest + * @class MessageDigest class which is very similar to java.security.MessageDigest class + * @param {Array} params parameters for constructor + * @property {Array} HASHLENGTH static Array of resulted byte length of hash (ex. HASHLENGTH["sha1"] == 20) + * @description + *
+ * Currently this supports following algorithm and providers combination: + *
    + *
  • md5 - cryptojs
  • + *
  • sha1 - cryptojs
  • + *
  • sha224 - cryptojs
  • + *
  • sha256 - cryptojs
  • + *
  • sha384 - cryptojs
  • + *
  • sha512 - cryptojs
  • + *
  • ripemd160 - cryptojs
  • + *
  • sha256 - sjcl (NEW from crypto.js 1.0.4)
  • + *
+ * @example + * // CryptoJS provider sample + * var md = new KJUR.crypto.MessageDigest({alg: "sha1", prov: "cryptojs"}); + * md.updateString('aaa') + * var mdHex = md.digest() + * + * // SJCL(Stanford JavaScript Crypto Library) provider sample + * var md = new KJUR.crypto.MessageDigest({alg: "sha256", prov: "sjcl"}); // sjcl supports sha256 only + * md.updateString('aaa') + * var mdHex = md.digest() + * + * // HASHLENGTH property + * KJUR.crypto.MessageDigest.HASHLENGTH['sha1'] &rarr 20 + * KJUR.crypto.MessageDigest.HASHLENGTH['sha512'] &rarr 64 + */ +KJUR.crypto.MessageDigest = function(params) { + var md = null; + var algName = null; + var provName = null; + + /** + * set hash algorithm and provider
+ * @name setAlgAndProvider + * @memberOf KJUR.crypto.MessageDigest# + * @function + * @param {String} alg hash algorithm name + * @param {String} prov provider name + * @description + * This methods set an algorithm and a cryptographic provider.
+ * Here is acceptable algorithm names ignoring cases and hyphens: + *
    + *
  • MD5
  • + *
  • SHA1
  • + *
  • SHA224
  • + *
  • SHA256
  • + *
  • SHA384
  • + *
  • SHA512
  • + *
  • RIPEMD160
  • + *
+ * NOTE: Since jsrsasign 6.2.0 crypto 1.1.10, this method ignores + * upper or lower cases. Also any hyphens (i.e. "-") will be ignored + * so that "SHA1" or "SHA-1" will be acceptable. + * @example + * // for SHA1 + * md.setAlgAndProvider('sha1', 'cryptojs'); + * md.setAlgAndProvider('SHA1'); + * // for RIPEMD160 + * md.setAlgAndProvider('ripemd160', 'cryptojs'); + */ + this.setAlgAndProvider = function(alg, prov) { + alg = KJUR.crypto.MessageDigest.getCanonicalAlgName(alg); + + if (alg !== null && prov === undefined) prov = KJUR.crypto.Util.DEFAULTPROVIDER[alg]; + + // for cryptojs + if (':md5:sha1:sha224:sha256:sha384:sha512:ripemd160:'.indexOf(alg) != -1 && + prov == 'cryptojs') { + try { + this.md = KJUR.crypto.Util.CRYPTOJSMESSAGEDIGESTNAME[alg].create(); + } catch (ex) { + throw "setAlgAndProvider hash alg set fail alg=" + alg + "/" + ex; + } + this.updateString = function(str) { + this.md.update(str); + }; + this.updateHex = function(hex) { + var wHex = CryptoJS.enc.Hex.parse(hex); + this.md.update(wHex); + }; + this.digest = function() { + var hash = this.md.finalize(); + return hash.toString(CryptoJS.enc.Hex); + }; + this.digestString = function(str) { + this.updateString(str); + return this.digest(); + }; + this.digestHex = function(hex) { + this.updateHex(hex); + return this.digest(); + }; + } + if (':sha256:'.indexOf(alg) != -1 && + prov == 'sjcl') { + try { + this.md = new sjcl.hash.sha256(); + } catch (ex) { + throw "setAlgAndProvider hash alg set fail alg=" + alg + "/" + ex; + } + this.updateString = function(str) { + this.md.update(str); + }; + this.updateHex = function(hex) { + var baHex = sjcl.codec.hex.toBits(hex); + this.md.update(baHex); + }; + this.digest = function() { + var hash = this.md.finalize(); + return sjcl.codec.hex.fromBits(hash); + }; + this.digestString = function(str) { + this.updateString(str); + return this.digest(); + }; + this.digestHex = function(hex) { + this.updateHex(hex); + return this.digest(); + }; + } + }; + + /** + * update digest by specified string + * @name updateString + * @memberOf KJUR.crypto.MessageDigest# + * @function + * @param {String} str string to update + * @description + * @example + * md.updateString('New York'); + */ + this.updateString = function(str) { + throw "updateString(str) not supported for this alg/prov: " + this.algName + "/" + this.provName; + }; + + /** + * update digest by specified hexadecimal string + * @name updateHex + * @memberOf KJUR.crypto.MessageDigest# + * @function + * @param {String} hex hexadecimal string to update + * @description + * @example + * md.updateHex('0afe36'); + */ + this.updateHex = function(hex) { + throw "updateHex(hex) not supported for this alg/prov: " + this.algName + "/" + this.provName; + }; + + /** + * completes hash calculation and returns hash result + * @name digest + * @memberOf KJUR.crypto.MessageDigest# + * @function + * @description + * @example + * md.digest() + */ + this.digest = function() { + throw "digest() not supported for this alg/prov: " + this.algName + "/" + this.provName; + }; + + /** + * performs final update on the digest using string, then completes the digest computation + * @name digestString + * @memberOf KJUR.crypto.MessageDigest# + * @function + * @param {String} str string to final update + * @description + * @example + * md.digestString('aaa') + */ + this.digestString = function(str) { + throw "digestString(str) not supported for this alg/prov: " + this.algName + "/" + this.provName; + }; + + /** + * performs final update on the digest using hexadecimal string, then completes the digest computation + * @name digestHex + * @memberOf KJUR.crypto.MessageDigest# + * @function + * @param {String} hex hexadecimal string to final update + * @description + * @example + * md.digestHex('0f2abd') + */ + this.digestHex = function(hex) { + throw "digestHex(hex) not supported for this alg/prov: " + this.algName + "/" + this.provName; + }; + + if (params !== undefined) { + if (params['alg'] !== undefined) { + this.algName = params['alg']; + if (params['prov'] === undefined) + this.provName = KJUR.crypto.Util.DEFAULTPROVIDER[this.algName]; + this.setAlgAndProvider(this.algName, this.provName); + } + } +}; + +/** + * get canonical hash algorithm name
+ * @name getCanonicalAlgName + * @memberOf KJUR.crypto.MessageDigest + * @function + * @param {String} alg hash algorithm name (ex. MD5, SHA-1, SHA1, SHA512 et.al.) + * @return {String} canonical hash algorithm name + * @since jsrsasign 6.2.0 crypto 1.1.10 + * @description + * This static method normalizes from any hash algorithm name such as + * "SHA-1", "SHA1", "MD5", "sha512" to lower case name without hyphens + * such as "sha1". + * @example + * KJUR.crypto.MessageDigest.getCanonicalAlgName("SHA-1") &rarr "sha1" + * KJUR.crypto.MessageDigest.getCanonicalAlgName("MD5") &rarr "md5" + */ +KJUR.crypto.MessageDigest.getCanonicalAlgName = function(alg) { + if (typeof alg === "string") { + alg = alg.toLowerCase(); + alg = alg.replace(/-/, ''); + } + return alg; +}; + +/** + * get resulted hash byte length for specified algorithm name
+ * @name getHashLength + * @memberOf KJUR.crypto.MessageDigest + * @function + * @param {String} alg non-canonicalized hash algorithm name (ex. MD5, SHA-1, SHA1, SHA512 et.al.) + * @return {Integer} resulted hash byte length + * @since jsrsasign 6.2.0 crypto 1.1.10 + * @description + * This static method returns resulted byte length for specified algorithm name such as "SHA-1". + * @example + * KJUR.crypto.MessageDigest.getHashLength("SHA-1") &rarr 20 + * KJUR.crypto.MessageDigest.getHashLength("sha1") &rarr 20 + */ +KJUR.crypto.MessageDigest.getHashLength = function(alg) { + var MD = KJUR.crypto.MessageDigest + var alg2 = MD.getCanonicalAlgName(alg); + if (MD.HASHLENGTH[alg2] === undefined) + throw "not supported algorithm: " + alg; + return MD.HASHLENGTH[alg2]; +}; + +// described in KJUR.crypto.MessageDigest class (since jsrsasign 6.2.0 crypto 1.1.10) +KJUR.crypto.MessageDigest.HASHLENGTH = { + 'md5': 16, + 'sha1': 20, + 'sha224': 28, + 'sha256': 32, + 'sha384': 48, + 'sha512': 64, + 'ripemd160': 20 +}; + +// === Mac =============================================================== + +/** + * Mac(Message Authentication Code) class which is very similar to java.security.Mac class + * @name KJUR.crypto.Mac + * @class Mac class which is very similar to java.security.Mac class + * @param {Array} params parameters for constructor + * @description + *
+ * Currently this supports following algorithm and providers combination: + *
    + *
  • hmacmd5 - cryptojs
  • + *
  • hmacsha1 - cryptojs
  • + *
  • hmacsha224 - cryptojs
  • + *
  • hmacsha256 - cryptojs
  • + *
  • hmacsha384 - cryptojs
  • + *
  • hmacsha512 - cryptojs
  • + *
+ * NOTE: HmacSHA224 and HmacSHA384 issue was fixed since jsrsasign 4.1.4. + * Please use 'ext/cryptojs-312-core-fix*.js' instead of 'core.js' of original CryptoJS + * to avoid those issue. + *
+ * NOTE2: Hmac signature bug was fixed in jsrsasign 4.9.0 by providing CryptoJS + * bug workaround. + *
+ * Please see {@link KJUR.crypto.Mac.setPassword}, how to provide password + * in various ways in detail. + * @example + * var mac = new KJUR.crypto.Mac({alg: "HmacSHA1", "pass": "pass"}); + * mac.updateString('aaa') + * var macHex = mac.doFinal() + * + * // other password representation + * var mac = new KJUR.crypto.Mac({alg: "HmacSHA256", "pass": {"hex": "6161"}}); + * var mac = new KJUR.crypto.Mac({alg: "HmacSHA256", "pass": {"utf8": "aa"}}); + * var mac = new KJUR.crypto.Mac({alg: "HmacSHA256", "pass": {"rstr": "\x61\x61"}}); + * var mac = new KJUR.crypto.Mac({alg: "HmacSHA256", "pass": {"b64": "Mi02/+...a=="}}); + * var mac = new KJUR.crypto.Mac({alg: "HmacSHA256", "pass": {"b64u": "Mi02_-...a"}}); + */ +KJUR.crypto.Mac = function(params) { + var mac = null; + var pass = null; + var algName = null; + var provName = null; + var algProv = null; + + this.setAlgAndProvider = function(alg, prov) { + alg = alg.toLowerCase(); + + if (alg == null) alg = "hmacsha1"; + + alg = alg.toLowerCase(); + if (alg.substr(0, 4) != "hmac") { + throw "setAlgAndProvider unsupported HMAC alg: " + alg; + } + + if (prov === undefined) prov = KJUR.crypto.Util.DEFAULTPROVIDER[alg]; + this.algProv = alg + "/" + prov; + + var hashAlg = alg.substr(4); + + // for cryptojs + if (':md5:sha1:sha224:sha256:sha384:sha512:ripemd160:'.indexOf(hashAlg) != -1 && + prov == 'cryptojs') { + try { + var mdObj = KJUR.crypto.Util.CRYPTOJSMESSAGEDIGESTNAME[hashAlg]; + this.mac = CryptoJS.algo.HMAC.create(mdObj, this.pass); + } catch (ex) { + throw "setAlgAndProvider hash alg set fail hashAlg=" + hashAlg + "/" + ex; + } + this.updateString = function(str) { + this.mac.update(str); + }; + this.updateHex = function(hex) { + var wHex = CryptoJS.enc.Hex.parse(hex); + this.mac.update(wHex); + }; + this.doFinal = function() { + var hash = this.mac.finalize(); + return hash.toString(CryptoJS.enc.Hex); + }; + this.doFinalString = function(str) { + this.updateString(str); + return this.doFinal(); + }; + this.doFinalHex = function(hex) { + this.updateHex(hex); + return this.doFinal(); + }; + } + }; + + /** + * update digest by specified string + * @name updateString + * @memberOf KJUR.crypto.Mac# + * @function + * @param {String} str string to update + * @description + * @example + * mac.updateString('New York'); + */ + this.updateString = function(str) { + throw "updateString(str) not supported for this alg/prov: " + this.algProv; + }; + + /** + * update digest by specified hexadecimal string + * @name updateHex + * @memberOf KJUR.crypto.Mac# + * @function + * @param {String} hex hexadecimal string to update + * @description + * @example + * mac.updateHex('0afe36'); + */ + this.updateHex = function(hex) { + throw "updateHex(hex) not supported for this alg/prov: " + this.algProv; + }; + + /** + * completes hash calculation and returns hash result + * @name doFinal + * @memberOf KJUR.crypto.Mac# + * @function + * @description + * @example + * mac.digest() + */ + this.doFinal = function() { + throw "digest() not supported for this alg/prov: " + this.algProv; + }; + + /** + * performs final update on the digest using string, then completes the digest computation + * @name doFinalString + * @memberOf KJUR.crypto.Mac# + * @function + * @param {String} str string to final update + * @description + * @example + * mac.digestString('aaa') + */ + this.doFinalString = function(str) { + throw "digestString(str) not supported for this alg/prov: " + this.algProv; + }; + + /** + * performs final update on the digest using hexadecimal string, + * then completes the digest computation + * @name doFinalHex + * @memberOf KJUR.crypto.Mac# + * @function + * @param {String} hex hexadecimal string to final update + * @description + * @example + * mac.digestHex('0f2abd') + */ + this.doFinalHex = function(hex) { + throw "digestHex(hex) not supported for this alg/prov: " + this.algProv; + }; + + /** + * set password for Mac + * @name setPassword + * @memberOf KJUR.crypto.Mac# + * @function + * @param {Object} pass password for Mac + * @since crypto 1.1.7 jsrsasign 4.9.0 + * @description + * This method will set password for (H)Mac internally. + * Argument 'pass' can be specified as following: + *
    + *
  • even length string of 0..9, a..f or A-F: implicitly specified as hexadecimal string
  • + *
  • not above string: implicitly specified as raw string
  • + *
  • {rstr: "\x65\x70"}: explicitly specified as raw string
  • + *
  • {hex: "6570"}: explicitly specified as hexacedimal string
  • + *
  • {utf8: "秘密"}: explicitly specified as UTF8 string
  • + *
  • {b64: "Mi78..=="}: explicitly specified as Base64 string
  • + *
  • {b64u: "Mi7-_"}: explicitly specified as Base64URL string
  • + *
+ * It is *STRONGLY RECOMMENDED* that explicit representation of password argument + * to avoid ambiguity. For example string "6161" can mean a string "6161" or + * a hexadecimal string of "aa" (i.e. \x61\x61). + * @example + * mac = KJUR.crypto.Mac({'alg': 'hmacsha256'}); + * // set password by implicit raw string + * mac.setPassword("\x65\x70\xb9\x0b"); + * mac.setPassword("password"); + * // set password by implicit hexadecimal string + * mac.setPassword("6570b90b"); + * mac.setPassword("6570B90B"); + * // set password by explicit raw string + * mac.setPassword({"rstr": "\x65\x70\xb9\x0b"}); + * // set password by explicit hexadecimal string + * mac.setPassword({"hex": "6570b90b"}); + * // set password by explicit utf8 string + * mac.setPassword({"utf8": "passwordパスワード"); + * // set password by explicit Base64 string + * mac.setPassword({"b64": "Mb+c3f/=="}); + * // set password by explicit Base64URL string + * mac.setPassword({"b64u": "Mb-c3f_"}); + */ + this.setPassword = function(pass) { + // internal this.pass shall be CryptoJS DWord Object for CryptoJS bug + // work around. CrytoJS HMac password can be passed by + // raw string as described in the manual however it doesn't + // work properly in some case. If password was passed + // by CryptoJS DWord which is not described in the manual + // it seems to work. (fixed since crypto 1.1.7) + + if (typeof pass == 'string') { + var hPass = pass; + if (pass.length % 2 == 1 || ! pass.match(/^[0-9A-Fa-f]+$/)) { // raw str + hPass = rstrtohex(pass); + } + this.pass = CryptoJS.enc.Hex.parse(hPass); + return; + } + + if (typeof pass != 'object') + throw "KJUR.crypto.Mac unsupported password type: " + pass; + + var hPass = null; + if (pass.hex !== undefined) { + if (pass.hex.length % 2 != 0 || ! pass.hex.match(/^[0-9A-Fa-f]+$/)) + throw "Mac: wrong hex password: " + pass.hex; + hPass = pass.hex; + } + if (pass.utf8 !== undefined) hPass = utf8tohex(pass.utf8); + if (pass.rstr !== undefined) hPass = rstrtohex(pass.rstr); + if (pass.b64 !== undefined) hPass = b64tohex(pass.b64); + if (pass.b64u !== undefined) hPass = b64utohex(pass.b64u); + + if (hPass == null) + throw "KJUR.crypto.Mac unsupported password type: " + pass; + + this.pass = CryptoJS.enc.Hex.parse(hPass); + }; + + if (params !== undefined) { + if (params.pass !== undefined) { + this.setPassword(params.pass); + } + if (params.alg !== undefined) { + this.algName = params.alg; + if (params['prov'] === undefined) + this.provName = KJUR.crypto.Util.DEFAULTPROVIDER[this.algName]; + this.setAlgAndProvider(this.algName, this.provName); + } + } +}; + +// ====== Signature class ========================================================= +/** + * Signature class which is very similar to java.security.Signature class + * @name KJUR.crypto.Signature + * @class Signature class which is very similar to java.security.Signature class + * @param {Array} params parameters for constructor + * @property {String} state Current state of this signature object whether 'SIGN', 'VERIFY' or null + * @description + *
+ * As for params of constructor's argument, it can be specify following attributes: + *
    + *
  • alg - signature algorithm name (ex. {MD5,SHA1,SHA224,SHA256,SHA384,SHA512,RIPEMD160}with{RSA,ECDSA,DSA})
  • + *
  • provider - currently 'cryptojs/jsrsa' only
  • + *
+ *

SUPPORTED ALGORITHMS AND PROVIDERS

+ * This Signature class supports following signature algorithm and provider names: + *
    + *
  • MD5withRSA - cryptojs/jsrsa
  • + *
  • SHA1withRSA - cryptojs/jsrsa
  • + *
  • SHA224withRSA - cryptojs/jsrsa
  • + *
  • SHA256withRSA - cryptojs/jsrsa
  • + *
  • SHA384withRSA - cryptojs/jsrsa
  • + *
  • SHA512withRSA - cryptojs/jsrsa
  • + *
  • RIPEMD160withRSA - cryptojs/jsrsa
  • + *
  • MD5withECDSA - cryptojs/jsrsa
  • + *
  • SHA1withECDSA - cryptojs/jsrsa
  • + *
  • SHA224withECDSA - cryptojs/jsrsa
  • + *
  • SHA256withECDSA - cryptojs/jsrsa
  • + *
  • SHA384withECDSA - cryptojs/jsrsa
  • + *
  • SHA512withECDSA - cryptojs/jsrsa
  • + *
  • RIPEMD160withECDSA - cryptojs/jsrsa
  • + *
  • MD5withRSAandMGF1 - cryptojs/jsrsa
  • + *
  • SHA1withRSAandMGF1 - cryptojs/jsrsa
  • + *
  • SHA224withRSAandMGF1 - cryptojs/jsrsa
  • + *
  • SHA256withRSAandMGF1 - cryptojs/jsrsa
  • + *
  • SHA384withRSAandMGF1 - cryptojs/jsrsa
  • + *
  • SHA512withRSAandMGF1 - cryptojs/jsrsa
  • + *
  • RIPEMD160withRSAandMGF1 - cryptojs/jsrsa
  • + *
  • SHA1withDSA - cryptojs/jsrsa
  • + *
  • SHA224withDSA - cryptojs/jsrsa
  • + *
  • SHA256withDSA - cryptojs/jsrsa
  • + *
+ * Here are supported elliptic cryptographic curve names and their aliases for ECDSA: + *
    + *
  • secp256k1
  • + *
  • secp256r1, NIST P-256, P-256, prime256v1
  • + *
  • secp384r1, NIST P-384, P-384
  • + *
+ * NOTE1: DSA signing algorithm is also supported since crypto 1.1.5. + *

EXAMPLES

+ * @example + * // RSA signature generation + * var sig = new KJUR.crypto.Signature({"alg": "SHA1withRSA"}); + * sig.init(prvKeyPEM); + * sig.updateString('aaa'); + * var hSigVal = sig.sign(); + * + * // DSA signature validation + * var sig2 = new KJUR.crypto.Signature({"alg": "SHA1withDSA"}); + * sig2.init(certPEM); + * sig.updateString('aaa'); + * var isValid = sig2.verify(hSigVal); + * + * // ECDSA signing + * var sig = new KJUR.crypto.Signature({'alg':'SHA1withECDSA'}); + * sig.init(prvKeyPEM); + * sig.updateString('aaa'); + * var sigValueHex = sig.sign(); + * + * // ECDSA verifying + * var sig2 = new KJUR.crypto.Signature({'alg':'SHA1withECDSA'}); + * sig.init(certPEM); + * sig.updateString('aaa'); + * var isValid = sig.verify(sigValueHex); + */ +KJUR.crypto.Signature = function(params) { + var prvKey = null; // RSAKey/KJUR.crypto.{ECDSA,DSA} object for signing + var pubKey = null; // RSAKey/KJUR.crypto.{ECDSA,DSA} object for verifying + + var md = null; // KJUR.crypto.MessageDigest object + var sig = null; + var algName = null; + var provName = null; + var algProvName = null; + var mdAlgName = null; + var pubkeyAlgName = null; // rsa,ecdsa,rsaandmgf1(=rsapss) + var state = null; + var pssSaltLen = -1; + var initParams = null; + + var sHashHex = null; // hex hash value for hex + var hDigestInfo = null; + var hPaddedDigestInfo = null; + var hSign = null; + + this._setAlgNames = function() { + var matchResult = this.algName.match(/^(.+)with(.+)$/); + if (matchResult) { + this.mdAlgName = matchResult[1].toLowerCase(); + this.pubkeyAlgName = matchResult[2].toLowerCase(); + } + }; + + this._zeroPaddingOfSignature = function(hex, bitLength) { + var s = ""; + var nZero = bitLength / 4 - hex.length; + for (var i = 0; i < nZero; i++) { + s = s + "0"; + } + return s + hex; + }; + + /** + * set signature algorithm and provider + * @name setAlgAndProvider + * @memberOf KJUR.crypto.Signature# + * @function + * @param {String} alg signature algorithm name + * @param {String} prov provider name + * @description + * @example + * md.setAlgAndProvider('SHA1withRSA', 'cryptojs/jsrsa'); + */ + this.setAlgAndProvider = function(alg, prov) { + this._setAlgNames(); + if (prov != 'cryptojs/jsrsa') + throw "provider not supported: " + prov; + + if (':md5:sha1:sha224:sha256:sha384:sha512:ripemd160:'.indexOf(this.mdAlgName) != -1) { + try { + this.md = new KJUR.crypto.MessageDigest({'alg':this.mdAlgName}); + } catch (ex) { + throw "setAlgAndProvider hash alg set fail alg=" + + this.mdAlgName + "/" + ex; + } + + this.init = function(keyparam, pass) { + var keyObj = null; + try { + if (pass === undefined) { + keyObj = KEYUTIL.getKey(keyparam); + } else { + keyObj = KEYUTIL.getKey(keyparam, pass); + } + } catch (ex) { + throw "init failed:" + ex; + } + + if (keyObj.isPrivate === true) { + this.prvKey = keyObj; + this.state = "SIGN"; + } else if (keyObj.isPublic === true) { + this.pubKey = keyObj; + this.state = "VERIFY"; + } else { + throw "init failed.:" + keyObj; + } + }; + + this.updateString = function(str) { + this.md.updateString(str); + }; + + this.updateHex = function(hex) { + this.md.updateHex(hex); + }; + + this.sign = function() { + this.sHashHex = this.md.digest(); + if (typeof this.ecprvhex != "undefined" && + typeof this.eccurvename != "undefined") { + var ec = new KJUR.crypto.ECDSA({'curve': this.eccurvename}); + this.hSign = ec.signHex(this.sHashHex, this.ecprvhex); + } else if (this.prvKey instanceof RSAKey && + this.pubkeyAlgName === "rsaandmgf1") { + this.hSign = this.prvKey.signWithMessageHashPSS(this.sHashHex, + this.mdAlgName, + this.pssSaltLen); + } else if (this.prvKey instanceof RSAKey && + this.pubkeyAlgName === "rsa") { + this.hSign = this.prvKey.signWithMessageHash(this.sHashHex, + this.mdAlgName); + } else if (this.prvKey instanceof KJUR.crypto.ECDSA) { + this.hSign = this.prvKey.signWithMessageHash(this.sHashHex); + } else if (this.prvKey instanceof KJUR.crypto.DSA) { + this.hSign = this.prvKey.signWithMessageHash(this.sHashHex); + } else { + throw "Signature: unsupported private key alg: " + this.pubkeyAlgName; + } + return this.hSign; + }; + this.signString = function(str) { + this.updateString(str); + return this.sign(); + }; + this.signHex = function(hex) { + this.updateHex(hex); + return this.sign(); + }; + this.verify = function(hSigVal) { + this.sHashHex = this.md.digest(); + if (typeof this.ecpubhex != "undefined" && + typeof this.eccurvename != "undefined") { + var ec = new KJUR.crypto.ECDSA({curve: this.eccurvename}); + return ec.verifyHex(this.sHashHex, hSigVal, this.ecpubhex); + } else if (this.pubKey instanceof RSAKey && + this.pubkeyAlgName === "rsaandmgf1") { + return this.pubKey.verifyWithMessageHashPSS(this.sHashHex, hSigVal, + this.mdAlgName, + this.pssSaltLen); + } else if (this.pubKey instanceof RSAKey && + this.pubkeyAlgName === "rsa") { + return this.pubKey.verifyWithMessageHash(this.sHashHex, hSigVal); + } else if (KJUR.crypto.ECDSA !== undefined && + this.pubKey instanceof KJUR.crypto.ECDSA) { + return this.pubKey.verifyWithMessageHash(this.sHashHex, hSigVal); + } else if (KJUR.crypto.DSA !== undefined && + this.pubKey instanceof KJUR.crypto.DSA) { + return this.pubKey.verifyWithMessageHash(this.sHashHex, hSigVal); + } else { + throw "Signature: unsupported public key alg: " + this.pubkeyAlgName; + } + }; + } + }; + + /** + * Initialize this object for signing or verifying depends on key + * @name init + * @memberOf KJUR.crypto.Signature# + * @function + * @param {Object} key specifying public or private key as plain/encrypted PKCS#5/8 PEM file, certificate PEM or {@link RSAKey}, {@link KJUR.crypto.DSA} or {@link KJUR.crypto.ECDSA} object + * @param {String} pass (OPTION) passcode for encrypted private key + * @since crypto 1.1.3 + * @description + * This method is very useful initialize method for Signature class since + * you just specify key then this method will automatically initialize it + * using {@link KEYUTIL.getKey} method. + * As for 'key', following argument type are supported: + *
signing
+ *
    + *
  • PEM formatted PKCS#8 encrypted RSA/ECDSA private key concluding "BEGIN ENCRYPTED PRIVATE KEY"
  • + *
  • PEM formatted PKCS#5 encrypted RSA/DSA private key concluding "BEGIN RSA/DSA PRIVATE KEY" and ",ENCRYPTED"
  • + *
  • PEM formatted PKCS#8 plain RSA/ECDSA private key concluding "BEGIN PRIVATE KEY"
  • + *
  • PEM formatted PKCS#5 plain RSA/DSA private key concluding "BEGIN RSA/DSA PRIVATE KEY" without ",ENCRYPTED"
  • + *
  • RSAKey object of private key
  • + *
  • KJUR.crypto.ECDSA object of private key
  • + *
  • KJUR.crypto.DSA object of private key
  • + *
+ *
verification
+ *
    + *
  • PEM formatted PKCS#8 RSA/EC/DSA public key concluding "BEGIN PUBLIC KEY"
  • + *
  • PEM formatted X.509 certificate with RSA/EC/DSA public key concluding + * "BEGIN CERTIFICATE", "BEGIN X509 CERTIFICATE" or "BEGIN TRUSTED CERTIFICATE".
  • + *
  • RSAKey object of public key
  • + *
  • KJUR.crypto.ECDSA object of public key
  • + *
  • KJUR.crypto.DSA object of public key
  • + *
+ * @example + * sig.init(sCertPEM) + */ + this.init = function(key, pass) { + throw "init(key, pass) not supported for this alg:prov=" + + this.algProvName; + }; + + /** + * Updates the data to be signed or verified by a string + * @name updateString + * @memberOf KJUR.crypto.Signature# + * @function + * @param {String} str string to use for the update + * @description + * @example + * sig.updateString('aaa') + */ + this.updateString = function(str) { + throw "updateString(str) not supported for this alg:prov=" + this.algProvName; + }; + + /** + * Updates the data to be signed or verified by a hexadecimal string + * @name updateHex + * @memberOf KJUR.crypto.Signature# + * @function + * @param {String} hex hexadecimal string to use for the update + * @description + * @example + * sig.updateHex('1f2f3f') + */ + this.updateHex = function(hex) { + throw "updateHex(hex) not supported for this alg:prov=" + this.algProvName; + }; + + /** + * Returns the signature bytes of all data updates as a hexadecimal string + * @name sign + * @memberOf KJUR.crypto.Signature# + * @function + * @return the signature bytes as a hexadecimal string + * @description + * @example + * var hSigValue = sig.sign() + */ + this.sign = function() { + throw "sign() not supported for this alg:prov=" + this.algProvName; + }; + + /** + * performs final update on the sign using string, then returns the signature bytes of all data updates as a hexadecimal string + * @name signString + * @memberOf KJUR.crypto.Signature# + * @function + * @param {String} str string to final update + * @return the signature bytes of a hexadecimal string + * @description + * @example + * var hSigValue = sig.signString('aaa') + */ + this.signString = function(str) { + throw "digestString(str) not supported for this alg:prov=" + this.algProvName; + }; + + /** + * performs final update on the sign using hexadecimal string, then returns the signature bytes of all data updates as a hexadecimal string + * @name signHex + * @memberOf KJUR.crypto.Signature# + * @function + * @param {String} hex hexadecimal string to final update + * @return the signature bytes of a hexadecimal string + * @description + * @example + * var hSigValue = sig.signHex('1fdc33') + */ + this.signHex = function(hex) { + throw "digestHex(hex) not supported for this alg:prov=" + this.algProvName; + }; + + /** + * verifies the passed-in signature. + * @name verify + * @memberOf KJUR.crypto.Signature# + * @function + * @param {String} str string to final update + * @return {Boolean} true if the signature was verified, otherwise false + * @description + * @example + * var isValid = sig.verify('1fbcefdca4823a7(snip)') + */ + this.verify = function(hSigVal) { + throw "verify(hSigVal) not supported for this alg:prov=" + this.algProvName; + }; + + this.initParams = params; + + if (params !== undefined) { + if (params.alg !== undefined) { + this.algName = params.alg; + if (params.prov === undefined) { + this.provName = KJUR.crypto.Util.DEFAULTPROVIDER[this.algName]; + } else { + this.provName = params.prov; + } + this.algProvName = this.algName + ":" + this.provName; + this.setAlgAndProvider(this.algName, this.provName); + this._setAlgNames(); + } + + if (params['psssaltlen'] !== undefined) this.pssSaltLen = params['psssaltlen']; + + if (params.prvkeypem !== undefined) { + if (params.prvkeypas !== undefined) { + throw "both prvkeypem and prvkeypas parameters not supported"; + } else { + try { + var prvKey = KEYUTIL.getKey(params.prvkeypem); + this.init(prvKey); + } catch (ex) { + throw "fatal error to load pem private key: " + ex; + } + } + } + } +}; + +// ====== Cipher class ============================================================ +/** + * Cipher class to encrypt and decrypt data
+ * @name KJUR.crypto.Cipher + * @class Cipher class to encrypt and decrypt data
+ * @param {Array} params parameters for constructor + * @since jsrsasign 6.2.0 crypto 1.1.10 + * @description + * Here is supported canonicalized cipher algorithm names and its standard names: + *
    + *
  • RSA - RSA/ECB/PKCS1Padding (default for RSAKey)
  • + *
  • RSAOAEP - RSA/ECB/OAEPWithSHA-1AndMGF1Padding
  • + *
  • RSAOAEP224 - RSA/ECB/OAEPWithSHA-224AndMGF1Padding(*)
  • + *
  • RSAOAEP256 - RSA/ECB/OAEPWithSHA-256AndMGF1Padding
  • + *
  • RSAOAEP384 - RSA/ECB/OAEPWithSHA-384AndMGF1Padding(*)
  • + *
  • RSAOAEP512 - RSA/ECB/OAEPWithSHA-512AndMGF1Padding(*)
  • + *
+ * NOTE: (*) is not supported in Java JCE.
+ * Currently this class supports only RSA encryption and decryption. + * However it is planning to implement also symmetric ciphers near in the future. + * @example + */ +KJUR.crypto.Cipher = function(params) { +}; + +/** + * encrypt raw string by specified key and algorithm
+ * @name encrypt + * @memberOf KJUR.crypto.Cipher + * @function + * @param {String} s input string to encrypt + * @param {Object} keyObj RSAKey object or hexadecimal string of symmetric cipher key + * @param {String} algName short/long algorithm name for encryption/decryption + * @return {String} hexadecimal encrypted string + * @since jsrsasign 6.2.0 crypto 1.1.10 + * @description + * This static method encrypts raw string with specified key and algorithm. + * @example + * KJUR.crypto.Cipher.encrypt("aaa", pubRSAKeyObj) → "1abc2d..." + * KJUR.crypto.Cipher.encrypt("aaa", pubRSAKeyObj, "RSAOAEP") → "23ab02..." + */ +KJUR.crypto.Cipher.encrypt = function(s, keyObj, algName) { + if (keyObj instanceof RSAKey && keyObj.isPublic) { + var algName2 = KJUR.crypto.Cipher.getAlgByKeyAndName(keyObj, algName); + if (algName2 === "RSA") return keyObj.encrypt(s); + if (algName2 === "RSAOAEP") return keyObj.encryptOAEP(s, "sha1"); + + var a = algName2.match(/^RSAOAEP(\d+)$/); + if (a !== null) return keyObj.encryptOAEP(s, "sha" + a[1]); + + throw "Cipher.encrypt: unsupported algorithm for RSAKey: " + algName; + } else { + throw "Cipher.encrypt: unsupported key or algorithm"; + } +}; + +/** + * decrypt encrypted hexadecimal string with specified key and algorithm
+ * @name decrypt + * @memberOf KJUR.crypto.Cipher + * @function + * @param {String} hex hexadecial string of encrypted message + * @param {Object} keyObj RSAKey object or hexadecimal string of symmetric cipher key + * @param {String} algName short/long algorithm name for encryption/decryption + * @return {String} hexadecimal encrypted string + * @since jsrsasign 6.2.0 crypto 1.1.10 + * @description + * This static method decrypts encrypted hexadecimal string with specified key and algorithm. + * @example + * KJUR.crypto.Cipher.decrypt("aaa", prvRSAKeyObj) → "1abc2d..." + * KJUR.crypto.Cipher.decrypt("aaa", prvRSAKeyObj, "RSAOAEP) → "23ab02..." + */ +KJUR.crypto.Cipher.decrypt = function(hex, keyObj, algName) { + if (keyObj instanceof RSAKey && keyObj.isPrivate) { + var algName2 = KJUR.crypto.Cipher.getAlgByKeyAndName(keyObj, algName); + if (algName2 === "RSA") return keyObj.decrypt(hex); + if (algName2 === "RSAOAEP") return keyObj.decryptOAEP(hex, "sha1"); + + var a = algName2.match(/^RSAOAEP(\d+)$/); + if (a !== null) return keyObj.decryptOAEP(hex, "sha" + a[1]); + + throw "Cipher.decrypt: unsupported algorithm for RSAKey: " + algName; + } else { + throw "Cipher.decrypt: unsupported key or algorithm"; + } +}; + +/** + * get canonicalized encrypt/decrypt algorithm name by key and short/long algorithm name
+ * @name getAlgByKeyAndName + * @memberOf KJUR.crypto.Cipher + * @function + * @param {Object} keyObj RSAKey object or hexadecimal string of symmetric cipher key + * @param {String} algName short/long algorithm name for encryption/decryption + * @return {String} canonicalized algorithm name for encryption/decryption + * @since jsrsasign 6.2.0 crypto 1.1.10 + * @description + * Here is supported canonicalized cipher algorithm names and its standard names: + *
    + *
  • RSA - RSA/ECB/PKCS1Padding (default for RSAKey)
  • + *
  • RSAOAEP - RSA/ECB/OAEPWithSHA-1AndMGF1Padding
  • + *
  • RSAOAEP224 - RSA/ECB/OAEPWithSHA-224AndMGF1Padding(*)
  • + *
  • RSAOAEP256 - RSA/ECB/OAEPWithSHA-256AndMGF1Padding
  • + *
  • RSAOAEP384 - RSA/ECB/OAEPWithSHA-384AndMGF1Padding(*)
  • + *
  • RSAOAEP512 - RSA/ECB/OAEPWithSHA-512AndMGF1Padding(*)
  • + *
+ * NOTE: (*) is not supported in Java JCE. + * @example + * KJUR.crypto.Cipher.getAlgByKeyAndName(objRSAKey) → "RSA" + * KJUR.crypto.Cipher.getAlgByKeyAndName(objRSAKey, "RSAOAEP") → "RSAOAEP" + */ +KJUR.crypto.Cipher.getAlgByKeyAndName = function(keyObj, algName) { + if (keyObj instanceof RSAKey) { + if (":RSA:RSAOAEP:RSAOAEP224:RSAOAEP256:RSAOAEP384:RSAOAEP512:".indexOf(algName) != -1) + return algName; + if (algName === null || algName === undefined) return "RSA"; + throw "getAlgByKeyAndName: not supported algorithm name for RSAKey: " + algName; + } + throw "getAlgByKeyAndName: not supported algorithm name: " + algName; +} + +// ====== Other Utility class ===================================================== + +/** + * static object for cryptographic function utilities + * @name KJUR.crypto.OID + * @class static object for cryptography related OIDs + * @property {Array} oidhex2name key value of hexadecimal OID and its name + * (ex. '2a8648ce3d030107' and 'secp256r1') + * @since crypto 1.1.3 + * @description + */ +KJUR.crypto.OID = new function() { + this.oidhex2name = { + '2a864886f70d010101': 'rsaEncryption', + '2a8648ce3d0201': 'ecPublicKey', + '2a8648ce380401': 'dsa', + '2a8648ce3d030107': 'secp256r1', + '2b8104001f': 'secp192k1', + '2b81040021': 'secp224r1', + '2b8104000a': 'secp256k1', + '2b81040023': 'secp521r1', + '2b81040022': 'secp384r1', + '2a8648ce380403': 'SHA1withDSA', // 1.2.840.10040.4.3 + '608648016503040301': 'SHA224withDSA', // 2.16.840.1.101.3.4.3.1 + '608648016503040302': 'SHA256withDSA', // 2.16.840.1.101.3.4.3.2 + }; +}; diff --git a/source/cryptojs-312-core-fix.js b/source/cryptojs-312-core-fix.js new file mode 100644 index 0000000..4e67688 --- /dev/null +++ b/source/cryptojs-312-core-fix.js @@ -0,0 +1,711 @@ +/*! CryptoJS v3.1.2 core-fix.js + * code.google.com/p/crypto-js + * (c) 2009-2013 by Jeff Mott. All rights reserved. + * code.google.com/p/crypto-js/wiki/License + * THIS IS FIX of 'core.js' to fix Hmac issue. + * https://code.google.com/p/crypto-js/issues/detail?id=84 + * https://crypto-js.googlecode.com/svn-history/r667/branches/3.x/src/core.js + */ +/** + * CryptoJS core components. + */ +var CryptoJS = CryptoJS || (function (Math, undefined) { + /** + * CryptoJS namespace. + */ + var C = {}; + + /** + * Library namespace. + */ + var C_lib = C.lib = {}; + + /** + * Base object for prototypal inheritance. + */ + var Base = C_lib.Base = (function () { + function F() {} + + return { + /** + * Creates a new object that inherits from this object. + * + * @param {Object} overrides Properties to copy into the new object. + * + * @return {Object} The new object. + * + * @static + * + * @example + * + * var MyType = CryptoJS.lib.Base.extend({ + * field: 'value', + * + * method: function () { + * } + * }); + */ + extend: function (overrides) { + // Spawn + F.prototype = this; + var subtype = new F(); + + // Augment + if (overrides) { + subtype.mixIn(overrides); + } + + // Create default initializer + if (!subtype.hasOwnProperty('init')) { + subtype.init = function () { + subtype.$super.init.apply(this, arguments); + }; + } + + // Initializer's prototype is the subtype object + subtype.init.prototype = subtype; + + // Reference supertype + subtype.$super = this; + + return subtype; + }, + + /** + * Extends this object and runs the init method. + * Arguments to create() will be passed to init(). + * + * @return {Object} The new object. + * + * @static + * + * @example + * + * var instance = MyType.create(); + */ + create: function () { + var instance = this.extend(); + instance.init.apply(instance, arguments); + + return instance; + }, + + /** + * Initializes a newly created object. + * Override this method to add some logic when your objects are created. + * + * @example + * + * var MyType = CryptoJS.lib.Base.extend({ + * init: function () { + * // ... + * } + * }); + */ + init: function () { + }, + + /** + * Copies properties into this object. + * + * @param {Object} properties The properties to mix in. + * + * @example + * + * MyType.mixIn({ + * field: 'value' + * }); + */ + mixIn: function (properties) { + for (var propertyName in properties) { + if (properties.hasOwnProperty(propertyName)) { + this[propertyName] = properties[propertyName]; + } + } + + // IE won't copy toString using the loop above + if (properties.hasOwnProperty('toString')) { + this.toString = properties.toString; + } + }, + + /** + * Creates a copy of this object. + * + * @return {Object} The clone. + * + * @example + * + * var clone = instance.clone(); + */ + clone: function () { + return this.init.prototype.extend(this); + } + }; + }()); + + /** + * An array of 32-bit words. + * + * @property {Array} words The array of 32-bit words. + * @property {number} sigBytes The number of significant bytes in this word array. + */ + var WordArray = C_lib.WordArray = Base.extend({ + /** + * Initializes a newly created word array. + * + * @param {Array} words (Optional) An array of 32-bit words. + * @param {number} sigBytes (Optional) The number of significant bytes in the words. + * + * @example + * + * var wordArray = CryptoJS.lib.WordArray.create(); + * var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607]); + * var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607], 6); + */ + init: function (words, sigBytes) { + words = this.words = words || []; + + if (sigBytes != undefined) { + this.sigBytes = sigBytes; + } else { + this.sigBytes = words.length * 4; + } + }, + + /** + * Converts this word array to a string. + * + * @param {Encoder} encoder (Optional) The encoding strategy to use. Default: CryptoJS.enc.Hex + * + * @return {string} The stringified word array. + * + * @example + * + * var string = wordArray + ''; + * var string = wordArray.toString(); + * var string = wordArray.toString(CryptoJS.enc.Utf8); + */ + toString: function (encoder) { + return (encoder || Hex).stringify(this); + }, + + /** + * Concatenates a word array to this word array. + * + * @param {WordArray} wordArray The word array to append. + * + * @return {WordArray} This word array. + * + * @example + * + * wordArray1.concat(wordArray2); + */ + concat: function (wordArray) { + // Shortcuts + var thisWords = this.words; + var thatWords = wordArray.words; + var thisSigBytes = this.sigBytes; + var thatSigBytes = wordArray.sigBytes; + + // Clamp excess bits + this.clamp(); + + // Concat + if (thisSigBytes % 4) { + // Copy one byte at a time + for (var i = 0; i < thatSigBytes; i++) { + var thatByte = (thatWords[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; + thisWords[(thisSigBytes + i) >>> 2] |= thatByte << (24 - ((thisSigBytes + i) % 4) * 8); + } + } else { + // Copy one word at a time + for (var i = 0; i < thatSigBytes; i += 4) { + thisWords[(thisSigBytes + i) >>> 2] = thatWords[i >>> 2]; + } + } + this.sigBytes += thatSigBytes; + + // Chainable + return this; + }, + + /** + * Removes insignificant bits. + * + * @example + * + * wordArray.clamp(); + */ + clamp: function () { + // Shortcuts + var words = this.words; + var sigBytes = this.sigBytes; + + // Clamp + words[sigBytes >>> 2] &= 0xffffffff << (32 - (sigBytes % 4) * 8); + words.length = Math.ceil(sigBytes / 4); + }, + + /** + * Creates a copy of this word array. + * + * @return {WordArray} The clone. + * + * @example + * + * var clone = wordArray.clone(); + */ + clone: function () { + var clone = Base.clone.call(this); + clone.words = this.words.slice(0); + + return clone; + }, + + /** + * Creates a word array filled with random bytes. + * + * @param {number} nBytes The number of random bytes to generate. + * + * @return {WordArray} The random word array. + * + * @static + * + * @example + * + * var wordArray = CryptoJS.lib.WordArray.random(16); + */ + random: function (nBytes) { + var words = []; + for (var i = 0; i < nBytes; i += 4) { + words.push((Math.random() * 0x100000000) | 0); + } + + return new WordArray.init(words, nBytes); + } + }); + + /** + * Encoder namespace. + */ + var C_enc = C.enc = {}; + + /** + * Hex encoding strategy. + */ + var Hex = C_enc.Hex = { + /** + * Converts a word array to a hex string. + * + * @param {WordArray} wordArray The word array. + * + * @return {string} The hex string. + * + * @static + * + * @example + * + * var hexString = CryptoJS.enc.Hex.stringify(wordArray); + */ + stringify: function (wordArray) { + // Shortcuts + var words = wordArray.words; + var sigBytes = wordArray.sigBytes; + + // Convert + var hexChars = []; + for (var i = 0; i < sigBytes; i++) { + var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; + hexChars.push((bite >>> 4).toString(16)); + hexChars.push((bite & 0x0f).toString(16)); + } + + return hexChars.join(''); + }, + + /** + * Converts a hex string to a word array. + * + * @param {string} hexStr The hex string. + * + * @return {WordArray} The word array. + * + * @static + * + * @example + * + * var wordArray = CryptoJS.enc.Hex.parse(hexString); + */ + parse: function (hexStr) { + // Shortcut + var hexStrLength = hexStr.length; + + // Convert + var words = []; + for (var i = 0; i < hexStrLength; i += 2) { + words[i >>> 3] |= parseInt(hexStr.substr(i, 2), 16) << (24 - (i % 8) * 4); + } + + return new WordArray.init(words, hexStrLength / 2); + } + }; + + /** + * Latin1 encoding strategy. + */ + var Latin1 = C_enc.Latin1 = { + /** + * Converts a word array to a Latin1 string. + * + * @param {WordArray} wordArray The word array. + * + * @return {string} The Latin1 string. + * + * @static + * + * @example + * + * var latin1String = CryptoJS.enc.Latin1.stringify(wordArray); + */ + stringify: function (wordArray) { + // Shortcuts + var words = wordArray.words; + var sigBytes = wordArray.sigBytes; + + // Convert + var latin1Chars = []; + for (var i = 0; i < sigBytes; i++) { + var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; + latin1Chars.push(String.fromCharCode(bite)); + } + + return latin1Chars.join(''); + }, + + /** + * Converts a Latin1 string to a word array. + * + * @param {string} latin1Str The Latin1 string. + * + * @return {WordArray} The word array. + * + * @static + * + * @example + * + * var wordArray = CryptoJS.enc.Latin1.parse(latin1String); + */ + parse: function (latin1Str) { + // Shortcut + var latin1StrLength = latin1Str.length; + + // Convert + var words = []; + for (var i = 0; i < latin1StrLength; i++) { + words[i >>> 2] |= (latin1Str.charCodeAt(i) & 0xff) << (24 - (i % 4) * 8); + } + + return new WordArray.init(words, latin1StrLength); + } + }; + + /** + * UTF-8 encoding strategy. + */ + var Utf8 = C_enc.Utf8 = { + /** + * Converts a word array to a UTF-8 string. + * + * @param {WordArray} wordArray The word array. + * + * @return {string} The UTF-8 string. + * + * @static + * + * @example + * + * var utf8String = CryptoJS.enc.Utf8.stringify(wordArray); + */ + stringify: function (wordArray) { + try { + return decodeURIComponent(escape(Latin1.stringify(wordArray))); + } catch (e) { + throw new Error('Malformed UTF-8 data'); + } + }, + + /** + * Converts a UTF-8 string to a word array. + * + * @param {string} utf8Str The UTF-8 string. + * + * @return {WordArray} The word array. + * + * @static + * + * @example + * + * var wordArray = CryptoJS.enc.Utf8.parse(utf8String); + */ + parse: function (utf8Str) { + return Latin1.parse(unescape(encodeURIComponent(utf8Str))); + } + }; + + /** + * Abstract buffered block algorithm template. + * + * The property blockSize must be implemented in a concrete subtype. + * + * @property {number} _minBufferSize The number of blocks that should be kept unprocessed in the buffer. Default: 0 + */ + var BufferedBlockAlgorithm = C_lib.BufferedBlockAlgorithm = Base.extend({ + /** + * Resets this block algorithm's data buffer to its initial state. + * + * @example + * + * bufferedBlockAlgorithm.reset(); + */ + reset: function () { + // Initial values + this._data = new WordArray.init(); + this._nDataBytes = 0; + }, + + /** + * Adds new data to this block algorithm's buffer. + * + * @param {WordArray|string} data The data to append. Strings are converted to a WordArray using UTF-8. + * + * @example + * + * bufferedBlockAlgorithm._append('data'); + * bufferedBlockAlgorithm._append(wordArray); + */ + _append: function (data) { + // Convert string to WordArray, else assume WordArray already + if (typeof data == 'string') { + data = Utf8.parse(data); + } + + // Append + this._data.concat(data); + this._nDataBytes += data.sigBytes; + }, + + /** + * Processes available data blocks. + * + * This method invokes _doProcessBlock(offset), which must be implemented by a concrete subtype. + * + * @param {boolean} doFlush Whether all blocks and partial blocks should be processed. + * + * @return {WordArray} The processed data. + * + * @example + * + * var processedData = bufferedBlockAlgorithm._process(); + * var processedData = bufferedBlockAlgorithm._process(!!'flush'); + */ + _process: function (doFlush) { + // Shortcuts + var data = this._data; + var dataWords = data.words; + var dataSigBytes = data.sigBytes; + var blockSize = this.blockSize; + var blockSizeBytes = blockSize * 4; + + // Count blocks ready + var nBlocksReady = dataSigBytes / blockSizeBytes; + if (doFlush) { + // Round up to include partial blocks + nBlocksReady = Math.ceil(nBlocksReady); + } else { + // Round down to include only full blocks, + // less the number of blocks that must remain in the buffer + nBlocksReady = Math.max((nBlocksReady | 0) - this._minBufferSize, 0); + } + + // Count words ready + var nWordsReady = nBlocksReady * blockSize; + + // Count bytes ready + var nBytesReady = Math.min(nWordsReady * 4, dataSigBytes); + + // Process blocks + if (nWordsReady) { + for (var offset = 0; offset < nWordsReady; offset += blockSize) { + // Perform concrete-algorithm logic + this._doProcessBlock(dataWords, offset); + } + + // Remove processed words + var processedWords = dataWords.splice(0, nWordsReady); + data.sigBytes -= nBytesReady; + } + + // Return processed words + return new WordArray.init(processedWords, nBytesReady); + }, + + /** + * Creates a copy of this object. + * + * @return {Object} The clone. + * + * @example + * + * var clone = bufferedBlockAlgorithm.clone(); + */ + clone: function () { + var clone = Base.clone.call(this); + clone._data = this._data.clone(); + + return clone; + }, + + _minBufferSize: 0 + }); + + /** + * Abstract hasher template. + * + * @property {number} blockSize The number of 32-bit words this hasher operates on. Default: 16 (512 bits) + */ + var Hasher = C_lib.Hasher = BufferedBlockAlgorithm.extend({ + /** + * Configuration options. + */ + cfg: Base.extend(), + + /** + * Initializes a newly created hasher. + * + * @param {Object} cfg (Optional) The configuration options to use for this hash computation. + * + * @example + * + * var hasher = CryptoJS.algo.SHA256.create(); + */ + init: function (cfg) { + // Apply config defaults + this.cfg = this.cfg.extend(cfg); + + // Set initial values + this.reset(); + }, + + /** + * Resets this hasher to its initial state. + * + * @example + * + * hasher.reset(); + */ + reset: function () { + // Reset data buffer + BufferedBlockAlgorithm.reset.call(this); + + // Perform concrete-hasher logic + this._doReset(); + }, + + /** + * Updates this hasher with a message. + * + * @param {WordArray|string} messageUpdate The message to append. + * + * @return {Hasher} This hasher. + * + * @example + * + * hasher.update('message'); + * hasher.update(wordArray); + */ + update: function (messageUpdate) { + // Append + this._append(messageUpdate); + + // Update the hash + this._process(); + + // Chainable + return this; + }, + + /** + * Finalizes the hash computation. + * Note that the finalize operation is effectively a destructive, read-once operation. + * + * @param {WordArray|string} messageUpdate (Optional) A final message update. + * + * @return {WordArray} The hash. + * + * @example + * + * var hash = hasher.finalize(); + * var hash = hasher.finalize('message'); + * var hash = hasher.finalize(wordArray); + */ + finalize: function (messageUpdate) { + // Final message update + if (messageUpdate) { + this._append(messageUpdate); + } + + // Perform concrete-hasher logic + var hash = this._doFinalize(); + + return hash; + }, + + blockSize: 512/32, + + /** + * Creates a shortcut function to a hasher's object interface. + * + * @param {Hasher} hasher The hasher to create a helper for. + * + * @return {Function} The shortcut function. + * + * @static + * + * @example + * + * var SHA256 = CryptoJS.lib.Hasher._createHelper(CryptoJS.algo.SHA256); + */ + _createHelper: function (hasher) { + return function (message, cfg) { + return new hasher.init(cfg).finalize(message); + }; + }, + + /** + * Creates a shortcut function to the HMAC's object interface. + * + * @param {Hasher} hasher The hasher to use in this HMAC helper. + * + * @return {Function} The shortcut function. + * + * @static + * + * @example + * + * var HmacSHA256 = CryptoJS.lib.Hasher._createHmacHelper(CryptoJS.algo.SHA256); + */ + _createHmacHelper: function (hasher) { + return function (message, key) { + return new C_algo.HMAC.init(hasher, key).finalize(message); + }; + } + }); + + /** + * Algorithm namespace. + */ + var C_algo = C.algo = {}; + + return C; +}(Math)); diff --git a/source/ec.js b/source/ec.js new file mode 100644 index 0000000..71aedee --- /dev/null +++ b/source/ec.js @@ -0,0 +1,318 @@ +/*! (c) Tom Wu | http://www-cs-students.stanford.edu/~tjw/jsbn/ + */ +// Basic Javascript Elliptic Curve implementation +// Ported loosely from BouncyCastle's Java EC code +// Only Fp curves implemented for now + +// Requires jsbn.js and jsbn2.js + +// ---------------- +// ECFieldElementFp + +// constructor +function ECFieldElementFp(q,x) { + this.x = x; + // TODO if(x.compareTo(q) >= 0) error + this.q = q; +} + +function feFpEquals(other) { + if(other == this) return true; + return (this.q.equals(other.q) && this.x.equals(other.x)); +} + +function feFpToBigInteger() { + return this.x; +} + +function feFpNegate() { + return new ECFieldElementFp(this.q, this.x.negate().mod(this.q)); +} + +function feFpAdd(b) { + return new ECFieldElementFp(this.q, this.x.add(b.toBigInteger()).mod(this.q)); +} + +function feFpSubtract(b) { + return new ECFieldElementFp(this.q, this.x.subtract(b.toBigInteger()).mod(this.q)); +} + +function feFpMultiply(b) { + return new ECFieldElementFp(this.q, this.x.multiply(b.toBigInteger()).mod(this.q)); +} + +function feFpSquare() { + return new ECFieldElementFp(this.q, this.x.square().mod(this.q)); +} + +function feFpDivide(b) { + return new ECFieldElementFp(this.q, this.x.multiply(b.toBigInteger().modInverse(this.q)).mod(this.q)); +} + +ECFieldElementFp.prototype.equals = feFpEquals; +ECFieldElementFp.prototype.toBigInteger = feFpToBigInteger; +ECFieldElementFp.prototype.negate = feFpNegate; +ECFieldElementFp.prototype.add = feFpAdd; +ECFieldElementFp.prototype.subtract = feFpSubtract; +ECFieldElementFp.prototype.multiply = feFpMultiply; +ECFieldElementFp.prototype.square = feFpSquare; +ECFieldElementFp.prototype.divide = feFpDivide; + +// ---------------- +// ECPointFp + +// constructor +function ECPointFp(curve,x,y,z) { + this.curve = curve; + this.x = x; + this.y = y; + // Projective coordinates: either zinv == null or z * zinv == 1 + // z and zinv are just BigIntegers, not fieldElements + if(z == null) { + this.z = BigInteger.ONE; + } + else { + this.z = z; + } + this.zinv = null; + //TODO: compression flag +} + +function pointFpGetX() { + if(this.zinv == null) { + this.zinv = this.z.modInverse(this.curve.q); + } + return this.curve.fromBigInteger(this.x.toBigInteger().multiply(this.zinv).mod(this.curve.q)); +} + +function pointFpGetY() { + if(this.zinv == null) { + this.zinv = this.z.modInverse(this.curve.q); + } + return this.curve.fromBigInteger(this.y.toBigInteger().multiply(this.zinv).mod(this.curve.q)); +} + +function pointFpEquals(other) { + if(other == this) return true; + if(this.isInfinity()) return other.isInfinity(); + if(other.isInfinity()) return this.isInfinity(); + var u, v; + // u = Y2 * Z1 - Y1 * Z2 + u = other.y.toBigInteger().multiply(this.z).subtract(this.y.toBigInteger().multiply(other.z)).mod(this.curve.q); + if(!u.equals(BigInteger.ZERO)) return false; + // v = X2 * Z1 - X1 * Z2 + v = other.x.toBigInteger().multiply(this.z).subtract(this.x.toBigInteger().multiply(other.z)).mod(this.curve.q); + return v.equals(BigInteger.ZERO); +} + +function pointFpIsInfinity() { + if((this.x == null) && (this.y == null)) return true; + return this.z.equals(BigInteger.ZERO) && !this.y.toBigInteger().equals(BigInteger.ZERO); +} + +function pointFpNegate() { + return new ECPointFp(this.curve, this.x, this.y.negate(), this.z); +} + +function pointFpAdd(b) { + if(this.isInfinity()) return b; + if(b.isInfinity()) return this; + + // u = Y2 * Z1 - Y1 * Z2 + var u = b.y.toBigInteger().multiply(this.z).subtract(this.y.toBigInteger().multiply(b.z)).mod(this.curve.q); + // v = X2 * Z1 - X1 * Z2 + var v = b.x.toBigInteger().multiply(this.z).subtract(this.x.toBigInteger().multiply(b.z)).mod(this.curve.q); + + if(BigInteger.ZERO.equals(v)) { + if(BigInteger.ZERO.equals(u)) { + return this.twice(); // this == b, so double + } + return this.curve.getInfinity(); // this = -b, so infinity + } + + var THREE = new BigInteger("3"); + var x1 = this.x.toBigInteger(); + var y1 = this.y.toBigInteger(); + var x2 = b.x.toBigInteger(); + var y2 = b.y.toBigInteger(); + + var v2 = v.square(); + var v3 = v2.multiply(v); + var x1v2 = x1.multiply(v2); + var zu2 = u.square().multiply(this.z); + + // x3 = v * (z2 * (z1 * u^2 - 2 * x1 * v^2) - v^3) + var x3 = zu2.subtract(x1v2.shiftLeft(1)).multiply(b.z).subtract(v3).multiply(v).mod(this.curve.q); + // y3 = z2 * (3 * x1 * u * v^2 - y1 * v^3 - z1 * u^3) + u * v^3 + var y3 = x1v2.multiply(THREE).multiply(u).subtract(y1.multiply(v3)).subtract(zu2.multiply(u)).multiply(b.z).add(u.multiply(v3)).mod(this.curve.q); + // z3 = v^3 * z1 * z2 + var z3 = v3.multiply(this.z).multiply(b.z).mod(this.curve.q); + + return new ECPointFp(this.curve, this.curve.fromBigInteger(x3), this.curve.fromBigInteger(y3), z3); +} + +function pointFpTwice() { + if(this.isInfinity()) return this; + if(this.y.toBigInteger().signum() == 0) return this.curve.getInfinity(); + + // TODO: optimized handling of constants + var THREE = new BigInteger("3"); + var x1 = this.x.toBigInteger(); + var y1 = this.y.toBigInteger(); + + var y1z1 = y1.multiply(this.z); + var y1sqz1 = y1z1.multiply(y1).mod(this.curve.q); + var a = this.curve.a.toBigInteger(); + + // w = 3 * x1^2 + a * z1^2 + var w = x1.square().multiply(THREE); + if(!BigInteger.ZERO.equals(a)) { + w = w.add(this.z.square().multiply(a)); + } + w = w.mod(this.curve.q); + // x3 = 2 * y1 * z1 * (w^2 - 8 * x1 * y1^2 * z1) + var x3 = w.square().subtract(x1.shiftLeft(3).multiply(y1sqz1)).shiftLeft(1).multiply(y1z1).mod(this.curve.q); + // y3 = 4 * y1^2 * z1 * (3 * w * x1 - 2 * y1^2 * z1) - w^3 + var y3 = w.multiply(THREE).multiply(x1).subtract(y1sqz1.shiftLeft(1)).shiftLeft(2).multiply(y1sqz1).subtract(w.square().multiply(w)).mod(this.curve.q); + // z3 = 8 * (y1 * z1)^3 + var z3 = y1z1.square().multiply(y1z1).shiftLeft(3).mod(this.curve.q); + + return new ECPointFp(this.curve, this.curve.fromBigInteger(x3), this.curve.fromBigInteger(y3), z3); +} + +// Simple NAF (Non-Adjacent Form) multiplication algorithm +// TODO: modularize the multiplication algorithm +function pointFpMultiply(k) { + if(this.isInfinity()) return this; + if(k.signum() == 0) return this.curve.getInfinity(); + + var e = k; + var h = e.multiply(new BigInteger("3")); + + var neg = this.negate(); + var R = this; + + var i; + for(i = h.bitLength() - 2; i > 0; --i) { + R = R.twice(); + + var hBit = h.testBit(i); + var eBit = e.testBit(i); + + if (hBit != eBit) { + R = R.add(hBit ? this : neg); + } + } + + return R; +} + +// Compute this*j + x*k (simultaneous multiplication) +function pointFpMultiplyTwo(j,x,k) { + var i; + if(j.bitLength() > k.bitLength()) + i = j.bitLength() - 1; + else + i = k.bitLength() - 1; + + var R = this.curve.getInfinity(); + var both = this.add(x); + while(i >= 0) { + R = R.twice(); + if(j.testBit(i)) { + if(k.testBit(i)) { + R = R.add(both); + } + else { + R = R.add(this); + } + } + else { + if(k.testBit(i)) { + R = R.add(x); + } + } + --i; + } + + return R; +} + +ECPointFp.prototype.getX = pointFpGetX; +ECPointFp.prototype.getY = pointFpGetY; +ECPointFp.prototype.equals = pointFpEquals; +ECPointFp.prototype.isInfinity = pointFpIsInfinity; +ECPointFp.prototype.negate = pointFpNegate; +ECPointFp.prototype.add = pointFpAdd; +ECPointFp.prototype.twice = pointFpTwice; +ECPointFp.prototype.multiply = pointFpMultiply; +ECPointFp.prototype.multiplyTwo = pointFpMultiplyTwo; + +// ---------------- +// ECCurveFp + +// constructor +function ECCurveFp(q,a,b) { + this.q = q; + this.a = this.fromBigInteger(a); + this.b = this.fromBigInteger(b); + this.infinity = new ECPointFp(this, null, null); +} + +function curveFpGetQ() { + return this.q; +} + +function curveFpGetA() { + return this.a; +} + +function curveFpGetB() { + return this.b; +} + +function curveFpEquals(other) { + if(other == this) return true; + return(this.q.equals(other.q) && this.a.equals(other.a) && this.b.equals(other.b)); +} + +function curveFpGetInfinity() { + return this.infinity; +} + +function curveFpFromBigInteger(x) { + return new ECFieldElementFp(this.q, x); +} + +// for now, work with hex strings because they're easier in JS +function curveFpDecodePointHex(s) { + switch(parseInt(s.substr(0,2), 16)) { // first byte + case 0: + return this.infinity; + case 2: + case 3: + // point compression not supported yet + return null; + case 4: + case 6: + case 7: + var len = (s.length - 2) / 2; + var xHex = s.substr(2, len); + var yHex = s.substr(len+2, len); + + return new ECPointFp(this, + this.fromBigInteger(new BigInteger(xHex, 16)), + this.fromBigInteger(new BigInteger(yHex, 16))); + + default: // unsupported + return null; + } +} + +ECCurveFp.prototype.getQ = curveFpGetQ; +ECCurveFp.prototype.getA = curveFpGetA; +ECCurveFp.prototype.getB = curveFpGetB; +ECCurveFp.prototype.equals = curveFpEquals; +ECCurveFp.prototype.getInfinity = curveFpGetInfinity; +ECCurveFp.prototype.fromBigInteger = curveFpFromBigInteger; +ECCurveFp.prototype.decodePointHex = curveFpDecodePointHex; diff --git a/source/ecdsa-modified-1.0.js b/source/ecdsa-modified-1.0.js new file mode 100644 index 0000000..c46039d --- /dev/null +++ b/source/ecdsa-modified-1.0.js @@ -0,0 +1,839 @@ +/* ecdsa-modified-1.1.1.js (c) Stephan Thomas, Kenji Urushima | github.com/bitcoinjs/bitcoinjs-lib/blob/master/LICENSE + */ +/* + * ecdsa-modified.js - modified Bitcoin.ECDSA class + * + * Copyright (c) 2013-2017 Stefan Thomas (github.com/justmoon) + * Kenji Urushima (kenji.urushima@gmail.com) + * LICENSE + * https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/LICENSE + */ + +/** + * @fileOverview + * @name ecdsa-modified-1.0.js + * @author Stefan Thomas (github.com/justmoon) and Kenji Urushima (kenji.urushima@gmail.com) + * @version jsrsasign 7.2.0 ecdsa-modified 1.1.1 (2017-May-12) + * @since jsrsasign 4.0 + * @license MIT License + */ + +if (typeof KJUR == "undefined" || !KJUR) KJUR = {}; +if (typeof KJUR.crypto == "undefined" || !KJUR.crypto) KJUR.crypto = {}; + +/** + * class for EC key generation, ECDSA signing and verifcation + * @name KJUR.crypto.ECDSA + * @class class for EC key generation, ECDSA signing and verifcation + * @description + *

+ * CAUTION: Most of the case, you don't need to use this class except + * for generating an EC key pair. Please use {@link KJUR.crypto.Signature} class instead. + *

+ *

+ * This class was originally developped by Stefan Thomas for Bitcoin JavaScript library. + * (See {@link https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/src/ecdsa.js}) + * Currently this class supports following named curves and their aliases. + *

    + *
  • secp256r1, NIST P-256, P-256, prime256v1 (*)
  • + *
  • secp256k1 (*)
  • + *
  • secp384r1, NIST P-384, P-384 (*)
  • + *
+ *

+ */ +KJUR.crypto.ECDSA = function(params) { + var curveName = "secp256r1"; // curve name default + var ecparams = null; + var prvKeyHex = null; + var pubKeyHex = null; + + var rng = new SecureRandom(); + + var P_OVER_FOUR = null; + + this.type = "EC"; + this.isPrivate = false; + this.isPublic = false; + + function implShamirsTrick(P, k, Q, l) { + var m = Math.max(k.bitLength(), l.bitLength()); + var Z = P.add2D(Q); + var R = P.curve.getInfinity(); + + for (var i = m - 1; i >= 0; --i) { + R = R.twice2D(); + + R.z = BigInteger.ONE; + + if (k.testBit(i)) { + if (l.testBit(i)) { + R = R.add2D(Z); + } else { + R = R.add2D(P); + } + } else { + if (l.testBit(i)) { + R = R.add2D(Q); + } + } + } + + return R; + }; + + //=========================== + // PUBLIC METHODS + //=========================== + this.getBigRandom = function (limit) { + return new BigInteger(limit.bitLength(), rng) + .mod(limit.subtract(BigInteger.ONE)) + .add(BigInteger.ONE) + ; + }; + + this.setNamedCurve = function(curveName) { + this.ecparams = KJUR.crypto.ECParameterDB.getByName(curveName); + this.prvKeyHex = null; + this.pubKeyHex = null; + this.curveName = curveName; + }; + + this.setPrivateKeyHex = function(prvKeyHex) { + this.isPrivate = true; + this.prvKeyHex = prvKeyHex; + }; + + this.setPublicKeyHex = function(pubKeyHex) { + this.isPublic = true; + this.pubKeyHex = pubKeyHex; + }; + + /** + * get X and Y hexadecimal string value of public key + * @name getPublicKeyXYHex + * @memberOf KJUR.crypto.ECDSA# + * @function + * @return {Array} associative array of x and y value of public key + * @since ecdsa-modified 1.0.5 jsrsasign 5.0.14 + * @example + * ec = new KJUR.crypto.ECDSA({'curve': 'secp256r1', 'pub': pubHex}); + * ec.getPublicKeyXYHex() → { x: '01bacf...', y: 'c3bc22...' } + */ + this.getPublicKeyXYHex = function() { + var h = this.pubKeyHex; + if (h.substr(0, 2) !== "04") + throw "this method supports uncompressed format(04) only"; + + var charlen = this.ecparams.keylen / 4; + if (h.length !== 2 + charlen * 2) + throw "malformed public key hex length"; + + var result = {}; + result.x = h.substr(2, charlen); + result.y = h.substr(2 + charlen); + return result; + }; + + /** + * get NIST curve short name such as "P-256" or "P-384" + * @name getShortNISTPCurveName + * @memberOf KJUR.crypto.ECDSA# + * @function + * @return {String} short NIST P curve name such as "P-256" or "P-384" if it's NIST P curve otherwise null; + * @since ecdsa-modified 1.0.5 jsrsasign 5.0.14 + * @example + * ec = new KJUR.crypto.ECDSA({'curve': 'secp256r1', 'pub': pubHex}); + * ec.getShortPCurveName() → "P-256"; + */ + this.getShortNISTPCurveName = function() { + var s = this.curveName; + if (s === "secp256r1" || s === "NIST P-256" || + s === "P-256" || s === "prime256v1") + return "P-256"; + if (s === "secp384r1" || s === "NIST P-384" || s === "P-384") + return "P-384"; + return null; + }; + + /** + * generate a EC key pair + * @name generateKeyPairHex + * @memberOf KJUR.crypto.ECDSA# + * @function + * @return {Array} associative array of hexadecimal string of private and public key + * @since ecdsa-modified 1.0.1 + * @example + * var ec = new KJUR.crypto.ECDSA({'curve': 'secp256r1'}); + * var keypair = ec.generateKeyPairHex(); + * var pubhex = keypair.ecpubhex; // hexadecimal string of EC public key + * var prvhex = keypair.ecprvhex; // hexadecimal string of EC private key (=d) + */ + this.generateKeyPairHex = function() { + var biN = this.ecparams['n']; + var biPrv = this.getBigRandom(biN); + var epPub = this.ecparams['G'].multiply(biPrv); + var biX = epPub.getX().toBigInteger(); + var biY = epPub.getY().toBigInteger(); + + var charlen = this.ecparams['keylen'] / 4; + var hPrv = ("0000000000" + biPrv.toString(16)).slice(- charlen); + var hX = ("0000000000" + biX.toString(16)).slice(- charlen); + var hY = ("0000000000" + biY.toString(16)).slice(- charlen); + var hPub = "04" + hX + hY; + + this.setPrivateKeyHex(hPrv); + this.setPublicKeyHex(hPub); + return {'ecprvhex': hPrv, 'ecpubhex': hPub}; + }; + + this.signWithMessageHash = function(hashHex) { + return this.signHex(hashHex, this.prvKeyHex); + }; + + /** + * signing to message hash + * @name signHex + * @memberOf KJUR.crypto.ECDSA# + * @function + * @param {String} hashHex hexadecimal string of hash value of signing message + * @param {String} privHex hexadecimal string of EC private key + * @return {String} hexadecimal string of ECDSA signature + * @since ecdsa-modified 1.0.1 + * @example + * var ec = new KJUR.crypto.ECDSA({'curve': 'secp256r1'}); + * var sigValue = ec.signHex(hash, prvKey); + */ + this.signHex = function (hashHex, privHex) { + var d = new BigInteger(privHex, 16); + var n = this.ecparams['n']; + var e = new BigInteger(hashHex, 16); + + do { + var k = this.getBigRandom(n); + var G = this.ecparams['G']; + var Q = G.multiply(k); + var r = Q.getX().toBigInteger().mod(n); + } while (r.compareTo(BigInteger.ZERO) <= 0); + + var s = k.modInverse(n).multiply(e.add(d.multiply(r))).mod(n); + + return KJUR.crypto.ECDSA.biRSSigToASN1Sig(r, s); + }; + + this.sign = function (hash, priv) { + var d = priv; + var n = this.ecparams['n']; + var e = BigInteger.fromByteArrayUnsigned(hash); + + do { + var k = this.getBigRandom(n); + var G = this.ecparams['G']; + var Q = G.multiply(k); + var r = Q.getX().toBigInteger().mod(n); + } while (r.compareTo(BigInteger.ZERO) <= 0); + + var s = k.modInverse(n).multiply(e.add(d.multiply(r))).mod(n); + return this.serializeSig(r, s); + }; + + this.verifyWithMessageHash = function(hashHex, sigHex) { + return this.verifyHex(hashHex, sigHex, this.pubKeyHex); + }; + + /** + * verifying signature with message hash and public key + * @name verifyHex + * @memberOf KJUR.crypto.ECDSA# + * @function + * @param {String} hashHex hexadecimal string of hash value of signing message + * @param {String} sigHex hexadecimal string of signature value + * @param {String} pubkeyHex hexadecimal string of public key + * @return {Boolean} true if the signature is valid, otherwise false + * @since ecdsa-modified 1.0.1 + * @example + * var ec = new KJUR.crypto.ECDSA({'curve': 'secp256r1'}); + * var result = ec.verifyHex(msgHashHex, sigHex, pubkeyHex); + */ + this.verifyHex = function(hashHex, sigHex, pubkeyHex) { + var r,s; + + var obj = KJUR.crypto.ECDSA.parseSigHex(sigHex); + r = obj.r; + s = obj.s; + + var Q; + Q = ECPointFp.decodeFromHex(this.ecparams['curve'], pubkeyHex); + var e = new BigInteger(hashHex, 16); + + return this.verifyRaw(e, r, s, Q); + }; + + this.verify = function (hash, sig, pubkey) { + var r,s; + if (Bitcoin.Util.isArray(sig)) { + var obj = this.parseSig(sig); + r = obj.r; + s = obj.s; + } else if ("object" === typeof sig && sig.r && sig.s) { + r = sig.r; + s = sig.s; + } else { + throw "Invalid value for signature"; + } + + var Q; + if (pubkey instanceof ECPointFp) { + Q = pubkey; + } else if (Bitcoin.Util.isArray(pubkey)) { + Q = ECPointFp.decodeFrom(this.ecparams['curve'], pubkey); + } else { + throw "Invalid format for pubkey value, must be byte array or ECPointFp"; + } + var e = BigInteger.fromByteArrayUnsigned(hash); + + return this.verifyRaw(e, r, s, Q); + }; + + this.verifyRaw = function (e, r, s, Q) { + var n = this.ecparams['n']; + var G = this.ecparams['G']; + + if (r.compareTo(BigInteger.ONE) < 0 || + r.compareTo(n) >= 0) + return false; + + if (s.compareTo(BigInteger.ONE) < 0 || + s.compareTo(n) >= 0) + return false; + + var c = s.modInverse(n); + + var u1 = e.multiply(c).mod(n); + var u2 = r.multiply(c).mod(n); + + // TODO(!!!): For some reason Shamir's trick isn't working with + // signed message verification!? Probably an implementation + // error! + //var point = implShamirsTrick(G, u1, Q, u2); + var point = G.multiply(u1).add(Q.multiply(u2)); + + var v = point.getX().toBigInteger().mod(n); + + return v.equals(r); + }; + + /** + * Serialize a signature into DER format. + * + * Takes two BigIntegers representing r and s and returns a byte array. + */ + this.serializeSig = function (r, s) { + var rBa = r.toByteArraySigned(); + var sBa = s.toByteArraySigned(); + + var sequence = []; + sequence.push(0x02); // INTEGER + sequence.push(rBa.length); + sequence = sequence.concat(rBa); + + sequence.push(0x02); // INTEGER + sequence.push(sBa.length); + sequence = sequence.concat(sBa); + + sequence.unshift(sequence.length); + sequence.unshift(0x30); // SEQUENCE + return sequence; + }; + + /** + * Parses a byte array containing a DER-encoded signature. + * + * This function will return an object of the form: + * + * { + * r: BigInteger, + * s: BigInteger + * } + */ + this.parseSig = function (sig) { + var cursor; + if (sig[0] != 0x30) + throw new Error("Signature not a valid DERSequence"); + + cursor = 2; + if (sig[cursor] != 0x02) + throw new Error("First element in signature must be a DERInteger");; + var rBa = sig.slice(cursor+2, cursor+2+sig[cursor+1]); + + cursor += 2+sig[cursor+1]; + if (sig[cursor] != 0x02) + throw new Error("Second element in signature must be a DERInteger"); + var sBa = sig.slice(cursor+2, cursor+2+sig[cursor+1]); + + cursor += 2+sig[cursor+1]; + + //if (cursor != sig.length) + // throw new Error("Extra bytes in signature"); + + var r = BigInteger.fromByteArrayUnsigned(rBa); + var s = BigInteger.fromByteArrayUnsigned(sBa); + + return {r: r, s: s}; + }; + + this.parseSigCompact = function (sig) { + if (sig.length !== 65) { + throw "Signature has the wrong length"; + } + + // Signature is prefixed with a type byte storing three bits of + // information. + var i = sig[0] - 27; + if (i < 0 || i > 7) { + throw "Invalid signature type"; + } + + var n = this.ecparams['n']; + var r = BigInteger.fromByteArrayUnsigned(sig.slice(1, 33)).mod(n); + var s = BigInteger.fromByteArrayUnsigned(sig.slice(33, 65)).mod(n); + + return {r: r, s: s, i: i}; + }; + + /** + * read an ASN.1 hexadecimal string of PKCS#1/5 plain ECC private key
+ * @name readPKCS5PrvKeyHex + * @memberOf KJUR.crypto.ECDSA# + * @function + * @param {String} h hexadecimal string of PKCS#1/5 ECC private key + * @since jsrsasign 7.1.0 ecdsa-modified 1.1.0 + */ + this.readPKCS5PrvKeyHex = function(h) { + var _ASN1HEX = ASN1HEX; + var _getName = KJUR.crypto.ECDSA.getName; + var _getVbyList = _ASN1HEX.getVbyList; + + if (_ASN1HEX.isASN1HEX(h) === false) + throw "not ASN.1 hex string"; + + var hCurve, hPrv, hPub; + try { + hCurve = _getVbyList(h, 0, [2, 0], "06"); + hPrv = _getVbyList(h, 0, [1], "04"); + try { + hPub = _getVbyList(h, 0, [3, 0], "03").substr(2); + } catch(ex) {}; + } catch(ex) { + throw "malformed PKCS#1/5 plain ECC private key"; + } + + this.curveName = _getName(hCurve); + if (this.curveName === undefined) throw "unsupported curve name"; + + this.setNamedCurve(this.curveName); + this.setPublicKeyHex(hPub); + this.setPrivateKeyHex(hPrv); + this.isPublic = false; + }; + + /** + * read an ASN.1 hexadecimal string of PKCS#8 plain ECC private key
+ * @name readPKCS8PrvKeyHex + * @memberOf KJUR.crypto.ECDSA# + * @function + * @param {String} h hexadecimal string of PKCS#8 ECC private key + * @since jsrsasign 7.1.0 ecdsa-modified 1.1.0 + */ + this.readPKCS8PrvKeyHex = function(h) { + var _ASN1HEX = ASN1HEX; + var _getName = KJUR.crypto.ECDSA.getName; + var _getVbyList = _ASN1HEX.getVbyList; + + if (_ASN1HEX.isASN1HEX(h) === false) + throw "not ASN.1 hex string"; + + var hECOID, hCurve, hPrv, hPub; + try { + hECOID = _getVbyList(h, 0, [1, 0], "06"); + hCurve = _getVbyList(h, 0, [1, 1], "06"); + hPrv = _getVbyList(h, 0, [2, 0, 1], "04"); + try { + hPub = _getVbyList(h, 0, [2, 0, 2, 0], "03").substr(2); + } catch(ex) {}; + } catch(ex) { + throw "malformed PKCS#8 plain ECC private key"; + } + + this.curveName = _getName(hCurve); + if (this.curveName === undefined) throw "unsupported curve name"; + + this.setNamedCurve(this.curveName); + this.setPublicKeyHex(hPub); + this.setPrivateKeyHex(hPrv); + this.isPublic = false; + }; + + /** + * read an ASN.1 hexadecimal string of PKCS#8 ECC public key
+ * @name readPKCS8PubKeyHex + * @memberOf KJUR.crypto.ECDSA# + * @function + * @param {String} h hexadecimal string of PKCS#8 ECC public key + * @since jsrsasign 7.1.0 ecdsa-modified 1.1.0 + */ + this.readPKCS8PubKeyHex = function(h) { + var _ASN1HEX = ASN1HEX; + var _getName = KJUR.crypto.ECDSA.getName; + var _getVbyList = _ASN1HEX.getVbyList; + + if (_ASN1HEX.isASN1HEX(h) === false) + throw "not ASN.1 hex string"; + + var hECOID, hCurve, hPub; + try { + hECOID = _getVbyList(h, 0, [0, 0], "06"); + hCurve = _getVbyList(h, 0, [0, 1], "06"); + hPub = _getVbyList(h, 0, [1], "03").substr(2); + } catch(ex) { + throw "malformed PKCS#8 ECC public key"; + } + + this.curveName = _getName(hCurve); + if (this.curveName === null) throw "unsupported curve name"; + + this.setNamedCurve(this.curveName); + this.setPublicKeyHex(hPub); + }; + + /** + * read an ASN.1 hexadecimal string of X.509 ECC public key certificate
+ * @name readCertPubKeyHex + * @memberOf KJUR.crypto.ECDSA# + * @function + * @param {String} h hexadecimal string of X.509 ECC public key certificate + * @param {Integer} nthPKI nth index of publicKeyInfo. (DEFAULT: 6 for X509v3) + * @since jsrsasign 7.1.0 ecdsa-modified 1.1.0 + */ + this.readCertPubKeyHex = function(h, nthPKI) { + if (nthPKI !== 5) nthPKI = 6; + var _ASN1HEX = ASN1HEX; + var _getName = KJUR.crypto.ECDSA.getName; + var _getVbyList = _ASN1HEX.getVbyList; + + if (_ASN1HEX.isASN1HEX(h) === false) + throw "not ASN.1 hex string"; + + var hCurve, hPub; + try { + hCurve = _getVbyList(h, 0, [0, nthPKI, 0, 1], "06"); + hPub = _getVbyList(h, 0, [0, nthPKI, 1], "03").substr(2); + } catch(ex) { + throw "malformed X.509 certificate ECC public key"; + } + + this.curveName = _getName(hCurve); + if (this.curveName === null) throw "unsupported curve name"; + + this.setNamedCurve(this.curveName); + this.setPublicKeyHex(hPub); + }; + + /* + * Recover a public key from a signature. + * + * See SEC 1: Elliptic Curve Cryptography, section 4.1.6, "Public + * Key Recovery Operation". + * + * http://www.secg.org/download/aid-780/sec1-v2.pdf + */ + /* + recoverPubKey: function (r, s, hash, i) { + // The recovery parameter i has two bits. + i = i & 3; + + // The less significant bit specifies whether the y coordinate + // of the compressed point is even or not. + var isYEven = i & 1; + + // The more significant bit specifies whether we should use the + // first or second candidate key. + var isSecondKey = i >> 1; + + var n = this.ecparams['n']; + var G = this.ecparams['G']; + var curve = this.ecparams['curve']; + var p = curve.getQ(); + var a = curve.getA().toBigInteger(); + var b = curve.getB().toBigInteger(); + + // We precalculate (p + 1) / 4 where p is if the field order + if (!P_OVER_FOUR) { + P_OVER_FOUR = p.add(BigInteger.ONE).divide(BigInteger.valueOf(4)); + } + + // 1.1 Compute x + var x = isSecondKey ? r.add(n) : r; + + // 1.3 Convert x to point + var alpha = x.multiply(x).multiply(x).add(a.multiply(x)).add(b).mod(p); + var beta = alpha.modPow(P_OVER_FOUR, p); + + var xorOdd = beta.isEven() ? (i % 2) : ((i+1) % 2); + // If beta is even, but y isn't or vice versa, then convert it, + // otherwise we're done and y == beta. + var y = (beta.isEven() ? !isYEven : isYEven) ? beta : p.subtract(beta); + + // 1.4 Check that nR is at infinity + var R = new ECPointFp(curve, + curve.fromBigInteger(x), + curve.fromBigInteger(y)); + R.validate(); + + // 1.5 Compute e from M + var e = BigInteger.fromByteArrayUnsigned(hash); + var eNeg = BigInteger.ZERO.subtract(e).mod(n); + + // 1.6 Compute Q = r^-1 (sR - eG) + var rInv = r.modInverse(n); + var Q = implShamirsTrick(R, s, G, eNeg).multiply(rInv); + + Q.validate(); + if (!this.verifyRaw(e, r, s, Q)) { + throw "Pubkey recovery unsuccessful"; + } + + var pubKey = new Bitcoin.ECKey(); + pubKey.pub = Q; + return pubKey; + }, + */ + + /* + * Calculate pubkey extraction parameter. + * + * When extracting a pubkey from a signature, we have to + * distinguish four different cases. Rather than putting this + * burden on the verifier, Bitcoin includes a 2-bit value with the + * signature. + * + * This function simply tries all four cases and returns the value + * that resulted in a successful pubkey recovery. + */ + /* + calcPubkeyRecoveryParam: function (address, r, s, hash) { + for (var i = 0; i < 4; i++) { + try { + var pubkey = Bitcoin.ECDSA.recoverPubKey(r, s, hash, i); + if (pubkey.getBitcoinAddress().toString() == address) { + return i; + } + } catch (e) {} + } + throw "Unable to find valid recovery factor"; + } + */ + + if (params !== undefined) { + if (params['curve'] !== undefined) { + this.curveName = params['curve']; + } + } + if (this.curveName === undefined) this.curveName = curveName; + this.setNamedCurve(this.curveName); + if (params !== undefined) { + if (params.prv !== undefined) this.setPrivateKeyHex(params.prv); + if (params.pub !== undefined) this.setPublicKeyHex(params.pub); + } +}; + +/** + * parse ASN.1 DER encoded ECDSA signature + * @name parseSigHex + * @memberOf KJUR.crypto.ECDSA + * @function + * @static + * @param {String} sigHex hexadecimal string of ECDSA signature value + * @return {Array} associative array of signature field r and s of BigInteger + * @since ecdsa-modified 1.0.1 + * @example + * var ec = new KJUR.crypto.ECDSA({'curve': 'secp256r1'}); + * var sig = ec.parseSigHex('30...'); + * var biR = sig.r; // BigInteger object for 'r' field of signature. + * var biS = sig.s; // BigInteger object for 's' field of signature. + */ +KJUR.crypto.ECDSA.parseSigHex = function(sigHex) { + var p = KJUR.crypto.ECDSA.parseSigHexInHexRS(sigHex); + var biR = new BigInteger(p.r, 16); + var biS = new BigInteger(p.s, 16); + + return {'r': biR, 's': biS}; +}; + +/** + * parse ASN.1 DER encoded ECDSA signature + * @name parseSigHexInHexRS + * @memberOf KJUR.crypto.ECDSA + * @function + * @static + * @param {String} sigHex hexadecimal string of ECDSA signature value + * @return {Array} associative array of signature field r and s in hexadecimal + * @since ecdsa-modified 1.0.3 + * @example + * var ec = new KJUR.crypto.ECDSA({'curve': 'secp256r1'}); + * var sig = ec.parseSigHexInHexRS('30...'); + * var hR = sig.r; // hexadecimal string for 'r' field of signature. + * var hS = sig.s; // hexadecimal string for 's' field of signature. + */ +KJUR.crypto.ECDSA.parseSigHexInHexRS = function(sigHex) { + var _ASN1HEX = ASN1HEX; + var _getChildIdx = _ASN1HEX.getChildIdx; + var _getV = _ASN1HEX.getV; + + // 1. ASN.1 Sequence Check + if (sigHex.substr(0, 2) != "30") + throw "signature is not a ASN.1 sequence"; + + // 2. Items of ASN.1 Sequence Check + var a = _getChildIdx(sigHex, 0); + if (a.length != 2) + throw "number of signature ASN.1 sequence elements seem wrong"; + + // 3. Integer check + var iTLV1 = a[0]; + var iTLV2 = a[1]; + if (sigHex.substr(iTLV1, 2) != "02") + throw "1st item of sequene of signature is not ASN.1 integer"; + if (sigHex.substr(iTLV2, 2) != "02") + throw "2nd item of sequene of signature is not ASN.1 integer"; + + // 4. getting value + var hR = _getV(sigHex, iTLV1); + var hS = _getV(sigHex, iTLV2); + + return {'r': hR, 's': hS}; +}; + +/** + * convert hexadecimal ASN.1 encoded signature to concatinated signature + * @name asn1SigToConcatSig + * @memberOf KJUR.crypto.ECDSA + * @function + * @static + * @param {String} asn1Hex hexadecimal string of ASN.1 encoded ECDSA signature value + * @return {String} r-s concatinated format of ECDSA signature value + * @since ecdsa-modified 1.0.3 + */ +KJUR.crypto.ECDSA.asn1SigToConcatSig = function(asn1Sig) { + var pSig = KJUR.crypto.ECDSA.parseSigHexInHexRS(asn1Sig); + var hR = pSig.r; + var hS = pSig.s; + + // R and S length is assumed multiple of 128bit(32chars in hex). + // If leading is "00" and modulo of length is 2(chars) then + // leading "00" is for two's complement and will be removed. + if (hR.substr(0, 2) == "00" && (hR.length % 32) == 2) + hR = hR.substr(2); + + if (hS.substr(0, 2) == "00" && (hS.length % 32) == 2) + hS = hS.substr(2); + + // R and S length is assumed multiple of 128bit(32chars in hex). + // If missing two chars then it will be padded by "00". + if ((hR.length % 32) == 30) hR = "00" + hR; + if ((hS.length % 32) == 30) hS = "00" + hS; + + // If R and S length is not still multiple of 128bit(32 chars), + // then error + if (hR.length % 32 != 0) + throw "unknown ECDSA sig r length error"; + if (hS.length % 32 != 0) + throw "unknown ECDSA sig s length error"; + + return hR + hS; +}; + +/** + * convert hexadecimal concatinated signature to ASN.1 encoded signature + * @name concatSigToASN1Sig + * @memberOf KJUR.crypto.ECDSA + * @function + * @static + * @param {String} concatSig r-s concatinated format of ECDSA signature value + * @return {String} hexadecimal string of ASN.1 encoded ECDSA signature value + * @since ecdsa-modified 1.0.3 + */ +KJUR.crypto.ECDSA.concatSigToASN1Sig = function(concatSig) { + if ((((concatSig.length / 2) * 8) % (16 * 8)) != 0) + throw "unknown ECDSA concatinated r-s sig length error"; + + var hR = concatSig.substr(0, concatSig.length / 2); + var hS = concatSig.substr(concatSig.length / 2); + return KJUR.crypto.ECDSA.hexRSSigToASN1Sig(hR, hS); +}; + +/** + * convert hexadecimal R and S value of signature to ASN.1 encoded signature + * @name hexRSSigToASN1Sig + * @memberOf KJUR.crypto.ECDSA + * @function + * @static + * @param {String} hR hexadecimal string of R field of ECDSA signature value + * @param {String} hS hexadecimal string of S field of ECDSA signature value + * @return {String} hexadecimal string of ASN.1 encoded ECDSA signature value + * @since ecdsa-modified 1.0.3 + */ +KJUR.crypto.ECDSA.hexRSSigToASN1Sig = function(hR, hS) { + var biR = new BigInteger(hR, 16); + var biS = new BigInteger(hS, 16); + return KJUR.crypto.ECDSA.biRSSigToASN1Sig(biR, biS); +}; + +/** + * convert R and S BigInteger object of signature to ASN.1 encoded signature + * @name biRSSigToASN1Sig + * @memberOf KJUR.crypto.ECDSA + * @function + * @static + * @param {BigInteger} biR BigInteger object of R field of ECDSA signature value + * @param {BigInteger} biS BIgInteger object of S field of ECDSA signature value + * @return {String} hexadecimal string of ASN.1 encoded ECDSA signature value + * @since ecdsa-modified 1.0.3 + */ +KJUR.crypto.ECDSA.biRSSigToASN1Sig = function(biR, biS) { + var _KJUR_asn1 = KJUR.asn1; + var derR = new _KJUR_asn1.DERInteger({'bigint': biR}); + var derS = new _KJUR_asn1.DERInteger({'bigint': biS}); + var derSeq = new _KJUR_asn1.DERSequence({'array': [derR, derS]}); + return derSeq.getEncodedHex(); +}; + +/** + * static method to get normalized EC curve name from curve name or hexadecimal OID value + * @name getName + * @memberOf KJUR.crypto.ECDSA + * @function + * @static + * @param {String} s curve name (ex. P-256) or hexadecimal OID value (ex. 2a86...) + * @return {String} normalized EC curve name (ex. secp256r1) + * @since jsrsasign 7.1.0 ecdsa-modified 1.1.0 + * @description + * This static method returns normalized EC curve name + * which is supported in jsrsasign + * from curve name or hexadecimal OID value. + * When curve is not supported in jsrsasign, this method returns null. + * Normalized name will be "secp*" in jsrsasign. + * @example + * KJUR.crypto.ECDSA.getName("2b8104000a") → "secp256k1" + * KJUR.crypto.ECDSA.getName("NIST P-256") → "secp256r1" + * KJUR.crypto.ECDSA.getName("P-521") → undefined // not supported + */ +KJUR.crypto.ECDSA.getName = function(s) { + if (s === "2a8648ce3d030107") return "secp256r1"; // 1.2.840.10045.3.1.7 + if (s === "2b8104000a") return "secp256k1"; // 1.3.132.0.10 + if (s === "2b81040022") return "secp384r1"; // 1.3.132.0.34 + if ("|secp256r1|NIST P-256|P-256|prime256v1|".indexOf(s) !== -1) return "secp256r1"; + if ("|secp256k1|".indexOf(s) !== -1) return "secp256k1"; + if ("|secp384r1|NIST P-384|P-384|".indexOf(s) !== -1) return "secp384r1"; + return null; +}; + diff --git a/source/ecparam-1.0.js b/source/ecparam-1.0.js new file mode 100644 index 0000000..9626c3d --- /dev/null +++ b/source/ecparam-1.0.js @@ -0,0 +1,248 @@ +/* ecparam-1.0.0.js (c) 2013 Kenji Urushima | kjur.github.com/jsrsasign/license + */ +/* + * ecparam.js - Elliptic Curve Cryptography Curve Parameter Definition class + * + * Copyright (c) 2013 Kenji Urushima (kenji.urushima@gmail.com) + * + * This software is licensed under the terms of the MIT License. + * https://kjur.github.io/jsrsasign/license + * + * The above copyright and license notice shall be + * included in all copies or substantial portions of the Software. + */ + +/** + * @fileOverview + * @name ecparam-1.1.js + * @author Kenji Urushima kenji.urushima@gmail.com + * @version 1.0.0 (2013-Jul-17) + * @since jsrsasign 4.0 + * @license MIT License + */ + +if (typeof KJUR == "undefined" || !KJUR) KJUR = {}; +if (typeof KJUR.crypto == "undefined" || !KJUR.crypto) KJUR.crypto = {}; + +/** + * static object for elliptic curve names and parameters + * @name KJUR.crypto.ECParameterDB + * @class static object for elliptic curve names and parameters + * @description + * This class provides parameters for named elliptic curves. + * Currently it supoprts following curve names and aliases however + * the name marked (*) are available for {@link KJUR.crypto.ECDSA} and + * {@link KJUR.crypto.Signature} classes. + *
    + *
  • secp128r1
  • + *
  • secp160r1
  • + *
  • secp160k1
  • + *
  • secp192r1
  • + *
  • secp192k1
  • + *
  • secp224r1
  • + *
  • secp256r1, NIST P-256, P-256, prime256v1 (*)
  • + *
  • secp256k1 (*)
  • + *
  • secp384r1, NIST P-384, P-384 (*)
  • + *
  • secp521r1, NIST P-521, P-521
  • + *
+ * You can register new curves by using 'register' method. + */ +KJUR.crypto.ECParameterDB = new function() { + var db = {}; + var aliasDB = {}; + + function hex2bi(hex) { + return new BigInteger(hex, 16); + } + + /** + * get curve inforamtion associative array for curve name or alias + * @name getByName + * @memberOf KJUR.crypto.ECParameterDB + * @function + * @param {String} nameOrAlias curve name or alias name + * @return {Array} associative array of curve parameters + * @example + * var param = KJUR.crypto.ECParameterDB.getByName('prime256v1'); + * var keylen = param['keylen']; + * var n = param['n']; + */ + this.getByName = function(nameOrAlias) { + var name = nameOrAlias; + if (typeof aliasDB[name] != "undefined") { + name = aliasDB[nameOrAlias]; + } + if (typeof db[name] != "undefined") { + return db[name]; + } + throw "unregistered EC curve name: " + name; + }; + + /** + * register new curve + * @name regist + * @memberOf KJUR.crypto.ECParameterDB + * @function + * @param {String} name name of curve + * @param {Integer} keylen key length + * @param {String} pHex hexadecimal value of p + * @param {String} aHex hexadecimal value of a + * @param {String} bHex hexadecimal value of b + * @param {String} nHex hexadecimal value of n + * @param {String} hHex hexadecimal value of h + * @param {String} gxHex hexadecimal value of Gx + * @param {String} gyHex hexadecimal value of Gy + * @param {Array} aliasList array of string for curve names aliases + * @param {String} oid Object Identifier for the curve + * @param {String} info information string for the curve + */ + this.regist = function(name, keylen, pHex, aHex, bHex, nHex, hHex, gxHex, gyHex, aliasList, oid, info) { + db[name] = {}; + var p = hex2bi(pHex); + var a = hex2bi(aHex); + var b = hex2bi(bHex); + var n = hex2bi(nHex); + var h = hex2bi(hHex); + var curve = new ECCurveFp(p, a, b); + var G = curve.decodePointHex("04" + gxHex + gyHex); + db[name]['name'] = name; + db[name]['keylen'] = keylen; + db[name]['curve'] = curve; + db[name]['G'] = G; + db[name]['n'] = n; + db[name]['h'] = h; + db[name]['oid'] = oid; + db[name]['info'] = info; + + for (var i = 0; i < aliasList.length; i++) { + aliasDB[aliasList[i]] = name; + } + }; +}; + +KJUR.crypto.ECParameterDB.regist( + "secp128r1", // name / p = 2^128 - 2^97 - 1 + 128, + "FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF", // p + "FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFC", // a + "E87579C11079F43DD824993C2CEE5ED3", // b + "FFFFFFFE0000000075A30D1B9038A115", // n + "1", // h + "161FF7528B899B2D0C28607CA52C5B86", // gx + "CF5AC8395BAFEB13C02DA292DDED7A83", // gy + [], // alias + "", // oid (underconstruction) + "secp128r1 : SECG curve over a 128 bit prime field"); // info + +KJUR.crypto.ECParameterDB.regist( + "secp160k1", // name / p = 2^160 - 2^32 - 2^14 - 2^12 - 2^9 - 2^8 - 2^7 - 2^3 - 2^2 - 1 + 160, + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73", // p + "0", // a + "7", // b + "0100000000000000000001B8FA16DFAB9ACA16B6B3", // n + "1", // h + "3B4C382CE37AA192A4019E763036F4F5DD4D7EBB", // gx + "938CF935318FDCED6BC28286531733C3F03C4FEE", // gy + [], // alias + "", // oid + "secp160k1 : SECG curve over a 160 bit prime field"); // info + +KJUR.crypto.ECParameterDB.regist( + "secp160r1", // name / p = 2^160 - 2^31 - 1 + 160, + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF", // p + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFC", // a + "1C97BEFC54BD7A8B65ACF89F81D4D4ADC565FA45", // b + "0100000000000000000001F4C8F927AED3CA752257", // n + "1", // h + "4A96B5688EF573284664698968C38BB913CBFC82", // gx + "23A628553168947D59DCC912042351377AC5FB32", // gy + [], // alias + "", // oid + "secp160r1 : SECG curve over a 160 bit prime field"); // info + +KJUR.crypto.ECParameterDB.regist( + "secp192k1", // name / p = 2^192 - 2^32 - 2^12 - 2^8 - 2^7 - 2^6 - 2^3 - 1 + 192, + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFEE37", // p + "0", // a + "3", // b + "FFFFFFFFFFFFFFFFFFFFFFFE26F2FC170F69466A74DEFD8D", // n + "1", // h + "DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D", // gx + "9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D", // gy + []); // alias + +KJUR.crypto.ECParameterDB.regist( + "secp192r1", // name / p = 2^192 - 2^64 - 1 + 192, + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF", // p + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC", // a + "64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1", // b + "FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831", // n + "1", // h + "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012", // gx + "07192B95FFC8DA78631011ED6B24CDD573F977A11E794811", // gy + []); // alias + +KJUR.crypto.ECParameterDB.regist( + "secp224r1", // name / p = 2^224 - 2^96 + 1 + 224, + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001", // p + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFE", // a + "B4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4", // b + "FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D", // n + "1", // h + "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21", // gx + "BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34", // gy + []); // alias + +KJUR.crypto.ECParameterDB.regist( + "secp256k1", // name / p = 2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1 + 256, + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", // p + "0", // a + "7", // b + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", // n + "1", // h + "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", // gx + "483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8", // gy + []); // alias + +KJUR.crypto.ECParameterDB.regist( + "secp256r1", // name / p = 2^224 (2^32 - 1) + 2^192 + 2^96 - 1 + 256, + "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF", // p + "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC", // a + "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B", // b + "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551", // n + "1", // h + "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296", // gx + "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5", // gy + ["NIST P-256", "P-256", "prime256v1"]); // alias + +KJUR.crypto.ECParameterDB.regist( + "secp384r1", // name + 384, + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF", // p + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC", // a + "B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF", // b + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973", // n + "1", // h + "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7", // gx + "3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f", // gy + ["NIST P-384", "P-384"]); // alias + +KJUR.crypto.ECParameterDB.regist( + "secp521r1", // name + 521, + "1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", // p + "1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC", // a + "051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00", // b + "1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409", // n + "1", // h + "C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66", // gx + "011839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650", // gy + ["NIST P-521", "P-521"]); // alias + diff --git a/source/jsbn.js b/source/jsbn.js new file mode 100644 index 0000000..cc8ed54 --- /dev/null +++ b/source/jsbn.js @@ -0,0 +1,561 @@ +/*! (c) Tom Wu | http://www-cs-students.stanford.edu/~tjw/jsbn/ + */ +// Copyright (c) 2005 Tom Wu +// All Rights Reserved. +// See "LICENSE" for details. + +// Basic JavaScript BN library - subset useful for RSA encryption. + +// Bits per digit +var dbits; + +// JavaScript engine analysis +var canary = 0xdeadbeefcafe; +var j_lm = ((canary&0xffffff)==0xefcafe); + +// (public) Constructor +function BigInteger(a,b,c) { + if(a != null) + if("number" == typeof a) this.fromNumber(a,b,c); + else if(b == null && "string" != typeof a) this.fromString(a,256); + else this.fromString(a,b); +} + +// return new, unset BigInteger +function nbi() { return new BigInteger(null); } + +// am: Compute w_j += (x*this_i), propagate carries, +// c is initial carry, returns final carry. +// c < 3*dvalue, x < 2*dvalue, this_i < dvalue +// We need to select the fastest one that works in this environment. + +// am1: use a single mult and divide to get the high bits, +// max digit bits should be 26 because +// max internal value = 2*dvalue^2-2*dvalue (< 2^53) +function am1(i,x,w,j,c,n) { + while(--n >= 0) { + var v = x*this[i++]+w[j]+c; + c = Math.floor(v/0x4000000); + w[j++] = v&0x3ffffff; + } + return c; +} +// am2 avoids a big mult-and-extract completely. +// Max digit bits should be <= 30 because we do bitwise ops +// on values up to 2*hdvalue^2-hdvalue-1 (< 2^31) +function am2(i,x,w,j,c,n) { + var xl = x&0x7fff, xh = x>>15; + while(--n >= 0) { + var l = this[i]&0x7fff; + var h = this[i++]>>15; + var m = xh*l+h*xl; + l = xl*l+((m&0x7fff)<<15)+w[j]+(c&0x3fffffff); + c = (l>>>30)+(m>>>15)+xh*h+(c>>>30); + w[j++] = l&0x3fffffff; + } + return c; +} +// Alternately, set max digit bits to 28 since some +// browsers slow down when dealing with 32-bit numbers. +function am3(i,x,w,j,c,n) { + var xl = x&0x3fff, xh = x>>14; + while(--n >= 0) { + var l = this[i]&0x3fff; + var h = this[i++]>>14; + var m = xh*l+h*xl; + l = xl*l+((m&0x3fff)<<14)+w[j]+c; + c = (l>>28)+(m>>14)+xh*h; + w[j++] = l&0xfffffff; + } + return c; +} +if(j_lm && (navigator.appName == "Microsoft Internet Explorer")) { + BigInteger.prototype.am = am2; + dbits = 30; +} +else if(j_lm && (navigator.appName != "Netscape")) { + BigInteger.prototype.am = am1; + dbits = 26; +} +else { // Mozilla/Netscape seems to prefer am3 + BigInteger.prototype.am = am3; + dbits = 28; +} + +BigInteger.prototype.DB = dbits; +BigInteger.prototype.DM = ((1<= 0; --i) r[i] = this[i]; + r.t = this.t; + r.s = this.s; +} + +// (protected) set from integer value x, -DV <= x < DV +function bnpFromInt(x) { + this.t = 1; + this.s = (x<0)?-1:0; + if(x > 0) this[0] = x; + else if(x < -1) this[0] = x+this.DV; + else this.t = 0; +} + +// return bigint initialized to value +function nbv(i) { var r = nbi(); r.fromInt(i); return r; } + +// (protected) set from string and radix +function bnpFromString(s,b) { + var k; + if(b == 16) k = 4; + else if(b == 8) k = 3; + else if(b == 256) k = 8; // byte array + else if(b == 2) k = 1; + else if(b == 32) k = 5; + else if(b == 4) k = 2; + else { this.fromRadix(s,b); return; } + this.t = 0; + this.s = 0; + var i = s.length, mi = false, sh = 0; + while(--i >= 0) { + var x = (k==8)?s[i]&0xff:intAt(s,i); + if(x < 0) { + if(s.charAt(i) == "-") mi = true; + continue; + } + mi = false; + if(sh == 0) + this[this.t++] = x; + else if(sh+k > this.DB) { + this[this.t-1] |= (x&((1<<(this.DB-sh))-1))<>(this.DB-sh)); + } + else + this[this.t-1] |= x<= this.DB) sh -= this.DB; + } + if(k == 8 && (s[0]&0x80) != 0) { + this.s = -1; + if(sh > 0) this[this.t-1] |= ((1<<(this.DB-sh))-1)< 0 && this[this.t-1] == c) --this.t; +} + +// (public) return string representation in given radix +function bnToString(b) { + if(this.s < 0) return "-"+this.negate().toString(b); + var k; + if(b == 16) k = 4; + else if(b == 8) k = 3; + else if(b == 2) k = 1; + else if(b == 32) k = 5; + else if(b == 4) k = 2; + else return this.toRadix(b); + var km = (1< 0) { + if(p < this.DB && (d = this[i]>>p) > 0) { m = true; r = int2char(d); } + while(i >= 0) { + if(p < k) { + d = (this[i]&((1<>(p+=this.DB-k); + } + else { + d = (this[i]>>(p-=k))&km; + if(p <= 0) { p += this.DB; --i; } + } + if(d > 0) m = true; + if(m) r += int2char(d); + } + } + return m?r:"0"; +} + +// (public) -this +function bnNegate() { var r = nbi(); BigInteger.ZERO.subTo(this,r); return r; } + +// (public) |this| +function bnAbs() { return (this.s<0)?this.negate():this; } + +// (public) return + if this > a, - if this < a, 0 if equal +function bnCompareTo(a) { + var r = this.s-a.s; + if(r != 0) return r; + var i = this.t; + r = i-a.t; + if(r != 0) return (this.s<0)?-r:r; + while(--i >= 0) if((r=this[i]-a[i]) != 0) return r; + return 0; +} + +// returns bit length of the integer x +function nbits(x) { + var r = 1, t; + if((t=x>>>16) != 0) { x = t; r += 16; } + if((t=x>>8) != 0) { x = t; r += 8; } + if((t=x>>4) != 0) { x = t; r += 4; } + if((t=x>>2) != 0) { x = t; r += 2; } + if((t=x>>1) != 0) { x = t; r += 1; } + return r; +} + +// (public) return the number of bits in "this" +function bnBitLength() { + if(this.t <= 0) return 0; + return this.DB*(this.t-1)+nbits(this[this.t-1]^(this.s&this.DM)); +} + +// (protected) r = this << n*DB +function bnpDLShiftTo(n,r) { + var i; + for(i = this.t-1; i >= 0; --i) r[i+n] = this[i]; + for(i = n-1; i >= 0; --i) r[i] = 0; + r.t = this.t+n; + r.s = this.s; +} + +// (protected) r = this >> n*DB +function bnpDRShiftTo(n,r) { + for(var i = n; i < this.t; ++i) r[i-n] = this[i]; + r.t = Math.max(this.t-n,0); + r.s = this.s; +} + +// (protected) r = this << n +function bnpLShiftTo(n,r) { + var bs = n%this.DB; + var cbs = this.DB-bs; + var bm = (1<= 0; --i) { + r[i+ds+1] = (this[i]>>cbs)|c; + c = (this[i]&bm)<= 0; --i) r[i] = 0; + r[ds] = c; + r.t = this.t+ds+1; + r.s = this.s; + r.clamp(); +} + +// (protected) r = this >> n +function bnpRShiftTo(n,r) { + r.s = this.s; + var ds = Math.floor(n/this.DB); + if(ds >= this.t) { r.t = 0; return; } + var bs = n%this.DB; + var cbs = this.DB-bs; + var bm = (1<>bs; + for(var i = ds+1; i < this.t; ++i) { + r[i-ds-1] |= (this[i]&bm)<>bs; + } + if(bs > 0) r[this.t-ds-1] |= (this.s&bm)<>= this.DB; + } + if(a.t < this.t) { + c -= a.s; + while(i < this.t) { + c += this[i]; + r[i++] = c&this.DM; + c >>= this.DB; + } + c += this.s; + } + else { + c += this.s; + while(i < a.t) { + c -= a[i]; + r[i++] = c&this.DM; + c >>= this.DB; + } + c -= a.s; + } + r.s = (c<0)?-1:0; + if(c < -1) r[i++] = this.DV+c; + else if(c > 0) r[i++] = c; + r.t = i; + r.clamp(); +} + +// (protected) r = this * a, r != this,a (HAC 14.12) +// "this" should be the larger one if appropriate. +function bnpMultiplyTo(a,r) { + var x = this.abs(), y = a.abs(); + var i = x.t; + r.t = i+y.t; + while(--i >= 0) r[i] = 0; + for(i = 0; i < y.t; ++i) r[i+x.t] = x.am(0,y[i],r,i,0,x.t); + r.s = 0; + r.clamp(); + if(this.s != a.s) BigInteger.ZERO.subTo(r,r); +} + +// (protected) r = this^2, r != this (HAC 14.16) +function bnpSquareTo(r) { + var x = this.abs(); + var i = r.t = 2*x.t; + while(--i >= 0) r[i] = 0; + for(i = 0; i < x.t-1; ++i) { + var c = x.am(i,x[i],r,2*i,0,1); + if((r[i+x.t]+=x.am(i+1,2*x[i],r,2*i+1,c,x.t-i-1)) >= x.DV) { + r[i+x.t] -= x.DV; + r[i+x.t+1] = 1; + } + } + if(r.t > 0) r[r.t-1] += x.am(i,x[i],r,2*i,0,1); + r.s = 0; + r.clamp(); +} + +// (protected) divide this by m, quotient and remainder to q, r (HAC 14.20) +// r != q, this != m. q or r may be null. +function bnpDivRemTo(m,q,r) { + var pm = m.abs(); + if(pm.t <= 0) return; + var pt = this.abs(); + if(pt.t < pm.t) { + if(q != null) q.fromInt(0); + if(r != null) this.copyTo(r); + return; + } + if(r == null) r = nbi(); + var y = nbi(), ts = this.s, ms = m.s; + var nsh = this.DB-nbits(pm[pm.t-1]); // normalize modulus + if(nsh > 0) { pm.lShiftTo(nsh,y); pt.lShiftTo(nsh,r); } + else { pm.copyTo(y); pt.copyTo(r); } + var ys = y.t; + var y0 = y[ys-1]; + if(y0 == 0) return; + var yt = y0*(1<1)?y[ys-2]>>this.F2:0); + var d1 = this.FV/yt, d2 = (1<= 0) { + r[r.t++] = 1; + r.subTo(t,r); + } + BigInteger.ONE.dlShiftTo(ys,t); + t.subTo(y,y); // "negative" y so we can replace sub with am later + while(y.t < ys) y[y.t++] = 0; + while(--j >= 0) { + // Estimate quotient digit + var qd = (r[--i]==y0)?this.DM:Math.floor(r[i]*d1+(r[i-1]+e)*d2); + if((r[i]+=y.am(0,qd,r,j,0,ys)) < qd) { // Try it out + y.dlShiftTo(j,t); + r.subTo(t,r); + while(r[i] < --qd) r.subTo(t,r); + } + } + if(q != null) { + r.drShiftTo(ys,q); + if(ts != ms) BigInteger.ZERO.subTo(q,q); + } + r.t = ys; + r.clamp(); + if(nsh > 0) r.rShiftTo(nsh,r); // Denormalize remainder + if(ts < 0) BigInteger.ZERO.subTo(r,r); +} + +// (public) this mod a +function bnMod(a) { + var r = nbi(); + this.abs().divRemTo(a,null,r); + if(this.s < 0 && r.compareTo(BigInteger.ZERO) > 0) a.subTo(r,r); + return r; +} + +// Modular reduction using "classic" algorithm +function Classic(m) { this.m = m; } +function cConvert(x) { + if(x.s < 0 || x.compareTo(this.m) >= 0) return x.mod(this.m); + else return x; +} +function cRevert(x) { return x; } +function cReduce(x) { x.divRemTo(this.m,null,x); } +function cMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); } +function cSqrTo(x,r) { x.squareTo(r); this.reduce(r); } + +Classic.prototype.convert = cConvert; +Classic.prototype.revert = cRevert; +Classic.prototype.reduce = cReduce; +Classic.prototype.mulTo = cMulTo; +Classic.prototype.sqrTo = cSqrTo; + +// (protected) return "-1/this % 2^DB"; useful for Mont. reduction +// justification: +// xy == 1 (mod m) +// xy = 1+km +// xy(2-xy) = (1+km)(1-km) +// x[y(2-xy)] = 1-k^2m^2 +// x[y(2-xy)] == 1 (mod m^2) +// if y is 1/x mod m, then y(2-xy) is 1/x mod m^2 +// should reduce x and y(2-xy) by m^2 at each step to keep size bounded. +// JS multiply "overflows" differently from C/C++, so care is needed here. +function bnpInvDigit() { + if(this.t < 1) return 0; + var x = this[0]; + if((x&1) == 0) return 0; + var y = x&3; // y == 1/x mod 2^2 + y = (y*(2-(x&0xf)*y))&0xf; // y == 1/x mod 2^4 + y = (y*(2-(x&0xff)*y))&0xff; // y == 1/x mod 2^8 + y = (y*(2-(((x&0xffff)*y)&0xffff)))&0xffff; // y == 1/x mod 2^16 + // last step - calculate inverse mod DV directly; + // assumes 16 < DB <= 32 and assumes ability to handle 48-bit ints + y = (y*(2-x*y%this.DV))%this.DV; // y == 1/x mod 2^dbits + // we really want the negative inverse, and -DV < y < DV + return (y>0)?this.DV-y:-y; +} + +// Montgomery reduction +function Montgomery(m) { + this.m = m; + this.mp = m.invDigit(); + this.mpl = this.mp&0x7fff; + this.mph = this.mp>>15; + this.um = (1<<(m.DB-15))-1; + this.mt2 = 2*m.t; +} + +// xR mod m +function montConvert(x) { + var r = nbi(); + x.abs().dlShiftTo(this.m.t,r); + r.divRemTo(this.m,null,r); + if(x.s < 0 && r.compareTo(BigInteger.ZERO) > 0) this.m.subTo(r,r); + return r; +} + +// x/R mod m +function montRevert(x) { + var r = nbi(); + x.copyTo(r); + this.reduce(r); + return r; +} + +// x = x/R mod m (HAC 14.32) +function montReduce(x) { + while(x.t <= this.mt2) // pad x so am has enough room later + x[x.t++] = 0; + for(var i = 0; i < this.m.t; ++i) { + // faster way of calculating u0 = x[i]*mp mod DV + var j = x[i]&0x7fff; + var u0 = (j*this.mpl+(((j*this.mph+(x[i]>>15)*this.mpl)&this.um)<<15))&x.DM; + // use am to combine the multiply-shift-add into one call + j = i+this.m.t; + x[j] += this.m.am(0,u0,x,i,0,this.m.t); + // propagate carry + while(x[j] >= x.DV) { x[j] -= x.DV; x[++j]++; } + } + x.clamp(); + x.drShiftTo(this.m.t,x); + if(x.compareTo(this.m) >= 0) x.subTo(this.m,x); +} + +// r = "x^2/R mod m"; x != r +function montSqrTo(x,r) { x.squareTo(r); this.reduce(r); } + +// r = "xy/R mod m"; x,y != r +function montMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); } + +Montgomery.prototype.convert = montConvert; +Montgomery.prototype.revert = montRevert; +Montgomery.prototype.reduce = montReduce; +Montgomery.prototype.mulTo = montMulTo; +Montgomery.prototype.sqrTo = montSqrTo; + +// (protected) true iff this is even +function bnpIsEven() { return ((this.t>0)?(this[0]&1):this.s) == 0; } + +// (protected) this^e, e < 2^32, doing sqr and mul with "r" (HAC 14.79) +function bnpExp(e,z) { + if(e > 0xffffffff || e < 1) return BigInteger.ONE; + var r = nbi(), r2 = nbi(), g = z.convert(this), i = nbits(e)-1; + g.copyTo(r); + while(--i >= 0) { + z.sqrTo(r,r2); + if((e&(1< 0) z.mulTo(r2,g,r); + else { var t = r; r = r2; r2 = t; } + } + return z.revert(r); +} + +// (public) this^e % m, 0 <= e < 2^32 +function bnModPowInt(e,m) { + var z; + if(e < 256 || m.isEven()) z = new Classic(m); else z = new Montgomery(m); + return this.exp(e,z); +} + +// protected +BigInteger.prototype.copyTo = bnpCopyTo; +BigInteger.prototype.fromInt = bnpFromInt; +BigInteger.prototype.fromString = bnpFromString; +BigInteger.prototype.clamp = bnpClamp; +BigInteger.prototype.dlShiftTo = bnpDLShiftTo; +BigInteger.prototype.drShiftTo = bnpDRShiftTo; +BigInteger.prototype.lShiftTo = bnpLShiftTo; +BigInteger.prototype.rShiftTo = bnpRShiftTo; +BigInteger.prototype.subTo = bnpSubTo; +BigInteger.prototype.multiplyTo = bnpMultiplyTo; +BigInteger.prototype.squareTo = bnpSquareTo; +BigInteger.prototype.divRemTo = bnpDivRemTo; +BigInteger.prototype.invDigit = bnpInvDigit; +BigInteger.prototype.isEven = bnpIsEven; +BigInteger.prototype.exp = bnpExp; + +// public +BigInteger.prototype.toString = bnToString; +BigInteger.prototype.negate = bnNegate; +BigInteger.prototype.abs = bnAbs; +BigInteger.prototype.compareTo = bnCompareTo; +BigInteger.prototype.bitLength = bnBitLength; +BigInteger.prototype.mod = bnMod; +BigInteger.prototype.modPowInt = bnModPowInt; + +// "constants" +BigInteger.ZERO = nbv(0); +BigInteger.ONE = nbv(1); diff --git a/source/jsbn2.js b/source/jsbn2.js new file mode 100644 index 0000000..732ffae --- /dev/null +++ b/source/jsbn2.js @@ -0,0 +1,658 @@ +/*! (c) Tom Wu | http://www-cs-students.stanford.edu/~tjw/jsbn/ + */ +// Copyright (c) 2005-2009 Tom Wu +// All Rights Reserved. +// See "LICENSE" for details. + +// Extended JavaScript BN functions, required for RSA private ops. + +// Version 1.1: new BigInteger("0", 10) returns "proper" zero +// Version 1.2: square() API, isProbablePrime fix + +// (public) +function bnClone() { var r = nbi(); this.copyTo(r); return r; } + +// (public) return value as integer +function bnIntValue() { + if(this.s < 0) { + if(this.t == 1) return this[0]-this.DV; + else if(this.t == 0) return -1; + } + else if(this.t == 1) return this[0]; + else if(this.t == 0) return 0; + // assumes 16 < DB < 32 + return ((this[1]&((1<<(32-this.DB))-1))<>24; } + +// (public) return value as short (assumes DB>=16) +function bnShortValue() { return (this.t==0)?this.s:(this[0]<<16)>>16; } + +// (protected) return x s.t. r^x < DV +function bnpChunkSize(r) { return Math.floor(Math.LN2*this.DB/Math.log(r)); } + +// (public) 0 if this == 0, 1 if this > 0 +function bnSigNum() { + if(this.s < 0) return -1; + else if(this.t <= 0 || (this.t == 1 && this[0] <= 0)) return 0; + else return 1; +} + +// (protected) convert to radix string +function bnpToRadix(b) { + if(b == null) b = 10; + if(this.signum() == 0 || b < 2 || b > 36) return "0"; + var cs = this.chunkSize(b); + var a = Math.pow(b,cs); + var d = nbv(a), y = nbi(), z = nbi(), r = ""; + this.divRemTo(d,y,z); + while(y.signum() > 0) { + r = (a+z.intValue()).toString(b).substr(1) + r; + y.divRemTo(d,y,z); + } + return z.intValue().toString(b) + r; +} + +// (protected) convert from radix string +function bnpFromRadix(s,b) { + this.fromInt(0); + if(b == null) b = 10; + var cs = this.chunkSize(b); + var d = Math.pow(b,cs), mi = false, j = 0, w = 0; + for(var i = 0; i < s.length; ++i) { + var x = intAt(s,i); + if(x < 0) { + if(s.charAt(i) == "-" && this.signum() == 0) mi = true; + continue; + } + w = b*w+x; + if(++j >= cs) { + this.dMultiply(d); + this.dAddOffset(w,0); + j = 0; + w = 0; + } + } + if(j > 0) { + this.dMultiply(Math.pow(b,j)); + this.dAddOffset(w,0); + } + if(mi) BigInteger.ZERO.subTo(this,this); +} + +// (protected) alternate constructor +function bnpFromNumber(a,b,c) { + if("number" == typeof b) { + // new BigInteger(int,int,RNG) + if(a < 2) this.fromInt(1); + else { + this.fromNumber(a,c); + if(!this.testBit(a-1)) // force MSB set + this.bitwiseTo(BigInteger.ONE.shiftLeft(a-1),op_or,this); + if(this.isEven()) this.dAddOffset(1,0); // force odd + while(!this.isProbablePrime(b)) { + this.dAddOffset(2,0); + if(this.bitLength() > a) this.subTo(BigInteger.ONE.shiftLeft(a-1),this); + } + } + } + else { + // new BigInteger(int,RNG) + var x = new Array(), t = a&7; + x.length = (a>>3)+1; + b.nextBytes(x); + if(t > 0) x[0] &= ((1< 0) { + if(p < this.DB && (d = this[i]>>p) != (this.s&this.DM)>>p) + r[k++] = d|(this.s<<(this.DB-p)); + while(i >= 0) { + if(p < 8) { + d = (this[i]&((1<>(p+=this.DB-8); + } + else { + d = (this[i]>>(p-=8))&0xff; + if(p <= 0) { p += this.DB; --i; } + } + if((d&0x80) != 0) d |= -256; + if(k == 0 && (this.s&0x80) != (d&0x80)) ++k; + if(k > 0 || d != this.s) r[k++] = d; + } + } + return r; +} + +function bnEquals(a) { return(this.compareTo(a)==0); } +function bnMin(a) { return(this.compareTo(a)<0)?this:a; } +function bnMax(a) { return(this.compareTo(a)>0)?this:a; } + +// (protected) r = this op a (bitwise) +function bnpBitwiseTo(a,op,r) { + var i, f, m = Math.min(a.t,this.t); + for(i = 0; i < m; ++i) r[i] = op(this[i],a[i]); + if(a.t < this.t) { + f = a.s&this.DM; + for(i = m; i < this.t; ++i) r[i] = op(this[i],f); + r.t = this.t; + } + else { + f = this.s&this.DM; + for(i = m; i < a.t; ++i) r[i] = op(f,a[i]); + r.t = a.t; + } + r.s = op(this.s,a.s); + r.clamp(); +} + +// (public) this & a +function op_and(x,y) { return x&y; } +function bnAnd(a) { var r = nbi(); this.bitwiseTo(a,op_and,r); return r; } + +// (public) this | a +function op_or(x,y) { return x|y; } +function bnOr(a) { var r = nbi(); this.bitwiseTo(a,op_or,r); return r; } + +// (public) this ^ a +function op_xor(x,y) { return x^y; } +function bnXor(a) { var r = nbi(); this.bitwiseTo(a,op_xor,r); return r; } + +// (public) this & ~a +function op_andnot(x,y) { return x&~y; } +function bnAndNot(a) { var r = nbi(); this.bitwiseTo(a,op_andnot,r); return r; } + +// (public) ~this +function bnNot() { + var r = nbi(); + for(var i = 0; i < this.t; ++i) r[i] = this.DM&~this[i]; + r.t = this.t; + r.s = ~this.s; + return r; +} + +// (public) this << n +function bnShiftLeft(n) { + var r = nbi(); + if(n < 0) this.rShiftTo(-n,r); else this.lShiftTo(n,r); + return r; +} + +// (public) this >> n +function bnShiftRight(n) { + var r = nbi(); + if(n < 0) this.lShiftTo(-n,r); else this.rShiftTo(n,r); + return r; +} + +// return index of lowest 1-bit in x, x < 2^31 +function lbit(x) { + if(x == 0) return -1; + var r = 0; + if((x&0xffff) == 0) { x >>= 16; r += 16; } + if((x&0xff) == 0) { x >>= 8; r += 8; } + if((x&0xf) == 0) { x >>= 4; r += 4; } + if((x&3) == 0) { x >>= 2; r += 2; } + if((x&1) == 0) ++r; + return r; +} + +// (public) returns index of lowest 1-bit (or -1 if none) +function bnGetLowestSetBit() { + for(var i = 0; i < this.t; ++i) + if(this[i] != 0) return i*this.DB+lbit(this[i]); + if(this.s < 0) return this.t*this.DB; + return -1; +} + +// return number of 1 bits in x +function cbit(x) { + var r = 0; + while(x != 0) { x &= x-1; ++r; } + return r; +} + +// (public) return number of set bits +function bnBitCount() { + var r = 0, x = this.s&this.DM; + for(var i = 0; i < this.t; ++i) r += cbit(this[i]^x); + return r; +} + +// (public) true iff nth bit is set +function bnTestBit(n) { + var j = Math.floor(n/this.DB); + if(j >= this.t) return(this.s!=0); + return((this[j]&(1<<(n%this.DB)))!=0); +} + +// (protected) this op (1<>= this.DB; + } + if(a.t < this.t) { + c += a.s; + while(i < this.t) { + c += this[i]; + r[i++] = c&this.DM; + c >>= this.DB; + } + c += this.s; + } + else { + c += this.s; + while(i < a.t) { + c += a[i]; + r[i++] = c&this.DM; + c >>= this.DB; + } + c += a.s; + } + r.s = (c<0)?-1:0; + if(c > 0) r[i++] = c; + else if(c < -1) r[i++] = this.DV+c; + r.t = i; + r.clamp(); +} + +// (public) this + a +function bnAdd(a) { var r = nbi(); this.addTo(a,r); return r; } + +// (public) this - a +function bnSubtract(a) { var r = nbi(); this.subTo(a,r); return r; } + +// (public) this * a +function bnMultiply(a) { var r = nbi(); this.multiplyTo(a,r); return r; } + +// (public) this^2 +function bnSquare() { var r = nbi(); this.squareTo(r); return r; } + +// (public) this / a +function bnDivide(a) { var r = nbi(); this.divRemTo(a,r,null); return r; } + +// (public) this % a +function bnRemainder(a) { var r = nbi(); this.divRemTo(a,null,r); return r; } + +// (public) [this/a,this%a] +function bnDivideAndRemainder(a) { + var q = nbi(), r = nbi(); + this.divRemTo(a,q,r); + return new Array(q,r); +} + +// (protected) this *= n, this >= 0, 1 < n < DV +function bnpDMultiply(n) { + this[this.t] = this.am(0,n-1,this,0,0,this.t); + ++this.t; + this.clamp(); +} + +// (protected) this += n << w words, this >= 0 +function bnpDAddOffset(n,w) { + if(n == 0) return; + while(this.t <= w) this[this.t++] = 0; + this[w] += n; + while(this[w] >= this.DV) { + this[w] -= this.DV; + if(++w >= this.t) this[this.t++] = 0; + ++this[w]; + } +} + +// A "null" reducer +function NullExp() {} +function nNop(x) { return x; } +function nMulTo(x,y,r) { x.multiplyTo(y,r); } +function nSqrTo(x,r) { x.squareTo(r); } + +NullExp.prototype.convert = nNop; +NullExp.prototype.revert = nNop; +NullExp.prototype.mulTo = nMulTo; +NullExp.prototype.sqrTo = nSqrTo; + +// (public) this^e +function bnPow(e) { return this.exp(e,new NullExp()); } + +// (protected) r = lower n words of "this * a", a.t <= n +// "this" should be the larger one if appropriate. +function bnpMultiplyLowerTo(a,n,r) { + var i = Math.min(this.t+a.t,n); + r.s = 0; // assumes a,this >= 0 + r.t = i; + while(i > 0) r[--i] = 0; + var j; + for(j = r.t-this.t; i < j; ++i) r[i+this.t] = this.am(0,a[i],r,i,0,this.t); + for(j = Math.min(a.t,n); i < j; ++i) this.am(0,a[i],r,i,0,n-i); + r.clamp(); +} + +// (protected) r = "this * a" without lower n words, n > 0 +// "this" should be the larger one if appropriate. +function bnpMultiplyUpperTo(a,n,r) { + --n; + var i = r.t = this.t+a.t-n; + r.s = 0; // assumes a,this >= 0 + while(--i >= 0) r[i] = 0; + for(i = Math.max(n-this.t,0); i < a.t; ++i) + r[this.t+i-n] = this.am(n-i,a[i],r,0,0,this.t+i-n); + r.clamp(); + r.drShiftTo(1,r); +} + +// Barrett modular reduction +function Barrett(m) { + // setup Barrett + this.r2 = nbi(); + this.q3 = nbi(); + BigInteger.ONE.dlShiftTo(2*m.t,this.r2); + this.mu = this.r2.divide(m); + this.m = m; +} + +function barrettConvert(x) { + if(x.s < 0 || x.t > 2*this.m.t) return x.mod(this.m); + else if(x.compareTo(this.m) < 0) return x; + else { var r = nbi(); x.copyTo(r); this.reduce(r); return r; } +} + +function barrettRevert(x) { return x; } + +// x = x mod m (HAC 14.42) +function barrettReduce(x) { + x.drShiftTo(this.m.t-1,this.r2); + if(x.t > this.m.t+1) { x.t = this.m.t+1; x.clamp(); } + this.mu.multiplyUpperTo(this.r2,this.m.t+1,this.q3); + this.m.multiplyLowerTo(this.q3,this.m.t+1,this.r2); + while(x.compareTo(this.r2) < 0) x.dAddOffset(1,this.m.t+1); + x.subTo(this.r2,x); + while(x.compareTo(this.m) >= 0) x.subTo(this.m,x); +} + +// r = x^2 mod m; x != r +function barrettSqrTo(x,r) { x.squareTo(r); this.reduce(r); } + +// r = x*y mod m; x,y != r +function barrettMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); } + +Barrett.prototype.convert = barrettConvert; +Barrett.prototype.revert = barrettRevert; +Barrett.prototype.reduce = barrettReduce; +Barrett.prototype.mulTo = barrettMulTo; +Barrett.prototype.sqrTo = barrettSqrTo; + +// (public) this^e % m (HAC 14.85) +function bnModPow(e,m) { + var i = e.bitLength(), k, r = nbv(1), z; + if(i <= 0) return r; + else if(i < 18) k = 1; + else if(i < 48) k = 3; + else if(i < 144) k = 4; + else if(i < 768) k = 5; + else k = 6; + if(i < 8) + z = new Classic(m); + else if(m.isEven()) + z = new Barrett(m); + else + z = new Montgomery(m); + + // precomputation + var g = new Array(), n = 3, k1 = k-1, km = (1< 1) { + var g2 = nbi(); + z.sqrTo(g[1],g2); + while(n <= km) { + g[n] = nbi(); + z.mulTo(g2,g[n-2],g[n]); + n += 2; + } + } + + var j = e.t-1, w, is1 = true, r2 = nbi(), t; + i = nbits(e[j])-1; + while(j >= 0) { + if(i >= k1) w = (e[j]>>(i-k1))&km; + else { + w = (e[j]&((1<<(i+1))-1))<<(k1-i); + if(j > 0) w |= e[j-1]>>(this.DB+i-k1); + } + + n = k; + while((w&1) == 0) { w >>= 1; --n; } + if((i -= n) < 0) { i += this.DB; --j; } + if(is1) { // ret == 1, don't bother squaring or multiplying it + g[w].copyTo(r); + is1 = false; + } + else { + while(n > 1) { z.sqrTo(r,r2); z.sqrTo(r2,r); n -= 2; } + if(n > 0) z.sqrTo(r,r2); else { t = r; r = r2; r2 = t; } + z.mulTo(r2,g[w],r); + } + + while(j >= 0 && (e[j]&(1< 0) { + x.rShiftTo(g,x); + y.rShiftTo(g,y); + } + while(x.signum() > 0) { + if((i = x.getLowestSetBit()) > 0) x.rShiftTo(i,x); + if((i = y.getLowestSetBit()) > 0) y.rShiftTo(i,y); + if(x.compareTo(y) >= 0) { + x.subTo(y,x); + x.rShiftTo(1,x); + } + else { + y.subTo(x,y); + y.rShiftTo(1,y); + } + } + if(g > 0) y.lShiftTo(g,y); + return y; +} + +// (protected) this % n, n < 2^26 +function bnpModInt(n) { + if(n <= 0) return 0; + var d = this.DV%n, r = (this.s<0)?n-1:0; + if(this.t > 0) + if(d == 0) r = this[0]%n; + else for(var i = this.t-1; i >= 0; --i) r = (d*r+this[i])%n; + return r; +} + +// (public) 1/this % m (HAC 14.61) +function bnModInverse(m) { + var ac = m.isEven(); + if((this.isEven() && ac) || m.signum() == 0) return BigInteger.ZERO; + var u = m.clone(), v = this.clone(); + var a = nbv(1), b = nbv(0), c = nbv(0), d = nbv(1); + while(u.signum() != 0) { + while(u.isEven()) { + u.rShiftTo(1,u); + if(ac) { + if(!a.isEven() || !b.isEven()) { a.addTo(this,a); b.subTo(m,b); } + a.rShiftTo(1,a); + } + else if(!b.isEven()) b.subTo(m,b); + b.rShiftTo(1,b); + } + while(v.isEven()) { + v.rShiftTo(1,v); + if(ac) { + if(!c.isEven() || !d.isEven()) { c.addTo(this,c); d.subTo(m,d); } + c.rShiftTo(1,c); + } + else if(!d.isEven()) d.subTo(m,d); + d.rShiftTo(1,d); + } + if(u.compareTo(v) >= 0) { + u.subTo(v,u); + if(ac) a.subTo(c,a); + b.subTo(d,b); + } + else { + v.subTo(u,v); + if(ac) c.subTo(a,c); + d.subTo(b,d); + } + } + if(v.compareTo(BigInteger.ONE) != 0) return BigInteger.ZERO; + if(d.compareTo(m) >= 0) return d.subtract(m); + if(d.signum() < 0) d.addTo(m,d); else return d; + if(d.signum() < 0) return d.add(m); else return d; +} + +var lowprimes = [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509,521,523,541,547,557,563,569,571,577,587,593,599,601,607,613,617,619,631,641,643,647,653,659,661,673,677,683,691,701,709,719,727,733,739,743,751,757,761,769,773,787,797,809,811,821,823,827,829,839,853,857,859,863,877,881,883,887,907,911,919,929,937,941,947,953,967,971,977,983,991,997]; +var lplim = (1<<26)/lowprimes[lowprimes.length-1]; + +// (public) test primality with certainty >= 1-.5^t +function bnIsProbablePrime(t) { + var i, x = this.abs(); + if(x.t == 1 && x[0] <= lowprimes[lowprimes.length-1]) { + for(i = 0; i < lowprimes.length; ++i) + if(x[0] == lowprimes[i]) return true; + return false; + } + if(x.isEven()) return false; + i = 1; + while(i < lowprimes.length) { + var m = lowprimes[i], j = i+1; + while(j < lowprimes.length && m < lplim) m *= lowprimes[j++]; + m = x.modInt(m); + while(i < j) if(m%lowprimes[i++] == 0) return false; + } + return x.millerRabin(t); +} + +// (protected) true if probably prime (HAC 4.24, Miller-Rabin) +function bnpMillerRabin(t) { + var n1 = this.subtract(BigInteger.ONE); + var k = n1.getLowestSetBit(); + if(k <= 0) return false; + var r = n1.shiftRight(k); + t = (t+1)>>1; + if(t > lowprimes.length) t = lowprimes.length; + var a = nbi(); + for(var i = 0; i < t; ++i) { + //Pick bases at random, instead of starting at 2 + a.fromInt(lowprimes[Math.floor(Math.random()*lowprimes.length)]); + var y = a.modPow(r,this); + if(y.compareTo(BigInteger.ONE) != 0 && y.compareTo(n1) != 0) { + var j = 1; + while(j++ < k && y.compareTo(n1) != 0) { + y = y.modPowInt(2,this); + if(y.compareTo(BigInteger.ONE) == 0) return false; + } + if(y.compareTo(n1) != 0) return false; + } + } + return true; +} + +// protected +BigInteger.prototype.chunkSize = bnpChunkSize; +BigInteger.prototype.toRadix = bnpToRadix; +BigInteger.prototype.fromRadix = bnpFromRadix; +BigInteger.prototype.fromNumber = bnpFromNumber; +BigInteger.prototype.bitwiseTo = bnpBitwiseTo; +BigInteger.prototype.changeBit = bnpChangeBit; +BigInteger.prototype.addTo = bnpAddTo; +BigInteger.prototype.dMultiply = bnpDMultiply; +BigInteger.prototype.dAddOffset = bnpDAddOffset; +BigInteger.prototype.multiplyLowerTo = bnpMultiplyLowerTo; +BigInteger.prototype.multiplyUpperTo = bnpMultiplyUpperTo; +BigInteger.prototype.modInt = bnpModInt; +BigInteger.prototype.millerRabin = bnpMillerRabin; + +// public +BigInteger.prototype.clone = bnClone; +BigInteger.prototype.intValue = bnIntValue; +BigInteger.prototype.byteValue = bnByteValue; +BigInteger.prototype.shortValue = bnShortValue; +BigInteger.prototype.signum = bnSigNum; +BigInteger.prototype.toByteArray = bnToByteArray; +BigInteger.prototype.equals = bnEquals; +BigInteger.prototype.min = bnMin; +BigInteger.prototype.max = bnMax; +BigInteger.prototype.and = bnAnd; +BigInteger.prototype.or = bnOr; +BigInteger.prototype.xor = bnXor; +BigInteger.prototype.andNot = bnAndNot; +BigInteger.prototype.not = bnNot; +BigInteger.prototype.shiftLeft = bnShiftLeft; +BigInteger.prototype.shiftRight = bnShiftRight; +BigInteger.prototype.getLowestSetBit = bnGetLowestSetBit; +BigInteger.prototype.bitCount = bnBitCount; +BigInteger.prototype.testBit = bnTestBit; +BigInteger.prototype.setBit = bnSetBit; +BigInteger.prototype.clearBit = bnClearBit; +BigInteger.prototype.flipBit = bnFlipBit; +BigInteger.prototype.add = bnAdd; +BigInteger.prototype.subtract = bnSubtract; +BigInteger.prototype.multiply = bnMultiply; +BigInteger.prototype.divide = bnDivide; +BigInteger.prototype.remainder = bnRemainder; +BigInteger.prototype.divideAndRemainder = bnDivideAndRemainder; +BigInteger.prototype.modPow = bnModPow; +BigInteger.prototype.modInverse = bnModInverse; +BigInteger.prototype.pow = bnPow; +BigInteger.prototype.gcd = bnGCD; +BigInteger.prototype.isProbablePrime = bnIsProbablePrime; + +// JSBN-specific extension +BigInteger.prototype.square = bnSquare; + +// BigInteger interfaces not implemented in jsbn: + +// BigInteger(int signum, byte[] magnitude) +// double doubleValue() +// float floatValue() +// int hashCode() +// long longValue() +// static BigInteger valueOf(long val) diff --git a/source/keyutil-1.0.js b/source/keyutil-1.0.js new file mode 100644 index 0000000..99c97d1 --- /dev/null +++ b/source/keyutil-1.0.js @@ -0,0 +1,1756 @@ +/* keyutil-1.2.0.js (c) 2013-2017 Kenji Urushima | kjur.github.com/jsrsasign/license + */ +/* + * keyutil.js - key utility for PKCS#1/5/8 PEM, RSA/DSA/ECDSA key object + * + * Copyright (c) 2013-2017 Kenji Urushima (kenji.urushima@gmail.com) + * + * This software is licensed under the terms of the MIT License. + * https://kjur.github.io/jsrsasign/license + * + * The above copyright and license notice shall be + * included in all copies or substantial portions of the Software. + */ +/** + * @fileOverview + * @name keyutil-1.0.js + * @author Kenji Urushima kenji.urushima@gmail.com + * @version jsrsasign 8.0.0 keyutil 1.2.0 (2017-Jun-26) + * @since jsrsasign 4.1.4 + * @license MIT License + */ + +/** + * @name KEYUTIL + * @class class for RSA/ECC/DSA key utility + * @description + *
+ * {@link KEYUTIL} class is an update of former {@link PKCS5PKEY} class. + * {@link KEYUTIL} class has following features: + *
+ *
key loading - {@link KEYUTIL.getKey} + *
+ *
    + *
  • supports RSAKey and KJUR.crypto.{ECDSA,DSA} key object
  • + *
  • supports private key and public key
  • + *
  • supports encrypted and plain private key
  • + *
  • supports PKCS#1, PKCS#5 and PKCS#8 key
  • + *
  • supports public key in X.509 certificate
  • + *
  • key represented by JSON object
  • + *
+ * NOTE1: Encrypted PKCS#8 only supports PBKDF2/HmacSHA1/3DES
+ * NOTE2: Encrypted PKCS#5 supports DES-CBC, DES-EDE3-CBC, AES-{128,192.256}-CBC
+ * + *
exporting key - {@link KEYUTIL.getPEM} + *
+ * {@link KEYUTIL.getPEM} method supports following formats: + *
    + *
  • supports RSA/EC/DSA keys
  • + *
  • PKCS#1 plain RSA/EC/DSA private key
  • + *
  • PKCS#5 encrypted RSA/EC/DSA private key with DES-CBC, DES-EDE3-CBC, AES-{128,192.256}-CBC
  • + *
  • PKCS#8 plain RSA/EC/DSA private key
  • + *
  • PKCS#8 encrypted RSA/EC/DSA private key with PBKDF2_HmacSHA1_3DES
  • + *
+ * + *
keypair generation - {@link KEYUTIL.generateKeypair} + *
    + *
  • generate key pair of {@link RSAKey} or {@link KJUR.crypto.ECDSA}.
  • + *
  • generate private key and convert it to PKCS#5 encrypted private key.
  • + *
+ * NOTE: {@link KJUR.crypto.DSA} is not yet supported. + *
+ * + * @example + * // 1. loading PEM private key + * var key = KEYUTIL.getKey(pemPKCS1PrivateKey); + * var key = KEYUTIL.getKey(pemPKCS5EncryptedPrivateKey, "passcode"); + * var key = KEYUTIL.getKey(pemPKC85PlainPrivateKey); + * var key = KEYUTIL.getKey(pemPKC85EncryptedPrivateKey, "passcode"); + * // 2. loading PEM public key + * var key = KEYUTIL.getKey(pemPKCS8PublicKey); + * var key = KEYUTIL.getKey(pemX509Certificate); + * // 3. exporting private key + * var pem = KEYUTIL.getPEM(privateKeyObj, "PKCS1PRV"); + * var pem = KEYUTIL.getPEM(privateKeyObj, "PKCS5PRV", "passcode"); // DES-EDE3-CBC by default + * var pem = KEYUTIL.getPEM(privateKeyObj, "PKCS5PRV", "passcode", "DES-CBC"); + * var pem = KEYUTIL.getPEM(privateKeyObj, "PKCS8PRV"); + * var pem = KEYUTIL.getPEM(privateKeyObj, "PKCS8PRV", "passcode"); + * // 4. exporting public key + * var pem = KEYUTIL.getPEM(publicKeyObj); + */ +var KEYUTIL = function() { + // ***************************************************************** + // *** PRIVATE PROPERTIES AND METHODS ******************************* + // ***************************************************************** + // shared key decryption ------------------------------------------ + var decryptAES = function(dataHex, keyHex, ivHex) { + return decryptGeneral(CryptoJS.AES, dataHex, keyHex, ivHex); + }; + + var decrypt3DES = function(dataHex, keyHex, ivHex) { + return decryptGeneral(CryptoJS.TripleDES, dataHex, keyHex, ivHex); + }; + + var decryptDES = function(dataHex, keyHex, ivHex) { + return decryptGeneral(CryptoJS.DES, dataHex, keyHex, ivHex); + }; + + var decryptGeneral = function(f, dataHex, keyHex, ivHex) { + var data = CryptoJS.enc.Hex.parse(dataHex); + var key = CryptoJS.enc.Hex.parse(keyHex); + var iv = CryptoJS.enc.Hex.parse(ivHex); + var encrypted = {}; + encrypted.key = key; + encrypted.iv = iv; + encrypted.ciphertext = data; + var decrypted = f.decrypt(encrypted, key, { iv: iv }); + return CryptoJS.enc.Hex.stringify(decrypted); + }; + + // shared key decryption ------------------------------------------ + var encryptAES = function(dataHex, keyHex, ivHex) { + return encryptGeneral(CryptoJS.AES, dataHex, keyHex, ivHex); + }; + + var encrypt3DES = function(dataHex, keyHex, ivHex) { + return encryptGeneral(CryptoJS.TripleDES, dataHex, keyHex, ivHex); + }; + + var encryptDES = function(dataHex, keyHex, ivHex) { + return encryptGeneral(CryptoJS.DES, dataHex, keyHex, ivHex); + }; + + var encryptGeneral = function(f, dataHex, keyHex, ivHex) { + var data = CryptoJS.enc.Hex.parse(dataHex); + var key = CryptoJS.enc.Hex.parse(keyHex); + var iv = CryptoJS.enc.Hex.parse(ivHex); + var encryptedHex = f.encrypt(data, key, { iv: iv }); + var encryptedWA = CryptoJS.enc.Hex.parse(encryptedHex.toString()); + var encryptedB64 = CryptoJS.enc.Base64.stringify(encryptedWA); + return encryptedB64; + }; + + // other methods and properties ---------------------------------------- + var ALGLIST = { + 'AES-256-CBC': { 'proc': decryptAES, 'eproc': encryptAES, keylen: 32, ivlen: 16 }, + 'AES-192-CBC': { 'proc': decryptAES, 'eproc': encryptAES, keylen: 24, ivlen: 16 }, + 'AES-128-CBC': { 'proc': decryptAES, 'eproc': encryptAES, keylen: 16, ivlen: 16 }, + 'DES-EDE3-CBC': { 'proc': decrypt3DES, 'eproc': encrypt3DES, keylen: 24, ivlen: 8 }, + 'DES-CBC': { 'proc': decryptDES, 'eproc': encryptDES, keylen: 8, ivlen: 8 } + }; + + var getFuncByName = function(algName) { + return ALGLIST[algName]['proc']; + }; + + var _generateIvSaltHex = function(numBytes) { + var wa = CryptoJS.lib.WordArray.random(numBytes); + var hex = CryptoJS.enc.Hex.stringify(wa); + return hex; + }; + + var _parsePKCS5PEM = function(sPKCS5PEM) { + var info = {}; + var matchResult1 = sPKCS5PEM.match(new RegExp("DEK-Info: ([^,]+),([0-9A-Fa-f]+)", "m")); + if (matchResult1) { + info.cipher = matchResult1[1]; + info.ivsalt = matchResult1[2]; + } + var matchResult2 = sPKCS5PEM.match(new RegExp("-----BEGIN ([A-Z]+) PRIVATE KEY-----")); + if (matchResult2) { + info.type = matchResult2[1]; + } + var i1 = -1; + var lenNEWLINE = 0; + if (sPKCS5PEM.indexOf("\r\n\r\n") != -1) { + i1 = sPKCS5PEM.indexOf("\r\n\r\n"); + lenNEWLINE = 2; + } + if (sPKCS5PEM.indexOf("\n\n") != -1) { + i1 = sPKCS5PEM.indexOf("\n\n"); + lenNEWLINE = 1; + } + var i2 = sPKCS5PEM.indexOf("-----END"); + if (i1 != -1 && i2 != -1) { + var s = sPKCS5PEM.substring(i1 + lenNEWLINE * 2, i2 - lenNEWLINE); + s = s.replace(/\s+/g, ''); + info.data = s; + } + return info; + }; + + var _getKeyAndUnusedIvByPasscodeAndIvsalt = function(algName, passcode, ivsaltHex) { + //alert("ivsaltHex(2) = " + ivsaltHex); + var saltHex = ivsaltHex.substring(0, 16); + //alert("salt = " + saltHex); + + var salt = CryptoJS.enc.Hex.parse(saltHex); + var data = CryptoJS.enc.Utf8.parse(passcode); + //alert("salt = " + salt); + //alert("data = " + data); + + var nRequiredBytes = ALGLIST[algName]['keylen'] + ALGLIST[algName]['ivlen']; + var hHexValueJoined = ''; + var hLastValue = null; + //alert("nRequiredBytes = " + nRequiredBytes); + for (;;) { + var h = CryptoJS.algo.MD5.create(); + if (hLastValue != null) { + h.update(hLastValue); + } + h.update(data); + h.update(salt); + hLastValue = h.finalize(); + hHexValueJoined = hHexValueJoined + CryptoJS.enc.Hex.stringify(hLastValue); + //alert("joined = " + hHexValueJoined); + if (hHexValueJoined.length >= nRequiredBytes * 2) { + break; + } + } + var result = {}; + result.keyhex = hHexValueJoined.substr(0, ALGLIST[algName]['keylen'] * 2); + result.ivhex = hHexValueJoined.substr(ALGLIST[algName]['keylen'] * 2, ALGLIST[algName]['ivlen'] * 2); + return result; + }; + + /* + * @param {String} privateKeyB64 base64 string of encrypted private key + * @param {String} sharedKeyAlgName algorithm name of shared key encryption + * @param {String} sharedKeyHex hexadecimal string of shared key to encrypt + * @param {String} ivsaltHex hexadecimal string of IV and salt + * @param {String} hexadecimal string of decrypted private key + */ + var _decryptKeyB64 = function(privateKeyB64, sharedKeyAlgName, sharedKeyHex, ivsaltHex) { + var privateKeyWA = CryptoJS.enc.Base64.parse(privateKeyB64); + var privateKeyHex = CryptoJS.enc.Hex.stringify(privateKeyWA); + var f = ALGLIST[sharedKeyAlgName]['proc']; + var decryptedKeyHex = f(privateKeyHex, sharedKeyHex, ivsaltHex); + return decryptedKeyHex; + }; + + /* + * @param {String} privateKeyHex hexadecimal string of private key + * @param {String} sharedKeyAlgName algorithm name of shared key encryption + * @param {String} sharedKeyHex hexadecimal string of shared key to encrypt + * @param {String} ivsaltHex hexadecimal string of IV and salt + * @param {String} base64 string of encrypted private key + */ + var _encryptKeyHex = function(privateKeyHex, sharedKeyAlgName, sharedKeyHex, ivsaltHex) { + var f = ALGLIST[sharedKeyAlgName]['eproc']; + var encryptedKeyB64 = f(privateKeyHex, sharedKeyHex, ivsaltHex); + return encryptedKeyB64; + }; + + // ***************************************************************** + // *** PUBLIC PROPERTIES AND METHODS ******************************* + // ***************************************************************** + return { + // -- UTILITY METHODS ------------------------------------------------------------ + /** + * decrypt private key by shared key + * @name version + * @memberOf KEYUTIL + * @property {String} version + * @description version string of KEYUTIL class + */ + version: "1.0.0", + + /** + * parse PEM formatted passcode protected PKCS#5 private key + * @name parsePKCS5PEM + * @memberOf KEYUTIL + * @function + * @param {String} sEncryptedPEM PEM formatted protected passcode protected PKCS#5 private key + * @return {Hash} hash of key information + * @description + * Resulted hash has following attributes. + *
    + *
  • cipher - symmetric key algorithm name (ex. 'DES-EBE3-CBC', 'AES-256-CBC')
  • + *
  • ivsalt - IV used for decrypt. Its heading 8 bytes will be used for passcode salt.
  • + *
  • type - asymmetric key algorithm name of private key described in PEM header.
  • + *
  • data - base64 encoded encrypted private key.
  • + *
+ * + */ + parsePKCS5PEM: function(sPKCS5PEM) { + return _parsePKCS5PEM(sPKCS5PEM); + }, + + /** + * the same function as OpenSSL EVP_BytsToKey to generate shared key and IV + * @name getKeyAndUnusedIvByPasscodeAndIvsalt + * @memberOf KEYUTIL + * @function + * @param {String} algName name of symmetric key algorithm (ex. 'DES-EBE3-CBC') + * @param {String} passcode passcode to decrypt private key (ex. 'password') + * @param {String} hexadecimal string of IV. heading 8 bytes will be used for passcode salt + * @return {Hash} hash of key and unused IV (ex. {keyhex:2fe3..., ivhex:3fad..}) + */ + getKeyAndUnusedIvByPasscodeAndIvsalt: function(algName, passcode, ivsaltHex) { + return _getKeyAndUnusedIvByPasscodeAndIvsalt(algName, passcode, ivsaltHex); + }, + + decryptKeyB64: function(privateKeyB64, sharedKeyAlgName, sharedKeyHex, ivsaltHex) { + return _decryptKeyB64(privateKeyB64, sharedKeyAlgName, sharedKeyHex, ivsaltHex); + }, + + /** + * decrypt PEM formatted protected PKCS#5 private key with passcode + * @name getDecryptedKeyHex + * @memberOf KEYUTIL + * @function + * @param {String} sEncryptedPEM PEM formatted protected passcode protected PKCS#5 private key + * @param {String} passcode passcode to decrypt private key (ex. 'password') + * @return {String} hexadecimal string of decrypted RSA priavte key + */ + getDecryptedKeyHex: function(sEncryptedPEM, passcode) { + // 1. parse pem + var info = _parsePKCS5PEM(sEncryptedPEM); + var publicKeyAlgName = info.type; + var sharedKeyAlgName = info.cipher; + var ivsaltHex = info.ivsalt; + var privateKeyB64 = info.data; + //alert("ivsaltHex = " + ivsaltHex); + + // 2. generate shared key + var sharedKeyInfo = _getKeyAndUnusedIvByPasscodeAndIvsalt(sharedKeyAlgName, passcode, ivsaltHex); + var sharedKeyHex = sharedKeyInfo.keyhex; + //alert("sharedKeyHex = " + sharedKeyHex); + + // 3. decrypt private key + var decryptedKey = _decryptKeyB64(privateKeyB64, sharedKeyAlgName, sharedKeyHex, ivsaltHex); + return decryptedKey; + }, + + /* + * get PEM formatted encrypted PKCS#5 private key from hexadecimal string of plain private key + * @name getEncryptedPKCS5PEMFromPrvKeyHex + * @memberOf KEYUTIL + * @function + * @param {String} pemHeadAlg algorithm name in the pem header (i.e. RSA,EC or DSA) + * @param {String} hPrvKey hexadecimal string of plain private key + * @param {String} passcode pass code to protect private key (ex. password) + * @param {String} sharedKeyAlgName algorithm name to protect private key (ex. AES-256-CBC) + * @param {String} ivsaltHex hexadecimal string of IV and salt + * @return {String} string of PEM formatted encrypted PKCS#5 private key + * @since pkcs5pkey 1.0.2 + * @description + *
+ * generate PEM formatted encrypted PKCS#5 private key by hexadecimal string encoded + * ASN.1 object of plain RSA private key. + * Following arguments can be omitted. + *
    + *
  • alg - AES-256-CBC will be used if omitted.
  • + *
  • ivsaltHex - automatically generate IV and salt which length depends on algorithm
  • + *
+ * NOTE1: DES-CBC, DES-EDE3-CBC, AES-{128,192.256}-CBC algorithm are supported. + * @example + * var pem = + * KEYUTIL.getEncryptedPKCS5PEMFromPrvKeyHex(plainKeyHex, "password"); + * var pem2 = + * KEYUTIL.getEncryptedPKCS5PEMFromPrvKeyHex(plainKeyHex, "password", "AES-128-CBC"); + * var pem3 = + * KEYUTIL.getEncryptedPKCS5PEMFromPrvKeyHex(plainKeyHex, "password", "AES-128-CBC", "1f3d02..."); + */ + getEncryptedPKCS5PEMFromPrvKeyHex: function(pemHeadAlg, hPrvKey, passcode, sharedKeyAlgName, ivsaltHex) { + var sPEM = ""; + + // 1. set sharedKeyAlgName if undefined (default AES-256-CBC) + if (typeof sharedKeyAlgName == "undefined" || sharedKeyAlgName == null) { + sharedKeyAlgName = "AES-256-CBC"; + } + if (typeof ALGLIST[sharedKeyAlgName] == "undefined") + throw "KEYUTIL unsupported algorithm: " + sharedKeyAlgName; + + // 2. set ivsaltHex if undefined + if (typeof ivsaltHex == "undefined" || ivsaltHex == null) { + var ivlen = ALGLIST[sharedKeyAlgName]['ivlen']; + var randIV = _generateIvSaltHex(ivlen); + ivsaltHex = randIV.toUpperCase(); + } + + // 3. get shared key + //alert("ivsalthex=" + ivsaltHex); + var sharedKeyInfo = _getKeyAndUnusedIvByPasscodeAndIvsalt(sharedKeyAlgName, passcode, ivsaltHex); + var sharedKeyHex = sharedKeyInfo.keyhex; + // alert("sharedKeyHex = " + sharedKeyHex); + + // 3. get encrypted Key in Base64 + var encryptedKeyB64 = _encryptKeyHex(hPrvKey, sharedKeyAlgName, sharedKeyHex, ivsaltHex); + + var pemBody = encryptedKeyB64.replace(/(.{64})/g, "$1\r\n"); + var sPEM = "-----BEGIN " + pemHeadAlg + " PRIVATE KEY-----\r\n"; + sPEM += "Proc-Type: 4,ENCRYPTED\r\n"; + sPEM += "DEK-Info: " + sharedKeyAlgName + "," + ivsaltHex + "\r\n"; + sPEM += "\r\n"; + sPEM += pemBody; + sPEM += "\r\n-----END " + pemHeadAlg + " PRIVATE KEY-----\r\n"; + + return sPEM; + }, + + // === PKCS8 =============================================================== + + /** + * generate PBKDF2 key hexstring with specified passcode and information + * @name parseHexOfEncryptedPKCS8 + * @memberOf KEYUTIL + * @function + * @param {String} passcode passcode to decrypto private key + * @return {Array} info associative array of PKCS#8 parameters + * @since pkcs5pkey 1.0.3 + * @description + * The associative array which is returned by this method has following properties: + *
    + *
  • info.pbkdf2Salt - hexadecimal string of PBKDF2 salt
  • + *
  • info.pkbdf2Iter - iteration count
  • + *
  • info.ciphertext - hexadecimal string of encrypted private key
  • + *
  • info.encryptionSchemeAlg - encryption algorithm name (currently TripleDES only)
  • + *
  • info.encryptionSchemeIV - initial vector for encryption algorithm
  • + *
+ * Currently, this method only supports PKCS#5v2.0 with PBES2/PBDKF2 of HmacSHA1 and TripleDES. + *
    + *
  • keyDerivationFunc = pkcs5PBKDF2 with HmacSHA1
  • + *
  • encryptionScheme = des-EDE3-CBC(i.e. TripleDES
  • + *
+ * @example + * // to convert plain PKCS#5 private key to encrypted PKCS#8 private + * // key with PBKDF2 with TripleDES + * % openssl pkcs8 -in plain_p5.pem -topk8 -v2 -des3 -out encrypted_p8.pem + */ + parseHexOfEncryptedPKCS8: function(sHEX) { + var _ASN1HEX = ASN1HEX; + var _getChildIdx = _ASN1HEX.getChildIdx; + var _getV = _ASN1HEX.getV; + var info = {}; + + var a0 = _getChildIdx(sHEX, 0); + if (a0.length != 2) + throw "malformed format: SEQUENCE(0).items != 2: " + a0.length; + + // 1. ciphertext + info.ciphertext = _getV(sHEX, a0[1]); + + // 2. pkcs5PBES2 + var a0_0 = _getChildIdx(sHEX, a0[0]); + if (a0_0.length != 2) + throw "malformed format: SEQUENCE(0.0).items != 2: " + a0_0.length; + + // 2.1 check if pkcs5PBES2(1 2 840 113549 1 5 13) + if (_getV(sHEX, a0_0[0]) != "2a864886f70d01050d") + throw "this only supports pkcs5PBES2"; + + // 2.2 pkcs5PBES2 param + var a0_0_1 = _getChildIdx(sHEX, a0_0[1]); + if (a0_0.length != 2) + throw "malformed format: SEQUENCE(0.0.1).items != 2: " + a0_0_1.length; + + // 2.2.1 encryptionScheme + var a0_0_1_1 = _getChildIdx(sHEX, a0_0_1[1]); + if (a0_0_1_1.length != 2) + throw "malformed format: SEQUENCE(0.0.1.1).items != 2: " + a0_0_1_1.length; + if (_getV(sHEX, a0_0_1_1[0]) != "2a864886f70d0307") + throw "this only supports TripleDES"; + info.encryptionSchemeAlg = "TripleDES"; + + // 2.2.1.1 IV of encryptionScheme + info.encryptionSchemeIV = _getV(sHEX, a0_0_1_1[1]); + + // 2.2.2 keyDerivationFunc + var a0_0_1_0 = _getChildIdx(sHEX, a0_0_1[0]); + if (a0_0_1_0.length != 2) + throw "malformed format: SEQUENCE(0.0.1.0).items != 2: " + a0_0_1_0.length; + if (_getV(sHEX, a0_0_1_0[0]) != "2a864886f70d01050c") + throw "this only supports pkcs5PBKDF2"; + + // 2.2.2.1 pkcs5PBKDF2 param + var a0_0_1_0_1 = _getChildIdx(sHEX, a0_0_1_0[1]); + if (a0_0_1_0_1.length < 2) + throw "malformed format: SEQUENCE(0.0.1.0.1).items < 2: " + a0_0_1_0_1.length; + + // 2.2.2.1.1 PBKDF2 salt + info.pbkdf2Salt = _getV(sHEX, a0_0_1_0_1[0]); + + // 2.2.2.1.2 PBKDF2 iter + var iterNumHex = _getV(sHEX, a0_0_1_0_1[1]); + try { + info.pbkdf2Iter = parseInt(iterNumHex, 16); + } catch(ex) { + throw "malformed format pbkdf2Iter: " + iterNumHex; + } + + return info; + }, + + /** + * generate PBKDF2 key hexstring with specified passcode and information + * @name getPBKDF2KeyHexFromParam + * @memberOf KEYUTIL + * @function + * @param {Array} info result of {@link parseHexOfEncryptedPKCS8} which has preference of PKCS#8 file + * @param {String} passcode passcode to decrypto private key + * @return {String} hexadecimal string of PBKDF2 key + * @since pkcs5pkey 1.0.3 + * @description + * As for info, this uses following properties: + *
    + *
  • info.pbkdf2Salt - hexadecimal string of PBKDF2 salt
  • + *
  • info.pkbdf2Iter - iteration count
  • + *
+ * Currently, this method only supports PKCS#5v2.0 with PBES2/PBDKF2 of HmacSHA1 and TripleDES. + *
    + *
  • keyDerivationFunc = pkcs5PBKDF2 with HmacSHA1
  • + *
  • encryptionScheme = des-EDE3-CBC(i.e. TripleDES
  • + *
+ * @example + * // to convert plain PKCS#5 private key to encrypted PKCS#8 private + * // key with PBKDF2 with TripleDES + * % openssl pkcs8 -in plain_p5.pem -topk8 -v2 -des3 -out encrypted_p8.pem + */ + getPBKDF2KeyHexFromParam: function(info, passcode) { + var pbkdf2SaltWS = CryptoJS.enc.Hex.parse(info.pbkdf2Salt); + var pbkdf2Iter = info.pbkdf2Iter; + var pbkdf2KeyWS = CryptoJS.PBKDF2(passcode, + pbkdf2SaltWS, + { keySize: 192/32, iterations: pbkdf2Iter }); + var pbkdf2KeyHex = CryptoJS.enc.Hex.stringify(pbkdf2KeyWS); + return pbkdf2KeyHex; + }, + + /* + * read PEM formatted encrypted PKCS#8 private key and returns hexadecimal string of plain PKCS#8 private key + * @name getPlainPKCS8HexFromEncryptedPKCS8PEM + * @memberOf KEYUTIL + * @function + * @param {String} pkcs8PEM PEM formatted encrypted PKCS#8 private key + * @param {String} passcode passcode to decrypto private key + * @return {String} hexadecimal string of plain PKCS#8 private key + * @since pkcs5pkey 1.0.3 + * @description + * Currently, this method only supports PKCS#5v2.0 with PBES2/PBDKF2 of HmacSHA1 and TripleDES. + *
    + *
  • keyDerivationFunc = pkcs5PBKDF2 with HmacSHA1
  • + *
  • encryptionScheme = des-EDE3-CBC(i.e. TripleDES
  • + *
+ * @example + * // to convert plain PKCS#5 private key to encrypted PKCS#8 private + * // key with PBKDF2 with TripleDES + * % openssl pkcs8 -in plain_p5.pem -topk8 -v2 -des3 -out encrypted_p8.pem + */ + _getPlainPKCS8HexFromEncryptedPKCS8PEM: function(pkcs8PEM, passcode) { + // 1. derHex - PKCS#8 private key encrypted by PBKDF2 + var derHex = pemtohex(pkcs8PEM, "ENCRYPTED PRIVATE KEY"); + // 2. info - PKCS#5 PBES info + var info = this.parseHexOfEncryptedPKCS8(derHex); + // 3. hKey - PBKDF2 key + var pbkdf2KeyHex = KEYUTIL.getPBKDF2KeyHexFromParam(info, passcode); + // 4. decrypt ciphertext by PBKDF2 key + var encrypted = {}; + encrypted.ciphertext = CryptoJS.enc.Hex.parse(info.ciphertext); + var pbkdf2KeyWS = CryptoJS.enc.Hex.parse(pbkdf2KeyHex); + var des3IVWS = CryptoJS.enc.Hex.parse(info.encryptionSchemeIV); + var decWS = CryptoJS.TripleDES.decrypt(encrypted, pbkdf2KeyWS, { iv: des3IVWS }); + var decHex = CryptoJS.enc.Hex.stringify(decWS); + return decHex; + }, + + /** + * get RSAKey/ECDSA private key object from encrypted PEM PKCS#8 private key + * @name getKeyFromEncryptedPKCS8PEM + * @memberOf KEYUTIL + * @function + * @param {String} pkcs8PEM string of PEM formatted PKCS#8 private key + * @param {String} passcode passcode string to decrypt key + * @return {Object} RSAKey or KJUR.crypto.ECDSA private key object + * @since pkcs5pkey 1.0.5 + */ + getKeyFromEncryptedPKCS8PEM: function(pkcs8PEM, passcode) { + var prvKeyHex = this._getPlainPKCS8HexFromEncryptedPKCS8PEM(pkcs8PEM, passcode); + var key = this.getKeyFromPlainPrivatePKCS8Hex(prvKeyHex); + return key; + }, + + /** + * parse hexadecimal string of plain PKCS#8 private key + * @name parsePlainPrivatePKCS8Hex + * @memberOf KEYUTIL + * @function + * @param {String} pkcs8PrvHex hexadecimal string of PKCS#8 plain private key + * @return {Array} associative array of parsed key + * @since pkcs5pkey 1.0.5 + * @description + * Resulted associative array has following properties: + *
    + *
  • algoid - hexadecimal string of OID of asymmetric key algorithm
  • + *
  • algparam - hexadecimal string of OID of ECC curve name or null
  • + *
  • keyidx - string starting index of key in pkcs8PrvHex
  • + *
+ */ + parsePlainPrivatePKCS8Hex: function(pkcs8PrvHex) { + var _ASN1HEX = ASN1HEX; + var _getChildIdx = _ASN1HEX.getChildIdx; + var _getV = _ASN1HEX.getV; + var result = {}; + result.algparam = null; + + // 1. sequence + if (pkcs8PrvHex.substr(0, 2) != "30") + throw "malformed plain PKCS8 private key(code:001)"; // not sequence + + var a1 = _getChildIdx(pkcs8PrvHex, 0); + if (a1.length != 3) + throw "malformed plain PKCS8 private key(code:002)"; + + // 2. AlgID + if (pkcs8PrvHex.substr(a1[1], 2) != "30") + throw "malformed PKCS8 private key(code:003)"; // AlgId not sequence + + var a2 = _getChildIdx(pkcs8PrvHex, a1[1]); + if (a2.length != 2) + throw "malformed PKCS8 private key(code:004)"; // AlgId not have two elements + + // 2.1. AlgID OID + if (pkcs8PrvHex.substr(a2[0], 2) != "06") + throw "malformed PKCS8 private key(code:005)"; // AlgId.oid is not OID + + result.algoid = _getV(pkcs8PrvHex, a2[0]); + + // 2.2. AlgID param + if (pkcs8PrvHex.substr(a2[1], 2) == "06") { + result.algparam = _getV(pkcs8PrvHex, a2[1]); + } + + // 3. Key index + if (pkcs8PrvHex.substr(a1[2], 2) != "04") + throw "malformed PKCS8 private key(code:006)"; // not octet string + + result.keyidx = _ASN1HEX.getVidx(pkcs8PrvHex, a1[2]); + + return result; + }, + + /** + * get RSAKey/ECDSA private key object from PEM plain PEM PKCS#8 private key + * @name getKeyFromPlainPrivatePKCS8PEM + * @memberOf KEYUTIL + * @function + * @param {String} pkcs8PEM string of plain PEM formatted PKCS#8 private key + * @return {Object} RSAKey or KJUR.crypto.ECDSA private key object + * @since pkcs5pkey 1.0.5 + */ + getKeyFromPlainPrivatePKCS8PEM: function(prvKeyPEM) { + var prvKeyHex = pemtohex(prvKeyPEM, "PRIVATE KEY"); + var key = this.getKeyFromPlainPrivatePKCS8Hex(prvKeyHex); + return key; + }, + + /** + * get RSAKey/DSA/ECDSA private key object from HEX plain PEM PKCS#8 private key + * @name getKeyFromPlainPrivatePKCS8Hex + * @memberOf KEYUTIL + * @function + * @param {String} prvKeyHex hexadecimal string of plain PKCS#8 private key + * @return {Object} RSAKey or KJUR.crypto.{DSA,ECDSA} private key object + * @since pkcs5pkey 1.0.5 + */ + getKeyFromPlainPrivatePKCS8Hex: function(prvKeyHex) { + var p8 = this.parsePlainPrivatePKCS8Hex(prvKeyHex); + var key; + + if (p8.algoid == "2a864886f70d010101") { // RSA + key = new RSAKey(); + } else if (p8.algoid == "2a8648ce380401") { // DSA + key = new KJUR.crypto.DSA(); + } else if (p8.algoid == "2a8648ce3d0201") { // ECC + key = new KJUR.crypto.ECDSA(); + } else { + throw "unsupported private key algorithm"; + } + + key.readPKCS8PrvKeyHex(prvKeyHex); + return key; + }, + + // === PKCS8 RSA Public Key ================================================ + + /* + * get RSAKey/DSA/ECDSA public key object from hexadecimal string of PKCS#8 public key + * @name _getKeyFromPublicPKCS8Hex + * @memberOf KEYUTIL + * @function + * @param {String} pkcsPub8Hex hexadecimal string of PKCS#8 public key + * @return {Object} RSAKey or KJUR.crypto.{ECDSA,DSA} private key object + * @since pkcs5pkey 1.0.5 + */ + _getKeyFromPublicPKCS8Hex: function(h) { + var key; + var hOID = ASN1HEX.getVbyList(h, 0, [0, 0], "06"); + + if (hOID === "2a864886f70d010101") { // oid=RSA + key = new RSAKey(); + } else if (hOID === "2a8648ce380401") { // oid=DSA + key = new KJUR.crypto.DSA(); + } else if (hOID === "2a8648ce3d0201") { // oid=ECPUB + key = new KJUR.crypto.ECDSA(); + } else { + throw "unsupported PKCS#8 public key hex"; + } + key.readPKCS8PubKeyHex(h); + return key; + }, + + /** + * parse hexadecimal string of plain PKCS#8 private key + * @name parsePublicRawRSAKeyHex + * @memberOf KEYUTIL + * @function + * @param {String} pubRawRSAHex hexadecimal string of ASN.1 encoded PKCS#8 public key + * @return {Array} associative array of parsed key + * @since pkcs5pkey 1.0.5 + * @description + * Resulted associative array has following properties: + *
    + *
  • n - hexadecimal string of public key + *
  • e - hexadecimal string of public exponent + *
+ */ + parsePublicRawRSAKeyHex: function(pubRawRSAHex) { + var _ASN1HEX = ASN1HEX; + var _getChildIdx = _ASN1HEX.getChildIdx; + var _getV = _ASN1HEX.getV; + var result = {}; + + // 1. Sequence + if (pubRawRSAHex.substr(0, 2) != "30") + throw "malformed RSA key(code:001)"; // not sequence + + var a1 = _getChildIdx(pubRawRSAHex, 0); + if (a1.length != 2) + throw "malformed RSA key(code:002)"; // not 2 items in seq + + // 2. public key "N" + if (pubRawRSAHex.substr(a1[0], 2) != "02") + throw "malformed RSA key(code:003)"; // 1st item is not integer + + result.n = _getV(pubRawRSAHex, a1[0]); + + // 3. public key "E" + if (pubRawRSAHex.substr(a1[1], 2) != "02") + throw "malformed RSA key(code:004)"; // 2nd item is not integer + + result.e = _getV(pubRawRSAHex, a1[1]); + + return result; + }, + + /** + * parse hexadecimal string of PKCS#8 RSA/EC/DSA public key + * @name parsePublicPKCS8Hex + * @memberOf KEYUTIL + * @function + * @param {String} pkcs8PubHex hexadecimal string of PKCS#8 public key + * @return {Hash} hash of key information + * @description + * Resulted hash has following attributes. + *
    + *
  • algoid - hexadecimal string of OID of asymmetric key algorithm
  • + *
  • algparam - hexadecimal string of OID of ECC curve name, parameter SEQUENCE of DSA or null
  • + *
  • key - hexadecimal string of public key
  • + *
+ */ + parsePublicPKCS8Hex: function(pkcs8PubHex) { + var _ASN1HEX = ASN1HEX; + var _getChildIdx = _ASN1HEX.getChildIdx; + var _getV = _ASN1HEX.getV; + var result = {}; + result.algparam = null; + + // 1. AlgID and Key bit string + var a1 = _getChildIdx(pkcs8PubHex, 0); + if (a1.length != 2) + throw "outer DERSequence shall have 2 elements: " + a1.length; + + // 2. AlgID + var idxAlgIdTLV = a1[0]; + if (pkcs8PubHex.substr(idxAlgIdTLV, 2) != "30") + throw "malformed PKCS8 public key(code:001)"; // AlgId not sequence + + var a2 = _getChildIdx(pkcs8PubHex, idxAlgIdTLV); + if (a2.length != 2) + throw "malformed PKCS8 public key(code:002)"; // AlgId not have two elements + + // 2.1. AlgID OID + if (pkcs8PubHex.substr(a2[0], 2) != "06") + throw "malformed PKCS8 public key(code:003)"; // AlgId.oid is not OID + + result.algoid = _getV(pkcs8PubHex, a2[0]); + + // 2.2. AlgID param + if (pkcs8PubHex.substr(a2[1], 2) == "06") { // OID for EC + result.algparam = _getV(pkcs8PubHex, a2[1]); + } else if (pkcs8PubHex.substr(a2[1], 2) == "30") { // SEQ for DSA + result.algparam = {}; + result.algparam.p = _ASN1HEX.getVbyList(pkcs8PubHex, a2[1], [0], "02"); + result.algparam.q = _ASN1HEX.getVbyList(pkcs8PubHex, a2[1], [1], "02"); + result.algparam.g = _ASN1HEX.getVbyList(pkcs8PubHex, a2[1], [2], "02"); + } + + // 3. Key + if (pkcs8PubHex.substr(a1[1], 2) != "03") + throw "malformed PKCS8 public key(code:004)"; // Key is not bit string + + result.key = _getV(pkcs8PubHex, a1[1]).substr(2); + + // 4. return result assoc array + return result; + }, + }; +}(); + +// -- MAJOR PUBLIC METHODS ------------------------------------------------------- +/** + * get private or public key object from any arguments + * @name getKey + * @memberOf KEYUTIL + * @function + * @static + * @param {Object} param parameter to get key object. see description in detail. + * @param {String} passcode (OPTION) parameter to get key object. see description in detail. + * @param {String} hextype (OPTOIN) parameter to get key object. see description in detail. + * @return {Object} {@link RSAKey}, {@link KJUR.crypto.ECDSA} or {@link KJUR.crypto.ECDSA} object + * @since keyutil 1.0.0 + * @description + * This method gets private or public key object({@link RSAKey}, {@link KJUR.crypto.DSA} or {@link KJUR.crypto.ECDSA}) + * for RSA, DSA and ECC. + * Arguments for this methods depends on a key format you specify. + * Following key representations are supported. + *
    + *
  • ECC private/public key object(as is): param=KJUR.crypto.ECDSA
  • + *
  • DSA private/public key object(as is): param=KJUR.crypto.DSA
  • + *
  • RSA private/public key object(as is): param=RSAKey
  • + *
  • ECC private key parameters: param={d: d, curve: curveName}
  • + *
  • RSA private key parameters: param={n: n, e: e, d: d, p: p, q: q, dp: dp, dq: dq, co: co}
    + * NOTE: Each value shall be hexadecimal string of key spec.
  • + *
  • DSA private key parameters: param={p: p, q: q, g: g, y: y, x: x}
    + * NOTE: Each value shall be hexadecimal string of key spec.
  • + *
  • ECC public key parameters: param={xy: xy, curve: curveName}
    + * NOTE: ECC public key 'xy' shall be concatination of "04", x-bytes-hex and y-bytes-hex.
  • + *
  • DSA public key parameters: param={p: p, q: q, g: g, y: y}
    + * NOTE: Each value shall be hexadecimal string of key spec.
  • + *
  • RSA public key parameters: param={n: n, e: e}
  • + *
  • X.509v1/v3 PEM certificate (RSA/DSA/ECC): param=pemString
  • + *
  • PKCS#8 hexadecimal RSA/ECC public key: param=pemString, null, "pkcs8pub"
  • + *
  • PKCS#8 PEM RSA/DSA/ECC public key: param=pemString
  • + *
  • PKCS#5 plain hexadecimal RSA private key: param=hexString, null, "pkcs5prv"
  • + *
  • PKCS#5 plain PEM DSA/RSA private key: param=pemString
  • + *
  • PKCS#8 plain PEM RSA/ECDSA private key: param=pemString
  • + *
  • PKCS#5 encrypted PEM RSA/DSA private key: param=pemString, passcode
  • + *
  • PKCS#8 encrypted PEM RSA/ECDSA private key: param=pemString, passcode
  • + *
+ * Please note following limitation on encrypted keys: + *
    + *
  • Encrypted PKCS#8 only supports PBKDF2/HmacSHA1/3DES
  • + *
  • Encrypted PKCS#5 supports DES-CBC, DES-EDE3-CBC, AES-{128,192.256}-CBC
  • + *
  • JWT plain ECC private/public key
  • + *
  • JWT plain RSA public key
  • + *
  • JWT plain RSA private key with P/Q/DP/DQ/COEFF
  • + *
  • JWT plain RSA private key without P/Q/DP/DQ/COEFF (since jsrsasign 5.0.0)
  • + *
+ * NOTE1: RFC 7517 JSON Web Key(JWK) support for RSA/ECC private/public key from jsrsasign 4.8.1.
+ * NOTE2: X509v1 support is added since jsrsasign 5.0.11. + * + *
EXAMPLE
+ * @example + * // 1. loading private key from PEM string + * keyObj = KEYUTIL.getKey("-----BEGIN RSA PRIVATE KEY..."); + * keyObj = KEYUTIL.getKey("-----BEGIN RSA PRIVATE KEY..., "passcode"); + * keyObj = KEYUTIL.getKey("-----BEGIN PRIVATE KEY..."); + * keyObj = KEYUTIL.getKey("-----BEGIN PRIVATE KEY...", "passcode"); + * // 2. loading public key from PEM string + * keyObj = KEYUTIL.getKey("-----BEGIN PUBLIC KEY..."); + * keyObj = KEYUTIL.getKey("-----BEGIN X509 CERTIFICATE..."); + * // 3. loading hexadecimal PKCS#5/PKCS#8 key + * keyObj = KEYUTIL.getKey("308205c1...", null, "pkcs8pub"); + * keyObj = KEYUTIL.getKey("3082048b...", null, "pkcs5prv"); + * // 4. loading JSON Web Key(JWK) + * keyObj = KEYUTIL.getKey({kty: "RSA", n: "0vx7...", e: "AQAB"}); + * keyObj = KEYUTIL.getKey({kty: "EC", crv: "P-256", + * x: "MKBC...", y: "4Etl6...", d: "870Mb..."}); + * // 5. bare hexadecimal key + * keyObj = KEYUTIL.getKey({n: "75ab..", e: "010001"}); + */ +KEYUTIL.getKey = function(param, passcode, hextype) { + var _ASN1HEX = ASN1HEX, + _getChildIdx = _ASN1HEX.getChildIdx, + _getV = _ASN1HEX.getV, + _getVbyList = _ASN1HEX.getVbyList, + _KJUR_crypto = KJUR.crypto, + _KJUR_crypto_ECDSA = _KJUR_crypto.ECDSA, + _KJUR_crypto_DSA = _KJUR_crypto.DSA, + _RSAKey = RSAKey, + _pemtohex = pemtohex, + _KEYUTIL = KEYUTIL; + + // 1. by key RSAKey/KJUR.crypto.ECDSA/KJUR.crypto.DSA object + if (typeof _RSAKey != 'undefined' && param instanceof _RSAKey) + return param; + if (typeof _KJUR_crypto_ECDSA != 'undefined' && param instanceof _KJUR_crypto_ECDSA) + return param; + if (typeof _KJUR_crypto_DSA != 'undefined' && param instanceof _KJUR_crypto_DSA) + return param; + + // 2. by parameters of key + + // 2.1. bare ECC + // 2.1.1. bare ECC public key by hex values + if (param.curve !== undefined && + param.xy !== undefined && param.d === undefined) { + return new _KJUR_crypto_ECDSA({pub: param.xy, curve: param.curve}); + } + + // 2.1.2. bare ECC private key by hex values + if (param.curve !== undefined && param.d !== undefined) { + return new _KJUR_crypto_ECDSA({prv: param.d, curve: param.curve}); + } + + // 2.2. bare RSA + // 2.2.1. bare RSA public key by hex values + if (param.kty === undefined && + param.n !== undefined && param.e !== undefined && + param.d === undefined) { + var key = new _RSAKey(); + key.setPublic(param.n, param.e); + return key; + } + + // 2.2.2. bare RSA private key with P/Q/DP/DQ/COEFF by hex values + if (param.kty === undefined && + param.n !== undefined && + param.e !== undefined && + param.d !== undefined && + param.p !== undefined && + param.q !== undefined && + param.dp !== undefined && + param.dq !== undefined && + param.co !== undefined && + param.qi === undefined) { + var key = new _RSAKey(); + key.setPrivateEx(param.n, param.e, param.d, param.p, param.q, + param.dp, param.dq, param.co); + return key; + } + + // 2.2.3. bare RSA public key without P/Q/DP/DQ/COEFF by hex values + if (param.kty === undefined && + param.n !== undefined && + param.e !== undefined && + param.d !== undefined && + param.p === undefined) { + var key = new _RSAKey(); + key.setPrivate(param.n, param.e, param.d); + return key; + } + + // 2.3. bare DSA + // 2.3.1. bare DSA public key by hex values + if (param.p !== undefined && param.q !== undefined && + param.g !== undefined && + param.y !== undefined && param.x === undefined) { + var key = new _KJUR_crypto_DSA(); + key.setPublic(param.p, param.q, param.g, param.y); + return key; + } + + // 2.3.2. bare DSA private key by hex values + if (param.p !== undefined && param.q !== undefined && + param.g !== undefined && + param.y !== undefined && param.x !== undefined) { + var key = new _KJUR_crypto_DSA(); + key.setPrivate(param.p, param.q, param.g, param.y, param.x); + return key; + } + + // 3. JWK + // 3.1. JWK RSA + // 3.1.1. JWK RSA public key by b64u values + if (param.kty === "RSA" && + param.n !== undefined && + param.e !== undefined && + param.d === undefined) { + var key = new _RSAKey(); + key.setPublic(b64utohex(param.n), b64utohex(param.e)); + return key; + } + + // 3.1.2. JWK RSA private key with p/q/dp/dq/coeff by b64u values + if (param.kty === "RSA" && + param.n !== undefined && + param.e !== undefined && + param.d !== undefined && + param.p !== undefined && + param.q !== undefined && + param.dp !== undefined && + param.dq !== undefined && + param.qi !== undefined) { + var key = new _RSAKey(); + key.setPrivateEx(b64utohex(param.n), + b64utohex(param.e), + b64utohex(param.d), + b64utohex(param.p), + b64utohex(param.q), + b64utohex(param.dp), + b64utohex(param.dq), + b64utohex(param.qi)); + return key; + } + + // 3.1.3. JWK RSA private key without p/q/dp/dq/coeff by b64u + // since jsrsasign 5.0.0 keyutil 1.0.11 + if (param.kty === "RSA" && + param.n !== undefined && + param.e !== undefined && + param.d !== undefined) { + var key = new _RSAKey(); + key.setPrivate(b64utohex(param.n), + b64utohex(param.e), + b64utohex(param.d)); + return key; + } + + // 3.2. JWK ECC + // 3.2.1. JWK ECC public key by b64u values + if (param.kty === "EC" && + param.crv !== undefined && + param.x !== undefined && + param.y !== undefined && + param.d === undefined) { + var ec = new _KJUR_crypto_ECDSA({"curve": param.crv}); + var charlen = ec.ecparams.keylen / 4; + var hX = ("0000000000" + b64utohex(param.x)).slice(- charlen); + var hY = ("0000000000" + b64utohex(param.y)).slice(- charlen); + var hPub = "04" + hX + hY; + ec.setPublicKeyHex(hPub); + return ec; + } + + // 3.2.2. JWK ECC private key by b64u values + if (param.kty === "EC" && + param.crv !== undefined && + param.x !== undefined && + param.y !== undefined && + param.d !== undefined) { + var ec = new _KJUR_crypto_ECDSA({"curve": param.crv}); + var charlen = ec.ecparams.keylen / 4; + var hX = ("0000000000" + b64utohex(param.x)).slice(- charlen); + var hY = ("0000000000" + b64utohex(param.y)).slice(- charlen); + var hPub = "04" + hX + hY; + var hPrv = ("0000000000" + b64utohex(param.d)).slice(- charlen); + ec.setPublicKeyHex(hPub); + ec.setPrivateKeyHex(hPrv); + return ec; + } + + // 4. (plain) hexadecimal data + // 4.1. get private key by PKCS#5 plain RSA/DSA/ECDSA hexadecimal string + if (hextype === "pkcs5prv") { + var h = param, _ASN1HEX = ASN1HEX, a, key; + a = _getChildIdx(h, 0); + if (a.length === 9) { // RSA (INT x 9) + key = new _RSAKey(); + key.readPKCS5PrvKeyHex(h); + } else if (a.length === 6) { // DSA (INT x 6) + key = new _KJUR_crypto_DSA(); + key.readPKCS5PrvKeyHex(h); + } else if (a.length > 2 && // ECDSA (INT, OCT prv, [0] curve, [1] pub) + h.substr(a[1], 2) === "04") { + key = new _KJUR_crypto_ECDSA(); + key.readPKCS5PrvKeyHex(h); + } else { + throw "unsupported PKCS#1/5 hexadecimal key"; + } + + return key; + } + + // 4.2. get private key by PKCS#8 plain RSA/DSA/ECDSA hexadecimal string + if (hextype === "pkcs8prv") { + var key = _KEYUTIL.getKeyFromPlainPrivatePKCS8Hex(param); + return key; + } + + // 4.3. get public key by PKCS#8 RSA/DSA/ECDSA hexadecimal string + if (hextype === "pkcs8pub") { + return _KEYUTIL._getKeyFromPublicPKCS8Hex(param); + } + + // 4.4. get public key by X.509 hexadecimal string for RSA/DSA/ECDSA + if (hextype === "x509pub") { + return X509.getPublicKeyFromCertHex(param); + } + + // 5. by PEM certificate (-----BEGIN ... CERTIFICATE----) + if (param.indexOf("-END CERTIFICATE-", 0) != -1 || + param.indexOf("-END X509 CERTIFICATE-", 0) != -1 || + param.indexOf("-END TRUSTED CERTIFICATE-", 0) != -1) { + return X509.getPublicKeyFromCertPEM(param); + } + + // 6. public key by PKCS#8 PEM string + if (param.indexOf("-END PUBLIC KEY-") != -1) { + var pubKeyHex = pemtohex(param, "PUBLIC KEY"); + return _KEYUTIL._getKeyFromPublicPKCS8Hex(pubKeyHex); + } + + // 8.1 private key by plain PKCS#5 PEM RSA string + // getKey("-----BEGIN RSA PRIVATE KEY-...") + if (param.indexOf("-END RSA PRIVATE KEY-") != -1 && + param.indexOf("4,ENCRYPTED") == -1) { + var hex = _pemtohex(param, "RSA PRIVATE KEY"); + return _KEYUTIL.getKey(hex, null, "pkcs5prv"); + } + + // 8.2. private key by plain PKCS#5 PEM DSA string + if (param.indexOf("-END DSA PRIVATE KEY-") != -1 && + param.indexOf("4,ENCRYPTED") == -1) { + + var hKey = _pemtohex(param, "DSA PRIVATE KEY"); + var p = _getVbyList(hKey, 0, [1], "02"); + var q = _getVbyList(hKey, 0, [2], "02"); + var g = _getVbyList(hKey, 0, [3], "02"); + var y = _getVbyList(hKey, 0, [4], "02"); + var x = _getVbyList(hKey, 0, [5], "02"); + var key = new _KJUR_crypto_DSA(); + key.setPrivate(new BigInteger(p, 16), + new BigInteger(q, 16), + new BigInteger(g, 16), + new BigInteger(y, 16), + new BigInteger(x, 16)); + return key; + } + + // 10. private key by plain PKCS#8 PEM ECC/RSA string + if (param.indexOf("-END PRIVATE KEY-") != -1) { + return _KEYUTIL.getKeyFromPlainPrivatePKCS8PEM(param); + } + + // 11.1 private key by encrypted PKCS#5 PEM RSA string + if (param.indexOf("-END RSA PRIVATE KEY-") != -1 && + param.indexOf("4,ENCRYPTED") != -1) { + var hPKey = _KEYUTIL.getDecryptedKeyHex(param, passcode); + var rsaKey = new RSAKey(); + rsaKey.readPKCS5PrvKeyHex(hPKey); + return rsaKey; + } + + // 11.2. private key by encrypted PKCS#5 PEM ECDSA string + if (param.indexOf("-END EC PRIVATE KEY-") != -1 && + param.indexOf("4,ENCRYPTED") != -1) { + var hKey = _KEYUTIL.getDecryptedKeyHex(param, passcode); + + var key = _getVbyList(hKey, 0, [1], "04"); + var curveNameOidHex = _getVbyList(hKey, 0, [2,0], "06"); + var pubkey = _getVbyList(hKey, 0, [3,0], "03").substr(2); + var curveName = ""; + + if (KJUR.crypto.OID.oidhex2name[curveNameOidHex] !== undefined) { + curveName = KJUR.crypto.OID.oidhex2name[curveNameOidHex]; + } else { + throw "undefined OID(hex) in KJUR.crypto.OID: " + curveNameOidHex; + } + + var ec = new _KJUR_crypto_ECDSA({'curve': curveName}); + ec.setPublicKeyHex(pubkey); + ec.setPrivateKeyHex(key); + ec.isPublic = false; + return ec; + } + + // 11.3. private key by encrypted PKCS#5 PEM DSA string + if (param.indexOf("-END DSA PRIVATE KEY-") != -1 && + param.indexOf("4,ENCRYPTED") != -1) { + var hKey = _KEYUTIL.getDecryptedKeyHex(param, passcode); + var p = _getVbyList(hKey, 0, [1], "02"); + var q = _getVbyList(hKey, 0, [2], "02"); + var g = _getVbyList(hKey, 0, [3], "02"); + var y = _getVbyList(hKey, 0, [4], "02"); + var x = _getVbyList(hKey, 0, [5], "02"); + var key = new _KJUR_crypto_DSA(); + key.setPrivate(new BigInteger(p, 16), + new BigInteger(q, 16), + new BigInteger(g, 16), + new BigInteger(y, 16), + new BigInteger(x, 16)); + return key; + } + + // 11. private key by encrypted PKCS#8 hexadecimal RSA/ECDSA string + if (param.indexOf("-END ENCRYPTED PRIVATE KEY-") != -1) { + return _KEYUTIL.getKeyFromEncryptedPKCS8PEM(param, passcode); + } + + throw "not supported argument"; +}; + +/** + * @name generateKeypair + * @memberOf KEYUTIL + * @function + * @static + * @param {String} alg 'RSA' or 'EC' + * @param {Object} keylenOrCurve key length for RSA or curve name for EC + * @return {Array} associative array of keypair which has prvKeyObj and pubKeyObj parameters + * @since keyutil 1.0.1 + * @description + * This method generates a key pair of public key algorithm. + * The result will be an associative array which has following + * parameters: + *
    + *
  • prvKeyObj - RSAKey or ECDSA object of private key
  • + *
  • pubKeyObj - RSAKey or ECDSA object of public key
  • + *
+ * NOTE1: As for RSA algoirthm, public exponent has fixed + * value '0x10001'. + * NOTE2: As for EC algorithm, supported names of curve are + * secp256r1, secp256k1 and secp384r1. + * NOTE3: DSA is not supported yet. + * @example + * var rsaKeypair = KEYUTIL.generateKeypair("RSA", 1024); + * var ecKeypair = KEYUTIL.generateKeypair("EC", "secp256r1"); + * + */ +KEYUTIL.generateKeypair = function(alg, keylenOrCurve) { + if (alg == "RSA") { + var keylen = keylenOrCurve; + var prvKey = new RSAKey(); + prvKey.generate(keylen, '10001'); + prvKey.isPrivate = true; + prvKey.isPublic = true; + + var pubKey = new RSAKey(); + var hN = prvKey.n.toString(16); + var hE = prvKey.e.toString(16); + pubKey.setPublic(hN, hE); + pubKey.isPrivate = false; + pubKey.isPublic = true; + + var result = {}; + result.prvKeyObj = prvKey; + result.pubKeyObj = pubKey; + return result; + } else if (alg == "EC") { + var curve = keylenOrCurve; + var ec = new KJUR.crypto.ECDSA({curve: curve}); + var keypairHex = ec.generateKeyPairHex(); + + var prvKey = new KJUR.crypto.ECDSA({curve: curve}); + prvKey.setPublicKeyHex(keypairHex.ecpubhex); + prvKey.setPrivateKeyHex(keypairHex.ecprvhex); + prvKey.isPrivate = true; + prvKey.isPublic = false; + + var pubKey = new KJUR.crypto.ECDSA({curve: curve}); + pubKey.setPublicKeyHex(keypairHex.ecpubhex); + pubKey.isPrivate = false; + pubKey.isPublic = true; + + var result = {}; + result.prvKeyObj = prvKey; + result.pubKeyObj = pubKey; + return result; + } else { + throw "unknown algorithm: " + alg; + } +}; + +/** + * get PEM formatted private or public key file from a RSA/ECDSA/DSA key object + * @name getPEM + * @memberOf KEYUTIL + * @function + * @static + * @param {Object} keyObjOrHex key object {@link RSAKey}, {@link KJUR.crypto.ECDSA} or {@link KJUR.crypto.DSA} to encode to + * @param {String} formatType (OPTION) output format type of "PKCS1PRV", "PKCS5PRV" or "PKCS8PRV" for private key + * @param {String} passwd (OPTION) password to protect private key + * @param {String} encAlg (OPTION) encryption algorithm for PKCS#5. currently supports DES-CBC, DES-EDE3-CBC and AES-{128,192,256}-CBC + * @param {String} hexType (OPTION) type of hex string (ex. pkcs5prv, pkcs8prv) + * @param {String} ivsaltHex hexadecimal string of IV and salt (default generated random IV) + * @since keyutil 1.0.4 + * @description + *
+ *
NOTE1: + *
+ * PKCS#5 encrypted private key protection algorithm supports DES-CBC, + * DES-EDE3-CBC and AES-{128,192,256}-CBC + *
NOTE2: + *
+ * OpenSSL supports + *
NOTE3: + *
+ * Parameter "ivsaltHex" supported since jsrsasign 8.0.0 keyutil 1.2.0. + *
+ * @example + * KEUUTIL.getPEM(publicKey) => generates PEM PKCS#8 public key + * KEUUTIL.getPEM(privateKey, "PKCS1PRV") => generates PEM PKCS#1 plain private key + * KEUUTIL.getPEM(privateKey, "PKCS5PRV", "pass") => generates PEM PKCS#5 encrypted private key + * with DES-EDE3-CBC (DEFAULT) + * KEUUTIL.getPEM(privateKey, "PKCS5PRV", "pass", "DES-CBC") => generates PEM PKCS#5 encrypted + * private key with DES-CBC + * KEUUTIL.getPEM(privateKey, "PKCS8PRV") => generates PEM PKCS#8 plain private key + * KEUUTIL.getPEM(privateKey, "PKCS8PRV", "pass") => generates PEM PKCS#8 encrypted private key + * with PBKDF2_HmacSHA1_3DES + */ +KEYUTIL.getPEM = function(keyObjOrHex, formatType, passwd, encAlg, hexType, ivsaltHex) { + var _KJUR = KJUR, + _KJUR_asn1 = _KJUR.asn1, + _DERObjectIdentifier = _KJUR_asn1.DERObjectIdentifier, + _DERInteger = _KJUR_asn1.DERInteger, + _newObject = _KJUR_asn1.ASN1Util.newObject, + _KJUR_asn1_x509 = _KJUR_asn1.x509, + _SubjectPublicKeyInfo = _KJUR_asn1_x509.SubjectPublicKeyInfo, + _KJUR_crypto = _KJUR.crypto, + _DSA = _KJUR_crypto.DSA, + _ECDSA = _KJUR_crypto.ECDSA, + _RSAKey = RSAKey; + + function _rsaprv2asn1obj(keyObjOrHex) { + var asn1Obj = _newObject({ + "seq": [ + {"int": 0 }, + {"int": {"bigint": keyObjOrHex.n}}, + {"int": keyObjOrHex.e}, + {"int": {"bigint": keyObjOrHex.d}}, + {"int": {"bigint": keyObjOrHex.p}}, + {"int": {"bigint": keyObjOrHex.q}}, + {"int": {"bigint": keyObjOrHex.dmp1}}, + {"int": {"bigint": keyObjOrHex.dmq1}}, + {"int": {"bigint": keyObjOrHex.coeff}} + ] + }); + return asn1Obj; + }; + + function _ecdsaprv2asn1obj(keyObjOrHex) { + var asn1Obj2 = _newObject({ + "seq": [ + {"int": 1 }, + {"octstr": {"hex": keyObjOrHex.prvKeyHex}}, + {"tag": ['a0', true, {'oid': {'name': keyObjOrHex.curveName}}]}, + {"tag": ['a1', true, {'bitstr': {'hex': '00' + keyObjOrHex.pubKeyHex}}]} + ] + }); + return asn1Obj2; + }; + + function _dsaprv2asn1obj(keyObjOrHex) { + var asn1Obj = _newObject({ + "seq": [ + {"int": 0 }, + {"int": {"bigint": keyObjOrHex.p}}, + {"int": {"bigint": keyObjOrHex.q}}, + {"int": {"bigint": keyObjOrHex.g}}, + {"int": {"bigint": keyObjOrHex.y}}, + {"int": {"bigint": keyObjOrHex.x}} + ] + }); + return asn1Obj; + }; + + // 1. public key + + // x. PEM PKCS#8 public key of RSA/ECDSA/DSA public key object + if (((_RSAKey !== undefined && keyObjOrHex instanceof _RSAKey) || + (_DSA !== undefined && keyObjOrHex instanceof _DSA) || + (_ECDSA !== undefined && keyObjOrHex instanceof _ECDSA)) && + keyObjOrHex.isPublic == true && + (formatType === undefined || formatType == "PKCS8PUB")) { + var asn1Obj = new _SubjectPublicKeyInfo(keyObjOrHex); + var asn1Hex = asn1Obj.getEncodedHex(); + return hextopem(asn1Hex, "PUBLIC KEY"); + } + + // 2. private + + // x. PEM PKCS#1 plain private key of RSA private key object + if (formatType == "PKCS1PRV" && + _RSAKey !== undefined && + keyObjOrHex instanceof _RSAKey && + (passwd === undefined || passwd == null) && + keyObjOrHex.isPrivate == true) { + + var asn1Obj = _rsaprv2asn1obj(keyObjOrHex); + var asn1Hex = asn1Obj.getEncodedHex(); + return hextopem(asn1Hex, "RSA PRIVATE KEY"); + } + + // x. PEM PKCS#1 plain private key of ECDSA private key object + if (formatType == "PKCS1PRV" && + _ECDSA !== undefined && + keyObjOrHex instanceof _ECDSA && + (passwd === undefined || passwd == null) && + keyObjOrHex.isPrivate == true) { + + var asn1Obj1 = + new _DERObjectIdentifier({'name': keyObjOrHex.curveName}); + var asn1Hex1 = asn1Obj1.getEncodedHex(); + var asn1Obj2 = _ecdsaprv2asn1obj(keyObjOrHex); + var asn1Hex2 = asn1Obj2.getEncodedHex(); + + var s = ""; + s += hextopem(asn1Hex1, "EC PARAMETERS"); + s += hextopem(asn1Hex2, "EC PRIVATE KEY"); + return s; + } + + // x. PEM PKCS#1 plain private key of DSA private key object + if (formatType == "PKCS1PRV" && + _DSA !== undefined && + keyObjOrHex instanceof _DSA && + (passwd === undefined || passwd == null) && + keyObjOrHex.isPrivate == true) { + + var asn1Obj = _dsaprv2asn1obj(keyObjOrHex); + var asn1Hex = asn1Obj.getEncodedHex(); + return hextopem(asn1Hex, "DSA PRIVATE KEY"); + } + + // 3. private + + // x. PEM PKCS#5 encrypted private key of RSA private key object + if (formatType == "PKCS5PRV" && + _RSAKey !== undefined && + keyObjOrHex instanceof _RSAKey && + (passwd !== undefined && passwd != null) && + keyObjOrHex.isPrivate == true) { + + var asn1Obj = _rsaprv2asn1obj(keyObjOrHex); + var asn1Hex = asn1Obj.getEncodedHex(); + + if (encAlg === undefined) encAlg = "DES-EDE3-CBC"; + return this.getEncryptedPKCS5PEMFromPrvKeyHex("RSA", asn1Hex, passwd, encAlg, ivsaltHex); + } + + // x. PEM PKCS#5 encrypted private key of ECDSA private key object + if (formatType == "PKCS5PRV" && + _ECDSA !== undefined && + keyObjOrHex instanceof _ECDSA && + (passwd !== undefined && passwd != null) && + keyObjOrHex.isPrivate == true) { + + var asn1Obj = _ecdsaprv2asn1obj(keyObjOrHex); + var asn1Hex = asn1Obj.getEncodedHex(); + + if (encAlg === undefined) encAlg = "DES-EDE3-CBC"; + return this.getEncryptedPKCS5PEMFromPrvKeyHex("EC", asn1Hex, passwd, encAlg, ivsaltHex); + } + + // x. PEM PKCS#5 encrypted private key of DSA private key object + if (formatType == "PKCS5PRV" && + _DSA !== undefined && + keyObjOrHex instanceof _DSA && + (passwd !== undefined && passwd != null) && + keyObjOrHex.isPrivate == true) { + + var asn1Obj = _dsaprv2asn1obj(keyObjOrHex); + var asn1Hex = asn1Obj.getEncodedHex(); + + if (encAlg === undefined) encAlg = "DES-EDE3-CBC"; + return this.getEncryptedPKCS5PEMFromPrvKeyHex("DSA", asn1Hex, passwd, encAlg, ivsaltHex); + } + + // x. ====================================================================== + + var _getEncryptedPKCS8 = function(plainKeyHex, passcode) { + var info = _getEencryptedPKCS8Info(plainKeyHex, passcode); + //alert("iv=" + info.encryptionSchemeIV); + //alert("info.ciphertext2[" + info.ciphertext.length + "=" + info.ciphertext); + var asn1Obj = new _newObject({ + "seq": [ + {"seq": [ + {"oid": {"name": "pkcs5PBES2"}}, + {"seq": [ + {"seq": [ + {"oid": {"name": "pkcs5PBKDF2"}}, + {"seq": [ + {"octstr": {"hex": info.pbkdf2Salt}}, + {"int": info.pbkdf2Iter} + ]} + ]}, + {"seq": [ + {"oid": {"name": "des-EDE3-CBC"}}, + {"octstr": {"hex": info.encryptionSchemeIV}} + ]} + ]} + ]}, + {"octstr": {"hex": info.ciphertext}} + ] + }); + return asn1Obj.getEncodedHex(); + }; + + var _getEencryptedPKCS8Info = function(plainKeyHex, passcode) { + var pbkdf2Iter = 100; + var pbkdf2SaltWS = CryptoJS.lib.WordArray.random(8); + var encryptionSchemeAlg = "DES-EDE3-CBC"; + var encryptionSchemeIVWS = CryptoJS.lib.WordArray.random(8); + // PBKDF2 key + var pbkdf2KeyWS = CryptoJS.PBKDF2(passcode, + pbkdf2SaltWS, { "keySize": 192/32, + "iterations": pbkdf2Iter }); + // ENCRYPT + var plainKeyWS = CryptoJS.enc.Hex.parse(plainKeyHex); + var encryptedKeyHex = + CryptoJS.TripleDES.encrypt(plainKeyWS, pbkdf2KeyWS, { "iv": encryptionSchemeIVWS }) + ""; + + //alert("encryptedKeyHex=" + encryptedKeyHex); + + var info = {}; + info.ciphertext = encryptedKeyHex; + //alert("info.ciphertext=" + info.ciphertext); + info.pbkdf2Salt = CryptoJS.enc.Hex.stringify(pbkdf2SaltWS); + info.pbkdf2Iter = pbkdf2Iter; + info.encryptionSchemeAlg = encryptionSchemeAlg; + info.encryptionSchemeIV = CryptoJS.enc.Hex.stringify(encryptionSchemeIVWS); + return info; + }; + + // x. PEM PKCS#8 plain private key of RSA private key object + if (formatType == "PKCS8PRV" && + _RSAKey != undefined && + keyObjOrHex instanceof _RSAKey && + keyObjOrHex.isPrivate == true) { + + var keyObj = _rsaprv2asn1obj(keyObjOrHex); + var keyHex = keyObj.getEncodedHex(); + + var asn1Obj = _newObject({ + "seq": [ + {"int": 0}, + {"seq": [{"oid": {"name": "rsaEncryption"}},{"null": true}]}, + {"octstr": {"hex": keyHex}} + ] + }); + var asn1Hex = asn1Obj.getEncodedHex(); + + if (passwd === undefined || passwd == null) { + return hextopem(asn1Hex, "PRIVATE KEY"); + } else { + var asn1Hex2 = _getEncryptedPKCS8(asn1Hex, passwd); + return hextopem(asn1Hex2, "ENCRYPTED PRIVATE KEY"); + } + } + + // x. PEM PKCS#8 plain private key of ECDSA private key object + if (formatType == "PKCS8PRV" && + _ECDSA !== undefined && + keyObjOrHex instanceof _ECDSA && + keyObjOrHex.isPrivate == true) { + + var keyObj = new _newObject({ + "seq": [ + {"int": 1}, + {"octstr": {"hex": keyObjOrHex.prvKeyHex}}, + {"tag": ['a1', true, {"bitstr": {"hex": "00" + keyObjOrHex.pubKeyHex}}]} + ] + }); + var keyHex = keyObj.getEncodedHex(); + + var asn1Obj = _newObject({ + "seq": [ + {"int": 0}, + {"seq": [ + {"oid": {"name": "ecPublicKey"}}, + {"oid": {"name": keyObjOrHex.curveName}} + ]}, + {"octstr": {"hex": keyHex}} + ] + }); + + var asn1Hex = asn1Obj.getEncodedHex(); + if (passwd === undefined || passwd == null) { + return hextopem(asn1Hex, "PRIVATE KEY"); + } else { + var asn1Hex2 = _getEncryptedPKCS8(asn1Hex, passwd); + return hextopem(asn1Hex2, "ENCRYPTED PRIVATE KEY"); + } + } + + // x. PEM PKCS#8 plain private key of DSA private key object + if (formatType == "PKCS8PRV" && + _DSA !== undefined && + keyObjOrHex instanceof _DSA && + keyObjOrHex.isPrivate == true) { + + var keyObj = new _DERInteger({'bigint': keyObjOrHex.x}); + var keyHex = keyObj.getEncodedHex(); + + var asn1Obj = _newObject({ + "seq": [ + {"int": 0}, + {"seq": [ + {"oid": {"name": "dsa"}}, + {"seq": [ + {"int": {"bigint": keyObjOrHex.p}}, + {"int": {"bigint": keyObjOrHex.q}}, + {"int": {"bigint": keyObjOrHex.g}} + ]} + ]}, + {"octstr": {"hex": keyHex}} + ] + }); + + var asn1Hex = asn1Obj.getEncodedHex(); + if (passwd === undefined || passwd == null) { + return hextopem(asn1Hex, "PRIVATE KEY"); + } else { + var asn1Hex2 = _getEncryptedPKCS8(asn1Hex, passwd); + return hextopem(asn1Hex2, "ENCRYPTED PRIVATE KEY"); + } + } + + throw "unsupported object nor format"; +}; + +// -- PUBLIC METHODS FOR CSR -------------------------------------------------- + +/** + * get RSAKey/DSA/ECDSA public key object from PEM formatted PKCS#10 CSR string + * @name getKeyFromCSRPEM + * @memberOf KEYUTIL + * @function + * @param {String} csrPEM PEM formatted PKCS#10 CSR string + * @return {Object} RSAKey/DSA/ECDSA public key object + * @since keyutil 1.0.5 + */ +KEYUTIL.getKeyFromCSRPEM = function(csrPEM) { + var csrHex = pemtohex(csrPEM, "CERTIFICATE REQUEST"); + var key = KEYUTIL.getKeyFromCSRHex(csrHex); + return key; +}; + +/** + * get RSAKey/DSA/ECDSA public key object from hexadecimal string of PKCS#10 CSR + * @name getKeyFromCSRHex + * @memberOf KEYUTIL + * @function + * @param {String} csrHex hexadecimal string of PKCS#10 CSR + * @return {Object} RSAKey/DSA/ECDSA public key object + * @since keyutil 1.0.5 + */ +KEYUTIL.getKeyFromCSRHex = function(csrHex) { + var info = KEYUTIL.parseCSRHex(csrHex); + var key = KEYUTIL.getKey(info.p8pubkeyhex, null, "pkcs8pub"); + return key; +}; + +/** + * parse hexadecimal string of PKCS#10 CSR (certificate signing request) + * @name parseCSRHex + * @memberOf KEYUTIL + * @function + * @param {String} csrHex hexadecimal string of PKCS#10 CSR + * @return {Array} associative array of parsed CSR + * @since keyutil 1.0.5 + * @description + * Resulted associative array has following properties: + *
    + *
  • p8pubkeyhex - hexadecimal string of subject public key in PKCS#8
  • + *
+ */ +KEYUTIL.parseCSRHex = function(csrHex) { + var _ASN1HEX = ASN1HEX; + var _getChildIdx = _ASN1HEX.getChildIdx; + var _getTLV = _ASN1HEX.getTLV; + var result = {}; + var h = csrHex; + + // 1. sequence + if (h.substr(0, 2) != "30") + throw "malformed CSR(code:001)"; // not sequence + + var a1 = _getChildIdx(h, 0); + if (a1.length < 1) + throw "malformed CSR(code:002)"; // short length + + // 2. 2nd sequence + if (h.substr(a1[0], 2) != "30") + throw "malformed CSR(code:003)"; // not sequence + + var a2 = _getChildIdx(h, a1[0]); + if (a2.length < 3) + throw "malformed CSR(code:004)"; // 2nd seq short elem + + result.p8pubkeyhex = _getTLV(h, a2[2]); + + return result; +}; + +// -- OTHER STATIC PUBLIC METHODS ------------------------------------------------- + +/** + * convert from RSAKey/KJUR.crypto.ECDSA public/private key object to RFC 7517 JSON Web Key(JWK) + * @name getJWKFromKey + * @memberOf KEYUTIL + * @function + * @static + * @param {Object} RSAKey/KJUR.crypto.ECDSA public/private key object + * @return {Object} JWK object + * @since keyutil 1.0.13 jsrsasign 5.0.14 + * @description + * This static method convert from RSAKey/KJUR.crypto.ECDSA public/private key object + * to RFC 7517 JSON Web Key(JWK) + * @example + * kp1 = KEYUTIL.generateKeypair("EC", "P-256"); + * jwkPrv1 = KEYUTIL.getJWKFromKey(kp1.prvKeyObj); + * jwkPub1 = KEYUTIL.getJWKFromKey(kp1.pubKeyObj); + * + * kp2 = KEYUTIL.generateKeypair("RSA", 2048); + * jwkPrv2 = KEYUTIL.getJWKFromKey(kp2.prvKeyObj); + * jwkPub2 = KEYUTIL.getJWKFromKey(kp2.pubKeyObj); + * + * // if you need RFC 7638 JWK thumprint as kid do like this: + * jwkPub2.kid = KJUR.jws.JWS.getJWKthumbprint(jwkPub2); + */ +KEYUTIL.getJWKFromKey = function(keyObj) { + var jwk = {}; + if (keyObj instanceof RSAKey && keyObj.isPrivate) { + jwk.kty = "RSA"; + jwk.n = hextob64u(keyObj.n.toString(16)); + jwk.e = hextob64u(keyObj.e.toString(16)); + jwk.d = hextob64u(keyObj.d.toString(16)); + jwk.p = hextob64u(keyObj.p.toString(16)); + jwk.q = hextob64u(keyObj.q.toString(16)); + jwk.dp = hextob64u(keyObj.dmp1.toString(16)); + jwk.dq = hextob64u(keyObj.dmq1.toString(16)); + jwk.qi = hextob64u(keyObj.coeff.toString(16)); + return jwk; + } else if (keyObj instanceof RSAKey && keyObj.isPublic) { + jwk.kty = "RSA"; + jwk.n = hextob64u(keyObj.n.toString(16)); + jwk.e = hextob64u(keyObj.e.toString(16)); + return jwk; + } else if (keyObj instanceof KJUR.crypto.ECDSA && keyObj.isPrivate) { + var name = keyObj.getShortNISTPCurveName(); + if (name !== "P-256" && name !== "P-384") + throw "unsupported curve name for JWT: " + name; + var xy = keyObj.getPublicKeyXYHex(); + jwk.kty = "EC"; + jwk.crv = name; + jwk.x = hextob64u(xy.x); + jwk.y = hextob64u(xy.y); + jwk.d = hextob64u(keyObj.prvKeyHex); + return jwk; + } else if (keyObj instanceof KJUR.crypto.ECDSA && keyObj.isPublic) { + var name = keyObj.getShortNISTPCurveName(); + if (name !== "P-256" && name !== "P-384") + throw "unsupported curve name for JWT: " + name; + var xy = keyObj.getPublicKeyXYHex(); + jwk.kty = "EC"; + jwk.crv = name; + jwk.x = hextob64u(xy.x); + jwk.y = hextob64u(xy.y); + return jwk; + } + throw "not supported key object"; +}; + + diff --git a/source/pack.js b/source/pack.js new file mode 100644 index 0000000..70e3b09 --- /dev/null +++ b/source/pack.js @@ -0,0 +1,384 @@ +module.exports = function pack (format) { + // discuss at: http://locutus.io/php/pack/ + // original by: Tim de Koning (http://www.kingsquare.nl) + // parts by: Jonas Raoni Soares Silva (http://www.jsfromhell.com) + // bugfixed by: Tim de Koning (http://www.kingsquare.nl) + // note 1: Float encoding by: Jonas Raoni Soares Silva + // note 1: Home: http://www.kingsquare.nl/blog/12-12-2009/13507444 + // note 1: Feedback: phpjs-pack@kingsquare.nl + // note 1: "machine dependent byte order and size" aren't + // note 1: applicable for JavaScript; pack works as on a 32bit, + // note 1: little endian machine. + // example 1: pack('nvc*', 0x1234, 0x5678, 65, 66) + // returns 1: '\u00124xVAB' + // example 2: pack('H4', '2345') + // returns 2: '#E' + // example 3: pack('H*', 'D5') + // returns 3: 'Õ' + // example 4: pack('d', -100.876) + // returns 4: "\u0000\u0000\u0000\u0000\u00008YÀ" + // test: skip-1 + + var formatPointer = 0 + var argumentPointer = 1 + var result = '' + var argument = '' + var i = 0 + var r = [] + var instruction, quantifier, word, precisionBits, exponentBits, extraNullCount + + // vars used by float encoding + var bias + var minExp + var maxExp + var minUnnormExp + var status + var exp + var len + var bin + var signal + var n + var intPart + var floatPart + var lastBit + var rounded + var j + var k + var tmpResult + + while (formatPointer < format.length) { + instruction = format.charAt(formatPointer) + quantifier = '' + formatPointer++ + while ((formatPointer < format.length) && (format.charAt(formatPointer) + .match(/[\d*]/) !== null)) { + quantifier += format.charAt(formatPointer) + formatPointer++ + } + if (quantifier === '') { + quantifier = '1' + } + + // Now pack variables: 'quantifier' times 'instruction' + switch (instruction) { + case 'a': + case 'A': + // NUL-padded string + // SPACE-padded string + if (typeof arguments[argumentPointer] === 'undefined') { + throw new Error('Warning: pack() Type ' + instruction + ': not enough arguments') + } else { + argument = String(arguments[argumentPointer]) + } + if (quantifier === '*') { + quantifier = argument.length + } + for (i = 0; i < quantifier; i++) { + if (typeof argument[i] === 'undefined') { + if (instruction === 'a') { + result += String.fromCharCode(0) + } else { + result += ' ' + } + } else { + result += argument[i] + } + } + argumentPointer++ + break + case 'h': + case 'H': + // Hex string, low nibble first + // Hex string, high nibble first + if (typeof arguments[argumentPointer] === 'undefined') { + throw new Error('Warning: pack() Type ' + instruction + ': not enough arguments') + } else { + argument = arguments[argumentPointer] + } + if (quantifier === '*') { + quantifier = argument.length + } + if (quantifier > argument.length) { + var msg = 'Warning: pack() Type ' + instruction + ': not enough characters in string' + throw new Error(msg) + } + + for (i = 0; i < quantifier; i += 2) { + // Always get per 2 bytes... + word = argument[i] + if (((i + 1) >= quantifier) || typeof argument[i + 1] === 'undefined') { + word += '0' + } else { + word += argument[i + 1] + } + // The fastest way to reverse? + if (instruction === 'h') { + word = word[1] + word[0] + } + result += String.fromCharCode(parseInt(word, 16)) + } + argumentPointer++ + break + + case 'c': + case 'C': + // signed char + // unsigned char + // c and C is the same in pack + if (quantifier === '*') { + quantifier = arguments.length - argumentPointer + } + if (quantifier > (arguments.length - argumentPointer)) { + throw new Error('Warning: pack() Type ' + instruction + ': too few arguments') + } + + for (i = 0; i < quantifier; i++) { + result += String.fromCharCode(arguments[argumentPointer]) + argumentPointer++ + } + break + + case 's': + case 'S': + case 'v': + // signed short (always 16 bit, machine byte order) + // unsigned short (always 16 bit, machine byte order) + // s and S is the same in pack + if (quantifier === '*') { + quantifier = arguments.length - argumentPointer + } + if (quantifier > (arguments.length - argumentPointer)) { + throw new Error('Warning: pack() Type ' + instruction + ': too few arguments') + } + + for (i = 0; i < quantifier; i++) { + result += String.fromCharCode(arguments[argumentPointer] & 0xFF) + result += String.fromCharCode(arguments[argumentPointer] >> 8 & 0xFF) + argumentPointer++ + } + break + + case 'n': + // unsigned short (always 16 bit, big endian byte order) + if (quantifier === '*') { + quantifier = arguments.length - argumentPointer + } + if (quantifier > (arguments.length - argumentPointer)) { + throw new Error('Warning: pack() Type ' + instruction + ': too few arguments') + } + + for (i = 0; i < quantifier; i++) { + result += String.fromCharCode(arguments[argumentPointer] >> 8 & 0xFF) + result += String.fromCharCode(arguments[argumentPointer] & 0xFF) + argumentPointer++ + } + break + + case 'i': + case 'I': + case 'l': + case 'L': + case 'V': + // signed integer (machine dependent size and byte order) + // unsigned integer (machine dependent size and byte order) + // signed long (always 32 bit, machine byte order) + // unsigned long (always 32 bit, machine byte order) + // unsigned long (always 32 bit, little endian byte order) + if (quantifier === '*') { + quantifier = arguments.length - argumentPointer + } + if (quantifier > (arguments.length - argumentPointer)) { + throw new Error('Warning: pack() Type ' + instruction + ': too few arguments') + } + + for (i = 0; i < quantifier; i++) { + result += String.fromCharCode(arguments[argumentPointer] & 0xFF) + result += String.fromCharCode(arguments[argumentPointer] >> 8 & 0xFF) + result += String.fromCharCode(arguments[argumentPointer] >> 16 & 0xFF) + result += String.fromCharCode(arguments[argumentPointer] >> 24 & 0xFF) + argumentPointer++ + } + + break + case 'N': + // unsigned long (always 32 bit, big endian byte order) + if (quantifier === '*') { + quantifier = arguments.length - argumentPointer + } + if (quantifier > (arguments.length - argumentPointer)) { + throw new Error('Warning: pack() Type ' + instruction + ': too few arguments') + } + + for (i = 0; i < quantifier; i++) { + result += String.fromCharCode(arguments[argumentPointer] >> 24 & 0xFF) + result += String.fromCharCode(arguments[argumentPointer] >> 16 & 0xFF) + result += String.fromCharCode(arguments[argumentPointer] >> 8 & 0xFF) + result += String.fromCharCode(arguments[argumentPointer] & 0xFF) + argumentPointer++ + } + break + + case 'f': + case 'd': + // float (machine dependent size and representation) + // double (machine dependent size and representation) + // version based on IEEE754 + precisionBits = 23 + exponentBits = 8 + if (instruction === 'd') { + precisionBits = 52 + exponentBits = 11 + } + + if (quantifier === '*') { + quantifier = arguments.length - argumentPointer + } + if (quantifier > (arguments.length - argumentPointer)) { + throw new Error('Warning: pack() Type ' + instruction + ': too few arguments') + } + for (i = 0; i < quantifier; i++) { + argument = arguments[argumentPointer] + bias = Math.pow(2, exponentBits - 1) - 1 + minExp = -bias + 1 + maxExp = bias + minUnnormExp = minExp - precisionBits + status = isNaN(n = parseFloat(argument)) || n === -Infinity || n === +Infinity ? n : 0 + exp = 0 + len = 2 * bias + 1 + precisionBits + 3 + bin = new Array(len) + signal = (n = status !== 0 ? 0 : n) < 0 + n = Math.abs(n) + intPart = Math.floor(n) + floatPart = n - intPart + + for (k = len; k;) { + bin[--k] = 0 + } + for (k = bias + 2; intPart && k;) { + bin[--k] = intPart % 2 + intPart = Math.floor(intPart / 2) + } + for (k = bias + 1; floatPart > 0 && k; --floatPart) { + (bin[++k] = ((floatPart *= 2) >= 1) - 0) + } + for (k = -1; ++k < len && !bin[k];) {} + + // @todo: Make this more readable: + var key = (lastBit = precisionBits - 1 + + (k = + (exp = bias + 1 - k) >= minExp && + exp <= maxExp ? k + 1 : bias + 1 - (exp = minExp - 1))) + 1 + + if (bin[key]) { + if (!(rounded = bin[lastBit])) { + for (j = lastBit + 2; !rounded && j < len; rounded = bin[j++]) {} + } + for (j = lastBit + 1; rounded && --j >= 0; + (bin[j] = !bin[j] - 0) && (rounded = 0)) {} + } + + for (k = k - 2 < 0 ? -1 : k - 3; ++k < len && !bin[k];) {} + + if ((exp = bias + 1 - k) >= minExp && exp <= maxExp) { + ++k + } else { + if (exp < minExp) { + if (exp !== bias + 1 - len && exp < minUnnormExp) { + // "encodeFloat::float underflow" + } + k = bias + 1 - (exp = minExp - 1) + } + } + + if (intPart || status !== 0) { + exp = maxExp + 1 + k = bias + 2 + if (status === -Infinity) { + signal = 1 + } else if (isNaN(status)) { + bin[k] = 1 + } + } + + n = Math.abs(exp + bias) + tmpResult = '' + + for (j = exponentBits + 1; --j;) { + tmpResult = (n % 2) + tmpResult + n = n >>= 1 + } + + n = 0 + j = 0 + k = (tmpResult = (signal ? '1' : '0') + tmpResult + (bin + .slice(k, k + precisionBits) + .join('')) + ).length + r = [] + + for (; k;) { + n += (1 << j) * tmpResult.charAt(--k) + if (j === 7) { + r[r.length] = String.fromCharCode(n) + n = 0 + } + j = (j + 1) % 8 + } + + r[r.length] = n ? String.fromCharCode(n) : '' + result += r.join('') + argumentPointer++ + } + break + + case 'x': + // NUL byte + if (quantifier === '*') { + throw new Error('Warning: pack(): Type x: \'*\' ignored') + } + for (i = 0; i < quantifier; i++) { + result += String.fromCharCode(0) + } + break + + case 'X': + // Back up one byte + if (quantifier === '*') { + throw new Error('Warning: pack(): Type X: \'*\' ignored') + } + for (i = 0; i < quantifier; i++) { + if (result.length === 0) { + throw new Error('Warning: pack(): Type X:' + ' outside of string') + } else { + result = result.substring(0, result.length - 1) + } + } + break + + case '@': + // NUL-fill to absolute position + if (quantifier === '*') { + throw new Error('Warning: pack(): Type X: \'*\' ignored') + } + if (quantifier > result.length) { + extraNullCount = quantifier - result.length + for (i = 0; i < extraNullCount; i++) { + result += String.fromCharCode(0) + } + } + if (quantifier < result.length) { + result = result.substring(0, quantifier) + } + break + + default: + throw new Error('Warning: pack() Type ' + instruction + ': unknown format code') + } + } + if (argumentPointer < arguments.length) { + var msg2 = 'Warning: pack(): ' + (arguments.length - argumentPointer) + ' arguments unused' + throw new Error(msg2) + } + + return result +} diff --git a/source/prng4.js b/source/prng4.js new file mode 100644 index 0000000..9c4fd68 --- /dev/null +++ b/source/prng4.js @@ -0,0 +1,47 @@ +/*! (c) Tom Wu | http://www-cs-students.stanford.edu/~tjw/jsbn/ + */ +// prng4.js - uses Arcfour as a PRNG + +function Arcfour() { + this.i = 0; + this.j = 0; + this.S = new Array(); +} + +// Initialize arcfour context from key, an array of ints, each from [0..255] +function ARC4init(key) { + var i, j, t; + for(i = 0; i < 256; ++i) + this.S[i] = i; + j = 0; + for(i = 0; i < 256; ++i) { + j = (j + this.S[i] + key[i % key.length]) & 255; + t = this.S[i]; + this.S[i] = this.S[j]; + this.S[j] = t; + } + this.i = 0; + this.j = 0; +} + +function ARC4next() { + var t; + this.i = (this.i + 1) & 255; + this.j = (this.j + this.S[this.i]) & 255; + t = this.S[this.i]; + this.S[this.i] = this.S[this.j]; + this.S[this.j] = t; + return this.S[(t + this.S[this.i]) & 255]; +} + +Arcfour.prototype.init = ARC4init; +Arcfour.prototype.next = ARC4next; + +// Plug in your RNG constructor here +function prng_newstate() { + return new Arcfour(); +} + +// Pool size must be a multiple of 4 and greater than 32. +// An array of bytes the size of the pool will be passed to init() +var rng_psize = 256; diff --git a/source/rng.js b/source/rng.js new file mode 100644 index 0000000..d7b3848 --- /dev/null +++ b/source/rng.js @@ -0,0 +1,81 @@ +/*! (c) Tom Wu | http://www-cs-students.stanford.edu/~tjw/jsbn/ + */ +// Random number generator - requires a PRNG backend, e.g. prng4.js + +// For best results, put code like +// +// in your main HTML document. + +var rng_state; +var rng_pool; +var rng_pptr; + +// Mix in a 32-bit integer into the pool +function rng_seed_int(x) { + rng_pool[rng_pptr++] ^= x & 255; + rng_pool[rng_pptr++] ^= (x >> 8) & 255; + rng_pool[rng_pptr++] ^= (x >> 16) & 255; + rng_pool[rng_pptr++] ^= (x >> 24) & 255; + if(rng_pptr >= rng_psize) rng_pptr -= rng_psize; +} + +// Mix in the current time (w/milliseconds) into the pool +function rng_seed_time() { + rng_seed_int(new Date().getTime()); +} + +// Initialize the pool with junk if needed. +if (rng_pool == null) { + rng_pool = new Array(); + rng_pptr = 0; + var t; + if (window !== undefined && + (window.crypto !== undefined || + window.msCrypto !== undefined)) { + var crypto = window.crypto || window.msCrypto; + if (crypto.getRandomValues) { + // Use webcrypto if available + var ua = new Uint8Array(32); + crypto.getRandomValues(ua); + for(t = 0; t < 32; ++t) + rng_pool[rng_pptr++] = ua[t]; + } else if (navigator.appName == "Netscape" && navigator.appVersion < "5") { + // Extract entropy (256 bits) from NS4 RNG if available + var z = window.crypto.random(32); + for(t = 0; t < z.length; ++t) + rng_pool[rng_pptr++] = z.charCodeAt(t) & 255; + } + } + while (rng_pptr < rng_psize) { // extract some randomness from Math.random() + t = Math.floor(65536 * Math.random()); + rng_pool[rng_pptr++] = t >>> 8; + rng_pool[rng_pptr++] = t & 255; + } + rng_pptr = 0; + rng_seed_time(); + //rng_seed_int(window.screenX); + //rng_seed_int(window.screenY); +} + +function rng_get_byte() { + if (rng_state == null) { + rng_seed_time(); + rng_state = prng_newstate(); + rng_state.init(rng_pool); + for(rng_pptr = 0; rng_pptr < rng_pool.length; ++rng_pptr) + rng_pool[rng_pptr] = 0; + rng_pptr = 0; + //rng_pool = null; + } + // TODO: allow reseeding after first request + return rng_state.next(); +} + +function rng_get_bytes(ba) { + var i; + for (i = 0; i < ba.length; ++i) ba[i] = rng_get_byte(); +} + +function SecureRandom() {} + +SecureRandom.prototype.nextBytes = rng_get_bytes; diff --git a/source/rsa.js b/source/rsa.js new file mode 100644 index 0000000..b27c421 --- /dev/null +++ b/source/rsa.js @@ -0,0 +1,212 @@ +/*! (c) Tom Wu | http://www-cs-students.stanford.edu/~tjw/jsbn/ + */ +// Depends on jsbn.js and rng.js + +// Version 1.1: support utf-8 encoding in pkcs1pad2 + +// convert a (hex) string to a bignum object +function parseBigInt(str,r) { + return new BigInteger(str,r); +} + +function linebrk(s,n) { + var ret = ""; + var i = 0; + while(i + n < s.length) { + ret += s.substring(i,i+n) + "\n"; + i += n; + } + return ret + s.substring(i,s.length); +} + +function byte2Hex(b) { + if(b < 0x10) + return "0" + b.toString(16); + else + return b.toString(16); +} + +// PKCS#1 (type 2, random) pad input string s to n bytes, and return a bigint +function pkcs1pad2(s,n) { + if(n < s.length + 11) { // TODO: fix for utf-8 + throw "Message too long for RSA"; + return null; + } + var ba = new Array(); + var i = s.length - 1; + while(i >= 0 && n > 0) { + var c = s.charCodeAt(i--); + if(c < 128) { // encode using utf-8 + ba[--n] = c; + } + else if((c > 127) && (c < 2048)) { + ba[--n] = (c & 63) | 128; + ba[--n] = (c >> 6) | 192; + } + else { + ba[--n] = (c & 63) | 128; + ba[--n] = ((c >> 6) & 63) | 128; + ba[--n] = (c >> 12) | 224; + } + } + ba[--n] = 0; + var rng = new SecureRandom(); + var x = new Array(); + while(n > 2) { // random non-zero pad + x[0] = 0; + while(x[0] == 0) rng.nextBytes(x); + ba[--n] = x[0]; + } + ba[--n] = 2; + ba[--n] = 0; + return new BigInteger(ba); +} + +// PKCS#1 (OAEP) mask generation function +function oaep_mgf1_arr(seed, len, hash) +{ + var mask = '', i = 0; + + while (mask.length < len) + { + mask += hash(String.fromCharCode.apply(String, seed.concat([ + (i & 0xff000000) >> 24, + (i & 0x00ff0000) >> 16, + (i & 0x0000ff00) >> 8, + i & 0x000000ff]))); + i += 1; + } + + return mask; +} + +/** + * PKCS#1 (OAEP) pad input string s to n bytes, and return a bigint + * @name oaep_pad + * @param s raw string of message + * @param n key length of RSA key + * @param hash JavaScript function to calculate raw hash value from raw string or algorithm name (ex. "SHA1") + * @param hashLen byte length of resulted hash value (ex. 20 for SHA1) + * @return {BigInteger} BigInteger object of resulted PKCS#1 OAEP padded message + * @description + * This function calculates OAEP padded message from original message.
+ * NOTE: Since jsrsasign 6.2.0, 'hash' argument can accept an algorithm name such as "sha1". + * @example + * oaep_pad("aaa", 128) → big integer object // SHA-1 by default + * oaep_pad("aaa", 128, function(s) {...}, 20); + * oaep_pad("aaa", 128, "sha1"); + */ +function oaep_pad(s, n, hash, hashLen) { + var MD = KJUR.crypto.MessageDigest; + var Util = KJUR.crypto.Util; + var algName = null; + + if (!hash) hash = "sha1"; + + if (typeof hash === "string") { + algName = MD.getCanonicalAlgName(hash); + hashLen = MD.getHashLength(algName); + hash = function(s) { + return hextorstr(Util.hashHex(rstrtohex(s), algName)); + }; + } + + if (s.length + 2 * hashLen + 2 > n) { + throw "Message too long for RSA"; + } + + var PS = '', i; + + for (i = 0; i < n - s.length - 2 * hashLen - 2; i += 1) { + PS += '\x00'; + } + + var DB = hash('') + PS + '\x01' + s; + var seed = new Array(hashLen); + new SecureRandom().nextBytes(seed); + + var dbMask = oaep_mgf1_arr(seed, DB.length, hash); + var maskedDB = []; + + for (i = 0; i < DB.length; i += 1) { + maskedDB[i] = DB.charCodeAt(i) ^ dbMask.charCodeAt(i); + } + + var seedMask = oaep_mgf1_arr(maskedDB, seed.length, hash); + var maskedSeed = [0]; + + for (i = 0; i < seed.length; i += 1) { + maskedSeed[i + 1] = seed[i] ^ seedMask.charCodeAt(i); + } + + return new BigInteger(maskedSeed.concat(maskedDB)); +} + +// "empty" RSA key constructor +function RSAKey() { + this.n = null; + this.e = 0; + this.d = null; + this.p = null; + this.q = null; + this.dmp1 = null; + this.dmq1 = null; + this.coeff = null; +} + +// Set the public key fields N and e from hex strings +function RSASetPublic(N, E) { + this.isPublic = true; + this.isPrivate = false; + if (typeof N !== "string") { + this.n = N; + this.e = E; + } else if(N != null && E != null && N.length > 0 && E.length > 0) { + this.n = parseBigInt(N,16); + this.e = parseInt(E,16); + } else { + throw "Invalid RSA public key"; + } +} + +// Perform raw public operation on "x": return x^e (mod n) +function RSADoPublic(x) { + return x.modPowInt(this.e, this.n); +} + +// Return the PKCS#1 RSA encryption of "text" as an even-length hex string +function RSAEncrypt(text) { + var m = pkcs1pad2(text,(this.n.bitLength()+7)>>3); + if(m == null) return null; + var c = this.doPublic(m); + if(c == null) return null; + var h = c.toString(16); + if((h.length & 1) == 0) return h; else return "0" + h; +} + +// Return the PKCS#1 OAEP RSA encryption of "text" as an even-length hex string +function RSAEncryptOAEP(text, hash, hashLen) { + var m = oaep_pad(text, (this.n.bitLength() + 7) >> 3, hash, hashLen); + if(m == null) return null; + var c = this.doPublic(m); + if(c == null) return null; + var h = c.toString(16); + if((h.length & 1) == 0) return h; else return "0" + h; +} + +// Return the PKCS#1 RSA encryption of "text" as a Base64-encoded string +//function RSAEncryptB64(text) { +// var h = this.encrypt(text); +// if(h) return hex2b64(h); else return null; +//} + +// protected +RSAKey.prototype.doPublic = RSADoPublic; + +// public +RSAKey.prototype.setPublic = RSASetPublic; +RSAKey.prototype.encrypt = RSAEncrypt; +RSAKey.prototype.encryptOAEP = RSAEncryptOAEP; +//RSAKey.prototype.encrypt_b64 = RSAEncryptB64; + +RSAKey.prototype.type = "RSA"; diff --git a/source/sha256.js b/source/sha256.js new file mode 100644 index 0000000..a3790b0 --- /dev/null +++ b/source/sha256.js @@ -0,0 +1,185 @@ +/* +CryptoJS v3.1.2 +code.google.com/p/crypto-js +(c) 2009-2013 by Jeff Mott. All rights reserved. +code.google.com/p/crypto-js/wiki/License +*/ +(function (Math) { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var WordArray = C_lib.WordArray; + var Hasher = C_lib.Hasher; + var C_algo = C.algo; + + // Initialization and round constants tables + var H = []; + var K = []; + + // Compute constants + (function () { + function isPrime(n) { + var sqrtN = Math.sqrt(n); + for (var factor = 2; factor <= sqrtN; factor++) { + if (!(n % factor)) { + return false; + } + } + + return true; + } + + function getFractionalBits(n) { + return ((n - (n | 0)) * 0x100000000) | 0; + } + + var n = 2; + var nPrime = 0; + while (nPrime < 64) { + if (isPrime(n)) { + if (nPrime < 8) { + H[nPrime] = getFractionalBits(Math.pow(n, 1 / 2)); + } + K[nPrime] = getFractionalBits(Math.pow(n, 1 / 3)); + + nPrime++; + } + + n++; + } + }()); + + // Reusable object + var W = []; + + /** + * SHA-256 hash algorithm. + */ + var SHA256 = C_algo.SHA256 = Hasher.extend({ + _doReset: function () { + this._hash = new WordArray.init(H.slice(0)); + }, + + _doProcessBlock: function (M, offset) { + // Shortcut + var H = this._hash.words; + + // Working variables + var a = H[0]; + var b = H[1]; + var c = H[2]; + var d = H[3]; + var e = H[4]; + var f = H[5]; + var g = H[6]; + var h = H[7]; + + // Computation + for (var i = 0; i < 64; i++) { + if (i < 16) { + W[i] = M[offset + i] | 0; + } else { + var gamma0x = W[i - 15]; + var gamma0 = ((gamma0x << 25) | (gamma0x >>> 7)) ^ + ((gamma0x << 14) | (gamma0x >>> 18)) ^ + (gamma0x >>> 3); + + var gamma1x = W[i - 2]; + var gamma1 = ((gamma1x << 15) | (gamma1x >>> 17)) ^ + ((gamma1x << 13) | (gamma1x >>> 19)) ^ + (gamma1x >>> 10); + + W[i] = gamma0 + W[i - 7] + gamma1 + W[i - 16]; + } + + var ch = (e & f) ^ (~e & g); + var maj = (a & b) ^ (a & c) ^ (b & c); + + var sigma0 = ((a << 30) | (a >>> 2)) ^ ((a << 19) | (a >>> 13)) ^ ((a << 10) | (a >>> 22)); + var sigma1 = ((e << 26) | (e >>> 6)) ^ ((e << 21) | (e >>> 11)) ^ ((e << 7) | (e >>> 25)); + + var t1 = h + sigma1 + ch + K[i] + W[i]; + var t2 = sigma0 + maj; + + h = g; + g = f; + f = e; + e = (d + t1) | 0; + d = c; + c = b; + b = a; + a = (t1 + t2) | 0; + } + + // Intermediate hash value + H[0] = (H[0] + a) | 0; + H[1] = (H[1] + b) | 0; + H[2] = (H[2] + c) | 0; + H[3] = (H[3] + d) | 0; + H[4] = (H[4] + e) | 0; + H[5] = (H[5] + f) | 0; + H[6] = (H[6] + g) | 0; + H[7] = (H[7] + h) | 0; + }, + + _doFinalize: function () { + // Shortcuts + var data = this._data; + var dataWords = data.words; + + var nBitsTotal = this._nDataBytes * 8; + var nBitsLeft = data.sigBytes * 8; + + // Add padding + dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32); + dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = Math.floor(nBitsTotal / 0x100000000); + dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 15] = nBitsTotal; + data.sigBytes = dataWords.length * 4; + + // Hash final blocks + this._process(); + + // Return final computed hash + return this._hash; + }, + + clone: function () { + var clone = Hasher.clone.call(this); + clone._hash = this._hash.clone(); + + return clone; + } + }); + + /** + * Shortcut function to the hasher's object interface. + * + * @param {WordArray|string} message The message to hash. + * + * @return {WordArray} The hash. + * + * @static + * + * @example + * + * var hash = CryptoJS.SHA256('message'); + * var hash = CryptoJS.SHA256(wordArray); + */ + C.SHA256 = Hasher._createHelper(SHA256); + + /** + * Shortcut function to the HMAC's object interface. + * + * @param {WordArray|string} message The message to hash. + * @param {WordArray|string} key The secret key. + * + * @return {WordArray} The HMAC. + * + * @static + * + * @example + * + * var hmac = CryptoJS.HmacSHA256(message, key); + */ + C.HmacSHA256 = Hasher._createHmacHelper(SHA256); +}(Math)); diff --git a/source/yahoo.js b/source/yahoo.js new file mode 100644 index 0000000..b088151 --- /dev/null +++ b/source/yahoo.js @@ -0,0 +1,72 @@ +/*! +Copyright (c) 2011, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.com/yui/license.html +version: 2.9.0 +*/ +if (YAHOO === undefined) {var YAHOO = {};} +YAHOO.lang = { + /** + * Utility to set up the prototype, constructor and superclass properties to + * support an inheritance strategy that can chain constructors and methods. + * Static members will not be inherited. + * + * @method extend + * @static + * @param {Function} subc the object to modify + * @param {Function} superc the object to inherit + * @param {Object} overrides additional properties/methods to add to the + * subclass prototype. These will override the + * matching items obtained from the superclass + * if present. + */ + extend: function(subc, superc, overrides) { + if (! superc || ! subc) { + throw new Error("YAHOO.lang.extend failed, please check that " + + "all dependencies are included."); + } + + var F = function() {}; + F.prototype = superc.prototype; + subc.prototype = new F(); + subc.prototype.constructor = subc; + subc.superclass = superc.prototype; + + if (superc.prototype.constructor == Object.prototype.constructor) { + superc.prototype.constructor = superc; + } + + if (overrides) { + var i; + for (i in overrides) { + subc.prototype[i] = overrides[i]; + } + + /* + * IE will not enumerate native functions in a derived object even if the + * function was overridden. This is a workaround for specific functions + * we care about on the Object prototype. + * @property _IEEnumFix + * @param {Function} r the object to receive the augmentation + * @param {Function} s the object that supplies the properties to augment + * @static + * @private + */ + var _IEEnumFix = function() {}, + ADD = ["toString", "valueOf"]; + try { + if (/MSIE/.test(navigator.userAgent)) { + _IEEnumFix = function(r, s) { + for (i = 0; i < ADD.length; i = i + 1) { + var fname = ADD[i], f = s[fname]; + if (typeof f === 'function' && f != Object.prototype[fname]) { + r[fname] = f; + } + } + }; + } + } catch (ex) {}; + _IEEnumFix(subc.prototype, overrides); + } + } +};