1 /* base64x-1.1.31 (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.7.0 base64x 1.1.31 (2023-Mar-11)
 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     return s.replace(new RegExp('(.{' + n + '})', 'g'), "$1\r\n");
537 }
538 
539 /**
540  * convert a Base64 encoded string with new lines to a hexadecimal string<br/>
541  * @name b64nltohex
542  * @function
543  * @param {String} s Base64 encoded string with new lines
544  * @return {String} hexadecimal string
545  * @since base64x 1.1.3
546  * @description
547  * This function converts from a Base64 encoded
548  * string with new lines to a hexadecimal string.
549  * This is useful to handle PEM encoded file.
550  * This function removes any non-Base64 characters (i.e. not 0-9,A-Z,a-z,\,+,=)
551  * including new line.
552  * @example
553  * hextob64nl(
554  * "MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4\r\n" +
555  * "OTAxMjM0NTY3ODkwCg==\r\n")
556  * →
557  * "123456789012345678901234567890123456789012345678901234567890"
558  */
559 function b64nltohex(s) {
560     var b64 = s.replace(/[^0-9A-Za-z\/+=]*/g, '');
561     var hex = b64tohex(b64);
562     return hex;
563 } 
564 
565 // ==== b64 / pem =========================================
566 /**
567  * get PEM string from Base64 string
568  * @name b64topem
569  * @function
570  * @param {string} b64 Base64 string of PEM body
571  * @param {string} pemHeader PEM header string (ex. 'RSA PRIVATE KEY')
572  * @return {string} PEM formatted string of input data
573  * @since jsrasign 10.7.0 base64x 1.1.31
574  * @description
575  * This function converts a Base64 string to a PEM string with
576  * a specified header. Its line break will be CRLF("\r\n").
577  * @example
578  * b64topem('YWFh', 'RSA PRIVATE KEY') →
579  * -----BEGIN PRIVATE KEY-----
580  * YWFh
581  * -----END PRIVATE KEY-----
582  */
583 function b64topem(b64, pemHeader) {
584     return "-----BEGIN " + pemHeader + "-----\r\n" + 
585 	foldnl(b64, 64) +
586         "\r\n-----END " + pemHeader + "-----\r\n";
587 }
588 
589 
590 
591 // ==== hex / pem =========================================
592 
593 /**
594  * get PEM string from hexadecimal data and header string
595  * @name hextopem
596  * @function
597  * @param {String} dataHex hexadecimal string of PEM body
598  * @param {String} pemHeader PEM header string (ex. 'RSA PRIVATE KEY')
599  * @return {String} PEM formatted string of input data
600  * @since jsrasign 7.2.1 base64x 1.1.12
601  * @description
602  * This function converts a hexadecimal string to a PEM string with
603  * a specified header. Its line break will be CRLF("\r\n").
604  * @example
605  * hextopem('616161', 'RSA PRIVATE KEY') →
606  * -----BEGIN PRIVATE KEY-----
607  * YWFh
608  * -----END PRIVATE KEY-----
609  */
610 function hextopem(dataHex, pemHeader) {
611     return "-----BEGIN " + pemHeader + "-----\r\n" + 
612 	foldnl(hextob64(dataHex), 64) +
613         "\r\n-----END " + pemHeader + "-----\r\n";
614 }
615 
616 /**
617  * get hexacedimal string from PEM format data<br/>
618  * @name pemtohex
619  * @function
620  * @param {String} s PEM formatted string
621  * @param {String} sHead PEM header string without BEGIN/END(OPTION)
622  * @return {String} hexadecimal string data of PEM contents
623  * @since jsrsasign 7.2.1 base64x 1.1.12
624  *
625  * @description
626  * This static method gets a hexacedimal string of contents 
627  * from PEM format data. You can explicitly specify PEM header 
628  * by sHead argument. 
629  * Any space characters such as white space or new line
630  * will be omitted.<br/>
631  * NOTE: Now {@link KEYUTIL.getHexFromPEM} and {@link X509.pemToHex}
632  * have been deprecated since jsrsasign 7.2.1. <br/>
633  * Please use this method instead.
634  * NOTE2: From jsrsasign 8.0.14 this can process multi
635  * "BEGIN...END" section such as "EC PRIVATE KEY" with "EC PARAMETERS".<br/>
636  *
637  * @example
638  * pemtohex("-----BEGIN PUBLIC KEY...") → "3082..."
639  * pemtohex("-----BEGIN CERTIFICATE...", "CERTIFICATE") → "3082..."
640  * pemtohex(" \r\n-----BEGIN DSA PRIVATE KEY...") → "3082..."
641  * pemtohex("-----BEGIN EC PARAMETERS...----BEGIN EC PRIVATE KEY...." → "3082..."
642  */
643 function pemtohex(s, sHead) {
644     if (s.indexOf("-----BEGIN ") == -1)
645         throw new Error("can't find PEM header");
646 
647     if (sHead !== undefined) {
648         s = s.replace(new RegExp('^[^]*-----BEGIN ' + sHead + '-----'), '');
649         s = s.replace(new RegExp('-----END ' + sHead + '-----[^]*$'), '');
650     } else {
651         s = s.replace(/^[^]*-----BEGIN [^-]+-----/, '');
652         s = s.replace(/-----END [^-]+-----[^]*$/, '');
653     }
654     return b64nltohex(s);
655 }
656 
657 /**
658  * get Base64 string from PEM format data<br/>
659  * @name pemtob64
660  * @function
661  * @param {string} s PEM formatted string
662  * @return {string} Base64 string or null
663  * @since jsrsasign 10.7.0 base64x 1.1.31
664  *
665  * @description
666  * This static method gets a Base64 string of contents 
667  * from PEM format data.
668  * When s is not PEM data, it returns null.
669  *
670  * @example
671  * pemtohex("-----BEGIN CERTIFICATE...", "CERTIFICATE") → "MIIBvTCC..."
672  */
673 function pemtob64(s) {
674     if (s.indexOf("-----BEGIN ") == -1 ||
675         s.indexOf("-----END ") == -1 ) return null;
676     s = s.replace(/^[\s\S]*?-----BEGIN [^-]+-----/m, '');
677     s = s.replace(/-----END [\s\S]+$/m, '');
678     s = s.replace(/\s+/g, '');
679     return (s.match(/^[0-9a-zA-Z+/=]+$/)) ? s : null;
680 }
681 
682 // ==== hex / ArrayBuffer =================================
683 
684 /**
685  * convert a hexadecimal string to an ArrayBuffer<br/>
686  * @name hextoArrayBuffer
687  * @function
688  * @param {String} hex hexadecimal string
689  * @return {ArrayBuffer} ArrayBuffer
690  * @since jsrsasign 6.1.4 base64x 1.1.8
691  * @description
692  * This function converts from a hexadecimal string to an ArrayBuffer.
693  * @example
694  * hextoArrayBuffer("fffa01") → ArrayBuffer of [255, 250, 1]
695  */
696 function hextoArrayBuffer(hex) {
697     if (hex.length % 2 != 0) throw "input is not even length";
698     if (hex.match(/^[0-9A-Fa-f]+$/) == null) throw "input is not hexadecimal";
699 
700     var buffer = new ArrayBuffer(hex.length / 2);
701     var view = new DataView(buffer);
702 
703     for (var i = 0; i < hex.length / 2; i++) {
704 	view.setUint8(i, parseInt(hex.substr(i * 2, 2), 16));
705     }
706 
707     return buffer;
708 }
709 
710 // ==== ArrayBuffer / hex =================================
711 
712 /**
713  * convert an ArrayBuffer to a hexadecimal string<br/>
714  * @name ArrayBuffertohex
715  * @function
716  * @param {ArrayBuffer} buffer ArrayBuffer
717  * @return {String} hexadecimal string
718  * @since jsrsasign 6.1.4 base64x 1.1.8
719  * @description
720  * This function converts from an ArrayBuffer to a hexadecimal string.
721  * @example
722  * var buffer = new ArrayBuffer(3);
723  * var view = new DataView(buffer);
724  * view.setUint8(0, 0xfa);
725  * view.setUint8(1, 0xfb);
726  * view.setUint8(2, 0x01);
727  * ArrayBuffertohex(buffer) → "fafb01"
728  */
729 function ArrayBuffertohex(buffer) {
730     var hex = "";
731     var view = new DataView(buffer);
732 
733     for (var i = 0; i < buffer.byteLength; i++) {
734 	hex += ("00" + view.getUint8(i).toString(16)).slice(-2);
735     }
736 
737     return hex;
738 }
739 
740 // ==== zulu / int =================================
741 /**
742  * GeneralizedTime or UTCTime string to milliseconds from Unix origin<br>
743  * @name zulutomsec
744  * @function
745  * @param {String} s GeneralizedTime or UTCTime string (ex. 20170412235959.384Z)
746  * @return {Number} milliseconds from Unix origin time (i.e. Jan 1, 1970 0:00:00 UTC)
747  * @since jsrsasign 7.1.3 base64x 1.1.9
748  * @description
749  * This function converts from GeneralizedTime string (i.e. YYYYMMDDHHmmSSZ) or
750  * UTCTime string (i.e. YYMMDDHHmmSSZ) to milliseconds from Unix origin time
751  * (i.e. Jan 1 1970 0:00:00 UTC). 
752  * Argument string may have fraction of seconds and
753  * its length is one or more digits such as "20170410235959.1234567Z".
754  * As for UTCTime, if year "YY" is equal or less than 49 then it is 20YY.
755  * If year "YY" is equal or greater than 50 then it is 19YY.
756  * @example
757  * zulutomsec(  "071231235959Z")       → 1199145599000 #Mon, 31 Dec 2007 23:59:59 GMT
758  * zulutomsec(  "071231235959.1Z")     → 1199145599100 #Mon, 31 Dec 2007 23:59:59 GMT
759  * zulutomsec(  "071231235959.12345Z") → 1199145599123 #Mon, 31 Dec 2007 23:59:59 GMT
760  * zulutomsec("20071231235959Z")       → 1199145599000 #Mon, 31 Dec 2007 23:59:59 GMT
761  * zulutomsec(  "931231235959Z")       → -410227201000 #Mon, 31 Dec 1956 23:59:59 GMT
762  */
763 function zulutomsec(s) {
764     var year, month, day, hour, min, sec, msec, d;
765     var sYear, sFrac, sMsec, matchResult;
766 
767     s = timetogen(s);
768     matchResult = s.match(/^(\d{4})(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)(|\.\d+)Z$/);
769 
770     if (matchResult) {
771 	year = parseInt(matchResult[1]);
772 	month = parseInt(matchResult[2]) - 1;
773 	day = parseInt(matchResult[3]);
774 	hour = parseInt(matchResult[4]);
775 	min = parseInt(matchResult[5]);
776 	sec = parseInt(matchResult[6]);
777 	msec = 0;
778 
779 	sFrac = matchResult[7];
780 	if (sFrac !== "") {
781 	    sMsec = (sFrac.substr(1) + "00").substr(0, 3); // .12 -> 012
782 	    msec = parseInt(sMsec);
783 	}
784 	return Date.UTC(year, month, day, hour, min, sec, msec);
785     }
786     throw new Error("unsupported zulu format: " + s);
787 }
788 
789 /**
790  * GeneralizedTime or UTCTime string to seconds from Unix origin<br>
791  * @name zulutosec
792  * @function
793  * @param {String} s GeneralizedTime or UTCTime string (ex. 20170412235959.384Z)
794  * @return {Number} seconds from Unix origin time (i.e. Jan 1, 1970 0:00:00 UTC)
795  * @since jsrsasign 7.1.3 base64x 1.1.9
796  * @description
797  * This function converts from GeneralizedTime string (i.e. YYYYMMDDHHmmSSZ) or
798  * UTCTime string (i.e. YYMMDDHHmmSSZ) to seconds from Unix origin time
799  * (i.e. Jan 1 1970 0:00:00 UTC). Argument string may have fraction of seconds 
800  * however result value will be omitted.
801  * As for UTCTime, if year "YY" is equal or less than 49 then it is 20YY.
802  * If year "YY" is equal or greater than 50 then it is 19YY.
803  * @example
804  * zulutosec(  "071231235959Z")       → 1199145599 #Mon, 31 Dec 2007 23:59:59 GMT
805  * zulutosec(  "071231235959.1Z")     → 1199145599 #Mon, 31 Dec 2007 23:59:59 GMT
806  * zulutosec("20071231235959Z")       → 1199145599 #Mon, 31 Dec 2007 23:59:59 GMT
807  */
808 function zulutosec(s) {
809     return Math.round(zulutomsec(s) / 1000.0);
810 }
811 
812 // ==== zulu / Date =================================
813 
814 /**
815  * GeneralizedTime or UTCTime string to Date object<br>
816  * @name zulutodate
817  * @function
818  * @param {String} s GeneralizedTime or UTCTime string (ex. 20170412235959.384Z)
819  * @return {Date} Date object for specified time
820  * @since jsrsasign 7.1.3 base64x 1.1.9
821  * @description
822  * This function converts from GeneralizedTime string (i.e. YYYYMMDDHHmmSSZ) or
823  * UTCTime string (i.e. YYMMDDHHmmSSZ) to Date object.
824  * Argument string may have fraction of seconds and
825  * its length is one or more digits such as "20170410235959.1234567Z".
826  * As for UTCTime, if year "YY" is equal or less than 49 then it is 20YY.
827  * If year "YY" is equal or greater than 50 then it is 19YY.
828  * @example
829  * zulutodate(  "071231235959Z").toUTCString()   → "Mon, 31 Dec 2007 23:59:59 GMT"
830  * zulutodate(  "071231235959.1Z").toUTCString() → "Mon, 31 Dec 2007 23:59:59 GMT"
831  * zulutodate("20071231235959Z").toUTCString()   → "Mon, 31 Dec 2007 23:59:59 GMT"
832  * zulutodate(  "071231235959.34").getMilliseconds() → 340
833  */
834 function zulutodate(s) {
835     return new Date(zulutomsec(s));
836 }
837 
838 /**
839  * Date object to zulu time string<br>
840  * @name datetozulu
841  * @function
842  * @param {Date} d Date object for specified time
843  * @param {Boolean} flagUTCTime if this is true year will be YY otherwise YYYY
844  * @param {Boolean} flagMilli if this is true result concludes milliseconds
845  * @return {String} GeneralizedTime or UTCTime string (ex. 20170412235959.384Z)
846  * @since jsrsasign 7.2.0 base64x 1.1.11
847  * @description
848  * This function converts from Date object to GeneralizedTime string (i.e. YYYYMMDDHHmmSSZ) or
849  * UTCTime string (i.e. YYMMDDHHmmSSZ).
850  * As for UTCTime, if year "YY" is equal or less than 49 then it is 20YY.
851  * If year "YY" is equal or greater than 50 then it is 19YY.
852  * If flagMilli is true its result concludes milliseconds such like
853  * "20170520235959.42Z". 
854  * @example
855  * d = new Date(Date.UTC(2017,4,20,23,59,59,670));
856  * datetozulu(d) → "20170520235959Z"
857  * datetozulu(d, true) → "170520235959Z"
858  * datetozulu(d, false, true) → "20170520235959.67Z"
859  */
860 function datetozulu(d, flagUTCTime, flagMilli) {
861     var s;
862     var year = d.getUTCFullYear();
863     if (flagUTCTime) {
864 	if (year < 1950 || 2049 < year) 
865 	    throw "not proper year for UTCTime: " + year;
866 	s = ("" + year).slice(-2);
867     } else {
868 	s = ("000" + year).slice(-4);
869     }
870     s += ("0" + (d.getUTCMonth() + 1)).slice(-2);
871     s += ("0" + d.getUTCDate()).slice(-2);
872     s += ("0" + d.getUTCHours()).slice(-2);
873     s += ("0" + d.getUTCMinutes()).slice(-2);
874     s += ("0" + d.getUTCSeconds()).slice(-2);
875     if (flagMilli) {
876 	var milli = d.getUTCMilliseconds();
877 	if (milli !== 0) {
878 	    milli = ("00" + milli).slice(-3);
879 	    milli = milli.replace(/0+$/g, "");
880 	    s += "." + milli;
881 	}
882     }
883     s += "Z";
884     return s;
885 }
886 
887 /**
888  * GeneralizedTime or UTCTime string to GeneralizedTime<br>
889  * @name timetogen
890  * @function
891  * @param {string} s GeneralizedTime or UTCTime string (ex. 20170412235959.384Z)
892  * @return {string} GeneralizedTime
893  * @since jsrsasign 10.7.0 base64x 1.1.31
894  * @description
895  * This function converts UTCTime string (i.e. YYMMDDHHmmSSZ ) to 
896  * GeneralizedTime (YYYYMMDDHHmmSSZ) when the argument 's' is UTCTime. 
897  * Argument string may have fraction of seconds and
898  * its length is one or more digits such as "170410235959.1234567Z".
899  * As for UTCTime, if year "YY" is equal or less than 49 then it is 20YY.
900  * If year "YY" is equal or greater than 50 then it is 19YY.
901  * @example
902  * timetogen(  "071231235959Z") → "20071231235959Z"
903  * timetogen(  "971231235959Z") → "19971231235959Z"
904  * timetogen("20071231235959Z") → "20071231235959Z"
905  * timetogen(  "971231235959.123Z") → "19971231235959.123Z"
906  */
907 function timetogen(s) {
908     if (s.match(/^[0-9]{12}Z$/) || s.match(/^[0-9]{12}[.][0-9]*Z$/)) {
909 	return (s.match(/^[0-4]/)) ? "20" + s : "19" + s;
910     }
911     return s;
912 }
913 
914 // ==== URIComponent / hex ================================
915 /**
916  * convert a URLComponent string such like "%67%68" to a hexadecimal string.<br/>
917  * @name uricmptohex
918  * @function
919  * @param {String} s URIComponent string such like "%67%68"
920  * @return {String} hexadecimal string
921  * @since 1.1
922  */
923 function uricmptohex(s) {
924   return s.replace(/%/g, "");
925 }
926 
927 /**
928  * convert a hexadecimal string to a URLComponent string such like "%67%68".<br/>
929  * @name hextouricmp
930  * @function
931  * @param {String} s hexadecimal string
932  * @return {String} URIComponent string such like "%67%68"
933  * @since 1.1
934  */
935 function hextouricmp(s) {
936   return s.replace(/(..)/g, "%$1");
937 }
938 
939 // ==== hex / ipv6 =================================
940 
941 /**
942  * convert any IPv6 address to a 16 byte hexadecimal string
943  * @function
944  * @param s string of IPv6 address
945  * @return {String} 16 byte hexadecimal string of IPv6 address
946  * @description
947  * This function converts any IPv6 address representation string
948  * to a 16 byte hexadecimal string of address.
949  * @example
950  * 
951  */
952 function ipv6tohex(s) {
953   var msgMalformedAddress = "malformed IPv6 address";
954   if (! s.match(/^[0-9A-Fa-f:]+$/))
955     throw msgMalformedAddress;
956 
957   // 1. downcase
958   s = s.toLowerCase();
959 
960   // 2. expand ::
961   var num_colon = s.split(':').length - 1;
962   if (num_colon < 2) throw msgMalformedAddress;
963   var colon_replacer = ':'.repeat(7 - num_colon + 2);
964   s = s.replace('::', colon_replacer);
965 
966   // 3. fill zero
967   var a = s.split(':');
968   if (a.length != 8) throw msgMalformedAddress;
969   for (var i = 0; i < 8; i++) {
970     a[i] = ("0000" + a[i]).slice(-4);
971   }
972   return a.join('');
973 }
974 
975 /**
976  * convert a 16 byte hexadecimal string to RFC 5952 canonicalized IPv6 address<br/>
977  * @name hextoipv6
978  * @function
979  * @param {String} s hexadecimal string of 16 byte IPv6 address
980  * @return {String} IPv6 address string canonicalized by RFC 5952
981  * @since jsrsasign 8.0.10 base64x 1.1.13
982  * @description
983  * This function converts a 16 byte hexadecimal string to 
984  * <a href="https://tools.ietf.org/html/rfc5952">RFC 5952</a>
985  * canonicalized IPv6 address string.
986  * @example
987  * hextoipv6("871020010db8000000000000000000000004") &rarr "2001:db8::4"
988  * hextoipv6("871020010db8000000000000000000") &rarr raise exception
989  * hextoipv6("xyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyz") &rarr raise exception
990  */
991 function hextoipv6(s) {
992     if (! s.match(/^[0-9A-Fa-f]{32}$/))
993 	throw new Error("malformed IPv6 address: " + s);
994 
995     // 1. downcase
996     s = s.toLowerCase();
997 
998     // 2. split 4 > ["0123", "00a4", "0000", ..., "ffff"]
999     var a = s.match(/.{1,4}/g);
1000 
1001     // 3. trim leading 0 for items and join > "123:a4:0:...:ffff"
1002     a = a.map(function(s){return s.replace(/^0+/, '')});
1003     a = a.map(function(s){return s == '' ? '0' : s});
1004     s = ':' + a.join(':') + ':';
1005 
1006     // 4. find shrinkable candidates :0:0:..:0:
1007     var aZero = s.match(/:(0:){2,}/g);
1008 
1009     // 5. no shrinkable
1010     if (aZero == null) return s.slice(1, -1);
1011 
1012     // 6. fix max length zero(:0:...:0:)
1013     var sMaxZero = aZero.sort().slice(-1)[0];
1014 
1015     // 7. replace shrinked
1016     s = s.replace(sMaxZero.substr(0, sMaxZero.length - 1), ':');
1017 
1018     // 8. trim leading ':' if not '::'
1019     if (s.substr(0, 2) != '::') s = s.substr(1);
1020 
1021     // 9. trim tail ':' if not '::'
1022     if (s.substr(-2, 2) != '::') s = s.substr(0, s.length - 1);
1023 
1024     return s;
1025 }
1026 
1027 // ==== hex / ip =================================
1028 
1029 /**
1030  * convert a hexadecimal string to IP addresss<br/>
1031  * @name hextoip
1032  * @function
1033  * @param {String} s hexadecimal string of IP address
1034  * @return {String} IP address string
1035  * @since jsrsasign 8.0.10 base64x 1.1.13
1036  * @see hextoipv6
1037  * @see iptohex
1038  *
1039  * @description
1040  * This function converts a hexadecimal string of IPv4 or 
1041  * IPv6 address to IPv4 or IPv6 address string.
1042  * If byte length is not 4 nor 16, this returns a
1043  * hexadecimal string without conversion.
1044  * <br/>
1045  * NOTE: From jsrsasign 10.5.17, CIDR subnet mask notation also supported.
1046  *
1047  * @example
1048  * hextoip("c0a80101") → "192.168.1.1"
1049  * hextoip("871020010db8000000000000000000000004") &rarr "2001:db8::4"
1050  * hextoip("c0a80100ffffff00") → "192.168.1.0/24"
1051  * hextoip("c0a801010203") → "c0a801010203" // wrong 6 bytes
1052  * hextoip("zzz")) → raise exception because of not hexadecimal
1053  */
1054 function hextoip(s) {
1055     var malformedErr = new Error("malformed hex value");
1056     if (! s.match(/^([0-9A-Fa-f][0-9A-Fa-f]){1,}$/))
1057 	throw malformedErr;
1058     if (s.length == 8) { // ipv4
1059 	var ip;
1060 	try {
1061 	    ip = parseInt(s.substr(0, 2), 16) + "." +
1062  		 parseInt(s.substr(2, 2), 16) + "." +
1063 		 parseInt(s.substr(4, 2), 16) + "." +
1064 		 parseInt(s.substr(6, 2), 16);
1065 	    return ip;
1066 	} catch (ex) {
1067 	    throw malformedErr;
1068 	}
1069   } else if (s.length == 16) {
1070       try {
1071 	  return hextoip(s.substr(0, 8)) + "/" + ipprefixlen(s.substr(8));
1072       } catch (ex) {
1073 	  throw malformedErr;
1074       }
1075   } else if (s.length == 32) {
1076       return hextoipv6(s);
1077   } else if (s.length == 64) {
1078       try {
1079 	  return hextoipv6(s.substr(0, 32)) + "/" + ipprefixlen(s.substr(32));
1080       } catch (ex) {
1081 	  throw malformedErr;
1082       }
1083       return 
1084   } else {
1085     return s;
1086   }
1087 }
1088 
1089 /*
1090  * convert subnet mask hex to ip address prefix length<br/>
1091  * @name ipprefixlen
1092  * @param {string} hMask hexadecimal string of ipv4/6 subnet mask (ex. "ffffff00" for v4 class C)
1093  * @return {nummber} ip address prefix length (ex. 24 for IPv4 class C)
1094  */
1095 function ipprefixlen(hMask) {
1096     var malformedErr = new Error("malformed mask");
1097     var bMask;
1098     try {
1099 	bMask = new BigInteger(hMask, 16).toString(2);
1100     } catch(ex) {
1101 	throw malformedErr;
1102     }
1103     if (! bMask.match(/^1*0*$/)) throw malformedErr;
1104     return bMask.replace(/0+$/, '').length;
1105 }
1106 
1107 /**
1108  * convert IPv4/v6 addresss to a hexadecimal string<br/>
1109  * @name iptohex
1110  * @function
1111  * @param {String} s IPv4/v6 address string
1112  * @return {String} hexadecimal string of IP address
1113  * @since jsrsasign 8.0.12 base64x 1.1.14
1114  * @see hextoip
1115  * @see ipv6tohex
1116  *
1117  * @description
1118  * This function converts IPv4 or IPv6 address string to
1119  * a hexadecimal string of IPv4 or IPv6 address.
1120  * <br/>
1121  * NOTE: From jsrsasign 10.5.17, CIDR net mask notation also supported.
1122  *
1123  * @example
1124  * iptohex("192.168.1.1") → "c0a80101"
1125  * iptohex("2001:db8::4") → "871020010db8000000000000000000000004"
1126  * iptohex("192.168.1.1/24") → "c0a80101ffffff00"
1127  * iptohex("2001:db8::/120") → "871020010db8000000000000000000000000ffffffffffffffffffffffffffffffffff00"
1128  * iptohex("zzz")) → raise exception
1129  */
1130 function iptohex(s) {
1131     var malformedErr = new Error("malformed IP address");
1132     s = s.toLowerCase(s);
1133 
1134     if (! s.match(/^[0-9a-f.:/]+$/) ) throw malformedErr;
1135 
1136     if (s.match(/^[0-9.]+$/)) {
1137 	var a = s.split(".");
1138 	if (a.length !== 4) throw malformedErr;
1139 	var hex = "";
1140 	try {
1141 	    for (var i = 0; i < 4; i++) {
1142 		var d = parseInt(a[i]);
1143 		hex += ("0" + d.toString(16)).slice(-2);
1144 	    }
1145 	    return hex;
1146 	} catch(ex) {
1147 	    throw malformedErr;
1148 	}
1149     } else if (s.match(/^[0-9.]+\/[0-9]+$/)) {
1150 	var aItem = s.split("/");
1151 	return iptohex(aItem[0]) + ipnetmask(parseInt(aItem[1]), 32);
1152     } else if (s.match(/^[0-9a-f:]+$/) && s.indexOf(":") !== -1) {
1153 	return ipv6tohex(s);
1154     } else if (s.match(/^[0-9a-f:]+\/[0-9]+$/) && s.indexOf(":") !== -1) {
1155 	var aItem = s.split("/");
1156 	return ipv6tohex(aItem[0]) + ipnetmask(parseInt(aItem[1]), 128);
1157     } else {
1158 	throw malformedErr;
1159     }
1160 }
1161 
1162 /*
1163  * convert ip prefix length to net mask octets<br/>
1164  * @param {number} prefixlen ip prefix length value (ex. 24 for IPv4 class C)
1165  * @param {number} len ip address length (ex. 32 for IPv4 and 128 for IPv6)
1166  * @return {string} hexadecimal string of net mask octets
1167  * @example
1168  * ipnetmask(24, 32) → "ffffff00" 
1169  * ipnetmask(120, 128) → "ffffffffffffffffffffffffffffff00"
1170  */
1171 function ipnetmask(prefixlen, len) {
1172     if (len == 32 && prefixlen == 0) return "00000000"; // v4
1173     if (len == 128 && prefixlen == 0) return "00000000000000000000000000000000"; // v6
1174     var b = Array(prefixlen + 1).join("1") + Array(len - prefixlen + 1).join("0");
1175     return new BigInteger(b, 2).toString(16);
1176 }
1177 
1178 // ==== ucs2hex / utf8 ==============================
1179 
1180 /**
1181  * convert UCS-2 hexadecimal stirng to UTF-8 string<br/>
1182  * @name ucs2hextoutf8
1183  * @function
1184  * @param {String} s hexadecimal string of UCS-2 string (ex. "0066")
1185  * @return {String} UTF-8 string
1186  * @since jsrsasign 10.1.13 base64x 1.1.20
1187  * @description
1188  * This function converts hexadecimal value of UCS-2 string to 
1189  * UTF-8 string.
1190  * @example
1191  * ucs2hextoutf8("006600fc0072") &rarr "für"
1192  */
1193 /*
1194 See: http://nomenclator.la.coocan.jp/unicode/ucs_utf.htm
1195 UCS-2 to UTF-8
1196 UCS-2 code point | UCS-2 bytes       | UTF-8 bytes
1197 U+0000 .. U+007F | 00000000-0xxxxxxx | 0xxxxxxx (1 byte)
1198 U+0080 .. U+07FF | 00000xxx-xxyyyyyy | 110xxxxx 10yyyyyy (2 byte)
1199 U+0800 .. U+FFFF | xxxxyyyy-yyzzzzzz | 1110xxxx 10yyyyyy 10zzzzzz (3 byte)
1200  */
1201 function ucs2hextoutf8(s) {
1202     function _conv(s) {
1203 	var i1 = parseInt(s.substr(0, 2), 16);
1204 	var i2 = parseInt(s.substr(2), 16);
1205 	if (i1 == 0 & i2 < 0x80) { // 1 byte
1206 	    return String.fromCharCode(i2);
1207 	}
1208 	if (i1 < 8) { // 2 bytes
1209 	    var u1 = 0xc0 | ((i1 & 0x07) << 3) | ((i2 & 0xc0) >> 6);
1210 	    var u2 = 0x80 | (i2 & 0x3f);
1211 	    return hextoutf8(u1.toString(16) + u2.toString(16));
1212 	}
1213 	// 3 bytes
1214 	var u1 = 0xe0 | ((i1 & 0xf0) >> 4);
1215 	var u2 = 0x80 | ((i1 & 0x0f) << 2) | ((i2 & 0xc0) >> 6);
1216 	var u3 = 0x80 | (i2 & 0x3f);
1217 	return hextoutf8(u1.toString(16) + u2.toString(16) + u3.toString(16));
1218     }
1219     var a = s.match(/.{4}/g);
1220     var a2 = a.map(_conv);
1221     return a2.join("");
1222 }
1223 
1224 // ==== URIComponent ================================
1225 /**
1226  * convert UTFa hexadecimal string to a URLComponent string such like "%67%68".<br/>
1227  * Note that these "<code>0-9A-Za-z!'()*-._~</code>" characters will not
1228  * converted to "%xx" format by builtin 'encodeURIComponent()' function.
1229  * However this 'encodeURIComponentAll()' function will convert 
1230  * all of characters into "%xx" format.
1231  * @name encodeURIComponentAll
1232  * @function
1233  * @param {String} s hexadecimal string
1234  * @return {String} URIComponent string such like "%67%68"
1235  * @since 1.1
1236  */
1237 function encodeURIComponentAll(u8) {
1238   var s = encodeURIComponent(u8);
1239   var s2 = "";
1240   for (var i = 0; i < s.length; i++) {
1241     if (s[i] == "%") {
1242       s2 = s2 + s.substr(i, 3);
1243       i = i + 2;
1244     } else {
1245       s2 = s2 + "%" + stohex(s[i]);
1246     }
1247   }
1248   return s2;
1249 }
1250 
1251 // ==== new lines ================================
1252 /**
1253  * convert all DOS new line("\r\n") to UNIX new line("\n") in 
1254  * a String "s".
1255  * @name newline_toUnix
1256  * @function
1257  * @param {String} s string 
1258  * @return {String} converted string
1259  */
1260 function newline_toUnix(s) {
1261     s = s.replace(/\r\n/mg, "\n");
1262     return s;
1263 }
1264 
1265 /**
1266  * convert all UNIX new line("\r\n") to DOS new line("\n") in 
1267  * a String "s".
1268  * @name newline_toDos
1269  * @function
1270  * @param {String} s string 
1271  * @return {String} converted string
1272  */
1273 function newline_toDos(s) {
1274     s = s.replace(/\r\n/mg, "\n");
1275     s = s.replace(/\n/mg, "\r\n");
1276     return s;
1277 }
1278 
1279 // ==== string type checker ===================
1280 
1281 /**
1282  * check whether a string is an integer string or not<br/>
1283  * @name isInteger
1284  * @memberOf KJUR.lang.String
1285  * @function
1286  * @static
1287  * @param {String} s input string
1288  * @return {Boolean} true if a string "s" is an integer string otherwise false
1289  * @since base64x 1.1.7 jsrsasign 5.0.13
1290  * @example
1291  * KJUR.lang.String.isInteger("12345") → true
1292  * KJUR.lang.String.isInteger("123ab") → false
1293  */
1294 KJUR.lang.String.isInteger = function(s) {
1295     if (s.match(/^[0-9]+$/)) {
1296 	return true;
1297     } else if (s.match(/^-[0-9]+$/)) {
1298 	return true;
1299     } else {
1300 	return false;
1301     }
1302 };
1303 
1304 /**
1305  * check whether a string is an hexadecimal string or not (DEPRECATED)<br/>
1306  * @name isHex
1307  * @memberOf KJUR.lang.String
1308  * @function
1309  * @static
1310  * @param {String} s input string
1311  * @return {Boolean} true if a string "s" is an hexadecimal string otherwise false
1312  * @since base64x 1.1.7 jsrsasign 5.0.13
1313  * @deprecated from 10.0.6. please use {@link ishex}
1314  * @see ishex
1315  * @example
1316  * KJUR.lang.String.isHex("1234") → true
1317  * KJUR.lang.String.isHex("12ab") → true
1318  * KJUR.lang.String.isHex("12AB") → true
1319  * KJUR.lang.String.isHex("12ZY") → false
1320  * KJUR.lang.String.isHex("121") → false -- odd length
1321  */
1322 KJUR.lang.String.isHex = function(s) {
1323     return ishex(s);
1324 };
1325 
1326 /**
1327  * check whether a string is an hexadecimal string or not<br/>
1328  * @name ishex
1329  * @function
1330  * @static
1331  * @param {String} s input string
1332  * @return {Boolean} true if a string "s" is an hexadecimal string otherwise false
1333  * @since base64x 1.1.7 jsrsasign 5.0.13
1334  * @example
1335  * ishex("1234") → true
1336  * ishex("12ab") → true
1337  * ishex("12AB") → true
1338  * ishex("12ZY") → false
1339  * ishex("121") → false -- odd length
1340  */
1341 function ishex(s) {
1342     if (s.length % 2 == 0 &&
1343 	(s.match(/^[0-9a-f]+$/) || s.match(/^[0-9A-F]+$/))) {
1344 	return true;
1345     } else {
1346 	return false;
1347     }
1348 };
1349 
1350 /**
1351  * check whether a string is a base64 encoded string or not<br/>
1352  * Input string can conclude new lines or space characters.
1353  * @name isBase64
1354  * @memberOf KJUR.lang.String
1355  * @function
1356  * @static
1357  * @param {String} s input string
1358  * @return {Boolean} true if a string "s" is a base64 encoded string otherwise false
1359  * @since base64x 1.1.7 jsrsasign 5.0.13
1360  * @example
1361  * KJUR.lang.String.isBase64("YWE=") → true
1362  * KJUR.lang.String.isBase64("YW_=") → false
1363  * KJUR.lang.String.isBase64("YWE") → false -- length shall be multiples of 4
1364  */
1365 KJUR.lang.String.isBase64 = function(s) {
1366     s = s.replace(/\s+/g, "");
1367     if (s.match(/^[0-9A-Za-z+\/]+={0,3}$/) && s.length % 4 == 0) {
1368 	return true;
1369     } else {
1370 	return false;
1371     }
1372 };
1373 
1374 /**
1375  * check whether a string is a base64url encoded string or not<br/>
1376  * Input string can conclude new lines or space characters.
1377  * @name isBase64URL
1378  * @memberOf KJUR.lang.String
1379  * @function
1380  * @static
1381  * @param {String} s input string
1382  * @return {Boolean} true if a string "s" is a base64url encoded string otherwise false
1383  * @since base64x 1.1.7 jsrsasign 5.0.13
1384  * @example
1385  * KJUR.lang.String.isBase64URL("YWE") → true
1386  * KJUR.lang.String.isBase64URL("YW-") → true
1387  * KJUR.lang.String.isBase64URL("YW+") → false
1388  */
1389 KJUR.lang.String.isBase64URL = function(s) {
1390     if (s.match(/[+/=]/)) return false;
1391     s = b64utob64(s);
1392     return KJUR.lang.String.isBase64(s);
1393 };
1394 
1395 
1396 /**
1397  * check whether a string is a base64url encoded string and dot or not<br/>
1398  * Input string can conclude new lines or space characters.
1399  * @name isBase64URLDot
1400  * @function
1401  * @static
1402  * @param {String} s input string
1403  * @return {Boolean} true if a string "s" is a base64url encoded string and dot otherwise false
1404  * @since base64x 1.1.30 jsrsasign 10.5.25
1405  * @example
1406  * isBase64URLDot("YWE") → true
1407  * isBase64URLDot("YWE.YWE.YWE") → true
1408  * isBase64URLDot("YW-") → true
1409  * isBase64URLDot("YW+") → false
1410  */
1411 function isBase64URLDot(s) {
1412     if (s.match(/^[0-9A-Za-z-_.]+$/)) return true;
1413     return false;
1414 }
1415 
1416 /**
1417  * check whether a string is a string of integer array or not<br/>
1418  * Input string can conclude new lines or space characters.
1419  * @name isIntegerArray
1420  * @memberOf KJUR.lang.String
1421  * @function
1422  * @static
1423  * @param {String} s input string
1424  * @return {Boolean} true if a string "s" is a string of integer array otherwise false
1425  * @since base64x 1.1.7 jsrsasign 5.0.13
1426  * @example
1427  * KJUR.lang.String.isIntegerArray("[1,2,3]") → true
1428  * KJUR.lang.String.isIntegerArray("  [1, 2, 3  ] ") → true
1429  * KJUR.lang.String.isIntegerArray("[a,2]") → false
1430  */
1431 KJUR.lang.String.isIntegerArray = function(s) {
1432     s = s.replace(/\s+/g, "");
1433     if (s.match(/^\[[0-9,]+\]$/)) {
1434 	return true;
1435     } else {
1436 	return false;
1437     }
1438 };
1439 
1440 /**
1441  * check whether a string consists of PrintableString characters<br/>
1442  * @name isPrintable
1443  * @memberOf KJUR.lang.String
1444  * @function
1445  * @static
1446  * @param {String} s input string
1447  * @return {Boolean} true if a string "s" consists of PrintableString characters
1448  * @since jsrsasign 9.0.0 base64x 1.1.16
1449  * A PrintableString consists of following characters
1450  * <pre>
1451  * 0-9A-Za-z '()+,-./:=?
1452  * </pre>
1453  * This method returns false when other characters than above.
1454  * Otherwise it returns true.
1455  * @example
1456  * KJUR.lang.String.isPrintable("abc") → true
1457  * KJUR.lang.String.isPrintable("abc@") → false
1458  * KJUR.lang.String.isPrintable("あいう") → false
1459  */
1460 KJUR.lang.String.isPrintable = function(s) {
1461     if (s.match(/^[0-9A-Za-z '()+,-./:=?]*$/) !== null) return true;
1462     return false;
1463 };
1464 
1465 /**
1466  * check whether a string consists of IAString characters<br/>
1467  * @name isIA5
1468  * @memberOf KJUR.lang.String
1469  * @function
1470  * @static
1471  * @param {String} s input string
1472  * @return {Boolean} true if a string "s" consists of IA5String characters
1473  * @since jsrsasign 9.0.0 base64x 1.1.16
1474  * A IA5String consists of following characters
1475  * <pre>
1476  * %x00-21/%x23-7F (i.e. ASCII characters excludes double quote(%x22)
1477  * </pre>
1478  * This method returns false when other characters than above.
1479  * Otherwise it returns true.
1480  * @example
1481  * KJUR.lang.String.isIA5("abc") → true
1482  * KJUR.lang.String.isIA5('"abc"') → false
1483  * KJUR.lang.String.isIA5("あいう") → false
1484  */
1485 KJUR.lang.String.isIA5 = function(s) {
1486     if (s.match(/^[\x20-\x21\x23-\x7f]*$/) !== null) return true;
1487     return false;
1488 };
1489 
1490 /**
1491  * check whether a string is RFC 822 mail address<br/>
1492  * @name isMail
1493  * @memberOf KJUR.lang.String
1494  * @function
1495  * @static
1496  * @param {String} s input string
1497  * @return {Boolean} true if a string "s" RFC 822 mail address
1498  * @since jsrsasign 9.0.0 base64x 1.1.16
1499  * This static method will check string s is RFC 822 compliant mail address.
1500  * @example
1501  * KJUR.lang.String.isMail("abc") → false
1502  * KJUR.lang.String.isMail("abc@example") → false
1503  * KJUR.lang.String.isMail("abc@example.com") → true
1504  */
1505 KJUR.lang.String.isMail = function(s) {
1506     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;
1507     return false;
1508 };
1509 
1510 // ==== others ================================
1511 
1512 /**
1513  * canonicalize hexadecimal string of positive integer<br/>
1514  * @name hextoposhex
1515  * @function
1516  * @param {String} s hexadecimal string 
1517  * @return {String} canonicalized hexadecimal string of positive integer
1518  * @since base64x 1.1.10 jsrsasign 7.1.4
1519  * @description
1520  * This method canonicalize a hexadecimal string of positive integer
1521  * for two's complement representation.
1522  * Canonicalized hexadecimal string of positive integer will be:
1523  * <ul>
1524  * <li>Its length is always even.</li>
1525  * <li>If odd length it will be padded with leading zero.<li>
1526  * <li>If it is even length and its first character is "8" or greater,
1527  * it will be padded with "00" to make it positive integer.</li>
1528  * </ul>
1529  * @example
1530  * hextoposhex("abcd") → "00abcd"
1531  * hextoposhex("1234") → "1234"
1532  * hextoposhex("12345") → "012345"
1533  */
1534 function hextoposhex(s) {
1535     if (s.length % 2 == 1) return "0" + s;
1536     if (s.substr(0, 1) > "7") return "00" + s;
1537     return s;
1538 }
1539 
1540 /**
1541  * convert string of integer array to hexadecimal string.<br/>
1542  * @name intarystrtohex
1543  * @function
1544  * @param {String} s string of integer array
1545  * @return {String} hexadecimal string
1546  * @since base64x 1.1.6 jsrsasign 5.0.2
1547  * @throws "malformed integer array string: *" for wrong input
1548  * @description
1549  * This function converts a string of JavaScript integer array to
1550  * a hexadecimal string. Each integer value shall be in a range 
1551  * from 0 to 255 otherwise it raise exception. Input string can
1552  * have extra space or newline string so that they will be ignored.
1553  * 
1554  * @example
1555  * intarystrtohex(" [123, 34, 101, 34, 58] ")
1556  * → 7b2265223a (i.e. '{"e":' as string)
1557  */
1558 function intarystrtohex(s) {
1559   s = s.replace(/^\s*\[\s*/, '');
1560   s = s.replace(/\s*\]\s*$/, '');
1561   s = s.replace(/\s*/g, '');
1562   try {
1563     var hex = s.split(/,/).map(function(element, index, array) {
1564       var i = parseInt(element);
1565       if (i < 0 || 255 < i) throw "integer not in range 0-255";
1566       var hI = ("00" + i.toString(16)).slice(-2);
1567       return hI;
1568     }).join('');
1569     return hex;
1570   } catch(ex) {
1571     throw "malformed integer array string: " + ex;
1572   }
1573 }
1574 
1575 /**
1576  * find index of string where two string differs
1577  * @name strdiffidx
1578  * @function
1579  * @param {String} s1 string to compare
1580  * @param {String} s2 string to compare
1581  * @return {Number} string index of where character differs. Return -1 if same.
1582  * @since jsrsasign 4.9.0 base64x 1.1.5
1583  * @example
1584  * strdiffidx("abcdefg", "abcd4fg") -> 4
1585  * strdiffidx("abcdefg", "abcdefg") -> -1
1586  * strdiffidx("abcdefg", "abcdef") -> 6
1587  * strdiffidx("abcdefgh", "abcdef") -> 6
1588  */
1589 var strdiffidx = function(s1, s2) {
1590     var n = s1.length;
1591     if (s1.length > s2.length) n = s2.length;
1592     for (var i = 0; i < n; i++) {
1593 	if (s1.charCodeAt(i) != s2.charCodeAt(i)) return i;
1594     }
1595     if (s1.length != s2.length) return n;
1596     return -1; // same
1597 };
1598 
1599 // ==== hex / oid =================================
1600 
1601 /**
1602  * get hexadecimal value of object identifier from dot noted oid value
1603  * @name oidtohex
1604  * @function
1605  * @param {String} oidString dot noted string of object identifier
1606  * @return {String} hexadecimal value of object identifier
1607  * @since jsrsasign 10.1.0 base64x 1.1.18
1608  * @see hextooid
1609  * @see ASN1HEX.hextooidstr
1610  * @see KJUR.asn1.ASN1Util.oidIntToHex
1611  * @description
1612  * This static method converts from object identifier value string.
1613  * to hexadecimal string representation of it.
1614  * {@link hextooid} is a reverse function of this.
1615  * @example
1616  * oidtohex("2.5.4.6") → "550406"
1617  */
1618 function oidtohex(oidString) {
1619     var itox = function(i) {
1620         var h = i.toString(16);
1621         if (h.length == 1) h = '0' + h;
1622         return h;
1623     };
1624 
1625     var roidtox = function(roid) {
1626         var h = '';
1627         var bi = parseInt(roid, 10);
1628         var b = bi.toString(2);
1629 
1630         var padLen = 7 - b.length % 7;
1631         if (padLen == 7) padLen = 0;
1632         var bPad = '';
1633         for (var i = 0; i < padLen; i++) bPad += '0';
1634         b = bPad + b;
1635         for (var i = 0; i < b.length - 1; i += 7) {
1636             var b8 = b.substr(i, 7);
1637             if (i != b.length - 7) b8 = '1' + b8;
1638             h += itox(parseInt(b8, 2));
1639         }
1640         return h;
1641     };
1642     
1643     try {
1644 	if (! oidString.match(/^[0-9.]+$/)) return null;
1645     
1646 	var h = '';
1647 	var a = oidString.split('.');
1648 	var i0 = parseInt(a[0], 10) * 40 + parseInt(a[1], 10);
1649 	h += itox(i0);
1650 	a.splice(0, 2);
1651 	for (var i = 0; i < a.length; i++) {
1652             h += roidtox(a[i]);
1653 	}
1654 	return h;
1655     } catch(ex) {
1656 	return null;
1657     }
1658 };
1659 
1660 /**
1661  * get oid string from hexadecimal value of object identifier<br/>
1662  * @name hextooid
1663  * @function
1664  * @param {String} h hexadecimal value of object identifier
1665  * @return {String} dot noted string of object identifier (ex. "1.2.3.4")
1666  * @since jsrsasign 10.1.0 base64x 1.1.18
1667  * @see oidtohex
1668  * @see ASN1HEX.hextooidstr
1669  * @see KJUR.asn1.ASN1Util.oidIntToHex
1670  * @description
1671  * This static method converts from hexadecimal object identifier value 
1672  * to dot noted OID value (ex. "1.2.3.4").
1673  * {@link oidtohex} is a reverse function of this.
1674  * @example
1675  * hextooid("550406") → "2.5.4.6"
1676  */
1677 function hextooid(h) {
1678     if (! ishex(h)) return null;
1679     try {
1680 	var a = [];
1681 
1682 	// a[0], a[1]
1683 	var hex0 = h.substr(0, 2);
1684 	var i0 = parseInt(hex0, 16);
1685 	a[0] = new String(Math.floor(i0 / 40));
1686 	a[1] = new String(i0 % 40);
1687 
1688 	// a[2]..a[n]
1689 	var hex1 = h.substr(2);
1690 	var b = [];
1691 	for (var i = 0; i < hex1.length / 2; i++) {
1692 	    b.push(parseInt(hex1.substr(i * 2, 2), 16));
1693 	}
1694 	var c = [];
1695 	var cbin = "";
1696 	for (var i = 0; i < b.length; i++) {
1697             if (b[i] & 0x80) {
1698 		cbin = cbin + strpad((b[i] & 0x7f).toString(2), 7);
1699             } else {
1700 		cbin = cbin + strpad((b[i] & 0x7f).toString(2), 7);
1701 		c.push(new String(parseInt(cbin, 2)));
1702 		cbin = "";
1703             }
1704 	}
1705 
1706 	var s = a.join(".");
1707 	if (c.length > 0) s = s + "." + c.join(".");
1708 	return s;
1709     } catch(ex) {
1710 	return null;
1711     }
1712 };
1713 
1714 /**
1715  * string padding<br/>
1716  * @name strpad
1717  * @function
1718  * @param {String} s input string
1719  * @param {Number} len output string length
1720  * @param {String} padchar padding character (default is "0")
1721  * @return {String} padded string
1722  * @since jsrsasign 10.1.0 base64x 1.1.18
1723  * @example
1724  * strpad("1234", 10, "0") → "0000001234"
1725  * strpad("1234", 10, " ") → "      1234"
1726  * strpad("1234", 10)      → "0000001234"
1727  */
1728 var strpad = function(s, len, padchar) {
1729     if (padchar == undefined) padchar = "0";
1730     if (s.length >= len) return s;
1731     return new Array(len - s.length + 1).join(padchar) + s;
1732 };
1733 
1734 // ==== bitstr hex / int =================================
1735 
1736 /**
1737  * convert from hexadecimal string of ASN.1 BitString value with unused bit to integer value<br/>
1738  * @name bitstrtoint
1739  * @function
1740  * @param {String} h hexadecimal string of ASN.1 BitString value with unused bit
1741  * @return {Number} positive integer value of the BitString
1742  * @since jsrsasign 10.1.3 base64x 1.1.19
1743  * @see inttobitstr
1744  * @see KJUR.asn1.DERBitString
1745  * @see ASN1HEX.getInt
1746  * 
1747  * @description
1748  * This function converts from hexadecimal string of ASN.1 BitString
1749  * value with unused bit to its integer value. <br/>
1750  * When an improper hexadecimal string of BitString value
1751  * is applied, this returns -1.
1752  * 
1753  * @example
1754  * // "03c8" → 0xc8 unusedbit=03 → 11001000b unusedbit=03 → 11001b → 25
1755  * bitstrtoint("03c8") → 25
1756  * // "02fff8" → 0xfff8 unusedbit=02 → 1111111111111000b unusedbit=02
1757  * //   11111111111110b → 16382
1758  * bitstrtoint("02fff8") → 16382
1759  * bitstrtoint("05a0") → 5 (=101b)
1760  * bitstrtoint("ff00") → -1 // for improper BitString value
1761  * bitstrtoint("05a0").toString(2) → "101"
1762  * bitstrtoint("07a080").toString(2) → "101000001"
1763  */
1764 function bitstrtoint(h) {
1765     if (h.length % 2 != 0) return -1; 
1766     h = h.toLowerCase();
1767     if (h.match(/^[0-9a-f]+$/) == null) return -1;
1768     try {
1769 	var hUnusedbit = h.substr(0, 2);
1770 	if (hUnusedbit == "00")
1771 	    return parseInt(h.substr(2), 16);
1772 	var iUnusedbit = parseInt(hUnusedbit, 16);
1773 	if (iUnusedbit > 7) return -1;
1774 	var hValue = h.substr(2);
1775 	var bValue = parseInt(hValue, 16).toString(2);
1776 	if (bValue == "0") bValue = "00000000";
1777 	bValue = bValue.slice(0, 0 - iUnusedbit);
1778 	var iValue = parseInt(bValue, 2);
1779 	if (iValue == NaN) return -1;
1780 	return iValue;
1781     } catch(ex) {
1782 	return -1;
1783     }
1784 };
1785 
1786 /**
1787  * convert from integer value to hexadecimal string of ASN.1 BitString value with unused bit<br/>
1788  * @name inttobitstr
1789  * @function
1790  * @param {Number} n integer value of ASN.1 BitString
1791  * @return {String} hexadecimal string of ASN.1 BitString value with unused bit
1792  * @since jsrsasign 10.1.3 base64x 1.1.19
1793  * @see bitstrtoint
1794  * @see KJUR.asn1.DERBitString
1795  * @see ASN1HEX.getInt
1796  * 
1797  * @description
1798  * This function converts from an integer value to 
1799  * hexadecimal string of ASN.1 BitString value
1800  * with unused bit. <br/>
1801  * When "n" is not non-negative number, this returns null
1802  * 
1803  * @example
1804  * // 25 → 11001b → 11001000b unusedbit=03 → 0xc8 unusedbit=03 → "03c8"
1805  * inttobitstr(25) → "03c8"
1806  * inttobitstr(-3) → null
1807  * inttobitstr("abc") → null
1808  * inttobitstr(parseInt("11001", 2)) → "03c8"
1809  * inttobitstr(parseInt("101", 2)) → "05a0"
1810  * inttobitstr(parseInt("101000001", 2)) → "07a080"
1811  */
1812 function inttobitstr(n) {
1813     if (typeof n != "number") return null;
1814     if (n < 0) return null;
1815     var bValue = Number(n).toString(2);
1816     var iUnusedbit = 8 - bValue.length % 8;
1817     if (iUnusedbit == 8) iUnusedbit = 0;
1818     bValue = bValue + strpad("", iUnusedbit, "0");
1819     var hValue = parseInt(bValue, 2).toString(16);
1820     if (hValue.length % 2 == 1) hValue = "0" + hValue;
1821     var hUnusedbit = "0" + iUnusedbit;
1822     return hUnusedbit + hValue;
1823 };
1824 
1825 // ==== bitstr hex / binary string =======================
1826 
1827 /**
1828  * convert from hexadecimal string of ASN.1 BitString value with unused bit to binary string<br/>
1829  * @name bitstrtobinstr
1830  * @function
1831  * @param {string} h hexadecimal string of ASN.1 BitString value with unused bit
1832  * @return {string} binary string
1833  * @since jsrsasign 10.5.4 base64x 1.1.21
1834  * @see binstrtobitstr
1835  * @see inttobitstr
1836  * 
1837  * @description
1838  * This function converts from hexadecimal string of ASN.1 BitString
1839  * value with unused bit to its integer value. <br/>
1840  * When an improper hexadecimal string of BitString value
1841  * is applied, this returns null.
1842  * 
1843  * @example
1844  * bitstrtobinstr("05a0") → "101"
1845  * bitstrtobinstr("0520") → "001"
1846  * bitstrtobinstr("07a080") → "101000001"
1847  * bitstrtobinstr(502) → null // non ASN.1 BitString value
1848  * bitstrtobinstr("ff00") → null // for improper BitString value
1849  */
1850 function bitstrtobinstr(h) {
1851     if (typeof h != "string") return null;
1852     if (h.length % 2 != 0) return null;
1853     if (! h.match(/^[0-9a-f]+$/)) return null;
1854     try {
1855 	var unusedBits = parseInt(h.substr(0, 2), 16);
1856 	if (unusedBits < 0 || 7 < unusedBits) return null
1857 
1858 	var value = h.substr(2);
1859 	var bin = "";
1860 	for (var i = 0; i < value.length; i += 2) {
1861 	    var hi = value.substr(i, 2);
1862 	    var bi = parseInt(hi, 16).toString(2);
1863 	    bi = ("0000000" + bi).slice(-8);
1864 	    bin += bi;
1865 	}
1866 	return  bin.substr(0, bin.length - unusedBits);
1867     } catch(ex) {
1868 	return null;
1869     }
1870 }
1871 
1872 /**
1873  * convert from binary string to hexadecimal string of ASN.1 BitString value with unused bit<br/>
1874  * @name binstrtobitstr
1875  * @function
1876  * @param {string} s binary string (ex. "101")
1877  * @return {string} hexadecimal string of ASN.1 BitString value with unused bit
1878  * @since jsrsasign 10.5.4 base64x 1.1.21
1879  * @see bitstrtobinstr
1880  * @see inttobitstr
1881  * @see KJUR.asn1.DERBitString
1882  * 
1883  * @description
1884  * This function converts from an binary string (ex. "101") to 
1885  * hexadecimal string of ASN.1 BitString value
1886  * with unused bit (ex. "05a0"). <br/>
1887  * When "s" is not binary string, this returns null.
1888  * 
1889  * @example
1890  * binstrtobitstr("101") → "05a0"
1891  * binstrtobitstr("001") → "0520"
1892  * binstrtobitstr("11001") → "03c8"
1893  * binstrtobitstr("101000001") → "07a080"
1894  * binstrtobitstr(101) → null // not number
1895  * binstrtobitstr("xyz") → null // not binary string
1896  */
1897 function binstrtobitstr(s) {
1898     if (typeof s != "string") return null;
1899     if (s.match(/^[01]+$/) == null) return null;
1900     try {
1901 	var n = parseInt(s, 2);
1902 	return inttobitstr(n);
1903     } catch(ex) {
1904 	return null;
1905     }
1906 }
1907 
1908 // =======================================================
1909 /**
1910  * convert array of names to bit string<br/>
1911  * @name namearraytobinstr
1912  * @function
1913  * @param {array} namearray array of name string
1914  * @param {object} namedb associative array of name and value
1915  * @return {string} binary string (ex. "110001")
1916  * @since jsrsasign 10.5.21 base64x 1.1.27
1917  * @see KJUR.asn1.x509.KeyUsage
1918  * @see KJUR.asn1.tsp.PKIFailureInfo
1919  * 
1920  * @description
1921  * This function converts from an array of names to
1922  * a binary string. DB value bit will be set.
1923  * Note that ordering of namearray items
1924  * will be ignored.
1925  *
1926  * @example
1927  * db = { a: 0, b: 3, c: 8, d: 9, e: 17, f: 19 };
1928  * namearraytobinstr(['a', 'c', 'd'], db) &rarr: '1000000011'
1929  * namearraytobinstr(['c', 'b'], db) &rarr: '000100001'
1930  */
1931 function namearraytobinstr (namearray, namedb) {
1932     var d = 0;
1933     for (var i = 0; i < namearray.length; i++) {
1934 	d |= 1 << namedb[namearray[i]];
1935     }
1936 
1937     var s = d.toString(2);
1938     var r = "";
1939     for (var i = s.length - 1; i >=0; i--) {
1940 	r += s[i];
1941     }
1942     return r;
1943 }
1944 
1945 // =======================================================
1946 /**
1947  * set class inheritance<br/>
1948  * @name extendClass
1949  * @function
1950  * @param {Function} subClass sub class to set inheritance
1951  * @param {Function} superClass super class to inherit
1952  * @since jsrsasign 10.3.0 base64x 1.1.21
1953  *
1954  * @description
1955  * This function extends a class and set an inheritance
1956  * for member variables and methods.
1957  *
1958  * @example
1959  * var Animal = function() {
1960  *   this.hello = function(){console.log("Hello")};
1961  *   this.name="Ani";
1962  * };
1963  * var Dog = function() {
1964  *   Dog.superclass.constructor.call(this);
1965  *   this.vow = function(){console.log("Vow wow")};
1966  *   this.tail=true;
1967  * };
1968  * extendClass(Dog, Animal);
1969  */
1970 function extendClass(subClass, superClass) {
1971     var F = function() {};
1972     F.prototype = superClass.prototype;
1973     subClass.prototype = new F();
1974     subClass.prototype.constructor = subClass;
1975     subClass.superclass = superClass.prototype;
1976      
1977     if (superClass.prototype.constructor == Object.prototype.constructor) {
1978         superClass.prototype.constructor = superClass;
1979     }
1980 };
1981 
1982