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