1 /* base64x-1.1.16 (c) 2012-2020 Kenji Urushima | kjur.github.com/jsrsasign/license 2 */ 3 /* 4 * base64x.js - Base64url and supplementary functions for Tom Wu's base64.js library 5 * 6 * Copyright (c) 2012-2020 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 9.0.0 base64x 1.1.16 (2020-Aug-13) 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 */ 254 255 /** 256 * convert a Base64URL encoded string to a UTF-8 encoded string including CJK or Latin.<br/> 257 * @name b64utoutf8 258 * @function 259 * @param {String} s Base64URL encoded string 260 * @return {String} UTF-8 encoded string 261 * @since 1.1 262 */ 263 264 var utf8tob64u, b64utoutf8; 265 266 if (typeof Buffer === 'function') { 267 utf8tob64u = function (s) { 268 return b64tob64u(new Buffer(s, 'utf8').toString('base64')); 269 }; 270 271 b64utoutf8 = function (s) { 272 return new Buffer(b64utob64(s), 'base64').toString('utf8'); 273 }; 274 } else { 275 utf8tob64u = function (s) { 276 return hextob64u(uricmptohex(encodeURIComponentAll(s))); 277 }; 278 279 b64utoutf8 = function (s) { 280 return decodeURIComponent(hextouricmp(b64utohex(s))); 281 }; 282 } 283 284 // ==== utf8 / base64url ================================ 285 /** 286 * convert a UTF-8 encoded string including CJK or Latin to a Base64 encoded string.<br/> 287 * @name utf8tob64 288 * @function 289 * @param {String} s UTF-8 encoded string 290 * @return {String} Base64 encoded string 291 * @since 1.1.1 292 */ 293 function utf8tob64(s) { 294 return hex2b64(uricmptohex(encodeURIComponentAll(s))); 295 } 296 297 /** 298 * convert a Base64 encoded string to a UTF-8 encoded string including CJK or Latin.<br/> 299 * @name b64toutf8 300 * @function 301 * @param {String} s Base64 encoded string 302 * @return {String} UTF-8 encoded string 303 * @since 1.1.1 304 */ 305 function b64toutf8(s) { 306 return decodeURIComponent(hextouricmp(b64tohex(s))); 307 } 308 309 // ==== utf8 / hex ================================ 310 /** 311 * convert a UTF-8 encoded string including CJK or Latin to a hexadecimal encoded string.<br/> 312 * @name utf8tohex 313 * @function 314 * @param {String} s UTF-8 encoded string 315 * @return {String} hexadecimal encoded string 316 * @since 1.1.1 317 */ 318 function utf8tohex(s) { 319 return uricmptohex(encodeURIComponentAll(s)); 320 } 321 322 /** 323 * convert a hexadecimal encoded string to a UTF-8 encoded string including CJK or Latin.<br/> 324 * Note that when input is improper hexadecimal string as UTF-8 string, this function returns 325 * 'null'. 326 * @name hextoutf8 327 * @function 328 * @param {String} s hexadecimal encoded string 329 * @return {String} UTF-8 encoded string or null 330 * @since 1.1.1 331 */ 332 function hextoutf8(s) { 333 return decodeURIComponent(hextouricmp(s)); 334 } 335 336 /** 337 * convert a hexadecimal encoded string to raw string including non printable characters.<br/> 338 * @name hextorstr 339 * @function 340 * @param {String} s hexadecimal encoded string 341 * @return {String} raw string 342 * @since 1.1.2 343 * @example 344 * hextorstr("610061") → "a\x00a" 345 */ 346 function hextorstr(sHex) { 347 var s = ""; 348 for (var i = 0; i < sHex.length - 1; i += 2) { 349 s += String.fromCharCode(parseInt(sHex.substr(i, 2), 16)); 350 } 351 return s; 352 } 353 354 /** 355 * convert a raw string including non printable characters to hexadecimal encoded string.<br/> 356 * @name rstrtohex 357 * @function 358 * @param {String} s raw string 359 * @return {String} hexadecimal encoded string 360 * @since 1.1.2 361 * @example 362 * rstrtohex("a\x00a") → "610061" 363 */ 364 function rstrtohex(s) { 365 var result = ""; 366 for (var i = 0; i < s.length; i++) { 367 result += ("0" + s.charCodeAt(i).toString(16)).slice(-2); 368 } 369 return result; 370 } 371 372 // ==== hex / b64nl ======================================= 373 374 /** 375 * convert a hexadecimal string to Base64 encoded string<br/> 376 * @name hextob64 377 * @function 378 * @param {String} s hexadecimal string 379 * @return {String} resulted Base64 encoded string 380 * @since base64x 1.1.3 381 * @description 382 * This function converts from a hexadecimal string to Base64 encoded 383 * string without new lines. 384 * @example 385 * hextob64("616161") → "YWFh" 386 */ 387 function hextob64(s) { 388 return hex2b64(s); 389 } 390 391 /** 392 * convert a hexadecimal string to Base64 encoded string with new lines<br/> 393 * @name hextob64nl 394 * @function 395 * @param {String} s hexadecimal string 396 * @return {String} resulted Base64 encoded string with new lines 397 * @since base64x 1.1.3 398 * @description 399 * This function converts from a hexadecimal string to Base64 encoded 400 * string with new lines for each 64 characters. This is useful for 401 * PEM encoded file. 402 * @example 403 * hextob64nl("123456789012345678901234567890123456789012345678901234567890") 404 * → 405 * MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4 // new line 406 * OTAxMjM0NTY3ODkwCg== 407 */ 408 function hextob64nl(s) { 409 var b64 = hextob64(s); 410 var b64nl = b64.replace(/(.{64})/g, "$1\r\n"); 411 b64nl = b64nl.replace(/\r\n$/, ''); 412 return b64nl; 413 } 414 415 /** 416 * convert a Base64 encoded string with new lines to a hexadecimal string<br/> 417 * @name b64nltohex 418 * @function 419 * @param {String} s Base64 encoded string with new lines 420 * @return {String} hexadecimal string 421 * @since base64x 1.1.3 422 * @description 423 * This function converts from a Base64 encoded 424 * string with new lines to a hexadecimal string. 425 * This is useful to handle PEM encoded file. 426 * This function removes any non-Base64 characters (i.e. not 0-9,A-Z,a-z,\,+,=) 427 * including new line. 428 * @example 429 * hextob64nl( 430 * "MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4\r\n" + 431 * "OTAxMjM0NTY3ODkwCg==\r\n") 432 * → 433 * "123456789012345678901234567890123456789012345678901234567890" 434 */ 435 function b64nltohex(s) { 436 var b64 = s.replace(/[^0-9A-Za-z\/+=]*/g, ''); 437 var hex = b64tohex(b64); 438 return hex; 439 } 440 441 // ==== hex / pem ========================================= 442 443 /** 444 * get PEM string from hexadecimal data and header string 445 * @name hextopem 446 * @function 447 * @param {String} dataHex hexadecimal string of PEM body 448 * @param {String} pemHeader PEM header string (ex. 'RSA PRIVATE KEY') 449 * @return {String} PEM formatted string of input data 450 * @since jsrasign 7.2.1 base64x 1.1.12 451 * @description 452 * This function converts a hexadecimal string to a PEM string with 453 * a specified header. Its line break will be CRLF("\r\n"). 454 * @example 455 * hextopem('616161', 'RSA PRIVATE KEY') → 456 * -----BEGIN PRIVATE KEY----- 457 * YWFh 458 * -----END PRIVATE KEY----- 459 */ 460 function hextopem(dataHex, pemHeader) { 461 var pemBody = hextob64nl(dataHex); 462 return "-----BEGIN " + pemHeader + "-----\r\n" + 463 pemBody + 464 "\r\n-----END " + pemHeader + "-----\r\n"; 465 } 466 467 /** 468 * get hexacedimal string from PEM format data<br/> 469 * @name pemtohex 470 * @function 471 * @param {String} s PEM formatted string 472 * @param {String} sHead PEM header string without BEGIN/END(OPTION) 473 * @return {String} hexadecimal string data of PEM contents 474 * @since jsrsasign 7.2.1 base64x 1.1.12 475 * @description 476 * This static method gets a hexacedimal string of contents 477 * from PEM format data. You can explicitly specify PEM header 478 * by sHead argument. 479 * Any space characters such as white space or new line 480 * will be omitted.<br/> 481 * NOTE: Now {@link KEYUTIL.getHexFromPEM} and {@link X509.pemToHex} 482 * have been deprecated since jsrsasign 7.2.1. 483 * Please use this method instead. 484 * NOTE2: From jsrsasign 8.0.14 this can process multi 485 * "BEGIN...END" section such as "EC PRIVATE KEY" with "EC PARAMETERS". 486 * @example 487 * pemtohex("-----BEGIN PUBLIC KEY...") → "3082..." 488 * pemtohex("-----BEGIN CERTIFICATE...", "CERTIFICATE") → "3082..." 489 * pemtohex(" \r\n-----BEGIN DSA PRIVATE KEY...") → "3082..." 490 * pemtohex("-----BEGIN EC PARAMETERS...----BEGIN EC PRIVATE KEY...." → "3082..." 491 */ 492 function pemtohex(s, sHead) { 493 if (s.indexOf("-----BEGIN ") == -1) 494 throw "can't find PEM header: " + sHead; 495 496 if (sHead !== undefined) { 497 s = s.replace(new RegExp('^[^]*-----BEGIN ' + sHead + '-----'), ''); 498 s = s.replace(new RegExp('-----END ' + sHead + '-----[^]*$'), ''); 499 } else { 500 s = s.replace(/^[^]*-----BEGIN [^-]+-----/, ''); 501 s = s.replace(/-----END [^-]+-----[^]*$/, ''); 502 } 503 return b64nltohex(s); 504 } 505 506 // ==== hex / ArrayBuffer ================================= 507 508 /** 509 * convert a hexadecimal string to an ArrayBuffer<br/> 510 * @name hextoArrayBuffer 511 * @function 512 * @param {String} hex hexadecimal string 513 * @return {ArrayBuffer} ArrayBuffer 514 * @since jsrsasign 6.1.4 base64x 1.1.8 515 * @description 516 * This function converts from a hexadecimal string to an ArrayBuffer. 517 * @example 518 * hextoArrayBuffer("fffa01") → ArrayBuffer of [255, 250, 1] 519 */ 520 function hextoArrayBuffer(hex) { 521 if (hex.length % 2 != 0) throw "input is not even length"; 522 if (hex.match(/^[0-9A-Fa-f]+$/) == null) throw "input is not hexadecimal"; 523 524 var buffer = new ArrayBuffer(hex.length / 2); 525 var view = new DataView(buffer); 526 527 for (var i = 0; i < hex.length / 2; i++) { 528 view.setUint8(i, parseInt(hex.substr(i * 2, 2), 16)); 529 } 530 531 return buffer; 532 } 533 534 // ==== ArrayBuffer / hex ================================= 535 536 /** 537 * convert an ArrayBuffer to a hexadecimal string<br/> 538 * @name ArrayBuffertohex 539 * @function 540 * @param {ArrayBuffer} buffer ArrayBuffer 541 * @return {String} hexadecimal string 542 * @since jsrsasign 6.1.4 base64x 1.1.8 543 * @description 544 * This function converts from an ArrayBuffer to a hexadecimal string. 545 * @example 546 * var buffer = new ArrayBuffer(3); 547 * var view = new DataView(buffer); 548 * view.setUint8(0, 0xfa); 549 * view.setUint8(1, 0xfb); 550 * view.setUint8(2, 0x01); 551 * ArrayBuffertohex(buffer) → "fafb01" 552 */ 553 function ArrayBuffertohex(buffer) { 554 var hex = ""; 555 var view = new DataView(buffer); 556 557 for (var i = 0; i < buffer.byteLength; i++) { 558 hex += ("00" + view.getUint8(i).toString(16)).slice(-2); 559 } 560 561 return hex; 562 } 563 564 // ==== zulu / int ================================= 565 /** 566 * GeneralizedTime or UTCTime string to milliseconds from Unix origin<br> 567 * @name zulutomsec 568 * @function 569 * @param {String} s GeneralizedTime or UTCTime string (ex. 20170412235959.384Z) 570 * @return {Number} milliseconds from Unix origin time (i.e. Jan 1, 1970 0:00:00 UTC) 571 * @since jsrsasign 7.1.3 base64x 1.1.9 572 * @description 573 * This function converts from GeneralizedTime string (i.e. YYYYMMDDHHmmSSZ) or 574 * UTCTime string (i.e. YYMMDDHHmmSSZ) to milliseconds from Unix origin time 575 * (i.e. Jan 1 1970 0:00:00 UTC). 576 * Argument string may have fraction of seconds and 577 * its length is one or more digits such as "20170410235959.1234567Z". 578 * As for UTCTime, if year "YY" is equal or less than 49 then it is 20YY. 579 * If year "YY" is equal or greater than 50 then it is 19YY. 580 * @example 581 * zulutomsec( "071231235959Z") → 1199145599000 #Mon, 31 Dec 2007 23:59:59 GMT 582 * zulutomsec( "071231235959.1Z") → 1199145599100 #Mon, 31 Dec 2007 23:59:59 GMT 583 * zulutomsec( "071231235959.12345Z") → 1199145599123 #Mon, 31 Dec 2007 23:59:59 GMT 584 * zulutomsec("20071231235959Z") → 1199145599000 #Mon, 31 Dec 2007 23:59:59 GMT 585 * zulutomsec( "931231235959Z") → -410227201000 #Mon, 31 Dec 1956 23:59:59 GMT 586 */ 587 function zulutomsec(s) { 588 var year, month, day, hour, min, sec, msec, d; 589 var sYear, sFrac, sMsec, matchResult; 590 591 matchResult = s.match(/^(\d{2}|\d{4})(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)(|\.\d+)Z$/); 592 593 if (matchResult) { 594 sYear = matchResult[1]; 595 year = parseInt(sYear); 596 if (sYear.length === 2) { 597 if (50 <= year && year < 100) { 598 year = 1900 + year; 599 } else if (0 <= year && year < 50) { 600 year = 2000 + year; 601 } 602 } 603 month = parseInt(matchResult[2]) - 1; 604 day = parseInt(matchResult[3]); 605 hour = parseInt(matchResult[4]); 606 min = parseInt(matchResult[5]); 607 sec = parseInt(matchResult[6]); 608 msec = 0; 609 610 sFrac = matchResult[7]; 611 if (sFrac !== "") { 612 sMsec = (sFrac.substr(1) + "00").substr(0, 3); // .12 -> 012 613 msec = parseInt(sMsec); 614 } 615 return Date.UTC(year, month, day, hour, min, sec, msec); 616 } 617 throw "unsupported zulu format: " + s; 618 } 619 620 /** 621 * GeneralizedTime or UTCTime string to seconds from Unix origin<br> 622 * @name zulutosec 623 * @function 624 * @param {String} s GeneralizedTime or UTCTime string (ex. 20170412235959.384Z) 625 * @return {Number} seconds from Unix origin time (i.e. Jan 1, 1970 0:00:00 UTC) 626 * @since jsrsasign 7.1.3 base64x 1.1.9 627 * @description 628 * This function converts from GeneralizedTime string (i.e. YYYYMMDDHHmmSSZ) or 629 * UTCTime string (i.e. YYMMDDHHmmSSZ) to seconds from Unix origin time 630 * (i.e. Jan 1 1970 0:00:00 UTC). Argument string may have fraction of seconds 631 * however result value will be omitted. 632 * As for UTCTime, if year "YY" is equal or less than 49 then it is 20YY. 633 * If year "YY" is equal or greater than 50 then it is 19YY. 634 * @example 635 * zulutosec( "071231235959Z") → 1199145599 #Mon, 31 Dec 2007 23:59:59 GMT 636 * zulutosec( "071231235959.1Z") → 1199145599 #Mon, 31 Dec 2007 23:59:59 GMT 637 * zulutosec("20071231235959Z") → 1199145599 #Mon, 31 Dec 2007 23:59:59 GMT 638 */ 639 function zulutosec(s) { 640 var msec = zulutomsec(s); 641 return ~~(msec / 1000); 642 } 643 644 // ==== zulu / Date ================================= 645 646 /** 647 * GeneralizedTime or UTCTime string to Date object<br> 648 * @name zulutodate 649 * @function 650 * @param {String} s GeneralizedTime or UTCTime string (ex. 20170412235959.384Z) 651 * @return {Date} Date object for specified time 652 * @since jsrsasign 7.1.3 base64x 1.1.9 653 * @description 654 * This function converts from GeneralizedTime string (i.e. YYYYMMDDHHmmSSZ) or 655 * UTCTime string (i.e. YYMMDDHHmmSSZ) to Date object. 656 * Argument string may have fraction of seconds and 657 * its length is one or more digits such as "20170410235959.1234567Z". 658 * As for UTCTime, if year "YY" is equal or less than 49 then it is 20YY. 659 * If year "YY" is equal or greater than 50 then it is 19YY. 660 * @example 661 * zulutodate( "071231235959Z").toUTCString() → "Mon, 31 Dec 2007 23:59:59 GMT" 662 * zulutodate( "071231235959.1Z").toUTCString() → "Mon, 31 Dec 2007 23:59:59 GMT" 663 * zulutodate("20071231235959Z").toUTCString() → "Mon, 31 Dec 2007 23:59:59 GMT" 664 * zulutodate( "071231235959.34").getMilliseconds() → 340 665 */ 666 function zulutodate(s) { 667 return new Date(zulutomsec(s)); 668 } 669 670 // ==== Date / zulu ================================= 671 672 /** 673 * Date object to zulu time string<br> 674 * @name datetozulu 675 * @function 676 * @param {Date} d Date object for specified time 677 * @param {Boolean} flagUTCTime if this is true year will be YY otherwise YYYY 678 * @param {Boolean} flagMilli if this is true result concludes milliseconds 679 * @return {String} GeneralizedTime or UTCTime string (ex. 20170412235959.384Z) 680 * @since jsrsasign 7.2.0 base64x 1.1.11 681 * @description 682 * This function converts from Date object to GeneralizedTime string (i.e. YYYYMMDDHHmmSSZ) or 683 * UTCTime string (i.e. YYMMDDHHmmSSZ). 684 * As for UTCTime, if year "YY" is equal or less than 49 then it is 20YY. 685 * If year "YY" is equal or greater than 50 then it is 19YY. 686 * If flagMilli is true its result concludes milliseconds such like 687 * "20170520235959.42Z". 688 * @example 689 * d = new Date(Date.UTC(2017,4,20,23,59,59,670)); 690 * datetozulu(d) → "20170520235959Z" 691 * datetozulu(d, true) → "170520235959Z" 692 * datetozulu(d, false, true) → "20170520235959.67Z" 693 */ 694 function datetozulu(d, flagUTCTime, flagMilli) { 695 var s; 696 var year = d.getUTCFullYear(); 697 if (flagUTCTime) { 698 if (year < 1950 || 2049 < year) 699 throw "not proper year for UTCTime: " + year; 700 s = ("" + year).slice(-2); 701 } else { 702 s = ("000" + year).slice(-4); 703 } 704 s += ("0" + (d.getUTCMonth() + 1)).slice(-2); 705 s += ("0" + d.getUTCDate()).slice(-2); 706 s += ("0" + d.getUTCHours()).slice(-2); 707 s += ("0" + d.getUTCMinutes()).slice(-2); 708 s += ("0" + d.getUTCSeconds()).slice(-2); 709 if (flagMilli) { 710 var milli = d.getUTCMilliseconds(); 711 if (milli !== 0) { 712 milli = ("00" + milli).slice(-3); 713 milli = milli.replace(/0+$/g, ""); 714 s += "." + milli; 715 } 716 } 717 s += "Z"; 718 return s; 719 } 720 721 // ==== URIComponent / hex ================================ 722 /** 723 * convert a URLComponent string such like "%67%68" to a hexadecimal string.<br/> 724 * @name uricmptohex 725 * @function 726 * @param {String} s URIComponent string such like "%67%68" 727 * @return {String} hexadecimal string 728 * @since 1.1 729 */ 730 function uricmptohex(s) { 731 return s.replace(/%/g, ""); 732 } 733 734 /** 735 * convert a hexadecimal string to a URLComponent string such like "%67%68".<br/> 736 * @name hextouricmp 737 * @function 738 * @param {String} s hexadecimal string 739 * @return {String} URIComponent string such like "%67%68" 740 * @since 1.1 741 */ 742 function hextouricmp(s) { 743 return s.replace(/(..)/g, "%$1"); 744 } 745 746 // ==== hex / ipv6 ================================= 747 748 /** 749 * convert any IPv6 address to a 16 byte hexadecimal string 750 * @function 751 * @param s string of IPv6 address 752 * @return {String} 16 byte hexadecimal string of IPv6 address 753 * @description 754 * This function converts any IPv6 address representation string 755 * to a 16 byte hexadecimal string of address. 756 * @example 757 * 758 */ 759 function ipv6tohex(s) { 760 var msgMalformedAddress = "malformed IPv6 address"; 761 if (! s.match(/^[0-9A-Fa-f:]+$/)) 762 throw msgMalformedAddress; 763 764 // 1. downcase 765 s = s.toLowerCase(); 766 767 // 2. expand :: 768 var num_colon = s.split(':').length - 1; 769 if (num_colon < 2) throw msgMalformedAddress; 770 var colon_replacer = ':'.repeat(7 - num_colon + 2); 771 s = s.replace('::', colon_replacer); 772 773 // 3. fill zero 774 var a = s.split(':'); 775 if (a.length != 8) throw msgMalformedAddress; 776 for (var i = 0; i < 8; i++) { 777 a[i] = ("0000" + a[i]).slice(-4); 778 } 779 return a.join(''); 780 } 781 782 /** 783 * convert a 16 byte hexadecimal string to RFC 5952 canonicalized IPv6 address<br/> 784 * @name hextoipv6 785 * @function 786 * @param {String} s hexadecimal string of 16 byte IPv6 address 787 * @return {String} IPv6 address string canonicalized by RFC 5952 788 * @since jsrsasign 8.0.10 base64x 1.1.13 789 * @description 790 * This function converts a 16 byte hexadecimal string to 791 * <a href="https://tools.ietf.org/html/rfc5952">RFC 5952</a> 792 * canonicalized IPv6 address string. 793 * @example 794 * hextoip("871020010db8000000000000000000000004") &rarr "2001:db8::4" 795 * hextoip("871020010db8000000000000000000") &rarr raise exception 796 * hextoip("xyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyz") &rarr raise exception 797 */ 798 function hextoipv6(s) { 799 if (! s.match(/^[0-9A-Fa-f]{32}$/)) 800 throw "malformed IPv6 address octet"; 801 802 // 1. downcase 803 s = s.toLowerCase(); 804 805 // 2. split 4 806 var a = s.match(/.{1,4}/g); 807 808 // 3. trim leading 0 809 for (var i = 0; i < 8; i++) { 810 a[i] = a[i].replace(/^0+/, ""); 811 if (a[i] == '') a[i] = '0'; 812 } 813 s = ":" + a.join(":") + ":"; 814 815 // 4. find shrinkables :0:0:... 816 var aZero = s.match(/:(0:){2,}/g); 817 818 // 5. no shrinkable 819 if (aZero === null) return s.slice(1, -1); 820 821 // 6. find max length :0:0:... 822 var item = ''; 823 for (var i = 0; i < aZero.length; i++) { 824 if (aZero[i].length > item.length) item = aZero[i]; 825 } 826 827 // 7. shrink 828 s = s.replace(item, '::'); 829 return s.slice(1, -1); 830 } 831 832 // ==== hex / ip ================================= 833 834 /** 835 * convert a hexadecimal string to IP addresss<br/> 836 * @name hextoip 837 * @function 838 * @param {String} s hexadecimal string of IP address 839 * @return {String} IP address string 840 * @since jsrsasign 8.0.10 base64x 1.1.13 841 * @description 842 * This function converts a hexadecimal string of IPv4 or 843 * IPv6 address to IPv4 or IPv6 address string. 844 * If byte length is not 4 nor 16, this returns a 845 * hexadecimal string without conversion. 846 * @see {@link hextoipv6} 847 * @example 848 * hextoip("c0a80101") &rarr "192.168.1.1" 849 * hextoip("871020010db8000000000000000000000004") &rarr "2001:db8::4" 850 * hextoip("c0a801010203") &rarr "c0a801010203" // 6 bytes 851 * hextoip("zzz")) &rarr raise exception because of not hexadecimal 852 */ 853 function hextoip(s) { 854 var malformedMsg = "malformed hex value"; 855 if (! s.match(/^([0-9A-Fa-f][0-9A-Fa-f]){1,}$/)) 856 throw malformedMsg; 857 if (s.length == 8) { // ipv4 858 var ip; 859 try { 860 ip = parseInt(s.substr(0, 2), 16) + "." + 861 parseInt(s.substr(2, 2), 16) + "." + 862 parseInt(s.substr(4, 2), 16) + "." + 863 parseInt(s.substr(6, 2), 16); 864 return ip; 865 } catch (ex) { 866 throw malformedMsg; 867 } 868 } else if (s.length == 32) { 869 return hextoipv6(s); 870 } else { 871 return s; 872 } 873 } 874 875 /** 876 * convert IPv4/v6 addresss to a hexadecimal string<br/> 877 * @name iptohex 878 * @function 879 * @param {String} s IPv4/v6 address string 880 * @return {String} hexadecimal string of IP address 881 * @since jsrsasign 8.0.12 base64x 1.1.14 882 * @description 883 * This function converts IPv4 or IPv6 address string to 884 * a hexadecimal string of IPv4 or IPv6 address. 885 * @example 886 * iptohex("192.168.1.1") &rarr "c0a80101" 887 * iptohex("2001:db8::4") &rarr "871020010db8000000000000000000000004" 888 * iptohex("zzz")) &rarr raise exception 889 */ 890 function iptohex(s) { 891 var malformedMsg = "malformed IP address"; 892 s = s.toLowerCase(s); 893 894 if (s.match(/^[0-9.]+$/)) { 895 var a = s.split("."); 896 if (a.length !== 4) throw malformedMsg; 897 var hex = ""; 898 try { 899 for (var i = 0; i < 4; i++) { 900 var d = parseInt(a[i]); 901 hex += ("0" + d.toString(16)).slice(-2); 902 } 903 return hex; 904 } catch(ex) { 905 throw malformedMsg; 906 } 907 } else if (s.match(/^[0-9a-f:]+$/) && s.indexOf(":") !== -1) { 908 return ipv6tohex(s); 909 } else { 910 throw malformedMsg; 911 } 912 } 913 914 // ==== URIComponent ================================ 915 /** 916 * convert UTFa hexadecimal string to a URLComponent string such like "%67%68".<br/> 917 * Note that these "<code>0-9A-Za-z!'()*-._~</code>" characters will not 918 * converted to "%xx" format by builtin 'encodeURIComponent()' function. 919 * However this 'encodeURIComponentAll()' function will convert 920 * all of characters into "%xx" format. 921 * @name encodeURIComponentAll 922 * @function 923 * @param {String} s hexadecimal string 924 * @return {String} URIComponent string such like "%67%68" 925 * @since 1.1 926 */ 927 function encodeURIComponentAll(u8) { 928 var s = encodeURIComponent(u8); 929 var s2 = ""; 930 for (var i = 0; i < s.length; i++) { 931 if (s[i] == "%") { 932 s2 = s2 + s.substr(i, 3); 933 i = i + 2; 934 } else { 935 s2 = s2 + "%" + stohex(s[i]); 936 } 937 } 938 return s2; 939 } 940 941 // ==== new lines ================================ 942 /** 943 * convert all DOS new line("\r\n") to UNIX new line("\n") in 944 * a String "s". 945 * @name newline_toUnix 946 * @function 947 * @param {String} s string 948 * @return {String} converted string 949 */ 950 function newline_toUnix(s) { 951 s = s.replace(/\r\n/mg, "\n"); 952 return s; 953 } 954 955 /** 956 * convert all UNIX new line("\r\n") to DOS new line("\n") in 957 * a String "s". 958 * @name newline_toDos 959 * @function 960 * @param {String} s string 961 * @return {String} converted string 962 */ 963 function newline_toDos(s) { 964 s = s.replace(/\r\n/mg, "\n"); 965 s = s.replace(/\n/mg, "\r\n"); 966 return s; 967 } 968 969 // ==== string type checker =================== 970 971 /** 972 * check whether a string is an integer string or not<br/> 973 * @name isInteger 974 * @memberOf KJUR.lang.String 975 * @function 976 * @static 977 * @param {String} s input string 978 * @return {Boolean} true if a string "s" is an integer string otherwise false 979 * @since base64x 1.1.7 jsrsasign 5.0.13 980 * @example 981 * KJUR.lang.String.isInteger("12345") → true 982 * KJUR.lang.String.isInteger("123ab") → false 983 */ 984 KJUR.lang.String.isInteger = function(s) { 985 if (s.match(/^[0-9]+$/)) { 986 return true; 987 } else if (s.match(/^-[0-9]+$/)) { 988 return true; 989 } else { 990 return false; 991 } 992 }; 993 994 /** 995 * check whether a string is an hexadecimal string or not<br/> 996 * @name isHex 997 * @memberOf KJUR.lang.String 998 * @function 999 * @static 1000 * @param {String} s input string 1001 * @return {Boolean} true if a string "s" is an hexadecimal string otherwise false 1002 * @since base64x 1.1.7 jsrsasign 5.0.13 1003 * @example 1004 * KJUR.lang.String.isHex("1234") → true 1005 * KJUR.lang.String.isHex("12ab") → true 1006 * KJUR.lang.String.isHex("12AB") → true 1007 * KJUR.lang.String.isHex("12ZY") → false 1008 * KJUR.lang.String.isHex("121") → false -- odd length 1009 */ 1010 KJUR.lang.String.isHex = function(s) { 1011 if (s.length % 2 == 0 && 1012 (s.match(/^[0-9a-f]+$/) || s.match(/^[0-9A-F]+$/))) { 1013 return true; 1014 } else { 1015 return false; 1016 } 1017 }; 1018 1019 /** 1020 * check whether a string is a base64 encoded string or not<br/> 1021 * Input string can conclude new lines or space characters. 1022 * @name isBase64 1023 * @memberOf KJUR.lang.String 1024 * @function 1025 * @static 1026 * @param {String} s input string 1027 * @return {Boolean} true if a string "s" is a base64 encoded string otherwise false 1028 * @since base64x 1.1.7 jsrsasign 5.0.13 1029 * @example 1030 * KJUR.lang.String.isBase64("YWE=") → true 1031 * KJUR.lang.String.isBase64("YW_=") → false 1032 * KJUR.lang.String.isBase64("YWE") → false -- length shall be multiples of 4 1033 */ 1034 KJUR.lang.String.isBase64 = function(s) { 1035 s = s.replace(/\s+/g, ""); 1036 if (s.match(/^[0-9A-Za-z+\/]+={0,3}$/) && s.length % 4 == 0) { 1037 return true; 1038 } else { 1039 return false; 1040 } 1041 }; 1042 1043 /** 1044 * check whether a string is a base64url encoded string or not<br/> 1045 * Input string can conclude new lines or space characters. 1046 * @name isBase64URL 1047 * @memberOf KJUR.lang.String 1048 * @function 1049 * @static 1050 * @param {String} s input string 1051 * @return {Boolean} true if a string "s" is a base64url encoded string otherwise false 1052 * @since base64x 1.1.7 jsrsasign 5.0.13 1053 * @example 1054 * KJUR.lang.String.isBase64URL("YWE") → true 1055 * KJUR.lang.String.isBase64URL("YW-") → true 1056 * KJUR.lang.String.isBase64URL("YW+") → false 1057 */ 1058 KJUR.lang.String.isBase64URL = function(s) { 1059 if (s.match(/[+/=]/)) return false; 1060 s = b64utob64(s); 1061 return KJUR.lang.String.isBase64(s); 1062 }; 1063 1064 /** 1065 * check whether a string is a string of integer array or not<br/> 1066 * Input string can conclude new lines or space characters. 1067 * @name isIntegerArray 1068 * @memberOf KJUR.lang.String 1069 * @function 1070 * @static 1071 * @param {String} s input string 1072 * @return {Boolean} true if a string "s" is a string of integer array otherwise false 1073 * @since base64x 1.1.7 jsrsasign 5.0.13 1074 * @example 1075 * KJUR.lang.String.isIntegerArray("[1,2,3]") → true 1076 * KJUR.lang.String.isIntegerArray(" [1, 2, 3 ] ") → true 1077 * KJUR.lang.String.isIntegerArray("[a,2]") → false 1078 */ 1079 KJUR.lang.String.isIntegerArray = function(s) { 1080 s = s.replace(/\s+/g, ""); 1081 if (s.match(/^\[[0-9,]+\]$/)) { 1082 return true; 1083 } else { 1084 return false; 1085 } 1086 }; 1087 1088 /** 1089 * check whether a string consists of PrintableString characters<br/> 1090 * @name isPrintable 1091 * @memberOf KJUR.lang.String 1092 * @function 1093 * @static 1094 * @param {String} s input string 1095 * @return {Boolean} true if a string "s" consists of PrintableString characters 1096 * @since jsrsasign 9.0.0 base64x 1.1.16 1097 * A PrintableString consists of following characters 1098 * <pre> 1099 * 0-9A-Za-z '()+,-./:=? 1100 * </pre> 1101 * This method returns false when other characters than above. 1102 * Otherwise it returns true. 1103 * @example 1104 * KJUR.lang.String.isPrintable("abc") → true 1105 * KJUR.lang.String.isPrintable("abc@") → false 1106 * KJUR.lang.String.isPrintable("あいう") → false 1107 */ 1108 KJUR.lang.String.isPrintable = function(s) { 1109 if (s.match(/^[0-9A-Za-z '()+,-./:=?]*$/) !== null) return true; 1110 return false; 1111 }; 1112 1113 /** 1114 * check whether a string consists of IAString characters<br/> 1115 * @name isIA5 1116 * @memberOf KJUR.lang.String 1117 * @function 1118 * @static 1119 * @param {String} s input string 1120 * @return {Boolean} true if a string "s" consists of IA5String characters 1121 * @since jsrsasign 9.0.0 base64x 1.1.16 1122 * A IA5String consists of following characters 1123 * <pre> 1124 * %x00-21/%x23-7F (i.e. ASCII characters excludes double quote(%x22) 1125 * </pre> 1126 * This method returns false when other characters than above. 1127 * Otherwise it returns true. 1128 * @example 1129 * KJUR.lang.String.isIA5("abc") → true 1130 * KJUR.lang.String.isIA5('"abc"') → false 1131 * KJUR.lang.String.isIA5("あいう") → false 1132 */ 1133 KJUR.lang.String.isIA5 = function(s) { 1134 if (s.match(/^[\x20-\x21\x23-\x7f]*$/) !== null) return true; 1135 return false; 1136 }; 1137 1138 /** 1139 * check whether a string is RFC 822 mail address<br/> 1140 * @name isMail 1141 * @memberOf KJUR.lang.String 1142 * @function 1143 * @static 1144 * @param {String} s input string 1145 * @return {Boolean} true if a string "s" RFC 822 mail address 1146 * @since jsrsasign 9.0.0 base64x 1.1.16 1147 * This static method will check string s is RFC 822 compliant mail address. 1148 * @example 1149 * KJUR.lang.String.isMail("abc") → false 1150 * KJUR.lang.String.isMail("abc@example") → false 1151 * KJUR.lang.String.isMail("abc@example.com") → true 1152 */ 1153 KJUR.lang.String.isMail = function(s) { 1154 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; 1155 return false; 1156 }; 1157 1158 // ==== others ================================ 1159 1160 /** 1161 * canonicalize hexadecimal string of positive integer<br/> 1162 * @name hextoposhex 1163 * @function 1164 * @param {String} s hexadecimal string 1165 * @return {String} canonicalized hexadecimal string of positive integer 1166 * @since base64x 1.1.10 jsrsasign 7.1.4 1167 * @description 1168 * This method canonicalize a hexadecimal string of positive integer 1169 * for two's complement representation. 1170 * Canonicalized hexadecimal string of positive integer will be: 1171 * <ul> 1172 * <li>Its length is always even.</li> 1173 * <li>If odd length it will be padded with leading zero.<li> 1174 * <li>If it is even length and its first character is "8" or greater, 1175 * it will be padded with "00" to make it positive integer.</li> 1176 * </ul> 1177 * @example 1178 * hextoposhex("abcd") → "00abcd" 1179 * hextoposhex("1234") → "1234" 1180 * hextoposhex("12345") → "012345" 1181 */ 1182 function hextoposhex(s) { 1183 if (s.length % 2 == 1) return "0" + s; 1184 if (s.substr(0, 1) > "7") return "00" + s; 1185 return s; 1186 } 1187 1188 /** 1189 * convert string of integer array to hexadecimal string.<br/> 1190 * @name intarystrtohex 1191 * @function 1192 * @param {String} s string of integer array 1193 * @return {String} hexadecimal string 1194 * @since base64x 1.1.6 jsrsasign 5.0.2 1195 * @throws "malformed integer array string: *" for wrong input 1196 * @description 1197 * This function converts a string of JavaScript integer array to 1198 * a hexadecimal string. Each integer value shall be in a range 1199 * from 0 to 255 otherwise it raise exception. Input string can 1200 * have extra space or newline string so that they will be ignored. 1201 * 1202 * @example 1203 * intarystrtohex(" [123, 34, 101, 34, 58] ") 1204 * → 7b2265223a (i.e. '{"e":' as string) 1205 */ 1206 function intarystrtohex(s) { 1207 s = s.replace(/^\s*\[\s*/, ''); 1208 s = s.replace(/\s*\]\s*$/, ''); 1209 s = s.replace(/\s*/g, ''); 1210 try { 1211 var hex = s.split(/,/).map(function(element, index, array) { 1212 var i = parseInt(element); 1213 if (i < 0 || 255 < i) throw "integer not in range 0-255"; 1214 var hI = ("00" + i.toString(16)).slice(-2); 1215 return hI; 1216 }).join(''); 1217 return hex; 1218 } catch(ex) { 1219 throw "malformed integer array string: " + ex; 1220 } 1221 } 1222 1223 /** 1224 * find index of string where two string differs 1225 * @name strdiffidx 1226 * @function 1227 * @param {String} s1 string to compare 1228 * @param {String} s2 string to compare 1229 * @return {Number} string index of where character differs. Return -1 if same. 1230 * @since jsrsasign 4.9.0 base64x 1.1.5 1231 * @example 1232 * strdiffidx("abcdefg", "abcd4fg") -> 4 1233 * strdiffidx("abcdefg", "abcdefg") -> -1 1234 * strdiffidx("abcdefg", "abcdef") -> 6 1235 * strdiffidx("abcdefgh", "abcdef") -> 6 1236 */ 1237 var strdiffidx = function(s1, s2) { 1238 var n = s1.length; 1239 if (s1.length > s2.length) n = s2.length; 1240 for (var i = 0; i < n; i++) { 1241 if (s1.charCodeAt(i) != s2.charCodeAt(i)) return i; 1242 } 1243 if (s1.length != s2.length) return n; 1244 return -1; // same 1245 }; 1246 1247 1248