1 /* base64x-1.1.14 (c) 2012-2018 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 * version: 1.1.14 (2018-Apr-21) 7 * 8 * Copyright (c) 2012-2018 Kenji Urushima (kenji.urushima@gmail.com) 9 * 10 * This software is licensed under the terms of the MIT License. 11 * https://kjur.github.io/jsrsasign/license 12 * 13 * The above copyright and license notice shall be 14 * included in all copies or substantial portions of the Software. 15 */ 16 17 /** 18 * @fileOverview 19 * @name base64x-1.1.js 20 * @author Kenji Urushima kenji.urushima@gmail.com 21 * @version jsrsasign 8.0.12 base64x 1.1.14 (2018-Apr-22) 22 * @since jsrsasign 2.1 23 * @license <a href="https://kjur.github.io/jsrsasign/license/">MIT License</a> 24 */ 25 26 var KJUR; 27 if (typeof KJUR == "undefined" || !KJUR) KJUR = {}; 28 if (typeof KJUR.lang == "undefined" || !KJUR.lang) KJUR.lang = {}; 29 30 /** 31 * String and its utility class <br/> 32 * This class provides some static utility methods for string. 33 * @class String and its utility class 34 * @author Kenji Urushima 35 * @version 1.0 (2016-Aug-05) 36 * @since base64x 1.1.7 jsrsasign 5.0.13 37 * @description 38 * <br/> 39 * This class provides static methods for string utility. 40 * <dl> 41 * <dt><b>STRING TYPE CHECKERS</b> 42 * <dd> 43 * <ul> 44 * <li>{@link KJUR.lang.String.isInteger} - check whether argument is an integer</li> 45 * <li>{@link KJUR.lang.String.isHex} - check whether argument is a hexadecimal string</li> 46 * <li>{@link KJUR.lang.String.isBase64} - check whether argument is a Base64 encoded string</li> 47 * <li>{@link KJUR.lang.String.isBase64URL} - check whether argument is a Base64URL encoded string</li> 48 * <li>{@link KJUR.lang.String.isIntegerArray} - check whether argument is an array of integers</li> 49 * </ul> 50 * </dl> 51 */ 52 KJUR.lang.String = function() {}; 53 54 /** 55 * Base64URL and supplementary functions for Tom Wu's base64.js library.<br/> 56 * This class is just provide information about global functions 57 * defined in 'base64x.js'. The 'base64x.js' script file provides 58 * global functions for converting following data each other. 59 * <ul> 60 * <li>(ASCII) String</li> 61 * <li>UTF8 String including CJK, Latin and other characters</li> 62 * <li>byte array</li> 63 * <li>hexadecimal encoded String</li> 64 * <li>Full URIComponent encoded String (such like "%69%94")</li> 65 * <li>Base64 encoded String</li> 66 * <li>Base64URL encoded String</li> 67 * </ul> 68 * All functions in 'base64x.js' are defined in {@link global__} and not 69 * in this class. 70 * 71 * @class Base64URL and supplementary functions for Tom Wu's base64.js library 72 * @author Kenji Urushima 73 * @version 1.1 (07 May 2012) 74 * @requires base64.js 75 * @see <a href="https://kjur.github.io/jsjws/">'jwjws'(JWS JavaScript Library) home page https://kjur.github.io/jsjws/</a> 76 * @see <a href="https://kjur.github.io/jsrsasigns/">'jwrsasign'(RSA Sign JavaScript Library) home page https://kjur.github.io/jsrsasign/</a> 77 */ 78 function Base64x() { 79 } 80 81 // ==== string / byte array ================================ 82 /** 83 * convert a string to an array of character codes 84 * @name stoBA 85 * @function 86 * @param {String} s 87 * @return {Array of Numbers} 88 */ 89 function stoBA(s) { 90 var a = new Array(); 91 for (var i = 0; i < s.length; i++) { 92 a[i] = s.charCodeAt(i); 93 } 94 return a; 95 } 96 97 /** 98 * convert an array of character codes to a string 99 * @name BAtos 100 * @function 101 * @param {Array of Numbers} a array of character codes 102 * @return {String} s 103 */ 104 function BAtos(a) { 105 var s = ""; 106 for (var i = 0; i < a.length; i++) { 107 s = s + String.fromCharCode(a[i]); 108 } 109 return s; 110 } 111 112 // ==== byte array / hex ================================ 113 /** 114 * convert an array of bytes(Number) to hexadecimal string.<br/> 115 * @name BAtohex 116 * @function 117 * @param {Array of Numbers} a array of bytes 118 * @return {String} hexadecimal string 119 */ 120 function BAtohex(a) { 121 var s = ""; 122 for (var i = 0; i < a.length; i++) { 123 var hex1 = a[i].toString(16); 124 if (hex1.length == 1) hex1 = "0" + hex1; 125 s = s + hex1; 126 } 127 return s; 128 } 129 130 // ==== string / hex ================================ 131 /** 132 * convert a ASCII string to a hexadecimal string of ASCII codes.<br/> 133 * NOTE: This can't be used for non ASCII characters. 134 * @name stohex 135 * @function 136 * @param {s} s ASCII string 137 * @return {String} hexadecimal string 138 */ 139 function stohex(s) { 140 return BAtohex(stoBA(s)); 141 } 142 143 // ==== string / base64 ================================ 144 /** 145 * convert a ASCII string to a Base64 encoded string.<br/> 146 * NOTE: This can't be used for non ASCII characters. 147 * @name stob64 148 * @function 149 * @param {s} s ASCII string 150 * @return {String} Base64 encoded string 151 */ 152 function stob64(s) { 153 return hex2b64(stohex(s)); 154 } 155 156 // ==== string / base64url ================================ 157 /** 158 * convert a ASCII string to a Base64URL encoded string.<br/> 159 * NOTE: This can't be used for non ASCII characters. 160 * @name stob64u 161 * @function 162 * @param {s} s ASCII string 163 * @return {String} Base64URL encoded string 164 */ 165 function stob64u(s) { 166 return b64tob64u(hex2b64(stohex(s))); 167 } 168 169 /** 170 * convert a Base64URL encoded string to a ASCII string.<br/> 171 * NOTE: This can't be used for Base64URL encoded non ASCII characters. 172 * @name b64utos 173 * @function 174 * @param {s} s Base64URL encoded string 175 * @return {String} ASCII string 176 */ 177 function b64utos(s) { 178 return BAtos(b64toBA(b64utob64(s))); 179 } 180 181 // ==== base64 / base64url ================================ 182 /** 183 * convert a Base64 encoded string to a Base64URL encoded string.<br/> 184 * @name b64tob64u 185 * @function 186 * @param {String} s Base64 encoded string 187 * @return {String} Base64URL encoded string 188 * @example 189 * b64tob64u("ab+c3f/==") → "ab-c3f_" 190 */ 191 function b64tob64u(s) { 192 s = s.replace(/\=/g, ""); 193 s = s.replace(/\+/g, "-"); 194 s = s.replace(/\//g, "_"); 195 return s; 196 } 197 198 /** 199 * convert a Base64URL encoded string to a Base64 encoded string.<br/> 200 * @name b64utob64 201 * @function 202 * @param {String} s Base64URL encoded string 203 * @return {String} Base64 encoded string 204 * @example 205 * b64utob64("ab-c3f_") → "ab+c3f/==" 206 */ 207 function b64utob64(s) { 208 if (s.length % 4 == 2) s = s + "=="; 209 else if (s.length % 4 == 3) s = s + "="; 210 s = s.replace(/-/g, "+"); 211 s = s.replace(/_/g, "/"); 212 return s; 213 } 214 215 // ==== hex / base64url ================================ 216 /** 217 * convert a hexadecimal string to a Base64URL encoded string.<br/> 218 * @name hextob64u 219 * @function 220 * @param {String} s hexadecimal string 221 * @return {String} Base64URL encoded string 222 * @description 223 * convert a hexadecimal string to a Base64URL encoded string. 224 * NOTE: If leading "0" is omitted and odd number length for 225 * hexadecimal leading "0" is automatically added. 226 */ 227 function hextob64u(s) { 228 if (s.length % 2 == 1) s = "0" + s; 229 return b64tob64u(hex2b64(s)); 230 } 231 232 /** 233 * convert a Base64URL encoded string to a hexadecimal string.<br/> 234 * @name b64utohex 235 * @function 236 * @param {String} s Base64URL encoded string 237 * @return {String} hexadecimal string 238 */ 239 function b64utohex(s) { 240 return b64tohex(b64utob64(s)); 241 } 242 243 // ==== utf8 / base64url ================================ 244 245 /** 246 * convert a UTF-8 encoded string including CJK or Latin to a Base64URL encoded string.<br/> 247 * @name utf8tob64u 248 * @function 249 * @param {String} s UTF-8 encoded string 250 * @return {String} Base64URL encoded string 251 * @since 1.1 252 */ 253 254 /** 255 * convert a Base64URL encoded string to a UTF-8 encoded string including CJK or Latin.<br/> 256 * @name b64utoutf8 257 * @function 258 * @param {String} s Base64URL encoded string 259 * @return {String} UTF-8 encoded string 260 * @since 1.1 261 */ 262 263 var utf8tob64u, b64utoutf8; 264 265 if (typeof Buffer === 'function') { 266 utf8tob64u = function (s) { 267 return b64tob64u(new Buffer(s, 'utf8').toString('base64')); 268 }; 269 270 b64utoutf8 = function (s) { 271 return new Buffer(b64utob64(s), 'base64').toString('utf8'); 272 }; 273 } else { 274 utf8tob64u = function (s) { 275 return hextob64u(uricmptohex(encodeURIComponentAll(s))); 276 }; 277 278 b64utoutf8 = function (s) { 279 return decodeURIComponent(hextouricmp(b64utohex(s))); 280 }; 281 } 282 283 // ==== utf8 / base64url ================================ 284 /** 285 * convert a UTF-8 encoded string including CJK or Latin to a Base64 encoded string.<br/> 286 * @name utf8tob64 287 * @function 288 * @param {String} s UTF-8 encoded string 289 * @return {String} Base64 encoded string 290 * @since 1.1.1 291 */ 292 function utf8tob64(s) { 293 return hex2b64(uricmptohex(encodeURIComponentAll(s))); 294 } 295 296 /** 297 * convert a Base64 encoded string to a UTF-8 encoded string including CJK or Latin.<br/> 298 * @name b64toutf8 299 * @function 300 * @param {String} s Base64 encoded string 301 * @return {String} UTF-8 encoded string 302 * @since 1.1.1 303 */ 304 function b64toutf8(s) { 305 return decodeURIComponent(hextouricmp(b64tohex(s))); 306 } 307 308 // ==== utf8 / hex ================================ 309 /** 310 * convert a UTF-8 encoded string including CJK or Latin to a hexadecimal encoded string.<br/> 311 * @name utf8tohex 312 * @function 313 * @param {String} s UTF-8 encoded string 314 * @return {String} hexadecimal encoded string 315 * @since 1.1.1 316 */ 317 function utf8tohex(s) { 318 return uricmptohex(encodeURIComponentAll(s)); 319 } 320 321 /** 322 * convert a hexadecimal encoded string to a UTF-8 encoded string including CJK or Latin.<br/> 323 * Note that when input is improper hexadecimal string as UTF-8 string, this function returns 324 * 'null'. 325 * @name hextoutf8 326 * @function 327 * @param {String} s hexadecimal encoded string 328 * @return {String} UTF-8 encoded string or null 329 * @since 1.1.1 330 */ 331 function hextoutf8(s) { 332 return decodeURIComponent(hextouricmp(s)); 333 } 334 335 /** 336 * convert a hexadecimal encoded string to raw string including non printable characters.<br/> 337 * @name hextorstr 338 * @function 339 * @param {String} s hexadecimal encoded string 340 * @return {String} raw string 341 * @since 1.1.2 342 * @example 343 * hextorstr("610061") → "a\x00a" 344 */ 345 function hextorstr(sHex) { 346 var s = ""; 347 for (var i = 0; i < sHex.length - 1; i += 2) { 348 s += String.fromCharCode(parseInt(sHex.substr(i, 2), 16)); 349 } 350 return s; 351 } 352 353 /** 354 * convert a raw string including non printable characters to hexadecimal encoded string.<br/> 355 * @name rstrtohex 356 * @function 357 * @param {String} s raw string 358 * @return {String} hexadecimal encoded string 359 * @since 1.1.2 360 * @example 361 * rstrtohex("a\x00a") → "610061" 362 */ 363 function rstrtohex(s) { 364 var result = ""; 365 for (var i = 0; i < s.length; i++) { 366 result += ("0" + s.charCodeAt(i).toString(16)).slice(-2); 367 } 368 return result; 369 } 370 371 // ==== hex / b64nl ======================================= 372 373 /** 374 * convert a hexadecimal string to Base64 encoded string<br/> 375 * @name hextob64 376 * @function 377 * @param {String} s hexadecimal string 378 * @return {String} resulted Base64 encoded string 379 * @since base64x 1.1.3 380 * @description 381 * This function converts from a hexadecimal string to Base64 encoded 382 * string without new lines. 383 * @example 384 * hextob64("616161") → "YWFh" 385 */ 386 function hextob64(s) { 387 return hex2b64(s); 388 } 389 390 /** 391 * convert a hexadecimal string to Base64 encoded string with new lines<br/> 392 * @name hextob64nl 393 * @function 394 * @param {String} s hexadecimal string 395 * @return {String} resulted Base64 encoded string with new lines 396 * @since base64x 1.1.3 397 * @description 398 * This function converts from a hexadecimal string to Base64 encoded 399 * string with new lines for each 64 characters. This is useful for 400 * PEM encoded file. 401 * @example 402 * hextob64nl("123456789012345678901234567890123456789012345678901234567890") 403 * → 404 * MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4 // new line 405 * OTAxMjM0NTY3ODkwCg== 406 */ 407 function hextob64nl(s) { 408 var b64 = hextob64(s); 409 var b64nl = b64.replace(/(.{64})/g, "$1\r\n"); 410 b64nl = b64nl.replace(/\r\n$/, ''); 411 return b64nl; 412 } 413 414 /** 415 * convert a Base64 encoded string with new lines to a hexadecimal string<br/> 416 * @name b64nltohex 417 * @function 418 * @param {String} s Base64 encoded string with new lines 419 * @return {String} hexadecimal string 420 * @since base64x 1.1.3 421 * @description 422 * This function converts from a Base64 encoded 423 * string with new lines to a hexadecimal string. 424 * This is useful to handle PEM encoded file. 425 * This function removes any non-Base64 characters (i.e. not 0-9,A-Z,a-z,\,+,=) 426 * including new line. 427 * @example 428 * hextob64nl( 429 * "MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4\r\n" + 430 * "OTAxMjM0NTY3ODkwCg==\r\n") 431 * → 432 * "123456789012345678901234567890123456789012345678901234567890" 433 */ 434 function b64nltohex(s) { 435 var b64 = s.replace(/[^0-9A-Za-z\/+=]*/g, ''); 436 var hex = b64tohex(b64); 437 return hex; 438 } 439 440 // ==== hex / pem ========================================= 441 442 /** 443 * get PEM string from hexadecimal data and header string 444 * @name hextopem 445 * @function 446 * @param {String} dataHex hexadecimal string of PEM body 447 * @param {String} pemHeader PEM header string (ex. 'RSA PRIVATE KEY') 448 * @return {String} PEM formatted string of input data 449 * @since jsrasign 7.2.1 base64x 1.1.12 450 * @description 451 * This function converts a hexadecimal string to a PEM string with 452 * a specified header. Its line break will be CRLF("\r\n"). 453 * @example 454 * hextopem('616161', 'RSA PRIVATE KEY') → 455 * -----BEGIN PRIVATE KEY----- 456 * YWFh 457 * -----END PRIVATE KEY----- 458 */ 459 function hextopem(dataHex, pemHeader) { 460 var pemBody = hextob64nl(dataHex); 461 return "-----BEGIN " + pemHeader + "-----\r\n" + 462 pemBody + 463 "\r\n-----END " + pemHeader + "-----\r\n"; 464 } 465 466 /** 467 * get hexacedimal string from PEM format data<br/> 468 * @name pemtohex 469 * @function 470 * @param {String} s PEM formatted string 471 * @param {String} sHead PEM header string without BEGIN/END(OPTION) 472 * @return {String} hexadecimal string data of PEM contents 473 * @since jsrsasign 7.2.1 base64x 1.1.12 474 * @description 475 * This static method gets a hexacedimal string of contents 476 * from PEM format data. You can explicitly specify PEM header 477 * by sHead argument. 478 * Any space characters such as white space or new line 479 * will be omitted.<br/> 480 * NOTE: Now {@link KEYUTIL.getHexFromPEM} and {@link X509.pemToHex} 481 * have been deprecated since jsrsasign 7.2.1. 482 * Please use this method instead. 483 * @example 484 * pemtohex("-----BEGIN PUBLIC KEY...") → "3082..." 485 * pemtohex("-----BEGIN CERTIFICATE...", "CERTIFICATE") → "3082..." 486 * pemtohex(" \r\n-----BEGIN DSA PRIVATE KEY...") → "3082..." 487 */ 488 function pemtohex(s, sHead) { 489 if (s.indexOf("-----BEGIN ") == -1) 490 throw "can't find PEM header: " + sHead; 491 492 if (sHead !== undefined) { 493 s = s.replace("-----BEGIN " + sHead + "-----", ""); 494 s = s.replace("-----END " + sHead + "-----", ""); 495 } else { 496 s = s.replace(/-----BEGIN [^-]+-----/, ''); 497 s = s.replace(/-----END [^-]+-----/, ''); 498 } 499 return b64nltohex(s); 500 } 501 502 // ==== hex / ArrayBuffer ================================= 503 504 /** 505 * convert a hexadecimal string to an ArrayBuffer<br/> 506 * @name hextoArrayBuffer 507 * @function 508 * @param {String} hex hexadecimal string 509 * @return {ArrayBuffer} ArrayBuffer 510 * @since jsrsasign 6.1.4 base64x 1.1.8 511 * @description 512 * This function converts from a hexadecimal string to an ArrayBuffer. 513 * @example 514 * hextoArrayBuffer("fffa01") → ArrayBuffer of [255, 250, 1] 515 */ 516 function hextoArrayBuffer(hex) { 517 if (hex.length % 2 != 0) throw "input is not even length"; 518 if (hex.match(/^[0-9A-Fa-f]+$/) == null) throw "input is not hexadecimal"; 519 520 var buffer = new ArrayBuffer(hex.length / 2); 521 var view = new DataView(buffer); 522 523 for (var i = 0; i < hex.length / 2; i++) { 524 view.setUint8(i, parseInt(hex.substr(i * 2, 2), 16)); 525 } 526 527 return buffer; 528 } 529 530 // ==== ArrayBuffer / hex ================================= 531 532 /** 533 * convert an ArrayBuffer to a hexadecimal string<br/> 534 * @name ArrayBuffertohex 535 * @function 536 * @param {ArrayBuffer} buffer ArrayBuffer 537 * @return {String} hexadecimal string 538 * @since jsrsasign 6.1.4 base64x 1.1.8 539 * @description 540 * This function converts from an ArrayBuffer to a hexadecimal string. 541 * @example 542 * var buffer = new ArrayBuffer(3); 543 * var view = new DataView(buffer); 544 * view.setUint8(0, 0xfa); 545 * view.setUint8(1, 0xfb); 546 * view.setUint8(2, 0x01); 547 * ArrayBuffertohex(buffer) → "fafb01" 548 */ 549 function ArrayBuffertohex(buffer) { 550 var hex = ""; 551 var view = new DataView(buffer); 552 553 for (var i = 0; i < buffer.byteLength; i++) { 554 hex += ("00" + view.getUint8(i).toString(16)).slice(-2); 555 } 556 557 return hex; 558 } 559 560 // ==== zulu / int ================================= 561 /** 562 * GeneralizedTime or UTCTime string to milliseconds from Unix origin<br> 563 * @name zulutomsec 564 * @function 565 * @param {String} s GeneralizedTime or UTCTime string (ex. 20170412235959.384Z) 566 * @return {Number} milliseconds from Unix origin time (i.e. Jan 1, 1970 0:00:00 UTC) 567 * @since jsrsasign 7.1.3 base64x 1.1.9 568 * @description 569 * This function converts from GeneralizedTime string (i.e. YYYYMMDDHHmmSSZ) or 570 * UTCTime string (i.e. YYMMDDHHmmSSZ) to milliseconds from Unix origin time 571 * (i.e. Jan 1 1970 0:00:00 UTC). 572 * Argument string may have fraction of seconds and 573 * its length is one or more digits such as "20170410235959.1234567Z". 574 * As for UTCTime, if year "YY" is equal or less than 49 then it is 20YY. 575 * If year "YY" is equal or greater than 50 then it is 19YY. 576 * @example 577 * zulutomsec( "071231235959Z") → 1199145599000 #Mon, 31 Dec 2007 23:59:59 GMT 578 * zulutomsec( "071231235959.1Z") → 1199145599100 #Mon, 31 Dec 2007 23:59:59 GMT 579 * zulutomsec( "071231235959.12345Z") → 1199145599123 #Mon, 31 Dec 2007 23:59:59 GMT 580 * zulutomsec("20071231235959Z") → 1199145599000 #Mon, 31 Dec 2007 23:59:59 GMT 581 * zulutomsec( "931231235959Z") → -410227201000 #Mon, 31 Dec 1956 23:59:59 GMT 582 */ 583 function zulutomsec(s) { 584 var year, month, day, hour, min, sec, msec, d; 585 var sYear, sFrac, sMsec, matchResult; 586 587 matchResult = s.match(/^(\d{2}|\d{4})(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)(|\.\d+)Z$/); 588 589 if (matchResult) { 590 sYear = matchResult[1]; 591 year = parseInt(sYear); 592 if (sYear.length === 2) { 593 if (50 <= year && year < 100) { 594 year = 1900 + year; 595 } else if (0 <= year && year < 50) { 596 year = 2000 + year; 597 } 598 } 599 month = parseInt(matchResult[2]) - 1; 600 day = parseInt(matchResult[3]); 601 hour = parseInt(matchResult[4]); 602 min = parseInt(matchResult[5]); 603 sec = parseInt(matchResult[6]); 604 msec = 0; 605 606 sFrac = matchResult[7]; 607 if (sFrac !== "") { 608 sMsec = (sFrac.substr(1) + "00").substr(0, 3); // .12 -> 012 609 msec = parseInt(sMsec); 610 } 611 return Date.UTC(year, month, day, hour, min, sec, msec); 612 } 613 throw "unsupported zulu format: " + s; 614 } 615 616 /** 617 * GeneralizedTime or UTCTime string to seconds from Unix origin<br> 618 * @name zulutosec 619 * @function 620 * @param {String} s GeneralizedTime or UTCTime string (ex. 20170412235959.384Z) 621 * @return {Number} seconds from Unix origin time (i.e. Jan 1, 1970 0:00:00 UTC) 622 * @since jsrsasign 7.1.3 base64x 1.1.9 623 * @description 624 * This function converts from GeneralizedTime string (i.e. YYYYMMDDHHmmSSZ) or 625 * UTCTime string (i.e. YYMMDDHHmmSSZ) to seconds from Unix origin time 626 * (i.e. Jan 1 1970 0:00:00 UTC). Argument string may have fraction of seconds 627 * however result value will be omitted. 628 * As for UTCTime, if year "YY" is equal or less than 49 then it is 20YY. 629 * If year "YY" is equal or greater than 50 then it is 19YY. 630 * @example 631 * zulutosec( "071231235959Z") → 1199145599 #Mon, 31 Dec 2007 23:59:59 GMT 632 * zulutosec( "071231235959.1Z") → 1199145599 #Mon, 31 Dec 2007 23:59:59 GMT 633 * zulutosec("20071231235959Z") → 1199145599 #Mon, 31 Dec 2007 23:59:59 GMT 634 */ 635 function zulutosec(s) { 636 var msec = zulutomsec(s); 637 return ~~(msec / 1000); 638 } 639 640 // ==== zulu / Date ================================= 641 642 /** 643 * GeneralizedTime or UTCTime string to Date object<br> 644 * @name zulutodate 645 * @function 646 * @param {String} s GeneralizedTime or UTCTime string (ex. 20170412235959.384Z) 647 * @return {Date} Date object for specified time 648 * @since jsrsasign 7.1.3 base64x 1.1.9 649 * @description 650 * This function converts from GeneralizedTime string (i.e. YYYYMMDDHHmmSSZ) or 651 * UTCTime string (i.e. YYMMDDHHmmSSZ) to Date object. 652 * Argument string may have fraction of seconds and 653 * its length is one or more digits such as "20170410235959.1234567Z". 654 * As for UTCTime, if year "YY" is equal or less than 49 then it is 20YY. 655 * If year "YY" is equal or greater than 50 then it is 19YY. 656 * @example 657 * zulutodate( "071231235959Z").toUTCString() → "Mon, 31 Dec 2007 23:59:59 GMT" 658 * zulutodate( "071231235959.1Z").toUTCString() → "Mon, 31 Dec 2007 23:59:59 GMT" 659 * zulutodate("20071231235959Z").toUTCString() → "Mon, 31 Dec 2007 23:59:59 GMT" 660 * zulutodate( "071231235959.34").getMilliseconds() → 340 661 */ 662 function zulutodate(s) { 663 return new Date(zulutomsec(s)); 664 } 665 666 // ==== Date / zulu ================================= 667 668 /** 669 * Date object to zulu time string<br> 670 * @name datetozulu 671 * @function 672 * @param {Date} d Date object for specified time 673 * @param {Boolean} flagUTCTime if this is true year will be YY otherwise YYYY 674 * @param {Boolean} flagMilli if this is true result concludes milliseconds 675 * @return {String} GeneralizedTime or UTCTime string (ex. 20170412235959.384Z) 676 * @since jsrsasign 7.2.0 base64x 1.1.11 677 * @description 678 * This function converts from Date object to GeneralizedTime string (i.e. YYYYMMDDHHmmSSZ) or 679 * UTCTime string (i.e. YYMMDDHHmmSSZ). 680 * As for UTCTime, if year "YY" is equal or less than 49 then it is 20YY. 681 * If year "YY" is equal or greater than 50 then it is 19YY. 682 * If flagMilli is true its result concludes milliseconds such like 683 * "20170520235959.42Z". 684 * @example 685 * d = new Date(Date.UTC(2017,4,20,23,59,59,670)); 686 * datetozulu(d) → "20170520235959Z" 687 * datetozulu(d, true) → "170520235959Z" 688 * datetozulu(d, false, true) → "20170520235959.67Z" 689 */ 690 function datetozulu(d, flagUTCTime, flagMilli) { 691 var s; 692 var year = d.getUTCFullYear(); 693 if (flagUTCTime) { 694 if (year < 1950 || 2049 < year) 695 throw "not proper year for UTCTime: " + year; 696 s = ("" + year).slice(-2); 697 } else { 698 s = ("000" + year).slice(-4); 699 } 700 s += ("0" + (d.getUTCMonth() + 1)).slice(-2); 701 s += ("0" + d.getUTCDate()).slice(-2); 702 s += ("0" + d.getUTCHours()).slice(-2); 703 s += ("0" + d.getUTCMinutes()).slice(-2); 704 s += ("0" + d.getUTCSeconds()).slice(-2); 705 if (flagMilli) { 706 var milli = d.getUTCMilliseconds(); 707 if (milli !== 0) { 708 milli = ("00" + milli).slice(-3); 709 milli = milli.replace(/0+$/g, ""); 710 s += "." + milli; 711 } 712 } 713 s += "Z"; 714 return s; 715 } 716 717 // ==== URIComponent / hex ================================ 718 /** 719 * convert a URLComponent string such like "%67%68" to a hexadecimal string.<br/> 720 * @name uricmptohex 721 * @function 722 * @param {String} s URIComponent string such like "%67%68" 723 * @return {String} hexadecimal string 724 * @since 1.1 725 */ 726 function uricmptohex(s) { 727 return s.replace(/%/g, ""); 728 } 729 730 /** 731 * convert a hexadecimal string to a URLComponent string such like "%67%68".<br/> 732 * @name hextouricmp 733 * @function 734 * @param {String} s hexadecimal string 735 * @return {String} URIComponent string such like "%67%68" 736 * @since 1.1 737 */ 738 function hextouricmp(s) { 739 return s.replace(/(..)/g, "%$1"); 740 } 741 742 // ==== hex / ipv6 ================================= 743 744 /** 745 * convert any IPv6 address to a 16 byte hexadecimal string 746 * @function 747 * @param s string of IPv6 address 748 * @return {String} 16 byte hexadecimal string of IPv6 address 749 * @description 750 * This function converts any IPv6 address representation string 751 * to a 16 byte hexadecimal string of address. 752 * @example 753 * 754 */ 755 function ipv6tohex(s) { 756 var msgMalformedAddress = "malformed IPv6 address"; 757 if (! s.match(/^[0-9A-Fa-f:]+$/)) 758 throw msgMalformedAddress; 759 760 // 1. downcase 761 s = s.toLowerCase(); 762 763 // 2. expand :: 764 var num_colon = s.split(':').length - 1; 765 if (num_colon < 2) throw msgMalformedAddress; 766 var colon_replacer = ':'.repeat(7 - num_colon + 2); 767 s = s.replace('::', colon_replacer); 768 769 // 3. fill zero 770 var a = s.split(':'); 771 if (a.length != 8) throw msgMalformedAddress; 772 for (var i = 0; i < 8; i++) { 773 a[i] = ("0000" + a[i]).slice(-4); 774 } 775 return a.join(''); 776 } 777 778 /** 779 * convert a 16 byte hexadecimal string to RFC 5952 canonicalized IPv6 address<br/> 780 * @name hextoipv6 781 * @function 782 * @param {String} s hexadecimal string of 16 byte IPv6 address 783 * @return {String} IPv6 address string canonicalized by RFC 5952 784 * @since jsrsasign 8.0.10 base64x 1.1.13 785 * @description 786 * This function converts a 16 byte hexadecimal string to 787 * <a href="https://tools.ietf.org/html/rfc5952">RFC 5952</a> 788 * canonicalized IPv6 address string. 789 * @example 790 * hextoip("871020010db8000000000000000000000004") &rarr "2001:db8::4" 791 * hextoip("871020010db8000000000000000000") &rarr raise exception 792 * hextoip("xyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyz") &rarr raise exception 793 */ 794 function hextoipv6(s) { 795 if (! s.match(/^[0-9A-Fa-f]{32}$/)) 796 throw "malformed IPv6 address octet"; 797 798 // 1. downcase 799 s = s.toLowerCase(); 800 801 // 2. split 4 802 var a = s.match(/.{1,4}/g); 803 804 // 3. trim leading 0 805 for (var i = 0; i < 8; i++) { 806 a[i] = a[i].replace(/^0+/, ""); 807 if (a[i] == '') a[i] = '0'; 808 } 809 s = ":" + a.join(":") + ":"; 810 811 // 4. find shrinkables :0:0:... 812 var aZero = s.match(/:(0:){2,}/g); 813 814 // 5. no shrinkable 815 if (aZero === null) return s.slice(1, -1); 816 817 // 6. find max length :0:0:... 818 var item = ''; 819 for (var i = 0; i < aZero.length; i++) { 820 if (aZero[i].length > item.length) item = aZero[i]; 821 } 822 823 // 7. shrink 824 s = s.replace(item, '::'); 825 return s.slice(1, -1); 826 } 827 828 // ==== hex / ip ================================= 829 830 /** 831 * convert a hexadecimal string to IP addresss<br/> 832 * @name hextoip 833 * @function 834 * @param {String} s hexadecimal string of IP address 835 * @return {String} IP address string 836 * @since jsrsasign 8.0.10 base64x 1.1.13 837 * @description 838 * This function converts a hexadecimal string of IPv4 or 839 * IPv6 address to IPv4 or IPv6 address string. 840 * If byte length is not 4 nor 16, this returns a 841 * hexadecimal string without conversion. 842 * @see {@link hextoipv6} 843 * @example 844 * hextoip("c0a80101") &rarr "192.168.1.1" 845 * hextoip("871020010db8000000000000000000000004") &rarr "2001:db8::4" 846 * hextoip("c0a801010203") &rarr "c0a801010203" // 6 bytes 847 * hextoip("zzz")) &rarr raise exception because of not hexadecimal 848 */ 849 function hextoip(s) { 850 var malformedMsg = "malformed hex value"; 851 if (! s.match(/^([0-9A-Fa-f][0-9A-Fa-f]){1,}$/)) 852 throw malformedMsg; 853 if (s.length == 8) { // ipv4 854 var ip; 855 try { 856 ip = parseInt(s.substr(0, 2), 16) + "." + 857 parseInt(s.substr(2, 2), 16) + "." + 858 parseInt(s.substr(4, 2), 16) + "." + 859 parseInt(s.substr(6, 2), 16); 860 return ip; 861 } catch (ex) { 862 throw malformedMsg; 863 } 864 } else if (s.length == 32) { 865 return hextoipv6(s); 866 } else { 867 return s; 868 } 869 } 870 871 /** 872 * convert IPv4/v6 addresss to a hexadecimal string<br/> 873 * @name iptohex 874 * @function 875 * @param {String} s IPv4/v6 address string 876 * @return {String} hexadecimal string of IP address 877 * @since jsrsasign 8.0.12 base64x 1.1.14 878 * @description 879 * This function converts IPv4 or IPv6 address string to 880 * a hexadecimal string of IPv4 or IPv6 address. 881 * @example 882 * iptohex("192.168.1.1") &rarr "c0a80101" 883 * iptohex("2001:db8::4") &rarr "871020010db8000000000000000000000004" 884 * iptohex("zzz")) &rarr raise exception 885 */ 886 function iptohex(s) { 887 var malformedMsg = "malformed IP address"; 888 s = s.toLowerCase(s); 889 890 if (s.match(/^[0-9.]+$/)) { 891 var a = s.split("."); 892 if (a.length !== 4) throw malformedMsg; 893 var hex = ""; 894 try { 895 for (var i = 0; i < 4; i++) { 896 var d = parseInt(a[i]); 897 hex += ("0" + d.toString(16)).slice(-2); 898 } 899 return hex; 900 } catch(ex) { 901 throw malformedMsg; 902 } 903 } else if (s.match(/^[0-9a-f:]+$/) && s.indexOf(":") !== -1) { 904 return ipv6tohex(s); 905 } else { 906 throw malformedMsg; 907 } 908 } 909 910 // ==== URIComponent ================================ 911 /** 912 * convert UTFa hexadecimal string to a URLComponent string such like "%67%68".<br/> 913 * Note that these "<code>0-9A-Za-z!'()*-._~</code>" characters will not 914 * converted to "%xx" format by builtin 'encodeURIComponent()' function. 915 * However this 'encodeURIComponentAll()' function will convert 916 * all of characters into "%xx" format. 917 * @name encodeURIComponentAll 918 * @function 919 * @param {String} s hexadecimal string 920 * @return {String} URIComponent string such like "%67%68" 921 * @since 1.1 922 */ 923 function encodeURIComponentAll(u8) { 924 var s = encodeURIComponent(u8); 925 var s2 = ""; 926 for (var i = 0; i < s.length; i++) { 927 if (s[i] == "%") { 928 s2 = s2 + s.substr(i, 3); 929 i = i + 2; 930 } else { 931 s2 = s2 + "%" + stohex(s[i]); 932 } 933 } 934 return s2; 935 } 936 937 // ==== new lines ================================ 938 /** 939 * convert all DOS new line("\r\n") to UNIX new line("\n") in 940 * a String "s". 941 * @name newline_toUnix 942 * @function 943 * @param {String} s string 944 * @return {String} converted string 945 */ 946 function newline_toUnix(s) { 947 s = s.replace(/\r\n/mg, "\n"); 948 return s; 949 } 950 951 /** 952 * convert all UNIX new line("\r\n") to DOS new line("\n") in 953 * a String "s". 954 * @name newline_toDos 955 * @function 956 * @param {String} s string 957 * @return {String} converted string 958 */ 959 function newline_toDos(s) { 960 s = s.replace(/\r\n/mg, "\n"); 961 s = s.replace(/\n/mg, "\r\n"); 962 return s; 963 } 964 965 // ==== string type checker =================== 966 967 /** 968 * check whether a string is an integer string or not<br/> 969 * @name isInteger 970 * @memberOf KJUR.lang.String 971 * @function 972 * @static 973 * @param {String} s input string 974 * @return {Boolean} true if a string "s" is an integer string otherwise false 975 * @since base64x 1.1.7 jsrsasign 5.0.13 976 * @example 977 * KJUR.lang.String.isInteger("12345") → true 978 * KJUR.lang.String.isInteger("123ab") → false 979 */ 980 KJUR.lang.String.isInteger = function(s) { 981 if (s.match(/^[0-9]+$/)) { 982 return true; 983 } else if (s.match(/^-[0-9]+$/)) { 984 return true; 985 } else { 986 return false; 987 } 988 }; 989 990 /** 991 * check whether a string is an hexadecimal string or not<br/> 992 * @name isHex 993 * @memberOf KJUR.lang.String 994 * @function 995 * @static 996 * @param {String} s input string 997 * @return {Boolean} true if a string "s" is an hexadecimal string otherwise false 998 * @since base64x 1.1.7 jsrsasign 5.0.13 999 * @example 1000 * KJUR.lang.String.isHex("1234") → true 1001 * KJUR.lang.String.isHex("12ab") → true 1002 * KJUR.lang.String.isHex("12AB") → true 1003 * KJUR.lang.String.isHex("12ZY") → false 1004 * KJUR.lang.String.isHex("121") → false -- odd length 1005 */ 1006 KJUR.lang.String.isHex = function(s) { 1007 if (s.length % 2 == 0 && 1008 (s.match(/^[0-9a-f]+$/) || s.match(/^[0-9A-F]+$/))) { 1009 return true; 1010 } else { 1011 return false; 1012 } 1013 }; 1014 1015 /** 1016 * check whether a string is a base64 encoded string or not<br/> 1017 * Input string can conclude new lines or space characters. 1018 * @name isBase64 1019 * @memberOf KJUR.lang.String 1020 * @function 1021 * @static 1022 * @param {String} s input string 1023 * @return {Boolean} true if a string "s" is a base64 encoded string otherwise false 1024 * @since base64x 1.1.7 jsrsasign 5.0.13 1025 * @example 1026 * KJUR.lang.String.isBase64("YWE=") → true 1027 * KJUR.lang.String.isBase64("YW_=") → false 1028 * KJUR.lang.String.isBase64("YWE") → false -- length shall be multiples of 4 1029 */ 1030 KJUR.lang.String.isBase64 = function(s) { 1031 s = s.replace(/\s+/g, ""); 1032 if (s.match(/^[0-9A-Za-z+\/]+={0,3}$/) && s.length % 4 == 0) { 1033 return true; 1034 } else { 1035 return false; 1036 } 1037 }; 1038 1039 /** 1040 * check whether a string is a base64url encoded string or not<br/> 1041 * Input string can conclude new lines or space characters. 1042 * @name isBase64URL 1043 * @memberOf KJUR.lang.String 1044 * @function 1045 * @static 1046 * @param {String} s input string 1047 * @return {Boolean} true if a string "s" is a base64url encoded string otherwise false 1048 * @since base64x 1.1.7 jsrsasign 5.0.13 1049 * @example 1050 * KJUR.lang.String.isBase64URL("YWE") → true 1051 * KJUR.lang.String.isBase64URL("YW-") → true 1052 * KJUR.lang.String.isBase64URL("YW+") → false 1053 */ 1054 KJUR.lang.String.isBase64URL = function(s) { 1055 if (s.match(/[+/=]/)) return false; 1056 s = b64utob64(s); 1057 return KJUR.lang.String.isBase64(s); 1058 }; 1059 1060 /** 1061 * check whether a string is a string of integer array or not<br/> 1062 * Input string can conclude new lines or space characters. 1063 * @name isIntegerArray 1064 * @memberOf KJUR.lang.String 1065 * @function 1066 * @static 1067 * @param {String} s input string 1068 * @return {Boolean} true if a string "s" is a string of integer array otherwise false 1069 * @since base64x 1.1.7 jsrsasign 5.0.13 1070 * @example 1071 * KJUR.lang.String.isIntegerArray("[1,2,3]") → true 1072 * KJUR.lang.String.isIntegerArray(" [1, 2, 3 ] ") → true 1073 * KJUR.lang.String.isIntegerArray("[a,2]") → false 1074 */ 1075 KJUR.lang.String.isIntegerArray = function(s) { 1076 s = s.replace(/\s+/g, ""); 1077 if (s.match(/^\[[0-9,]+\]$/)) { 1078 return true; 1079 } else { 1080 return false; 1081 } 1082 }; 1083 1084 // ==== others ================================ 1085 1086 /** 1087 * canonicalize hexadecimal string of positive integer<br/> 1088 * @name hextoposhex 1089 * @function 1090 * @param {String} s hexadecimal string 1091 * @return {String} canonicalized hexadecimal string of positive integer 1092 * @since base64x 1.1.10 jsrsasign 7.1.4 1093 * @description 1094 * This method canonicalize a hexadecimal string of positive integer 1095 * for two's complement representation. 1096 * Canonicalized hexadecimal string of positive integer will be: 1097 * <ul> 1098 * <li>Its length is always even.</li> 1099 * <li>If odd length it will be padded with leading zero.<li> 1100 * <li>If it is even length and its first character is "8" or greater, 1101 * it will be padded with "00" to make it positive integer.</li> 1102 * </ul> 1103 * @example 1104 * hextoposhex("abcd") → "00abcd" 1105 * hextoposhex("1234") → "1234" 1106 * hextoposhex("12345") → "012345" 1107 */ 1108 function hextoposhex(s) { 1109 if (s.length % 2 == 1) return "0" + s; 1110 if (s.substr(0, 1) > "7") return "00" + s; 1111 return s; 1112 } 1113 1114 /** 1115 * convert string of integer array to hexadecimal string.<br/> 1116 * @name intarystrtohex 1117 * @function 1118 * @param {String} s string of integer array 1119 * @return {String} hexadecimal string 1120 * @since base64x 1.1.6 jsrsasign 5.0.2 1121 * @throws "malformed integer array string: *" for wrong input 1122 * @description 1123 * This function converts a string of JavaScript integer array to 1124 * a hexadecimal string. Each integer value shall be in a range 1125 * from 0 to 255 otherwise it raise exception. Input string can 1126 * have extra space or newline string so that they will be ignored. 1127 * 1128 * @example 1129 * intarystrtohex(" [123, 34, 101, 34, 58] ") 1130 * → 7b2265223a (i.e. '{"e":' as string) 1131 */ 1132 function intarystrtohex(s) { 1133 s = s.replace(/^\s*\[\s*/, ''); 1134 s = s.replace(/\s*\]\s*$/, ''); 1135 s = s.replace(/\s*/g, ''); 1136 try { 1137 var hex = s.split(/,/).map(function(element, index, array) { 1138 var i = parseInt(element); 1139 if (i < 0 || 255 < i) throw "integer not in range 0-255"; 1140 var hI = ("00" + i.toString(16)).slice(-2); 1141 return hI; 1142 }).join(''); 1143 return hex; 1144 } catch(ex) { 1145 throw "malformed integer array string: " + ex; 1146 } 1147 } 1148 1149 /** 1150 * find index of string where two string differs 1151 * @name strdiffidx 1152 * @function 1153 * @param {String} s1 string to compare 1154 * @param {String} s2 string to compare 1155 * @return {Number} string index of where character differs. Return -1 if same. 1156 * @since jsrsasign 4.9.0 base64x 1.1.5 1157 * @example 1158 * strdiffidx("abcdefg", "abcd4fg") -> 4 1159 * strdiffidx("abcdefg", "abcdefg") -> -1 1160 * strdiffidx("abcdefg", "abcdef") -> 6 1161 * strdiffidx("abcdefgh", "abcdef") -> 6 1162 */ 1163 var strdiffidx = function(s1, s2) { 1164 var n = s1.length; 1165 if (s1.length > s2.length) n = s2.length; 1166 for (var i = 0; i < n; i++) { 1167 if (s1.charCodeAt(i) != s2.charCodeAt(i)) return i; 1168 } 1169 if (s1.length != s2.length) return n; 1170 return -1; // same 1171 }; 1172 1173 1174