1 /* base64x-1.1.34 (c) 2012-2023 Kenji Urushima | kjur.github.io/jsrsasign/license
  2  */
  3 /*
  4  * base64x.js - Base64url and supplementary functions for Tom Wu's base64.js library
  5  *
  6  * Copyright (c) 2012-2023 Kenji Urushima (kenji.urushima@gmail.com)
  7  *
  8  * This software is licensed under the terms of the MIT License.
  9  * https://kjur.github.io/jsrsasign/license
 10  *
 11  * The above copyright and license notice shall be 
 12  * included in all copies or substantial portions of the Software.
 13  */
 14 
 15 /**
 16  * @fileOverview
 17  * @name base64x-1.1.js
 18  * @author Kenji Urushima kenji.urushima@gmail.com
 19  * @version jsrsasign 10.9.0 base64x 1.1.34 (2023-Nov-27)
 20  * @since jsrsasign 2.1
 21  * @license <a href="https://kjur.github.io/jsrsasign/license/">MIT License</a>
 22  */
 23 
 24 var KJUR;
 25 if (typeof KJUR == "undefined" || !KJUR) KJUR = {};
 26 if (typeof KJUR.lang == "undefined" || !KJUR.lang) KJUR.lang = {};
 27 
 28 /**
 29  * String and its utility class <br/>
 30  * This class provides some static utility methods for string.
 31  * @class String and its utility class
 32  * @author Kenji Urushima
 33  * @version 1.0 (2016-Aug-05)
 34  * @since base64x 1.1.7 jsrsasign 5.0.13
 35  * @description
 36  * <br/>
 37  * This class provides static methods for string utility.
 38  * <dl>
 39  * <dt><b>STRING TYPE CHECKERS</b>
 40  * <dd>
 41  * <ul>
 42  * <li>{@link KJUR.lang.String.isInteger} - check whether argument is an integer</li>
 43  * <li>{@link KJUR.lang.String.isHex} - check whether argument is a hexadecimal string</li>
 44  * <li>{@link KJUR.lang.String.isBase64} - check whether argument is a Base64 encoded string</li>
 45  * <li>{@link KJUR.lang.String.isBase64URL} - check whether argument is a Base64URL encoded string</li>
 46  * <li>{@link KJUR.lang.String.isIntegerArray} - check whether argument is an array of integers</li>
 47  * <li>{@link KJUR.lang.String.isPrintable} - check whether argument is PrintableString accepted characters</li>
 48  * <li>{@link KJUR.lang.String.isIA5} - check whether argument is IA5String accepted characters</li>
 49  * <li>{@link KJUR.lang.String.isMail} - check whether argument is RFC 822 e-mail address format</li>
 50  * </ul>
 51  * </dl>
 52  */
 53 KJUR.lang.String = function() {};
 54 
 55 /**
 56  * Base64URL and supplementary functions for Tom Wu's base64.js library.<br/>
 57  * This class is just provide information about global functions
 58  * defined in 'base64x.js'. The 'base64x.js' script file provides
 59  * global functions for converting following data each other.
 60  * <ul>
 61  * <li>(ASCII) String</li>
 62  * <li>UTF8 String including CJK, Latin and other characters</li>
 63  * <li>byte array</li>
 64  * <li>hexadecimal encoded String</li>
 65  * <li>Full URIComponent encoded String (such like "%69%94")</li>
 66  * <li>Base64 encoded String</li>
 67  * <li>Base64URL encoded String</li>
 68  * </ul>
 69  * All functions in 'base64x.js' are defined in {@link global__} and not
 70  * in this class.
 71  * 
 72  * @class Base64URL and supplementary functions for Tom Wu's base64.js library
 73  * @author Kenji Urushima
 74  * @version 1.1 (07 May 2012)
 75  * @requires base64.js
 76  * @see <a href="https://kjur.github.io/jsjws/">'jwjws'(JWS JavaScript Library) home page https://kjur.github.io/jsjws/</a>
 77  * @see <a href="https://kjur.github.io/jsrsasigns/">'jwrsasign'(RSA Sign JavaScript Library) home page https://kjur.github.io/jsrsasign/</a>
 78  */
 79 function Base64x() {
 80 }
 81 
 82 // ==== string / byte array ================================
 83 /**
 84  * convert a string to an array of character codes
 85  * @name stoBA
 86  * @function
 87  * @param {String} s
 88  * @return {Array of Numbers} 
 89  */
 90 function stoBA(s) {
 91     var a = new Array();
 92     for (var i = 0; i < s.length; i++) {
 93 	a[i] = s.charCodeAt(i);
 94     }
 95     return a;
 96 }
 97 
 98 /**
 99  * convert an array of character codes to a string
100  * @name BAtos
101  * @function
102  * @param {Array of Numbers} a array of character codes
103  * @return {String} s
104  */
105 function BAtos(a) {
106     var s = "";
107     for (var i = 0; i < a.length; i++) {
108 	s = s + String.fromCharCode(a[i]);
109     }
110     return s;
111 }
112 
113 // ==== byte array / hex ================================
114 /**
115  * convert an array of bytes(Number) to hexadecimal string.<br/>
116  * @name BAtohex
117  * @function
118  * @param {Array of Numbers} a array of bytes
119  * @return {String} hexadecimal string
120  */
121 function BAtohex(a) {
122     var s = "";
123     for (var i = 0; i < a.length; i++) {
124 	var hex1 = a[i].toString(16);
125 	if (hex1.length == 1) hex1 = "0" + hex1;
126 	s = s + hex1;
127     }
128     return s;
129 }
130 
131 // ==== string / hex ================================
132 /**
133  * convert a ASCII string to a hexadecimal string of ASCII codes.<br/>
134  * NOTE: This can't be used for non ASCII characters.
135  * @name stohex
136  * @function
137  * @param {s} s ASCII string
138  * @return {String} hexadecimal string
139  */
140 function stohex(s) {
141     return BAtohex(stoBA(s));
142 }
143 
144 // ==== string / base64 ================================
145 /**
146  * convert a ASCII string to a Base64 encoded string.<br/>
147  * NOTE: This can't be used for non ASCII characters.
148  * @name stob64
149  * @function
150  * @param {s} s ASCII string
151  * @return {String} Base64 encoded string
152  */
153 function stob64(s) {
154     return hex2b64(stohex(s));
155 }
156 
157 // ==== string / base64url ================================
158 /**
159  * convert a ASCII string to a Base64URL encoded string.<br/>
160  * NOTE: This can't be used for non ASCII characters.
161  * @name stob64u
162  * @function
163  * @param {s} s ASCII string
164  * @return {String} Base64URL encoded string
165  */
166 function stob64u(s) {
167     return b64tob64u(hex2b64(stohex(s)));
168 }
169 
170 /**
171  * convert a Base64URL encoded string to a ASCII string.<br/>
172  * NOTE: This can't be used for Base64URL encoded non ASCII characters.
173  * @name b64utos
174  * @function
175  * @param {s} s Base64URL encoded string
176  * @return {String} ASCII string
177  */
178 function b64utos(s) {
179     return BAtos(b64toBA(b64utob64(s)));
180 }
181 
182 // ==== base64 / base64url ================================
183 /**
184  * convert a Base64 encoded string to a Base64URL encoded string.<br/>
185  * @name b64tob64u
186  * @function
187  * @param {String} s Base64 encoded string
188  * @return {String} Base64URL encoded string
189  * @example
190  * b64tob64u("ab+c3f/==") → "ab-c3f_"
191  */
192 function b64tob64u(s) {
193     s = s.replace(/\=/g, "");
194     s = s.replace(/\+/g, "-");
195     s = s.replace(/\//g, "_");
196     return s;
197 }
198 
199 /**
200  * convert a Base64URL encoded string to a Base64 encoded string.<br/>
201  * @name b64utob64
202  * @function
203  * @param {String} s Base64URL encoded string
204  * @return {String} Base64 encoded string
205  * @example
206  * b64utob64("ab-c3f_") → "ab+c3f/=="
207  */
208 function b64utob64(s) {
209     if (s.length % 4 == 2) s = s + "==";
210     else if (s.length % 4 == 3) s = s + "=";
211     s = s.replace(/-/g, "+");
212     s = s.replace(/_/g, "/");
213     return s;
214 }
215 
216 // ==== hex / base64url ================================
217 /**
218  * convert a hexadecimal string to a Base64URL encoded string.<br/>
219  * @name hextob64u
220  * @function
221  * @param {String} s hexadecimal string
222  * @return {String} Base64URL encoded string
223  * @description
224  * convert a hexadecimal string to a Base64URL encoded string.
225  * NOTE: If leading "0" is omitted and odd number length for
226  * hexadecimal leading "0" is automatically added.
227  */
228 function hextob64u(s) {
229     if (s.length % 2 == 1) s = "0" + s;
230     return b64tob64u(hex2b64(s));
231 }
232 
233 /**
234  * convert a Base64URL encoded string to a hexadecimal string.<br/>
235  * @name b64utohex
236  * @function
237  * @param {String} s Base64URL encoded string
238  * @return {String} hexadecimal string
239  */
240 function b64utohex(s) {
241     return b64tohex(b64utob64(s));
242 }
243 
244 // ==== utf8 / base64url ================================
245 
246 /**
247  * convert a UTF-8 encoded string including CJK or Latin to a Base64URL encoded string.<br/>
248  * @name utf8tob64u
249  * @function
250  * @param {String} s UTF-8 encoded string
251  * @return {String} Base64URL encoded string
252  * @since 1.1
253  * @example
254  * utf8tob64u("あ") → "44GC"
255  * utf8tob64u("aaa") → "YWFh"
256  */
257 
258 /**
259  * convert a Base64URL encoded string to a UTF-8 encoded string including CJK or Latin.<br/>
260  * @name b64utoutf8
261  * @function
262  * @param {String} s Base64URL encoded string
263  * @return {String} UTF-8 encoded string
264  * @since 1.1
265  * @example
266  * b64utoutf8("44GC") → "あ"
267  * b64utoutf8("YWFh") → "aaa"
268  */
269 
270 var utf8tob64u, b64utoutf8;
271 
272 if (typeof Buffer === 'function') {
273   utf8tob64u = function (s) {
274     return b64tob64u(Buffer.from(s, 'utf8').toString('base64'));
275   };
276 
277   b64utoutf8 = function (s) {
278     return Buffer.from(b64utob64(s), 'base64').toString('utf8');
279   };
280 } else {
281   utf8tob64u = function (s) {
282     return hextob64u(uricmptohex(encodeURIComponentAll(s)));
283   };
284 
285   b64utoutf8 = function (s) {
286     return decodeURIComponent(hextouricmp(b64utohex(s)));
287   };
288 }
289 
290 // ==== utf8 / base64url ================================
291 /**
292  * convert a UTF-8 encoded string including CJK or Latin to a Base64 encoded string.<br/>
293  * @name utf8tob64
294  * @function
295  * @param {String} s UTF-8 encoded string
296  * @return {String} Base64 encoded string
297  * @since 1.1.1
298  */
299 function utf8tob64(s) {
300   return hex2b64(uricmptohex(encodeURIComponentAll(s)));
301 }
302 
303 /**
304  * convert a Base64 encoded string to a UTF-8 encoded string including CJK or Latin.<br/>
305  * @name b64toutf8
306  * @function
307  * @param {String} s Base64 encoded string
308  * @return {String} UTF-8 encoded string
309  * @since 1.1.1
310  */
311 function b64toutf8(s) {
312   return decodeURIComponent(hextouricmp(b64tohex(s)));
313 }
314 
315 // ==== utf8 / hex ================================
316 /**
317  * convert a UTF-8 encoded string including CJK or Latin to a hexadecimal encoded string.<br/>
318  * @name utf8tohex
319  * @function
320  * @param {String} s UTF-8 encoded string
321  * @return {String} hexadecimal encoded string
322  * @since 1.1.1
323  */
324 function utf8tohex(s) {
325   return uricmptohex(encodeURIComponentAll(s)).toLowerCase();
326 }
327 
328 /**
329  * convert a hexadecimal encoded string to a UTF-8 encoded string including CJK or Latin.<br/>
330  * Note that when input is improper hexadecimal string as UTF-8 string, this function returns
331  * 'null'.
332  * @name hextoutf8
333  * @function
334  * @param {String} s hexadecimal encoded string
335  * @return {String} UTF-8 encoded string or null
336  * @since 1.1.1
337  */
338 function hextoutf8(s) {
339   try {
340     return decodeURIComponent(hextouricmp(s));
341   } catch(ex) {
342     return null;
343   }
344 }
345 
346 // ==== iso8859-1 latin1 / utf8 ===================
347 /**
348  * convert a hexadecimal ISO 8859-1 latin string to UTF-8 string<br/>
349  * @name iso88591hextoutf8
350  * @function
351  * @param {String} h hexadecimal ISO 8859-1 latin string
352  * @return {String} UTF-8 string
353  * @since jsrsasign 10.5.12 base64x 1.1.25
354  * @see utf8toiso88591hex
355  *
356  * @example
357  * iso88591hextoutf8("41a9fa") → "A©ú"
358  */
359 function iso88591hextoutf8(h) {
360     return hextoutf8(iso88591hextoutf8hex(h));
361 }
362 
363 /**
364  * convert UTF-8 string to a hexadecimal ISO 8859-1 latin string<br/>
365  * @name utf8toiso88591hex
366  * @function
367  * @param {String} s hexadecimal ISO 8859-1 latin string
368  * @return {String} UTF-8 string
369  * @since jsrsasign 10.5.12 base64x 1.1.25
370  * @see iso88591hextoutf8
371  *
372  * @example
373  * utf8toiso88591hex("A©ú") → "41a9fa"
374  */
375 function utf8toiso88591hex(s) {
376     return utf8hextoiso88591hex(utf8tohex(s));
377 }
378 
379 /**
380  * convert a hexadecimal ISO 8859-1 latin string to UTF-8 hexadecimal string<br/>
381  * @name iso88591hextoutf8hex
382  * @function
383  * @param {String} h hexadecimal ISO 8859-1 latin string
384  * @return {String} UTF-8 hexadecimal string
385  * @since jsrsasign 10.5.12 base64x 1.1.25
386  * @see iso88591hextoutf8
387  * @see utf8hextoiso88591hex
388  *
389  * @example
390  * iso88591hextoutf8hex("41a9fa") → "41c2a9c3ba"
391  */
392 function iso88591hextoutf8hex(h) {
393     var a = h.match(/.{1,2}/g);
394     var a2 = [];
395     for (var i = 0; i < a.length; i++) {
396 	var di = parseInt(a[i], 16);
397 	if (0xa1 <= di && di <= 0xbf) {
398 	    a2.push("c2");
399 	    a2.push(a[i]);
400 	} else if (0xc0 <= di && di <= 0xff) {
401 	    a2.push("c3");
402 	    a2.push((di - 64).toString(16));
403 	} else {
404 	    a2.push(a[i]);
405 	}
406     }
407     return a2.join('');
408 }
409 
410 /**
411  * convert UTF-8 string to a hexadecimal ISO 8859-1 latin string<br/>
412  * @name utf8hextoiso88591hex
413  * @function
414  * @param {String} h hexadecimal UTF-8 string
415  * @return {String} hexadecimal ISO 8859-1 latin string
416  * @since jsrsasign 10.5.12 base64x 1.1.25
417  * @see iso88591hextoutf8hex
418  * @see utf8toiso88591hex
419  *
420  * @example
421  * utf8hextoiso88591hex("41c2a9c3ba") → "41a9fa"
422  */
423 function utf8hextoiso88591hex(h) {
424     var a = h.match(/.{1,2}/g);
425     var a2 = [];
426     for (var i = 0; i < a.length; i++) {
427 	if (a[i] == 'c2') {
428 	    i++;
429 	    a2.push(a[i]);
430 	} else if (a[i] == 'c3') {
431 	    i++;
432 	    var ci = a[i];
433 	    var di = parseInt(a[i], 16) + 64;
434 	    a2.push(di.toString(16));
435 	} else {
436 	    a2.push(a[i]);
437 	}
438     }
439     return a2.join('');
440 }
441 
442 // ==== rstr / hex ================================
443 /**
444  * convert a hexadecimal encoded string to raw string including non printable characters.<br/>
445  * @name hextorstr
446  * @function
447  * @param {String} s hexadecimal encoded string
448  * @return {String} raw string
449  * @since 1.1.2
450  * @example
451  * hextorstr("610061") → "a\x00a"
452  */
453 function hextorstr(sHex) {
454     var s = "";
455     for (var i = 0; i < sHex.length - 1; i += 2) {
456         s += String.fromCharCode(parseInt(sHex.substr(i, 2), 16));
457     }
458     return s;
459 }
460 
461 /**
462  * convert a raw string including non printable characters to hexadecimal encoded string.<br/>
463  * @name rstrtohex
464  * @function
465  * @param {String} s raw string
466  * @return {String} hexadecimal encoded string
467  * @since 1.1.2
468  * @example
469  * rstrtohex("a\x00a") → "610061"
470  */
471 function rstrtohex(s) {
472     var result = "";
473     for (var i = 0; i < s.length; i++) {
474         result += ("0" + s.charCodeAt(i).toString(16)).slice(-2);
475     }
476     return result;
477 }
478 
479 // ==== hex / b64nl =======================================
480 
481 /**
482  * convert a hexadecimal string to Base64 encoded string<br/>
483  * @name hextob64
484  * @function
485  * @param {String} s hexadecimal string
486  * @return {String} resulted Base64 encoded string
487  * @since base64x 1.1.3
488  * @description
489  * This function converts from a hexadecimal string to Base64 encoded
490  * string without new lines.
491  * @example
492  * hextob64("616161") → "YWFh"
493  */
494 function hextob64(s) {
495     return hex2b64(s);
496 }
497 
498 /**
499  * convert a hexadecimal string to Base64 encoded string with new lines<br/>
500  * @name hextob64nl
501  * @function
502  * @param {String} s hexadecimal string
503  * @return {String} resulted Base64 encoded string with new lines
504  * @since base64x 1.1.3
505  * @description
506  * This function converts from a hexadecimal string to Base64 encoded
507  * string with new lines for each 64 characters. This is useful for
508  * PEM encoded file.
509  * @example
510  * hextob64nl("123456789012345678901234567890123456789012345678901234567890")
511  * →
512  * MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4 // new line
513  * OTAxMjM0NTY3ODkwCg==
514  */
515 function hextob64nl(s) {
516     return foldnl(hextob64(s), 64);
517 }
518 
519 /**
520  * wrap string with new lines to fit in specified width<br/>
521  * @name foldnl
522  * @function
523  * @param {string} s string
524  * @param {number} n width
525  * @return {string} wrapped string with new lines
526  * @since jsrsasign 10.7.0 base64x 1.1.31
527  * @description
528  * This function wrap a string with new lines to fit in specified width.
529  * @example
530  * foldnl("1234567890", 6)
531  * →
532  * 123456
533  * 7890
534  */
535 function foldnl(s, n) {
536     s = s.replace(new RegExp('(.{' + n + '})', 'g'), "$1\r\n");
537     s = s.replace(/\s+$/, '');
538     return s;
539 }
540 
541 /**
542  * convert a Base64 encoded string with new lines to a hexadecimal string<br/>
543  * @name b64nltohex
544  * @function
545  * @param {String} s Base64 encoded string with new lines
546  * @return {String} hexadecimal string
547  * @since base64x 1.1.3
548  * @description
549  * This function converts from a Base64 encoded
550  * string with new lines to a hexadecimal string.
551  * This is useful to handle PEM encoded file.
552  * This function removes any non-Base64 characters (i.e. not 0-9,A-Z,a-z,\,+,=)
553  * including new line.
554  * @example
555  * hextob64nl(
556  * "MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4\r\n" +
557  * "OTAxMjM0NTY3ODkwCg==\r\n")
558  * →
559  * "123456789012345678901234567890123456789012345678901234567890"
560  */
561 function b64nltohex(s) {
562     var b64 = s.replace(/[^0-9A-Za-z\/+=]*/g, '');
563     var hex = b64tohex(b64);
564     return hex;
565 } 
566 
567 // ==== b64 / pem =========================================
568 /**
569  * get PEM string from Base64 string
570  * @name b64topem
571  * @function
572  * @param {string} b64 Base64 string of PEM body
573  * @param {string} pemHeader PEM header string (ex. 'RSA PRIVATE KEY')
574  * @return {string} PEM formatted string of input data
575  * @since jsrasign 10.7.0 base64x 1.1.31
576  * @description
577  * This function converts a Base64 string to a PEM string with
578  * a specified header. Its line break will be CRLF("\r\n").
579  * @example
580  * b64topem('YWFh', 'RSA PRIVATE KEY') →
581  * -----BEGIN PRIVATE KEY-----
582  * YWFh
583  * -----END PRIVATE KEY-----
584  */
585 function b64topem(b64, pemHeader) {
586     return "-----BEGIN " + pemHeader + "-----\r\n" + 
587 	foldnl(b64, 64) +
588         "\r\n-----END " + pemHeader + "-----\r\n";
589 }
590 
591 
592 
593 // ==== hex / pem =========================================
594 
595 /**
596  * get PEM string from hexadecimal data and header string
597  * @name hextopem
598  * @function
599  * @param {String} dataHex hexadecimal string of PEM body
600  * @param {String} pemHeader PEM header string (ex. 'RSA PRIVATE KEY')
601  * @return {String} PEM formatted string of input data
602  * @since jsrasign 7.2.1 base64x 1.1.12
603  * @description
604  * This function converts a hexadecimal string to a PEM string with
605  * a specified header. Its line break will be CRLF("\r\n").
606  * @example
607  * hextopem('616161', 'RSA PRIVATE KEY') →
608  * -----BEGIN PRIVATE KEY-----
609  * YWFh
610  * -----END PRIVATE KEY-----
611  */
612 function hextopem(dataHex, pemHeader) {
613     return "-----BEGIN " + pemHeader + "-----\r\n" + 
614 	foldnl(hextob64(dataHex), 64) +
615         "\r\n-----END " + pemHeader + "-----\r\n";
616 }
617 
618 /**
619  * get hexacedimal string from PEM format data<br/>
620  * @name pemtohex
621  * @function
622  * @param {String} s PEM formatted string
623  * @param {String} sHead PEM header string without BEGIN/END(OPTION)
624  * @return {String} hexadecimal string data of PEM contents
625  * @since jsrsasign 7.2.1 base64x 1.1.12
626  *
627  * @description
628  * This static method gets a hexacedimal string of contents 
629  * from PEM format data. You can explicitly specify PEM header 
630  * by sHead argument. 
631  * Any space characters such as white space or new line
632  * will be omitted.<br/>
633  * NOTE: Now {@link KEYUTIL.getHexFromPEM} and {@link X509.pemToHex}
634  * have been deprecated since jsrsasign 7.2.1. <br/>
635  * Please use this method instead.
636  * NOTE2: From jsrsasign 8.0.14 this can process multi
637  * "BEGIN...END" section such as "EC PRIVATE KEY" with "EC PARAMETERS".<br/>
638  *
639  * @example
640  * pemtohex("-----BEGIN PUBLIC KEY...") → "3082..."
641  * pemtohex("-----BEGIN CERTIFICATE...", "CERTIFICATE") → "3082..."
642  * pemtohex(" \r\n-----BEGIN DSA PRIVATE KEY...") → "3082..."
643  * pemtohex("-----BEGIN EC PARAMETERS...----BEGIN EC PRIVATE KEY...." → "3082..."
644  */
645 function pemtohex(s, sHead) {
646     if (s.indexOf("-----BEGIN ") == -1)
647         throw new Error("can't find PEM header");
648 
649     if (sHead !== undefined) {
650         s = s.replace(new RegExp('^[^]*-----BEGIN ' + sHead + '-----'), '');
651         s = s.replace(new RegExp('-----END ' + sHead + '-----[^]*$'), '');
652     } else {
653         s = s.replace(/^[^]*-----BEGIN [^-]+-----/, '');
654         s = s.replace(/-----END [^-]+-----[^]*$/, '');
655     }
656     return b64nltohex(s);
657 }
658 
659 /**
660  * get Base64 string from PEM format data<br/>
661  * @name pemtob64
662  * @function
663  * @param {string} s PEM formatted string
664  * @return {string} Base64 string or null
665  * @since jsrsasign 10.7.0 base64x 1.1.31
666  *
667  * @description
668  * This static method gets a Base64 string of contents 
669  * from PEM format data.
670  * When s is not PEM data, it returns null.
671  *
672  * @example
673  * pemtohex("-----BEGIN CERTIFICATE...", "CERTIFICATE") → "MIIBvTCC..."
674  */
675 function pemtob64(s) {
676     if (s.indexOf("-----BEGIN ") == -1 ||
677         s.indexOf("-----END ") == -1 ) return null;
678     s = s.replace(/^[\s\S]*?-----BEGIN [^-]+-----/m, '');
679     s = s.replace(/-----END [\s\S]+$/m, '');
680     s = s.replace(/\s+/g, '');
681     return (s.match(/^[0-9a-zA-Z+/=]+$/)) ? s : null;
682 }
683 
684 // ==== hex / ArrayBuffer =================================
685 
686 /**
687  * convert a hexadecimal string to an ArrayBuffer<br/>
688  * @name hextoArrayBuffer
689  * @function
690  * @param {String} hex hexadecimal string
691  * @return {ArrayBuffer} ArrayBuffer
692  * @since jsrsasign 6.1.4 base64x 1.1.8
693  * @description
694  * This function converts from a hexadecimal string to an ArrayBuffer.
695  * @example
696  * hextoArrayBuffer("fffa01") → ArrayBuffer of [255, 250, 1]
697  */
698 function hextoArrayBuffer(hex) {
699     if (hex.length % 2 != 0) throw "input is not even length";
700     if (hex.match(/^[0-9A-Fa-f]+$/) == null) throw "input is not hexadecimal";
701 
702     var buffer = new ArrayBuffer(hex.length / 2);
703     var view = new DataView(buffer);
704 
705     for (var i = 0; i < hex.length / 2; i++) {
706 	view.setUint8(i, parseInt(hex.substr(i * 2, 2), 16));
707     }
708 
709     return buffer;
710 }
711 
712 // ==== ArrayBuffer / hex =================================
713 
714 /**
715  * convert an ArrayBuffer to a hexadecimal string<br/>
716  * @name ArrayBuffertohex
717  * @function
718  * @param {ArrayBuffer} buffer ArrayBuffer
719  * @return {String} hexadecimal string
720  * @since jsrsasign 6.1.4 base64x 1.1.8
721  * @description
722  * This function converts from an ArrayBuffer to a hexadecimal string.
723  * @example
724  * var buffer = new ArrayBuffer(3);
725  * var view = new DataView(buffer);
726  * view.setUint8(0, 0xfa);
727  * view.setUint8(1, 0xfb);
728  * view.setUint8(2, 0x01);
729  * ArrayBuffertohex(buffer) → "fafb01"
730  */
731 function ArrayBuffertohex(buffer) {
732     var hex = "";
733     var view = new DataView(buffer);
734 
735     for (var i = 0; i < buffer.byteLength; i++) {
736 	hex += ("00" + view.getUint8(i).toString(16)).slice(-2);
737     }
738 
739     return hex;
740 }
741 
742 // ==== zulu / int =================================
743 /**
744  * GeneralizedTime or UTCTime string to milliseconds from Unix origin<br>
745  * @name zulutomsec
746  * @function
747  * @param {String} s GeneralizedTime or UTCTime string (ex. 20170412235959.384Z)
748  * @return {Number} milliseconds from Unix origin time (i.e. Jan 1, 1970 0:00:00 UTC)
749  * @since jsrsasign 7.1.3 base64x 1.1.9
750  * @description
751  * This function converts from GeneralizedTime string (i.e. YYYYMMDDHHmmSSZ) or
752  * UTCTime string (i.e. YYMMDDHHmmSSZ) to milliseconds from Unix origin time
753  * (i.e. Jan 1 1970 0:00:00 UTC). 
754  * Argument string may have fraction of seconds and
755  * its length is one or more digits such as "20170410235959.1234567Z".
756  * As for UTCTime, if year "YY" is equal or less than 49 then it is 20YY.
757  * If year "YY" is equal or greater than 50 then it is 19YY.
758  * @example
759  * zulutomsec(  "071231235959Z")       → 1199145599000 #Mon, 31 Dec 2007 23:59:59 GMT
760  * zulutomsec(  "071231235959.1Z")     → 1199145599100 #Mon, 31 Dec 2007 23:59:59 GMT
761  * zulutomsec(  "071231235959.12345Z") → 1199145599123 #Mon, 31 Dec 2007 23:59:59 GMT
762  * zulutomsec("20071231235959Z")       → 1199145599000 #Mon, 31 Dec 2007 23:59:59 GMT
763  * zulutomsec(  "931231235959Z")       → -410227201000 #Mon, 31 Dec 1956 23:59:59 GMT
764  */
765 function zulutomsec(s) {
766     var year, month, day, hour, min, sec, msec, d;
767     var sYear, sFrac, sMsec, matchResult;
768 
769     s = timetogen(s);
770     matchResult = s.match(/^(\d{4})(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)(|\.\d+)Z$/);
771 
772     if (matchResult) {
773 	year = parseInt(matchResult[1]);
774 	month = parseInt(matchResult[2]) - 1;
775 	day = parseInt(matchResult[3]);
776 	hour = parseInt(matchResult[4]);
777 	min = parseInt(matchResult[5]);
778 	sec = parseInt(matchResult[6]);
779 	msec = 0;
780 
781 	sFrac = matchResult[7];
782 	if (sFrac !== "") {
783 	    sMsec = (sFrac.substr(1) + "00").substr(0, 3); // .12 -> 012
784 	    msec = parseInt(sMsec);
785 	}
786 	return Date.UTC(year, month, day, hour, min, sec, msec);
787     }
788     throw new Error("unsupported zulu format: " + s);
789 }
790 
791 /**
792  * Unix origin milliseconds GeneralizedTime string<br>
793  * @name msectozulu
794  * @function
795  * @param {number} n milliseconds from Unix origin time (i.e. Jan 1, 1970 0:00:00 UTC)
796  * @return {string} GeneralizedTime string (ex. 20170412235959.384Z)
797  * @since jsrsasign 10.8.0 base64x 1.1.31
798  *
799  * @description
800  * This function converts from milliseconds of Unix origin time (ex. 1199145599000
801  * for 31 Dec 2007 23:59:59 GMT) to GeneralizedTime string (i.e. YYYYMMDDHHmmSSZ).
802  * The result string may have a fraction of second.
803  *
804  * @example
805  * msectozulu(1199145599000) → "20071231235959Z"       #Mon, 31 Dec 2007 23:59:59     GMT
806  * msectozulu(1199145599100) → "20071231235959.1Z"     #Mon, 31 Dec 2007 23:59:59.1   GMT
807  * msectozulu(1199145599123) → "20071231235959.123Z"   #Mon, 31 Dec 2007 23:59:59.123 GMT
808  */
809 function msectozulu(n) {
810     var d = new Date(n),
811         year = ("0000" + d.getUTCFullYear()).slice(-4),
812         mon =  ("00" + (d.getUTCMonth() + 1)).slice(-2),
813         day =  ("00" + d.getUTCDate()).slice(-2),
814         hour = ("00" + d.getUTCHours()).slice(-2),
815         min =  ("00" + d.getUTCMinutes()).slice(-2),
816         sec =  ("00" + d.getUTCSeconds()).slice(-2),
817 	msec = ("000" + d.getUTCMilliseconds()).slice(-3);
818     msec = msec.replace(/0+$/, '');
819     msec = (msec != '') ? '.' + msec : msec;
820     return year + mon + day + hour + min + sec + msec + "Z";
821 }
822 
823 /**
824  * GeneralizedTime or UTCTime string to seconds from Unix origin<br>
825  * @name zulutosec
826  * @function
827  * @param {String} s GeneralizedTime or UTCTime string (ex. 20170412235959.384Z)
828  * @return {Number} seconds from Unix origin time (i.e. Jan 1, 1970 0:00:00 UTC)
829  * @since jsrsasign 7.1.3 base64x 1.1.9
830  * @description
831  * This function converts from GeneralizedTime string (i.e. YYYYMMDDHHmmSSZ) or
832  * UTCTime string (i.e. YYMMDDHHmmSSZ) to seconds from Unix origin time
833  * (i.e. Jan 1 1970 0:00:00 UTC). Argument string may have fraction of seconds 
834  * however result value will be omitted.
835  * As for UTCTime, if year "YY" is equal or less than 49 then it is 20YY.
836  * If year "YY" is equal or greater than 50 then it is 19YY.
837  * @example
838  * zulutosec(  "071231235959Z")       → 1199145599 #Mon, 31 Dec 2007 23:59:59 GMT
839  * zulutosec(  "071231235959.1Z")     → 1199145599 #Mon, 31 Dec 2007 23:59:59 GMT
840  * zulutosec("20071231235959Z")       → 1199145599 #Mon, 31 Dec 2007 23:59:59 GMT
841  */
842 function zulutosec(s) {
843     return Math.round(zulutomsec(s) / 1000.0);
844 }
845 
846 // ==== zulu / Date =================================
847 
848 /**
849  * GeneralizedTime or UTCTime string to Date object<br>
850  * @name zulutodate
851  * @function
852  * @param {String} s GeneralizedTime or UTCTime string (ex. 20170412235959.384Z)
853  * @return {Date} Date object for specified time
854  * @since jsrsasign 7.1.3 base64x 1.1.9
855  * @description
856  * This function converts from GeneralizedTime string (i.e. YYYYMMDDHHmmSSZ) or
857  * UTCTime string (i.e. YYMMDDHHmmSSZ) to Date object.
858  * Argument string may have fraction of seconds and
859  * its length is one or more digits such as "20170410235959.1234567Z".
860  * As for UTCTime, if year "YY" is equal or less than 49 then it is 20YY.
861  * If year "YY" is equal or greater than 50 then it is 19YY.
862  * @example
863  * zulutodate(  "071231235959Z").toUTCString()   → "Mon, 31 Dec 2007 23:59:59 GMT"
864  * zulutodate(  "071231235959.1Z").toUTCString() → "Mon, 31 Dec 2007 23:59:59 GMT"
865  * zulutodate("20071231235959Z").toUTCString()   → "Mon, 31 Dec 2007 23:59:59 GMT"
866  * zulutodate(  "071231235959.34").getMilliseconds() → 340
867  */
868 function zulutodate(s) {
869     return new Date(zulutomsec(s));
870 }
871 
872 /**
873  * Date object to zulu time string<br>
874  * @name datetozulu
875  * @function
876  * @param {Date} d Date object for specified time
877  * @param {Boolean} flagUTCTime if this is true year will be YY otherwise YYYY
878  * @param {Boolean} flagMilli if this is true result concludes milliseconds
879  * @return {String} GeneralizedTime or UTCTime string (ex. 20170412235959.384Z)
880  * @since jsrsasign 7.2.0 base64x 1.1.11
881  * @description
882  * This function converts from Date object to GeneralizedTime string (i.e. YYYYMMDDHHmmSSZ) or
883  * UTCTime string (i.e. YYMMDDHHmmSSZ).
884  * As for UTCTime, if year "YY" is equal or less than 49 then it is 20YY.
885  * If year "YY" is equal or greater than 50 then it is 19YY.
886  * If flagMilli is true its result concludes milliseconds such like
887  * "20170520235959.42Z". 
888  * @example
889  * d = new Date(Date.UTC(2017,4,20,23,59,59,670));
890  * datetozulu(d) → "20170520235959Z"
891  * datetozulu(d, true) → "170520235959Z"
892  * datetozulu(d, false, true) → "20170520235959.67Z"
893  */
894 function datetozulu(d, flagUTCTime, flagMilli) {
895     var s;
896     var year = d.getUTCFullYear();
897     if (flagUTCTime) {
898 	if (year < 1950 || 2049 < year) 
899 	    throw "not proper year for UTCTime: " + year;
900 	s = ("" + year).slice(-2);
901     } else {
902 	s = ("000" + year).slice(-4);
903     }
904     s += ("0" + (d.getUTCMonth() + 1)).slice(-2);
905     s += ("0" + d.getUTCDate()).slice(-2);
906     s += ("0" + d.getUTCHours()).slice(-2);
907     s += ("0" + d.getUTCMinutes()).slice(-2);
908     s += ("0" + d.getUTCSeconds()).slice(-2);
909     if (flagMilli) {
910 	var milli = d.getUTCMilliseconds();
911 	if (milli !== 0) {
912 	    milli = ("00" + milli).slice(-3);
913 	    milli = milli.replace(/0+$/g, "");
914 	    s += "." + milli;
915 	}
916     }
917     s += "Z";
918     return s;
919 }
920 
921 /**
922  * GeneralizedTime or UTCTime string to GeneralizedTime<br>
923  * @name timetogen
924  * @function
925  * @param {string} s GeneralizedTime or UTCTime string (ex. 20170412235959.384Z)
926  * @return {string} GeneralizedTime
927  * @since jsrsasign 10.7.0 base64x 1.1.31
928  * @description
929  * This function converts UTCTime string (i.e. YYMMDDHHmmSSZ ) to 
930  * GeneralizedTime (YYYYMMDDHHmmSSZ) when the argument 's' is UTCTime. 
931  * Argument string may have fraction of seconds and
932  * its length is one or more digits such as "170410235959.1234567Z".
933  * As for UTCTime, if year "YY" is equal or less than 49 then it is 20YY.
934  * If year "YY" is equal or greater than 50 then it is 19YY.
935  * @example
936  * timetogen(  "071231235959Z") → "20071231235959Z"
937  * timetogen(  "971231235959Z") → "19971231235959Z"
938  * timetogen("20071231235959Z") → "20071231235959Z"
939  * timetogen(  "971231235959.123Z") → "19971231235959.123Z"
940  */
941 function timetogen(s) {
942     if (s.match(/^[0-9]{12}Z$/) || s.match(/^[0-9]{12}[.][0-9]*Z$/)) {
943 	return (s.match(/^[0-4]/)) ? "20" + s : "19" + s;
944     }
945     return s;
946 }
947 
948 // ==== URIComponent / hex ================================
949 /**
950  * convert a URLComponent string such like "%67%68" to a hexadecimal string.<br/>
951  * @name uricmptohex
952  * @function
953  * @param {String} s URIComponent string such like "%67%68"
954  * @return {String} hexadecimal string
955  * @since 1.1
956  */
957 function uricmptohex(s) {
958   return s.replace(/%/g, "");
959 }
960 
961 /**
962  * convert a hexadecimal string to a URLComponent string such like "%67%68".<br/>
963  * @name hextouricmp
964  * @function
965  * @param {String} s hexadecimal string
966  * @return {String} URIComponent string such like "%67%68"
967  * @since 1.1
968  */
969 function hextouricmp(s) {
970   return s.replace(/(..)/g, "%$1");
971 }
972 
973 // ==== hex / ipv6 =================================
974 
975 /**
976  * convert any IPv6 address to a 16 byte hexadecimal string
977  * @function
978  * @param s string of IPv6 address
979  * @return {String} 16 byte hexadecimal string of IPv6 address
980  * @description
981  * This function converts any IPv6 address representation string
982  * to a 16 byte hexadecimal string of address.
983  * @example
984  * 
985  */
986 function ipv6tohex(s) {
987   var msgMalformedAddress = "malformed IPv6 address";
988   if (! s.match(/^[0-9A-Fa-f:]+$/))
989     throw msgMalformedAddress;
990 
991   // 1. downcase
992   s = s.toLowerCase();
993 
994   // 2. expand ::
995   var num_colon = s.split(':').length - 1;
996   if (num_colon < 2) throw msgMalformedAddress;
997   var colon_replacer = ':'.repeat(7 - num_colon + 2);
998   s = s.replace('::', colon_replacer);
999 
1000   // 3. fill zero
1001   var a = s.split(':');
1002   if (a.length != 8) throw msgMalformedAddress;
1003   for (var i = 0; i < 8; i++) {
1004     a[i] = ("0000" + a[i]).slice(-4);
1005   }
1006   return a.join('');
1007 }
1008 
1009 /**
1010  * convert a 16 byte hexadecimal string to RFC 5952 canonicalized IPv6 address<br/>
1011  * @name hextoipv6
1012  * @function
1013  * @param {String} s hexadecimal string of 16 byte IPv6 address
1014  * @return {String} IPv6 address string canonicalized by RFC 5952
1015  * @since jsrsasign 8.0.10 base64x 1.1.13
1016  * @description
1017  * This function converts a 16 byte hexadecimal string to 
1018  * <a href="https://tools.ietf.org/html/rfc5952">RFC 5952</a>
1019  * canonicalized IPv6 address string.
1020  * @example
1021  * hextoipv6("871020010db8000000000000000000000004") &rarr "2001:db8::4"
1022  * hextoipv6("871020010db8000000000000000000") &rarr raise exception
1023  * hextoipv6("xyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyz") &rarr raise exception
1024  */
1025 function hextoipv6(s) {
1026     if (! s.match(/^[0-9A-Fa-f]{32}$/))
1027 	throw new Error("malformed IPv6 address: " + s);
1028 
1029     // 1. downcase
1030     s = s.toLowerCase();
1031 
1032     // 2. split 4 > ["0123", "00a4", "0000", ..., "ffff"]
1033     var a = s.match(/.{1,4}/g);
1034 
1035     // 3. trim leading 0 for items and join > "123:a4:0:...:ffff"
1036     a = a.map(function(s){return s.replace(/^0+/, '')});
1037     a = a.map(function(s){return s == '' ? '0' : s});
1038     s = ':' + a.join(':') + ':';
1039 
1040     // 4. find shrinkable candidates :0:0:..:0:
1041     var aZero = s.match(/:(0:){2,}/g);
1042 
1043     // 5. no shrinkable
1044     if (aZero == null) return s.slice(1, -1);
1045 
1046     // 6. fix max length zero(:0:...:0:)
1047     var sMaxZero = aZero.sort().slice(-1)[0];
1048 
1049     // 7. replace shrinked
1050     s = s.replace(sMaxZero.substr(0, sMaxZero.length - 1), ':');
1051 
1052     // 8. trim leading ':' if not '::'
1053     if (s.substr(0, 2) != '::') s = s.substr(1);
1054 
1055     // 9. trim tail ':' if not '::'
1056     if (s.substr(-2, 2) != '::') s = s.substr(0, s.length - 1);
1057 
1058     return s;
1059 }
1060 
1061 // ==== hex / ip =================================
1062 
1063 /**
1064  * convert a hexadecimal string to IP addresss<br/>
1065  * @name hextoip
1066  * @function
1067  * @param {String} s hexadecimal string of IP address
1068  * @return {String} IP address string
1069  * @since jsrsasign 8.0.10 base64x 1.1.13
1070  * @see hextoipv6
1071  * @see iptohex
1072  *
1073  * @description
1074  * This function converts a hexadecimal string of IPv4 or 
1075  * IPv6 address to IPv4 or IPv6 address string.
1076  * If byte length is not 4 nor 16, this returns a
1077  * hexadecimal string without conversion.
1078  * <br/>
1079  * NOTE: From jsrsasign 10.5.17, CIDR subnet mask notation also supported.
1080  *
1081  * @example
1082  * hextoip("c0a80101") → "192.168.1.1"
1083  * hextoip("871020010db8000000000000000000000004") &rarr "2001:db8::4"
1084  * hextoip("c0a80100ffffff00") → "192.168.1.0/24"
1085  * hextoip("c0a801010203") → "c0a801010203" // wrong 6 bytes
1086  * hextoip("zzz")) → raise exception because of not hexadecimal
1087  */
1088 function hextoip(s) {
1089     var malformedErr = new Error("malformed hex value");
1090     if (! s.match(/^([0-9A-Fa-f][0-9A-Fa-f]){1,}$/))
1091 	throw malformedErr;
1092     if (s.length == 8) { // ipv4
1093 	var ip;
1094 	try {
1095 	    ip = parseInt(s.substr(0, 2), 16) + "." +
1096  		 parseInt(s.substr(2, 2), 16) + "." +
1097 		 parseInt(s.substr(4, 2), 16) + "." +
1098 		 parseInt(s.substr(6, 2), 16);
1099 	    return ip;
1100 	} catch (ex) {
1101 	    throw malformedErr;
1102 	}
1103   } else if (s.length == 16) {
1104       try {
1105 	  return hextoip(s.substr(0, 8)) + "/" + ipprefixlen(s.substr(8));
1106       } catch (ex) {
1107 	  throw malformedErr;
1108       }
1109   } else if (s.length == 32) {
1110       return hextoipv6(s);
1111   } else if (s.length == 64) {
1112       try {
1113 	  return hextoipv6(s.substr(0, 32)) + "/" + ipprefixlen(s.substr(32));
1114       } catch (ex) {
1115 	  throw malformedErr;
1116       }
1117       return 
1118   } else {
1119     return s;
1120   }
1121 }
1122 
1123 /*
1124  * convert subnet mask hex to ip address prefix length<br/>
1125  * @name ipprefixlen
1126  * @param {string} hMask hexadecimal string of ipv4/6 subnet mask (ex. "ffffff00" for v4 class C)
1127  * @return {nummber} ip address prefix length (ex. 24 for IPv4 class C)
1128  */
1129 function ipprefixlen(hMask) {
1130     var malformedErr = new Error("malformed mask");
1131     var bMask;
1132     try {
1133 	bMask = new BigInteger(hMask, 16).toString(2);
1134     } catch(ex) {
1135 	throw malformedErr;
1136     }
1137     if (! bMask.match(/^1*0*$/)) throw malformedErr;
1138     return bMask.replace(/0+$/, '').length;
1139 }
1140 
1141 /**
1142  * convert IPv4/v6 addresss to a hexadecimal string<br/>
1143  * @name iptohex
1144  * @function
1145  * @param {String} s IPv4/v6 address string
1146  * @return {String} hexadecimal string of IP address
1147  * @since jsrsasign 8.0.12 base64x 1.1.14
1148  * @see hextoip
1149  * @see ipv6tohex
1150  *
1151  * @description
1152  * This function converts IPv4 or IPv6 address string to
1153  * a hexadecimal string of IPv4 or IPv6 address.
1154  * <br/>
1155  * NOTE: From jsrsasign 10.5.17, CIDR net mask notation also supported.
1156  *
1157  * @example
1158  * iptohex("192.168.1.1") → "c0a80101"
1159  * iptohex("2001:db8::4") → "871020010db8000000000000000000000004"
1160  * iptohex("192.168.1.1/24") → "c0a80101ffffff00"
1161  * iptohex("2001:db8::/120") → "871020010db8000000000000000000000000ffffffffffffffffffffffffffffffffff00"
1162  * iptohex("zzz")) → raise exception
1163  */
1164 function iptohex(s) {
1165     var malformedErr = new Error("malformed IP address");
1166     s = s.toLowerCase(s);
1167 
1168     if (! s.match(/^[0-9a-f.:/]+$/) ) throw malformedErr;
1169 
1170     if (s.match(/^[0-9.]+$/)) {
1171 	var a = s.split(".");
1172 	if (a.length !== 4) throw malformedErr;
1173 	var hex = "";
1174 	try {
1175 	    for (var i = 0; i < 4; i++) {
1176 		var d = parseInt(a[i]);
1177 		hex += ("0" + d.toString(16)).slice(-2);
1178 	    }
1179 	    return hex;
1180 	} catch(ex) {
1181 	    throw malformedErr;
1182 	}
1183     } else if (s.match(/^[0-9.]+\/[0-9]+$/)) {
1184 	var aItem = s.split("/");
1185 	return iptohex(aItem[0]) + ipnetmask(parseInt(aItem[1]), 32);
1186     } else if (s.match(/^[0-9a-f:]+$/) && s.indexOf(":") !== -1) {
1187 	return ipv6tohex(s);
1188     } else if (s.match(/^[0-9a-f:]+\/[0-9]+$/) && s.indexOf(":") !== -1) {
1189 	var aItem = s.split("/");
1190 	return ipv6tohex(aItem[0]) + ipnetmask(parseInt(aItem[1]), 128);
1191     } else {
1192 	throw malformedErr;
1193     }
1194 }
1195 
1196 /*
1197  * convert ip prefix length to net mask octets<br/>
1198  * @param {number} prefixlen ip prefix length value (ex. 24 for IPv4 class C)
1199  * @param {number} len ip address length (ex. 32 for IPv4 and 128 for IPv6)
1200  * @return {string} hexadecimal string of net mask octets
1201  * @example
1202  * ipnetmask(24, 32) → "ffffff00" 
1203  * ipnetmask(120, 128) → "ffffffffffffffffffffffffffffff00"
1204  */
1205 function ipnetmask(prefixlen, len) {
1206     if (len == 32 && prefixlen == 0) return "00000000"; // v4
1207     if (len == 128 && prefixlen == 0) return "00000000000000000000000000000000"; // v6
1208     var b = Array(prefixlen + 1).join("1") + Array(len - prefixlen + 1).join("0");
1209     return new BigInteger(b, 2).toString(16);
1210 }
1211 
1212 // ==== ucs2hex / utf8 ==============================
1213 
1214 /**
1215  * convert UCS-2 hexadecimal stirng to UTF-8 string<br/>
1216  * @name ucs2hextoutf8
1217  * @function
1218  * @param {String} s hexadecimal string of UCS-2 string (ex. "0066")
1219  * @return {String} UTF-8 string
1220  * @since jsrsasign 10.1.13 base64x 1.1.20
1221  * @description
1222  * This function converts hexadecimal value of UCS-2 string to 
1223  * UTF-8 string.
1224  * @example
1225  * ucs2hextoutf8("006600fc0072") &rarr "für"
1226  */
1227 /*
1228 See: http://nomenclator.la.coocan.jp/unicode/ucs_utf.htm
1229 UCS-2 to UTF-8
1230 UCS-2 code point | UCS-2 bytes       | UTF-8 bytes
1231 U+0000 .. U+007F | 00000000-0xxxxxxx | 0xxxxxxx (1 byte)
1232 U+0080 .. U+07FF | 00000xxx-xxyyyyyy | 110xxxxx 10yyyyyy (2 byte)
1233 U+0800 .. U+FFFF | xxxxyyyy-yyzzzzzz | 1110xxxx 10yyyyyy 10zzzzzz (3 byte)
1234  */
1235 function ucs2hextoutf8(s) {
1236     function _conv(s) {
1237 	var i1 = parseInt(s.substr(0, 2), 16);
1238 	var i2 = parseInt(s.substr(2), 16);
1239 	if (i1 == 0 & i2 < 0x80) { // 1 byte
1240 	    return String.fromCharCode(i2);
1241 	}
1242 	if (i1 < 8) { // 2 bytes
1243 	    var u1 = 0xc0 | ((i1 & 0x07) << 3) | ((i2 & 0xc0) >> 6);
1244 	    var u2 = 0x80 | (i2 & 0x3f);
1245 	    return hextoutf8(u1.toString(16) + u2.toString(16));
1246 	}
1247 	// 3 bytes
1248 	var u1 = 0xe0 | ((i1 & 0xf0) >> 4);
1249 	var u2 = 0x80 | ((i1 & 0x0f) << 2) | ((i2 & 0xc0) >> 6);
1250 	var u3 = 0x80 | (i2 & 0x3f);
1251 	return hextoutf8(u1.toString(16) + u2.toString(16) + u3.toString(16));
1252     }
1253     var a = s.match(/.{4}/g);
1254     var a2 = a.map(_conv);
1255     return a2.join("");
1256 }
1257 
1258 // ==== URIComponent ================================
1259 /**
1260  * convert UTFa hexadecimal string to a URLComponent string such like "%67%68".<br/>
1261  * Note that these "<code>0-9A-Za-z!'()*-._~</code>" characters will not
1262  * converted to "%xx" format by builtin 'encodeURIComponent()' function.
1263  * However this 'encodeURIComponentAll()' function will convert 
1264  * all of characters into "%xx" format.
1265  * @name encodeURIComponentAll
1266  * @function
1267  * @param {String} s hexadecimal string
1268  * @return {String} URIComponent string such like "%67%68"
1269  * @since 1.1
1270  */
1271 function encodeURIComponentAll(u8) {
1272   var s = encodeURIComponent(u8);
1273   var s2 = "";
1274   for (var i = 0; i < s.length; i++) {
1275     if (s[i] == "%") {
1276       s2 = s2 + s.substr(i, 3);
1277       i = i + 2;
1278     } else {
1279       s2 = s2 + "%" + stohex(s[i]);
1280     }
1281   }
1282   return s2;
1283 }
1284 
1285 // ==== new lines ================================
1286 /**
1287  * convert all DOS new line("\r\n") to UNIX new line("\n") in 
1288  * a String "s".
1289  * @name newline_toUnix
1290  * @function
1291  * @param {String} s string 
1292  * @return {String} converted string
1293  */
1294 function newline_toUnix(s) {
1295     s = s.replace(/\r\n/mg, "\n");
1296     return s;
1297 }
1298 
1299 /**
1300  * convert all UNIX new line("\r\n") to DOS new line("\n") in 
1301  * a String "s".
1302  * @name newline_toDos
1303  * @function
1304  * @param {String} s string 
1305  * @return {String} converted string
1306  */
1307 function newline_toDos(s) {
1308     s = s.replace(/\r\n/mg, "\n");
1309     s = s.replace(/\n/mg, "\r\n");
1310     return s;
1311 }
1312 
1313 // ==== string type checker ===================
1314 
1315 /**
1316  * check whether a string is an integer string or not<br/>
1317  * @name isInteger
1318  * @memberOf KJUR.lang.String
1319  * @function
1320  * @static
1321  * @param {String} s input string
1322  * @return {Boolean} true if a string "s" is an integer string otherwise false
1323  * @since base64x 1.1.7 jsrsasign 5.0.13
1324  * @example
1325  * KJUR.lang.String.isInteger("12345") → true
1326  * KJUR.lang.String.isInteger("123ab") → false
1327  */
1328 KJUR.lang.String.isInteger = function(s) {
1329     if (s.match(/^[0-9]+$/)) {
1330 	return true;
1331     } else if (s.match(/^-[0-9]+$/)) {
1332 	return true;
1333     } else {
1334 	return false;
1335     }
1336 };
1337 
1338 /**
1339  * check whether a string is an hexadecimal string or not (DEPRECATED)<br/>
1340  * @name isHex
1341  * @memberOf KJUR.lang.String
1342  * @function
1343  * @static
1344  * @param {String} s input string
1345  * @return {Boolean} true if a string "s" is an hexadecimal string otherwise false
1346  * @since base64x 1.1.7 jsrsasign 5.0.13
1347  * @deprecated from 10.0.6. please use {@link ishex}
1348  * @see ishex
1349  * @example
1350  * KJUR.lang.String.isHex("1234") → true
1351  * KJUR.lang.String.isHex("12ab") → true
1352  * KJUR.lang.String.isHex("12AB") → true
1353  * KJUR.lang.String.isHex("12ZY") → false
1354  * KJUR.lang.String.isHex("121") → false -- odd length
1355  */
1356 KJUR.lang.String.isHex = function(s) {
1357     return ishex(s);
1358 };
1359 
1360 /**
1361  * check whether a string is an hexadecimal string or not<br/>
1362  * @name ishex
1363  * @function
1364  * @static
1365  * @param {String} s input string
1366  * @return {Boolean} true if a string "s" is an hexadecimal string otherwise false
1367  * @since base64x 1.1.7 jsrsasign 5.0.13
1368  * @example
1369  * ishex("1234") → true
1370  * ishex("12ab") → true
1371  * ishex("12AB") → true
1372  * ishex("12ZY") → false
1373  * ishex("121") → false -- odd length
1374  */
1375 function ishex(s) {
1376     if (s.length % 2 == 0 &&
1377 	(s.match(/^[0-9a-f]+$/) || s.match(/^[0-9A-F]+$/))) {
1378 	return true;
1379     } else {
1380 	return false;
1381     }
1382 };
1383 
1384 /**
1385  * check whether a string is a base64 encoded string or not<br/>
1386  * Input string can conclude new lines or space characters.
1387  * @name isBase64
1388  * @memberOf KJUR.lang.String
1389  * @function
1390  * @static
1391  * @param {String} s input string
1392  * @return {Boolean} true if a string "s" is a base64 encoded string otherwise false
1393  * @since base64x 1.1.7 jsrsasign 5.0.13
1394  * @example
1395  * KJUR.lang.String.isBase64("YWE=") → true
1396  * KJUR.lang.String.isBase64("YW_=") → false
1397  * KJUR.lang.String.isBase64("YWE") → false -- length shall be multiples of 4
1398  */
1399 KJUR.lang.String.isBase64 = function(s) {
1400     s = s.replace(/\s+/g, "");
1401     if (s.match(/^[0-9A-Za-z+\/]+={0,3}$/) && s.length % 4 == 0) {
1402 	return true;
1403     } else {
1404 	return false;
1405     }
1406 };
1407 
1408 /**
1409  * check whether a string is a base64url encoded string or not<br/>
1410  * Input string can conclude new lines or space characters.
1411  * @name isBase64URL
1412  * @memberOf KJUR.lang.String
1413  * @function
1414  * @static
1415  * @param {String} s input string
1416  * @return {Boolean} true if a string "s" is a base64url encoded string otherwise false
1417  * @since base64x 1.1.7 jsrsasign 5.0.13
1418  * @example
1419  * KJUR.lang.String.isBase64URL("YWE") → true
1420  * KJUR.lang.String.isBase64URL("YW-") → true
1421  * KJUR.lang.String.isBase64URL("YW+") → false
1422  */
1423 KJUR.lang.String.isBase64URL = function(s) {
1424     if (s.match(/[+/=]/)) return false;
1425     s = b64utob64(s);
1426     return KJUR.lang.String.isBase64(s);
1427 };
1428 
1429 
1430 /**
1431  * check whether a string is a base64url encoded string and dot or not<br/>
1432  * Input string can conclude new lines or space characters.
1433  * @name isBase64URLDot
1434  * @function
1435  * @static
1436  * @param {String} s input string
1437  * @return {Boolean} true if a string "s" is a base64url encoded string and dot otherwise false
1438  * @since base64x 1.1.30 jsrsasign 10.5.25
1439  * @example
1440  * isBase64URLDot("YWE") → true
1441  * isBase64URLDot("YWE.YWE.YWE") → true
1442  * isBase64URLDot("YW-") → true
1443  * isBase64URLDot("YW+") → false
1444  */
1445 function isBase64URLDot(s) {
1446     if (s.match(/^[0-9A-Za-z-_.]+$/)) return true;
1447     return false;
1448 }
1449 
1450 /**
1451  * check whether a string is a string of integer array or not<br/>
1452  * Input string can conclude new lines or space characters.
1453  * @name isIntegerArray
1454  * @memberOf KJUR.lang.String
1455  * @function
1456  * @static
1457  * @param {String} s input string
1458  * @return {Boolean} true if a string "s" is a string of integer array otherwise false
1459  * @since base64x 1.1.7 jsrsasign 5.0.13
1460  * @example
1461  * KJUR.lang.String.isIntegerArray("[1,2,3]") → true
1462  * KJUR.lang.String.isIntegerArray("  [1, 2, 3  ] ") → true
1463  * KJUR.lang.String.isIntegerArray("[a,2]") → false
1464  */
1465 KJUR.lang.String.isIntegerArray = function(s) {
1466     s = s.replace(/\s+/g, "");
1467     if (s.match(/^\[[0-9,]+\]$/)) {
1468 	return true;
1469     } else {
1470 	return false;
1471     }
1472 };
1473 
1474 /**
1475  * check whether a string consists of PrintableString characters<br/>
1476  * @name isPrintable
1477  * @memberOf KJUR.lang.String
1478  * @function
1479  * @static
1480  * @param {String} s input string
1481  * @return {Boolean} true if a string "s" consists of PrintableString characters
1482  * @since jsrsasign 9.0.0 base64x 1.1.16
1483  * A PrintableString consists of following characters
1484  * <pre>
1485  * 0-9A-Za-z '()+,-./:=?
1486  * </pre>
1487  * This method returns false when other characters than above.
1488  * Otherwise it returns true.
1489  * @example
1490  * KJUR.lang.String.isPrintable("abc") → true
1491  * KJUR.lang.String.isPrintable("abc@") → false
1492  * KJUR.lang.String.isPrintable("あいう") → false
1493  */
1494 KJUR.lang.String.isPrintable = function(s) {
1495     if (s.match(/^[0-9A-Za-z '()+,-./:=?]*$/) !== null) return true;
1496     return false;
1497 };
1498 
1499 /**
1500  * check whether a string consists of IAString characters<br/>
1501  * @name isIA5
1502  * @memberOf KJUR.lang.String
1503  * @function
1504  * @static
1505  * @param {String} s input string
1506  * @return {Boolean} true if a string "s" consists of IA5String characters
1507  * @since jsrsasign 9.0.0 base64x 1.1.16
1508  * A IA5String consists of following characters
1509  * <pre>
1510  * %x00-21/%x23-7F (i.e. ASCII characters excludes double quote(%x22)
1511  * </pre>
1512  * This method returns false when other characters than above.
1513  * Otherwise it returns true.
1514  * @example
1515  * KJUR.lang.String.isIA5("abc") → true
1516  * KJUR.lang.String.isIA5('"abc"') → false
1517  * KJUR.lang.String.isIA5("あいう") → false
1518  */
1519 KJUR.lang.String.isIA5 = function(s) {
1520     if (s.match(/^[\x20-\x21\x23-\x7f]*$/) !== null) return true;
1521     return false;
1522 };
1523 
1524 /**
1525  * check whether a string is RFC 822 mail address<br/>
1526  * @name isMail
1527  * @memberOf KJUR.lang.String
1528  * @function
1529  * @static
1530  * @param {String} s input string
1531  * @return {Boolean} true if a string "s" RFC 822 mail address
1532  * @since jsrsasign 9.0.0 base64x 1.1.16
1533  * This static method will check string s is RFC 822 compliant mail address.
1534  * @example
1535  * KJUR.lang.String.isMail("abc") → false
1536  * KJUR.lang.String.isMail("abc@example") → false
1537  * KJUR.lang.String.isMail("abc@example.com") → true
1538  */
1539 KJUR.lang.String.isMail = function(s) {
1540     if (s.match(/^[A-Za-z0-9]{1}[A-Za-z0-9_.-]*@{1}[A-Za-z0-9_.-]{1,}\.[A-Za-z0-9]{1,}$/) !== null) return true;
1541     return false;
1542 };
1543 
1544 // ==== others ================================
1545 
1546 /**
1547  * canonicalize hexadecimal string of positive integer<br/>
1548  * @name hextoposhex
1549  * @function
1550  * @param {String} s hexadecimal string 
1551  * @return {String} canonicalized hexadecimal string of positive integer
1552  * @since base64x 1.1.10 jsrsasign 7.1.4
1553  * @description
1554  * This method canonicalize a hexadecimal string of positive integer
1555  * for two's complement representation.
1556  * Canonicalized hexadecimal string of positive integer will be:
1557  * <ul>
1558  * <li>Its length is always even.</li>
1559  * <li>If odd length it will be padded with leading zero.<li>
1560  * <li>If it is even length and its first character is "8" or greater,
1561  * it will be padded with "00" to make it positive integer.</li>
1562  * </ul>
1563  * @example
1564  * hextoposhex("abcd") → "00abcd"
1565  * hextoposhex("1234") → "1234"
1566  * hextoposhex("12345") → "012345"
1567  */
1568 function hextoposhex(s) {
1569     if (s.length % 2 == 1) return "0" + s;
1570     if (s.substr(0, 1) > "7") return "00" + s;
1571     return s;
1572 }
1573 
1574 /**
1575  * convert string of integer array to hexadecimal string.<br/>
1576  * @name intarystrtohex
1577  * @function
1578  * @param {String} s string of integer array
1579  * @return {String} hexadecimal string
1580  * @since base64x 1.1.6 jsrsasign 5.0.2
1581  * @throws "malformed integer array string: *" for wrong input
1582  * @description
1583  * This function converts a string of JavaScript integer array to
1584  * a hexadecimal string. Each integer value shall be in a range 
1585  * from 0 to 255 otherwise it raise exception. Input string can
1586  * have extra space or newline string so that they will be ignored.
1587  * 
1588  * @example
1589  * intarystrtohex(" [123, 34, 101, 34, 58] ")
1590  * → 7b2265223a (i.e. '{"e":' as string)
1591  */
1592 function intarystrtohex(s) {
1593   s = s.replace(/^\s*\[\s*/, '');
1594   s = s.replace(/\s*\]\s*$/, '');
1595   s = s.replace(/\s*/g, '');
1596   try {
1597     var hex = s.split(/,/).map(function(element, index, array) {
1598       var i = parseInt(element);
1599       if (i < 0 || 255 < i) throw "integer not in range 0-255";
1600       var hI = ("00" + i.toString(16)).slice(-2);
1601       return hI;
1602     }).join('');
1603     return hex;
1604   } catch(ex) {
1605     throw "malformed integer array string: " + ex;
1606   }
1607 }
1608 
1609 /**
1610  * find index of string where two string differs
1611  * @name strdiffidx
1612  * @function
1613  * @param {String} s1 string to compare
1614  * @param {String} s2 string to compare
1615  * @return {Number} string index of where character differs. Return -1 if same.
1616  * @since jsrsasign 4.9.0 base64x 1.1.5
1617  * @example
1618  * strdiffidx("abcdefg", "abcd4fg") -> 4
1619  * strdiffidx("abcdefg", "abcdefg") -> -1
1620  * strdiffidx("abcdefg", "abcdef") -> 6
1621  * strdiffidx("abcdefgh", "abcdef") -> 6
1622  */
1623 var strdiffidx = function(s1, s2) {
1624     var n = s1.length;
1625     if (s1.length > s2.length) n = s2.length;
1626     for (var i = 0; i < n; i++) {
1627 	if (s1.charCodeAt(i) != s2.charCodeAt(i)) return i;
1628     }
1629     if (s1.length != s2.length) return n;
1630     return -1; // same
1631 };
1632 
1633 // ==== hex / oid =================================
1634 
1635 /**
1636  * get hexadecimal value of object identifier from dot noted oid value
1637  * @name oidtohex
1638  * @function
1639  * @param {String} oidString dot noted string of object identifier
1640  * @return {String} hexadecimal value of object identifier
1641  * @since jsrsasign 10.1.0 base64x 1.1.18
1642  * @see hextooid
1643  * @see ASN1HEX.hextooidstr
1644  * @see KJUR.asn1.ASN1Util.oidIntToHex
1645  * @description
1646  * This static method converts from object identifier value string.
1647  * to hexadecimal string representation of it.
1648  * {@link hextooid} is a reverse function of this.
1649  * @example
1650  * oidtohex("2.5.4.6") → "550406"
1651  */
1652 function oidtohex(oidString) {
1653     var itox = function(i) {
1654         var h = i.toString(16);
1655         if (h.length == 1) h = '0' + h;
1656         return h;
1657     };
1658 
1659     var roidtox = function(roid) {
1660         var h = '';
1661         var bi = parseInt(roid, 10);
1662         var b = bi.toString(2);
1663 
1664         var padLen = 7 - b.length % 7;
1665         if (padLen == 7) padLen = 0;
1666         var bPad = '';
1667         for (var i = 0; i < padLen; i++) bPad += '0';
1668         b = bPad + b;
1669         for (var i = 0; i < b.length - 1; i += 7) {
1670             var b8 = b.substr(i, 7);
1671             if (i != b.length - 7) b8 = '1' + b8;
1672             h += itox(parseInt(b8, 2));
1673         }
1674         return h;
1675     };
1676     
1677     try {
1678 	if (! oidString.match(/^[0-9.]+$/)) return null;
1679     
1680 	var h = '';
1681 	var a = oidString.split('.');
1682 	var i0 = parseInt(a[0], 10) * 40 + parseInt(a[1], 10);
1683 	h += itox(i0);
1684 	a.splice(0, 2);
1685 	for (var i = 0; i < a.length; i++) {
1686             h += roidtox(a[i]);
1687 	}
1688 	return h;
1689     } catch(ex) {
1690 	return null;
1691     }
1692 };
1693 
1694 /**
1695  * get oid string from hexadecimal value of object identifier<br/>
1696  * @name hextooid
1697  * @function
1698  * @param {String} h hexadecimal value of object identifier
1699  * @return {String} dot noted string of object identifier (ex. "1.2.3.4")
1700  * @since jsrsasign 10.1.0 base64x 1.1.18
1701  * @see oidtohex
1702  * @see ASN1HEX.hextooidstr
1703  * @see KJUR.asn1.ASN1Util.oidIntToHex
1704  * @description
1705  * This static method converts from hexadecimal object identifier value 
1706  * to dot noted OID value (ex. "1.2.3.4").
1707  * {@link oidtohex} is a reverse function of this.
1708  * @example
1709  * hextooid("550406") → "2.5.4.6"
1710  */
1711 function hextooid(h) {
1712     if (! ishex(h)) return null;
1713     try {
1714 	var a = [];
1715 
1716 	// a[0], a[1]
1717 	var hex0 = h.substr(0, 2);
1718 	var i0 = parseInt(hex0, 16);
1719 	a[0] = new String(Math.floor(i0 / 40));
1720 	a[1] = new String(i0 % 40);
1721 
1722 	// a[2]..a[n]
1723 	var hex1 = h.substr(2);
1724 	var b = [];
1725 	for (var i = 0; i < hex1.length / 2; i++) {
1726 	    b.push(parseInt(hex1.substr(i * 2, 2), 16));
1727 	}
1728 	var c = [];
1729 	var cbin = "";
1730 	for (var i = 0; i < b.length; i++) {
1731             if (b[i] & 0x80) {
1732 		cbin = cbin + strpad((b[i] & 0x7f).toString(2), 7);
1733             } else {
1734 		cbin = cbin + strpad((b[i] & 0x7f).toString(2), 7);
1735 		c.push(new String(parseInt(cbin, 2)));
1736 		cbin = "";
1737             }
1738 	}
1739 
1740 	var s = a.join(".");
1741 	if (c.length > 0) s = s + "." + c.join(".");
1742 	return s;
1743     } catch(ex) {
1744 	return null;
1745     }
1746 };
1747 
1748 // ==== int / hex =================================
1749 /**
1750  * get hexadecimal string of minimum two's complement of integer<br/>
1751  * @name inttohex
1752  * @function
1753  * @param {number} i integer value
1754  * @return {string} hexadecimal string of two's complement of the integer
1755  * @since jsrsasign 10.9.0 base64x 1.1.34
1756  * @see twoscompl
1757  * @see DERInteger
1758  *
1759  * @description
1760  * This static method converts from integer value to a minimum length 
1761  * hexadecimal string of two's complement of the integer.
1762  * This method is useful for {@link DERInteger}.
1763  *
1764  * @example
1765  * inttohex(1) → "01"
1766  * inttohex(-1) → "ff"
1767  * inttohex(2048) → "0800"
1768  * inttohex(-2048) → "f800"
1769  */
1770 function inttohex(i) {
1771     var bi = new BigInteger(String(i), 10);
1772     return twoscompl(bi);
1773 }
1774 
1775 /**
1776  * get hexadecimal string of minimum two's complement of BigInteger<br/>
1777  * @name twoscompl
1778  * @function
1779  * @param {BigInteger} bi BigInteger object
1780  * @return {string} hexadecimal string of two's complement of the integer
1781  * @since jsrsasign 10.9.0 base64x 1.1.34
1782  * @see inttohex
1783  *
1784  * @description
1785  * This static method converts from a BigInteger object to a minimum length
1786  * hexadecimal string of two's complement of the integer.
1787  * <br/>
1788  * NOTE: This function is a replacement of deprecated ASN1Util.bigIntToMinTwosComplementsHex method.
1789  *
1790  * @example
1791  * twoscompl(new BigInteger("1", 10)) → "01"
1792  * twoscompl(new BigInteger("-1", 10)) → "ff"
1793  */
1794 function twoscompl(bi) {
1795     var h = bi.toString(16);
1796     // positive
1797     if (h.substr(0, 1) != '-') {
1798 	if (h.length % 2 == 1) {
1799 	    h = '0' + h;
1800 	} else {
1801 	    if (! h.match(/^[0-7]/)) {
1802 		h = '00' + h;
1803 	    }
1804 	}
1805 	return h;
1806     }
1807     // negative
1808     var hPos = h.substr(1);
1809     var xorLen = hPos.length;
1810     if (xorLen % 2 == 1) {
1811         xorLen += 1;
1812     } else {
1813         if (! h.match(/^[0-7]/)) {
1814             xorLen += 2;
1815         }
1816     }
1817     var hMask = '';
1818     for (var i = 0; i < xorLen; i++) {
1819         hMask += 'f';
1820     }
1821     var biMask = new BigInteger(hMask, 16);
1822     var biNeg = biMask.xor(bi).add(BigInteger.ONE);
1823     h = biNeg.toString(16).replace(/^-/, '');
1824     return h;
1825 }
1826 
1827 /**
1828  * string padding<br/>
1829  * @name strpad
1830  * @function
1831  * @param {String} s input string
1832  * @param {Number} len output string length
1833  * @param {String} padchar padding character (default is "0")
1834  * @return {String} padded string
1835  * @since jsrsasign 10.1.0 base64x 1.1.18
1836  * @example
1837  * strpad("1234", 10, "0") → "0000001234"
1838  * strpad("1234", 10, " ") → "      1234"
1839  * strpad("1234", 10)      → "0000001234"
1840  */
1841 var strpad = function(s, len, padchar) {
1842     if (padchar == undefined) padchar = "0";
1843     if (s.length >= len) return s;
1844     return new Array(len - s.length + 1).join(padchar) + s;
1845 };
1846 
1847 // ==== bitstr hex / int =================================
1848 
1849 /**
1850  * convert from hexadecimal string of ASN.1 BitString value with unused bit to integer value<br/>
1851  * @name bitstrtoint
1852  * @function
1853  * @param {String} h hexadecimal string of ASN.1 BitString value with unused bit
1854  * @return {Number} positive integer value of the BitString
1855  * @since jsrsasign 10.1.3 base64x 1.1.19
1856  * @see inttobitstr
1857  * @see KJUR.asn1.DERBitString
1858  * @see ASN1HEX.getInt
1859  * 
1860  * @description
1861  * This function converts from hexadecimal string of ASN.1 BitString
1862  * value with unused bit to its integer value. <br/>
1863  * When an improper hexadecimal string of BitString value
1864  * is applied, this returns -1.
1865  * 
1866  * @example
1867  * // "03c8" → 0xc8 unusedbit=03 → 11001000b unusedbit=03 → 11001b → 25
1868  * bitstrtoint("03c8") → 25
1869  * // "02fff8" → 0xfff8 unusedbit=02 → 1111111111111000b unusedbit=02
1870  * //   11111111111110b → 16382
1871  * bitstrtoint("02fff8") → 16382
1872  * bitstrtoint("05a0") → 5 (=101b)
1873  * bitstrtoint("ff00") → -1 // for improper BitString value
1874  * bitstrtoint("05a0").toString(2) → "101"
1875  * bitstrtoint("07a080").toString(2) → "101000001"
1876  */
1877 function bitstrtoint(h) {
1878     if (h.length % 2 != 0) return -1; 
1879     h = h.toLowerCase();
1880     if (h.match(/^[0-9a-f]+$/) == null) return -1;
1881     try {
1882 	var hUnusedbit = h.substr(0, 2);
1883 	if (hUnusedbit == "00")
1884 	    return parseInt(h.substr(2), 16);
1885 	var iUnusedbit = parseInt(hUnusedbit, 16);
1886 	if (iUnusedbit > 7) return -1;
1887 	var hValue = h.substr(2);
1888 	var bValue = parseInt(hValue, 16).toString(2);
1889 	if (bValue == "0") bValue = "00000000";
1890 	bValue = bValue.slice(0, 0 - iUnusedbit);
1891 	var iValue = parseInt(bValue, 2);
1892 	if (iValue == NaN) return -1;
1893 	return iValue;
1894     } catch(ex) {
1895 	return -1;
1896     }
1897 };
1898 
1899 /**
1900  * convert from integer value to hexadecimal string of ASN.1 BitString value with unused bit<br/>
1901  * @name inttobitstr
1902  * @function
1903  * @param {Number} n integer value of ASN.1 BitString
1904  * @return {String} hexadecimal string of ASN.1 BitString value with unused bit
1905  * @since jsrsasign 10.1.3 base64x 1.1.19
1906  * @see bitstrtoint
1907  * @see KJUR.asn1.DERBitString
1908  * @see ASN1HEX.getInt
1909  * 
1910  * @description
1911  * This function converts from an integer value to 
1912  * hexadecimal string of ASN.1 BitString value
1913  * with unused bit. <br/>
1914  * When "n" is not non-negative number, this returns null
1915  * 
1916  * @example
1917  * // 25 → 11001b → 11001000b unusedbit=03 → 0xc8 unusedbit=03 → "03c8"
1918  * inttobitstr(25) → "03c8"
1919  * inttobitstr(-3) → null
1920  * inttobitstr("abc") → null
1921  * inttobitstr(parseInt("11001", 2)) → "03c8"
1922  * inttobitstr(parseInt("101", 2)) → "05a0"
1923  * inttobitstr(parseInt("101000001", 2)) → "07a080"
1924  */
1925 function inttobitstr(n) {
1926     if (typeof n != "number") return null;
1927     if (n < 0) return null;
1928     var bValue = Number(n).toString(2);
1929     var iUnusedbit = 8 - bValue.length % 8;
1930     if (iUnusedbit == 8) iUnusedbit = 0;
1931     bValue = bValue + strpad("", iUnusedbit, "0");
1932     var hValue = parseInt(bValue, 2).toString(16);
1933     if (hValue.length % 2 == 1) hValue = "0" + hValue;
1934     var hUnusedbit = "0" + iUnusedbit;
1935     return hUnusedbit + hValue;
1936 };
1937 
1938 // ==== bitstr hex / binary string =======================
1939 
1940 /**
1941  * convert from hexadecimal string of ASN.1 BitString value with unused bit to binary string<br/>
1942  * @name bitstrtobinstr
1943  * @function
1944  * @param {string} h hexadecimal string of ASN.1 BitString value with unused bit
1945  * @return {string} binary string
1946  * @since jsrsasign 10.5.4 base64x 1.1.21
1947  * @see binstrtobitstr
1948  * @see inttobitstr
1949  * 
1950  * @description
1951  * This function converts from hexadecimal string of ASN.1 BitString
1952  * value with unused bit to its integer value. <br/>
1953  * When an improper hexadecimal string of BitString value
1954  * is applied, this returns null.
1955  * 
1956  * @example
1957  * bitstrtobinstr("05a0") → "101"
1958  * bitstrtobinstr("0520") → "001"
1959  * bitstrtobinstr("07a080") → "101000001"
1960  * bitstrtobinstr(502) → null // non ASN.1 BitString value
1961  * bitstrtobinstr("ff00") → null // for improper BitString value
1962  */
1963 function bitstrtobinstr(h) {
1964     if (typeof h != "string") return null;
1965     if (h.length % 2 != 0) return null;
1966     if (! h.match(/^[0-9a-f]+$/)) return null;
1967     try {
1968 	var unusedBits = parseInt(h.substr(0, 2), 16);
1969 	if (unusedBits < 0 || 7 < unusedBits) return null
1970 
1971 	var value = h.substr(2);
1972 	var bin = "";
1973 	for (var i = 0; i < value.length; i += 2) {
1974 	    var hi = value.substr(i, 2);
1975 	    var bi = parseInt(hi, 16).toString(2);
1976 	    bi = ("0000000" + bi).slice(-8);
1977 	    bin += bi;
1978 	}
1979 	return  bin.substr(0, bin.length - unusedBits);
1980     } catch(ex) {
1981 	return null;
1982     }
1983 }
1984 
1985 /**
1986  * convert from binary string to hexadecimal string of ASN.1 BitString value with unused bit<br/>
1987  * @name binstrtobitstr
1988  * @function
1989  * @param {string} s binary string (ex. "101")
1990  * @return {string} hexadecimal string of ASN.1 BitString value with unused bit
1991  * @since jsrsasign 10.5.4 base64x 1.1.21
1992  * @see bitstrtobinstr
1993  * @see inttobitstr
1994  * @see KJUR.asn1.DERBitString
1995  * 
1996  * @description
1997  * This function converts from an binary string (ex. "101") to 
1998  * hexadecimal string of ASN.1 BitString value
1999  * with unused bit (ex. "05a0"). <br/>
2000  * When "s" is not binary string, this returns null.
2001  * 
2002  * @example
2003  * binstrtobitstr("101") → "05a0"
2004  * binstrtobitstr("001") → "0520"
2005  * binstrtobitstr("11001") → "03c8"
2006  * binstrtobitstr("101000001") → "07a080"
2007  * binstrtobitstr(101) → null // not number
2008  * binstrtobitstr("xyz") → null // not binary string
2009  */
2010 function binstrtobitstr(s) {
2011     if (typeof s != "string") return null;
2012     if (s.match(/^[01]+$/) == null) return null;
2013     try {
2014 	var n = parseInt(s, 2);
2015 	return inttobitstr(n);
2016     } catch(ex) {
2017 	return null;
2018     }
2019 }
2020 
2021 // =======================================================
2022 /**
2023  * convert array of names to bit string<br/>
2024  * @name namearraytobinstr
2025  * @function
2026  * @param {array} namearray array of name string
2027  * @param {object} namedb associative array of name and value
2028  * @return {string} binary string (ex. "110001")
2029  * @since jsrsasign 10.5.21 base64x 1.1.27
2030  * @see KJUR.asn1.x509.KeyUsage
2031  * @see KJUR.asn1.tsp.PKIFailureInfo
2032  * 
2033  * @description
2034  * This function converts from an array of names to
2035  * a binary string. DB value bit will be set.
2036  * Note that ordering of namearray items
2037  * will be ignored.
2038  *
2039  * @example
2040  * db = { a: 0, b: 3, c: 8, d: 9, e: 17, f: 19 };
2041  * namearraytobinstr(['a', 'c', 'd'], db) &rarr: '1000000011'
2042  * namearraytobinstr(['c', 'b'], db) &rarr: '000100001'
2043  */
2044 function namearraytobinstr (namearray, namedb) {
2045     var d = 0;
2046     for (var i = 0; i < namearray.length; i++) {
2047 	d |= 1 << namedb[namearray[i]];
2048     }
2049 
2050     var s = d.toString(2);
2051     var r = "";
2052     for (var i = s.length - 1; i >=0; i--) {
2053 	r += s[i];
2054     }
2055     return r;
2056 }
2057 
2058 /**
2059  * get value of array by key name list<br/>
2060  * @function
2061  * @param {object} val array of associative array
2062  * @param {string} keys concatinated key list with dot (ex. 'type.name.0.info')
2063  * @param {object} def default value if value is not found (OPTIONAL)
2064  * @return {object} value if found otherwise returns def
2065  * @since jsrsasign 10.8.0 base64x 1.1.32
2066  *
2067  * @description
2068  * This function returns the value of an array or associative array 
2069  * which referred by a concatinated key list string.
2070  * If a value for key is not defined, it returns 'undefined' by default.
2071  * When an optional argument 'def' is specified and a value for key is
2072  * not defined, it returns a value of 'def'.
2073  * 
2074  * @example
2075  * let p = {
2076  *   fruit: apple,
2077  *   info: [
2078  *     { toy: 4 },
2079  *     { pen: 6 }
2080  *   ]
2081  * };
2082  * aryval(p, 'fruit') &rarr "apple"
2083  * aryval(p, 'info') &rarr [{toy: 4},{pen: 6}]
2084  * aryval(p, 'info.1') &rarr {pen: 6}
2085  * aryval(p, 'info.1.pen') &rarr 6
2086  * aryval(p, 'money.amount') &rarr undefined
2087  * aryval(p, 'money.amount', null) &rarr null
2088  */
2089 function aryval(val, keys, def) {
2090     if (typeof val != "object") return undefined
2091     var keys = String(keys).split('.');
2092     for (var i = 0; i < keys.length && val; i++) {
2093 	var key = keys[i];
2094 	if (key.match(/^[0-9]+$/)) key = parseInt(key);
2095         val = val[key];
2096     }
2097     return val || val === false ? val : def;
2098 }
2099 
2100 
2101 // =======================================================
2102 /**
2103  * set class inheritance<br/>
2104  * @name extendClass
2105  * @function
2106  * @param {Function} subClass sub class to set inheritance
2107  * @param {Function} superClass super class to inherit
2108  * @since jsrsasign 10.3.0 base64x 1.1.21
2109  *
2110  * @description
2111  * This function extends a class and set an inheritance
2112  * for member variables and methods.
2113  *
2114  * @example
2115  * var Animal = function() {
2116  *   this.hello = function(){console.log("Hello")};
2117  *   this.name="Ani";
2118  * };
2119  * var Dog = function() {
2120  *   Dog.superclass.constructor.call(this);
2121  *   this.vow = function(){console.log("Vow wow")};
2122  *   this.tail=true;
2123  * };
2124  * extendClass(Dog, Animal);
2125  */
2126 function extendClass(subClass, superClass) {
2127     var F = function() {};
2128     F.prototype = superClass.prototype;
2129     subClass.prototype = new F();
2130     subClass.prototype.constructor = subClass;
2131     subClass.superclass = superClass.prototype;
2132      
2133     if (superClass.prototype.constructor == Object.prototype.constructor) {
2134         superClass.prototype.constructor = superClass;
2135     }
2136 };
2137 
2138