1 /* keyutil-1.3.0.js (c) 2013-2023 Kenji Urushima | kjur.github.io/jsrsasign/license 2 */ 3 /* 4 * keyutil.js - key utility for PKCS#1/5/8 PEM, RSA/DSA/ECDSA key object 5 * 6 * Copyright (c) 2013-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 * @fileOverview 16 * @name keyutil-1.0.js 17 * @author Kenji Urushima kenji.urushima@gmail.com 18 * @version jsrsasign 10.9.0 keyutil 1.3.0 (2023-Nov-25) 19 * @since jsrsasign 4.1.4 20 * @license <a href="https://kjur.github.io/jsrsasign/license/">MIT License</a> 21 */ 22 23 /** 24 * @name KEYUTIL 25 * @class class for RSA/ECC/DSA key utility 26 * @description 27 * <br/> 28 * {@link KEYUTIL} class is an update of former {@link PKCS5PKEY} class. 29 * {@link KEYUTIL} class has following features: 30 * <dl> 31 * <dt><b>key loading - {@link KEYUTIL.getKey}</b> 32 * <dd> 33 * <ul> 34 * <li>supports RSAKey and KJUR.crypto.{ECDSA,DSA} key object</li> 35 * <li>supports private key and public key</li> 36 * <li>supports encrypted and plain private key</li> 37 * <li>supports PKCS#1, PKCS#5 and PKCS#8 key</li> 38 * <li>supports public key in X.509 certificate</li> 39 * <li>key represented by JSON object</li> 40 * </ul> 41 * NOTE1: Encrypted PKCS#8 only supports PBKDF2/HmacSHA1/3DES <br/> 42 * NOTE2: Encrypted PKCS#5 supports DES-CBC, DES-EDE3-CBC, AES-{128,192.256}-CBC <br/> 43 * 44 * <dt><b>exporting key - {@link KEYUTIL.getPEM}</b> 45 * <dd> 46 * {@link KEYUTIL.getPEM} method supports following formats: 47 * <ul> 48 * <li>supports RSA/EC/DSA keys</li> 49 * <li>PKCS#1 plain RSA/EC/DSA private key</li> 50 * <li>PKCS#5 encrypted RSA/EC/DSA private key with DES-CBC, DES-EDE3-CBC, AES-{128,192.256}-CBC</li> 51 * <li>PKCS#8 plain RSA/EC/DSA private key</li> 52 * <li>PKCS#8 encrypted RSA/EC/DSA private key with PBKDF2_HmacSHA1_3DES</li> 53 * </ul> 54 * 55 * <dt><b>keypair generation - {@link KEYUTIL.generateKeypair}</b> 56 * <ul> 57 * <li>generate key pair of {@link RSAKey} or {@link KJUR.crypto.ECDSA}.</li> 58 * <li>generate private key and convert it to PKCS#5 encrypted private key.</li> 59 * </ul> 60 * NOTE: {@link KJUR.crypto.DSA} is not yet supported. 61 * </dl> 62 * 63 * @example 64 * // 1. loading PEM private key 65 * var key = KEYUTIL.getKey(pemPKCS1PrivateKey); 66 * var key = KEYUTIL.getKey(pemPKCS5EncryptedPrivateKey, "passcode"); 67 * var key = KEYUTIL.getKey(pemPKCS5PlainRsaDssEcPrivateKey); 68 * var key = KEYUTIL.getKey(pemPKC85PlainPrivateKey); 69 * var key = KEYUTIL.getKey(pemPKC85EncryptedPrivateKey, "passcode"); 70 * // 2. loading PEM public key 71 * var key = KEYUTIL.getKey(pemPKCS8PublicKey); 72 * var key = KEYUTIL.getKey(pemX509Certificate); 73 * // 3. exporting private key 74 * var pem = KEYUTIL.getPEM(privateKeyObj, "PKCS1PRV"); 75 * var pem = KEYUTIL.getPEM(privateKeyObj, "PKCS5PRV", "passcode"); // DES-EDE3-CBC by default 76 * var pem = KEYUTIL.getPEM(privateKeyObj, "PKCS5PRV", "passcode", "DES-CBC"); 77 * var pem = KEYUTIL.getPEM(privateKeyObj, "PKCS8PRV"); 78 * var pem = KEYUTIL.getPEM(privateKeyObj, "PKCS8PRV", "passcode"); 79 * // 4. exporting public key 80 * var pem = KEYUTIL.getPEM(publicKeyObj); 81 */ 82 var KEYUTIL = function() { 83 // ***************************************************************** 84 // *** PRIVATE PROPERTIES AND METHODS ******************************* 85 // ***************************************************************** 86 // shared key decryption ------------------------------------------ 87 var decryptAES = function(dataHex, keyHex, ivHex) { 88 return decryptGeneral(CryptoJS.AES, dataHex, keyHex, ivHex); 89 }; 90 91 var decrypt3DES = function(dataHex, keyHex, ivHex) { 92 return decryptGeneral(CryptoJS.TripleDES, dataHex, keyHex, ivHex); 93 }; 94 95 var decryptDES = function(dataHex, keyHex, ivHex) { 96 return decryptGeneral(CryptoJS.DES, dataHex, keyHex, ivHex); 97 }; 98 99 var decryptGeneral = function(f, dataHex, keyHex, ivHex) { 100 var data = CryptoJS.enc.Hex.parse(dataHex); 101 var key = CryptoJS.enc.Hex.parse(keyHex); 102 var iv = CryptoJS.enc.Hex.parse(ivHex); 103 var encrypted = {}; 104 encrypted.key = key; 105 encrypted.iv = iv; 106 encrypted.ciphertext = data; 107 var decrypted = f.decrypt(encrypted, key, { iv: iv }); 108 return CryptoJS.enc.Hex.stringify(decrypted); 109 }; 110 111 // shared key decryption ------------------------------------------ 112 var encryptAES = function(dataHex, keyHex, ivHex) { 113 return encryptGeneral(CryptoJS.AES, dataHex, keyHex, ivHex); 114 }; 115 116 var encrypt3DES = function(dataHex, keyHex, ivHex) { 117 return encryptGeneral(CryptoJS.TripleDES, dataHex, keyHex, ivHex); 118 }; 119 120 var encryptDES = function(dataHex, keyHex, ivHex) { 121 return encryptGeneral(CryptoJS.DES, dataHex, keyHex, ivHex); 122 }; 123 124 var encryptGeneral = function(f, dataHex, keyHex, ivHex) { 125 var data = CryptoJS.enc.Hex.parse(dataHex); 126 var key = CryptoJS.enc.Hex.parse(keyHex); 127 var iv = CryptoJS.enc.Hex.parse(ivHex); 128 var encryptedHex = f.encrypt(data, key, { iv: iv }); 129 var encryptedWA = CryptoJS.enc.Hex.parse(encryptedHex.toString()); 130 var encryptedB64 = CryptoJS.enc.Base64.stringify(encryptedWA); 131 return encryptedB64; 132 }; 133 134 // other methods and properties ---------------------------------------- 135 var ALGLIST = { 136 'AES-256-CBC': { 'proc': decryptAES, 'eproc': encryptAES, keylen: 32, ivlen: 16 }, 137 'AES-192-CBC': { 'proc': decryptAES, 'eproc': encryptAES, keylen: 24, ivlen: 16 }, 138 'AES-128-CBC': { 'proc': decryptAES, 'eproc': encryptAES, keylen: 16, ivlen: 16 }, 139 'DES-EDE3-CBC': { 'proc': decrypt3DES, 'eproc': encrypt3DES, keylen: 24, ivlen: 8 }, 140 'DES-CBC': { 'proc': decryptDES, 'eproc': encryptDES, keylen: 8, ivlen: 8 } 141 }; 142 143 var getFuncByName = function(algName) { 144 return ALGLIST[algName]['proc']; 145 }; 146 147 var _generateIvSaltHex = function(numBytes) { 148 var wa = CryptoJS.lib.WordArray.random(numBytes); 149 var hex = CryptoJS.enc.Hex.stringify(wa); 150 return hex; 151 }; 152 153 var _parsePKCS5PEM = function(sPKCS5PEM) { 154 var info = {}; 155 var matchResult1 = sPKCS5PEM.match(new RegExp("DEK-Info: ([^,]+),([0-9A-Fa-f]+)", "m")); 156 if (matchResult1) { 157 info.cipher = matchResult1[1]; 158 info.ivsalt = matchResult1[2]; 159 } 160 var matchResult2 = sPKCS5PEM.match(new RegExp("-----BEGIN ([A-Z]+) PRIVATE KEY-----")); 161 if (matchResult2) { 162 info.type = matchResult2[1]; 163 } 164 var i1 = -1; 165 var lenNEWLINE = 0; 166 if (sPKCS5PEM.indexOf("\r\n\r\n") != -1) { 167 i1 = sPKCS5PEM.indexOf("\r\n\r\n"); 168 lenNEWLINE = 2; 169 } 170 if (sPKCS5PEM.indexOf("\n\n") != -1) { 171 i1 = sPKCS5PEM.indexOf("\n\n"); 172 lenNEWLINE = 1; 173 } 174 var i2 = sPKCS5PEM.indexOf("-----END"); 175 if (i1 != -1 && i2 != -1) { 176 var s = sPKCS5PEM.substring(i1 + lenNEWLINE * 2, i2 - lenNEWLINE); 177 s = s.replace(/\s+/g, ''); 178 info.data = s; 179 } 180 return info; 181 }; 182 183 var _getKeyAndUnusedIvByPasscodeAndIvsalt = function(algName, passcode, ivsaltHex) { 184 //alert("ivsaltHex(2) = " + ivsaltHex); 185 var saltHex = ivsaltHex.substring(0, 16); 186 //alert("salt = " + saltHex); 187 188 var salt = CryptoJS.enc.Hex.parse(saltHex); 189 var data = CryptoJS.enc.Utf8.parse(passcode); 190 //alert("salt = " + salt); 191 //alert("data = " + data); 192 193 var nRequiredBytes = ALGLIST[algName]['keylen'] + ALGLIST[algName]['ivlen']; 194 var hHexValueJoined = ''; 195 var hLastValue = null; 196 //alert("nRequiredBytes = " + nRequiredBytes); 197 for (;;) { 198 var h = CryptoJS.algo.MD5.create(); 199 if (hLastValue != null) { 200 h.update(hLastValue); 201 } 202 h.update(data); 203 h.update(salt); 204 hLastValue = h.finalize(); 205 hHexValueJoined = hHexValueJoined + CryptoJS.enc.Hex.stringify(hLastValue); 206 //alert("joined = " + hHexValueJoined); 207 if (hHexValueJoined.length >= nRequiredBytes * 2) { 208 break; 209 } 210 } 211 var result = {}; 212 result.keyhex = hHexValueJoined.substr(0, ALGLIST[algName]['keylen'] * 2); 213 result.ivhex = hHexValueJoined.substr(ALGLIST[algName]['keylen'] * 2, ALGLIST[algName]['ivlen'] * 2); 214 return result; 215 }; 216 217 /* 218 * @param {String} privateKeyB64 base64 string of encrypted private key 219 * @param {String} sharedKeyAlgName algorithm name of shared key encryption 220 * @param {String} sharedKeyHex hexadecimal string of shared key to encrypt 221 * @param {String} ivsaltHex hexadecimal string of IV and salt 222 * @param {String} hexadecimal string of decrypted private key 223 */ 224 var _decryptKeyB64 = function(privateKeyB64, sharedKeyAlgName, sharedKeyHex, ivsaltHex) { 225 var privateKeyWA = CryptoJS.enc.Base64.parse(privateKeyB64); 226 var privateKeyHex = CryptoJS.enc.Hex.stringify(privateKeyWA); 227 var f = ALGLIST[sharedKeyAlgName]['proc']; 228 var decryptedKeyHex = f(privateKeyHex, sharedKeyHex, ivsaltHex); 229 return decryptedKeyHex; 230 }; 231 232 /* 233 * @param {String} privateKeyHex hexadecimal string of private key 234 * @param {String} sharedKeyAlgName algorithm name of shared key encryption 235 * @param {String} sharedKeyHex hexadecimal string of shared key to encrypt 236 * @param {String} ivsaltHex hexadecimal string of IV and salt 237 * @param {String} base64 string of encrypted private key 238 */ 239 var _encryptKeyHex = function(privateKeyHex, sharedKeyAlgName, sharedKeyHex, ivsaltHex) { 240 var f = ALGLIST[sharedKeyAlgName]['eproc']; 241 var encryptedKeyB64 = f(privateKeyHex, sharedKeyHex, ivsaltHex); 242 return encryptedKeyB64; 243 }; 244 245 // ***************************************************************** 246 // *** PUBLIC PROPERTIES AND METHODS ******************************* 247 // ***************************************************************** 248 return { 249 // -- UTILITY METHODS ------------------------------------------------------------ 250 /** 251 * decrypt private key by shared key 252 * @name version 253 * @memberOf KEYUTIL 254 * @property {String} version 255 * @description version string of KEYUTIL class 256 */ 257 version: "1.0.0", 258 259 /** 260 * parse PEM formatted passcode protected PKCS#5 private key 261 * @name parsePKCS5PEM 262 * @memberOf KEYUTIL 263 * @function 264 * @param {String} sEncryptedPEM PEM formatted protected passcode protected PKCS#5 private key 265 * @return {Hash} hash of key information 266 * @description 267 * Resulted hash has following attributes. 268 * <ul> 269 * <li>cipher - symmetric key algorithm name (ex. 'DES-EBE3-CBC', 'AES-256-CBC')</li> 270 * <li>ivsalt - IV used for decrypt. Its heading 8 bytes will be used for passcode salt.</li> 271 * <li>type - asymmetric key algorithm name of private key described in PEM header.</li> 272 * <li>data - base64 encoded encrypted private key.</li> 273 * </ul> 274 * 275 */ 276 parsePKCS5PEM: function(sPKCS5PEM) { 277 return _parsePKCS5PEM(sPKCS5PEM); 278 }, 279 280 /** 281 * the same function as OpenSSL EVP_BytsToKey to generate shared key and IV 282 * @name getKeyAndUnusedIvByPasscodeAndIvsalt 283 * @memberOf KEYUTIL 284 * @function 285 * @param {String} algName name of symmetric key algorithm (ex. 'DES-EBE3-CBC') 286 * @param {String} passcode passcode to decrypt private key (ex. 'password') 287 * @param {String} hexadecimal string of IV. heading 8 bytes will be used for passcode salt 288 * @return {Hash} hash of key and unused IV (ex. {keyhex:2fe3..., ivhex:3fad..}) 289 */ 290 getKeyAndUnusedIvByPasscodeAndIvsalt: function(algName, passcode, ivsaltHex) { 291 return _getKeyAndUnusedIvByPasscodeAndIvsalt(algName, passcode, ivsaltHex); 292 }, 293 294 decryptKeyB64: function(privateKeyB64, sharedKeyAlgName, sharedKeyHex, ivsaltHex) { 295 return _decryptKeyB64(privateKeyB64, sharedKeyAlgName, sharedKeyHex, ivsaltHex); 296 }, 297 298 /** 299 * decrypt PEM formatted protected PKCS#5 private key with passcode 300 * @name getDecryptedKeyHex 301 * @memberOf KEYUTIL 302 * @function 303 * @param {String} sEncryptedPEM PEM formatted protected passcode protected PKCS#5 private key 304 * @param {String} passcode passcode to decrypt private key (ex. 'password') 305 * @return {String} hexadecimal string of decrypted RSA priavte key 306 */ 307 getDecryptedKeyHex: function(sEncryptedPEM, passcode) { 308 // 1. parse pem 309 var info = _parsePKCS5PEM(sEncryptedPEM); 310 var publicKeyAlgName = info.type; 311 var sharedKeyAlgName = info.cipher; 312 var ivsaltHex = info.ivsalt; 313 var privateKeyB64 = info.data; 314 //alert("ivsaltHex = " + ivsaltHex); 315 316 // 2. generate shared key 317 var sharedKeyInfo = _getKeyAndUnusedIvByPasscodeAndIvsalt(sharedKeyAlgName, passcode, ivsaltHex); 318 var sharedKeyHex = sharedKeyInfo.keyhex; 319 //alert("sharedKeyHex = " + sharedKeyHex); 320 321 // 3. decrypt private key 322 var decryptedKey = _decryptKeyB64(privateKeyB64, sharedKeyAlgName, sharedKeyHex, ivsaltHex); 323 return decryptedKey; 324 }, 325 326 /* 327 * get PEM formatted encrypted PKCS#5 private key from hexadecimal string of plain private key 328 * @name getEncryptedPKCS5PEMFromPrvKeyHex 329 * @memberOf KEYUTIL 330 * @function 331 * @param {String} pemHeadAlg algorithm name in the pem header (i.e. RSA,EC or DSA) 332 * @param {String} hPrvKey hexadecimal string of plain private key 333 * @param {String} passcode pass code to protect private key (ex. password) 334 * @param {String} sharedKeyAlgName algorithm name to protect private key (ex. AES-256-CBC) 335 * @param {String} ivsaltHex hexadecimal string of IV and salt 336 * @return {String} string of PEM formatted encrypted PKCS#5 private key 337 * @since pkcs5pkey 1.0.2 338 * @description 339 * <br/> 340 * generate PEM formatted encrypted PKCS#5 private key by hexadecimal string encoded 341 * ASN.1 object of plain RSA private key. 342 * Following arguments can be omitted. 343 * <ul> 344 * <li>alg - AES-256-CBC will be used if omitted.</li> 345 * <li>ivsaltHex - automatically generate IV and salt which length depends on algorithm</li> 346 * </ul> 347 * NOTE1: DES-CBC, DES-EDE3-CBC, AES-{128,192.256}-CBC algorithm are supported. 348 * @example 349 * var pem = 350 * KEYUTIL.getEncryptedPKCS5PEMFromPrvKeyHex(plainKeyHex, "password"); 351 * var pem2 = 352 * KEYUTIL.getEncryptedPKCS5PEMFromPrvKeyHex(plainKeyHex, "password", "AES-128-CBC"); 353 * var pem3 = 354 * KEYUTIL.getEncryptedPKCS5PEMFromPrvKeyHex(plainKeyHex, "password", "AES-128-CBC", "1f3d02..."); 355 */ 356 getEncryptedPKCS5PEMFromPrvKeyHex: function(pemHeadAlg, hPrvKey, passcode, sharedKeyAlgName, ivsaltHex) { 357 var sPEM = ""; 358 359 // 1. set sharedKeyAlgName if undefined (default AES-256-CBC) 360 if (typeof sharedKeyAlgName == "undefined" || 361 sharedKeyAlgName == null) { 362 sharedKeyAlgName = "AES-256-CBC"; 363 } 364 if (typeof ALGLIST[sharedKeyAlgName] == "undefined") 365 throw new Error("KEYUTIL unsupported algorithm: " + 366 sharedKeyAlgName); 367 368 // 2. set ivsaltHex if undefined 369 if (typeof ivsaltHex == "undefined" || ivsaltHex == null) { 370 var ivlen = ALGLIST[sharedKeyAlgName]['ivlen']; 371 var randIV = _generateIvSaltHex(ivlen); 372 ivsaltHex = randIV.toUpperCase(); 373 } 374 375 // 3. get shared key 376 //alert("ivsalthex=" + ivsaltHex); 377 var sharedKeyInfo = _getKeyAndUnusedIvByPasscodeAndIvsalt(sharedKeyAlgName, passcode, ivsaltHex); 378 var sharedKeyHex = sharedKeyInfo.keyhex; 379 // alert("sharedKeyHex = " + sharedKeyHex); 380 381 // 3. get encrypted Key in Base64 382 var encryptedKeyB64 = _encryptKeyHex(hPrvKey, sharedKeyAlgName, sharedKeyHex, ivsaltHex); 383 384 var pemBody = encryptedKeyB64.replace(/(.{64})/g, "$1\r\n"); 385 var sPEM = "-----BEGIN " + pemHeadAlg + " PRIVATE KEY-----\r\n"; 386 sPEM += "Proc-Type: 4,ENCRYPTED\r\n"; 387 sPEM += "DEK-Info: " + sharedKeyAlgName + "," + ivsaltHex + "\r\n"; 388 sPEM += "\r\n"; 389 sPEM += pemBody; 390 sPEM += "\r\n-----END " + pemHeadAlg + " PRIVATE KEY-----\r\n"; 391 392 return sPEM; 393 }, 394 395 // === NEW ENCRYPTED PKCS8 GENERATOR ======================================= 396 /* 397 * get Encrypted PKCS8 PEM private key by PEM string of plain priavte key 398 * @name getEncryptedPKCS8PEM 399 * @memberOf KEYUTIL 400 * @function 401 * @param {string} hPlainPKCS8Prv hexadecimal string of plain PKCS#8 private key 402 * @param {string} passcode password string for encrytion 403 * @param {object} param associative array object of parameters for encrypted PKCS#8 (OPITON) 404 * @return {string} PEM string of encrypted PKCS#8 private key 405 * @since jsrsasign 10.9.0 keyutil 1.3.0 406 * @see KEYUTIL.getEncryptedPKCS8Hex 407 * 408 * @description 409 * <br/> 410 * generate hexadecimal string of encrypted PKCS#8 private key by a hexadecimal string of 411 * plain PKCS#8 private key with encryption parameters. 412 * <pre> 413 * { // (OPTION) encryption algorithm (ex. des-EDE3-CBC,aes128-CBC) DEFAULT:aes256-CBC 414 * encalg: "aes128-CBC", 415 * // (OPTION) iteration count, DEFAULT:2048, 416 * iter: 1024, 417 * // (OPTION) psudorandom function (ex. hmacWithSHA{1,224,256,384,512}) DEFAULT: hmacWithSHA256 418 * prf: "hmacWithSHA512", 419 * // (OPTION) explicitly specifed 8 bytes hexadecimal salt string. 420 * salt: "12ab...", 421 * // (OPTION) explicitly specified hexadecimal IV string. 422 * enciv: "257c..." 423 * </pre> 424 * 425 * @example 426 * // generate with default parameters 427 * KEYUTIL.getEncryptedPKCS8PEM("3082...", "password") 428 * → "-----BEGIN ENCRYPTED PRIVATE KEY..." 429 * // des-EDE3-CBC with 4096 iteration 430 * KEYUTIL.getEncryptedPKCS8PEM("3082...", "password", { encalg: "des-EDE3-CBC", iter: 4096 }) 431 * → "-----BEGIN ENCRYPTED PRIVATE KEY..." 432 */ 433 getEncryptedPKCS8PEM: function(hPlainPKCS8Prv, passcode, param) { 434 var hP8E = this.getEncryptedPKCS8Hex(hPlainPKCS8Prv, passcode, param); 435 return hextopem(hP8E, "ENCRYPTED PRIVATE KEY"); 436 }, 437 438 /* 439 * get Encrypted PKCS8 private key by PEM string of plain priavte key 440 * @name 441 * @memberOf KEYUTIL 442 * @function getEncryptedPKCS8Hex 443 * @param {string} hPlainPKCS8Prv hexadecimal string of plain PKCS#8 private key 444 * @param {string} passcode password string for encrytion 445 * @param {object} param associative array object of parameters for encrypted PKCS#8 (OPTION) 446 * @return {string} PEM string of encrypted PKCS#8 private key 447 * @since jsrsasign 10.9.0 keyutil 1.3.0 448 * @see KEYUTIL.getEncryptedPKCS8PEM 449 * 450 * @description 451 * <br/> 452 * generate PEM formatted encrypted PKCS#8 private key by a hexadecimal string of 453 * plain PKCS#8 private key with encryption parameters. 454 * Regarding to "param", see {@link KEYUTIL.getEncryptedPKCS8PEM}. 455 * 456 * @example 457 * // generate with default parameters 458 * KEYUTIL.getEncryptedPKCS8Hex("3082...", "password") → "3082..." 459 * // des-EDE3-CBC with 4096 iteration 460 * KEYUTIL.getEncryptedPKCS8PEM("3082...", "password", { encalg: "des-EDE3-CBC", iter: 4096 }) → "3082..." 461 */ 462 getEncryptedPKCS8Hex: function(hPlainPKCS8Prv, passcode, param) { 463 var pParam2; 464 if (param == undefined || param == null) { 465 pParam2 = {}; 466 } else { 467 pParam2 = JSON.parse(JSON.stringify(param)); 468 } 469 pParam2.plain = hPlainPKCS8Prv; 470 471 this.initPBES2Param(pParam2); 472 this.encryptPBES2Param(pParam2, passcode); 473 var pASN = this.generatePBES2ASN1Param(pParam2); 474 return KJUR.asn1.ASN1Util.newObject(pASN).tohex(); 475 }, 476 477 /* 478 * set default PBES2 parameters if not specified 479 * @name 480 * @memberOf KEYUTIL 481 * @function initPBES2Param 482 * @param {object} param associative array object of parameters for encrypted PKCS#8 483 * @since jsrsasign 10.9.0 keyutil 1.3.0 484 * @see KEYUTIL.getEncryptedPKCS8PEM 485 * @see KEYUTIL.getEncryptedPKCS8Hex 486 * 487 * @description 488 * <br/> 489 * set default PBES2 parameters if not specified in the "param" associative array. 490 * Here is members: 491 * <ul> 492 * <li>encalg - set "aes256-CBC" encryption algorithm if not specified</li> 493 * <li>iter - set 2048 iteration count if not specified</li> 494 * <li>prf - set "hmacWithSHA256" psudorandom function if not specified</li> 495 * <li>salt - set 8 bytes random number hexadecimal string if not specified</li> 496 * <li>enciv - set random number hexadecimal string of initial vector if not specified. 497 * The length depends on encryption algorithm.</li> 498 * </ul> 499 */ 500 initPBES2Param: function(pPBES2) { 501 if (aryval(pPBES2, "encalg") == undefined) pPBES2.encalg = "aes256-CBC"; 502 if (aryval(pPBES2, "iter") == undefined) pPBES2.iter = 2048; 503 if (aryval(pPBES2, "prf") == undefined) pPBES2.prf = "hmacWithSHA256"; 504 if (aryval(pPBES2, "salt") == undefined) pPBES2.salt = CryptoJS.enc.Hex.stringify(CryptoJS.lib.WordArray.random(8)); 505 if (aryval(pPBES2, "enciv") == undefined) { 506 var nbytes; 507 if (pPBES2.encalg == "des-EDE3-CBC") nbytes = 8; 508 if (pPBES2.encalg == "aes128-CBC") nbytes = 16; 509 if (pPBES2.encalg == "aes256-CBC") nbytes = 16; 510 pPBES2.enciv = CryptoJS.enc.Hex.stringify(CryptoJS.lib.WordArray.random(nbytes)); 511 } 512 }, 513 514 /* 515 * encrypt plain private key with PBES2 paramters 516 * @name 517 * @memberOf KEYUTIL 518 * @function encryptPBES2Param 519 * @param {object} param associative array object of parameters for encrypted PKCS#8 private key 520 * @param {string} passcode password string for encrypted PKCS#8 private key. 521 * @since jsrsasign 10.9.0 keyutil 1.3.0 522 * @see KEYUTIL.getEncryptedPKCS8PEM 523 * @see KEYUTIL.getEncryptedPKCS8Hex 524 * 525 * @description 526 * <br/> 527 * encrypt plain private key with PBES2 parameters. 528 * Here is input members in PBES2 paramters. 529 * <ul> 530 * <li>plain - hexadecimal string of messages (i.e. plain private key) which will be encrypted</li> 531 * <li>encalg - encryption algorithm</li> 532 * <li>iter - iteration count</li> 533 * <li>prf - psudorandom function</li> 534 * <li>salt - salt</li> 535 * <li>enciv - initial vector</li> 536 * </ul> 537 * Encrypted result will be set as a new "enc" member of hexadecimal string in PBES2 parameters. 538 */ 539 encryptPBES2Param: function(pPBES2, passcode) { 540 var hKey = KEYUTIL.getDKFromPBES2Param(pPBES2, passcode); 541 try { 542 var hEnc = KJUR.crypto.Cipher.encrypt(pPBES2.plain, hKey, pPBES2.encalg, { iv: pPBES2.enciv }); 543 } catch(ex) { 544 throw new Error("encrypt error: " + pPBES2.plain + " " + hKey + " " + pPBES2.encalg + " " + pPBES2.enciv); 545 } 546 pPBES2.enc = hEnc; 547 }, 548 549 /* 550 * convert from PBES2 parameters to PKCS#8 encrypted private key ASN1 object 551 * @name 552 * @memberOf KEYUTIL 553 * @function generatePBES2ASN1Param 554 * @param {object} param associative array object of parameters for encrypted PKCS#8 private key 555 * @param {object} associative array object of ASN1 object 556 * @since jsrsasign 10.9.0 keyutil 1.3.0 557 * @see KEYUTIL.getEncryptedPKCS8PEM 558 * @see KEYUTIL.getEncryptedPKCS8Hex 559 * @see KJUR.asn1.ASN1Util.newObject 560 * 561 * @description 562 * <br/> 563 * convert from PBES2 paramters to ASN1 object which can be 564 * passwd to {@link KJUR.asn1.ASN1Util.newObject}. 565 * Here is input members in PBES2 paramters. 566 * <ul> 567 * <li>encalg - encryption algorithm</li> 568 * <li>iter - iteration count</li> 569 * <li>prf - psudorandom function</li> 570 * <li>salt - salt</li> 571 * <li>enciv - initial vector</li> 572 * <li>enc - encrypted private key</li> 573 * </ul> 574 * Note that prf will be omitted when prf is a default "hmacWithSHA1". 575 */ 576 generatePBES2ASN1Param: function(pPBES2) { 577 var pASN = 578 { seq: [ 579 { seq: [ 580 { oid: "pkcs5PBES2" }, 581 { seq: [ 582 { seq: [ 583 { oid: "pkcs5PBKDF2" }, 584 { seq: [ 585 { octstr: { hex: pPBES2.salt } }, 586 { "int": { hex: inttohex(pPBES2.iter) } } 587 ] } 588 ] }, 589 { seq: [ 590 { oid: pPBES2.encalg }, 591 { octstr: { hex: pPBES2.enciv } } 592 ] } 593 ] } 594 ] }, 595 { octstr: { hex: pPBES2.enc } } 596 ] }; 597 if (pPBES2.prf != "hmacWithSHA1") { 598 pASN.seq[0].seq[1].seq[0].seq[1].seq.push({seq:[{oid:pPBES2.prf},{"null":""}]}); 599 } 600 return pASN; 601 }, 602 603 // === PKCS8 =============================================================== 604 605 /** 606 * generate PBKDF2 key hexstring with specified passcode and information (DEPRECATED) 607 * @name parseHexOfEncryptedPKCS8 608 * @memberOf KEYUTIL 609 * @function 610 * @param {String} passcode passcode to decrypto private key 611 * @return {Array} info associative array of PKCS#8 parameters 612 * @since pkcs5pkey 1.0.3 613 * @deprecated since jsrsasign 10.9.0 keyutil 1.3.0. Use {@link KEYUTIL.parsePBES2} instead. 614 * 615 * @description 616 * The associative array which is returned by this method has following properties: 617 * <ul> 618 * <li>info.pbkdf2Salt - hexadecimal string of PBKDF2 salt</li> 619 * <li>info.pkbdf2Iter - iteration count</li> 620 * <li>info.ciphertext - hexadecimal string of encrypted private key</li> 621 * <li>info.encryptionSchemeAlg - encryption algorithm name (currently TripleDES only)</li> 622 * <li>info.encryptionSchemeIV - initial vector for encryption algorithm</li> 623 * </ul> 624 * Currently, this method only supports PKCS#5v2.0 with PBES2/PBDKF2 of HmacSHA1 and TripleDES. 625 * <ul> 626 * <li>keyDerivationFunc = pkcs5PBKDF2 with HmacSHA1</li> 627 * <li>encryptionScheme = des-EDE3-CBC(i.e. TripleDES</li> 628 * </ul> 629 * @example 630 * // to convert plain PKCS#5 private key to encrypted PKCS#8 private 631 * // key with PBKDF2 with TripleDES 632 * % openssl pkcs8 -in plain_p5.pem -topk8 -v2 -des3 -out encrypted_p8.pem 633 */ 634 parseHexOfEncryptedPKCS8: function(sHEX) { 635 var _ASN1HEX = ASN1HEX; 636 var _getChildIdx = _ASN1HEX.getChildIdx; 637 var _getV = _ASN1HEX.getV; 638 var info = {}; 639 640 var a0 = _getChildIdx(sHEX, 0); 641 if (a0.length != 2) 642 throw new Error("malformed format: SEQUENCE(0).items != 2: " + 643 a0.length); 644 645 // 1. ciphertext 646 info.ciphertext = _getV(sHEX, a0[1]); 647 648 // 2. pkcs5PBES2 649 var a0_0 = _getChildIdx(sHEX, a0[0]); 650 if (a0_0.length != 2) 651 throw new Error("malformed format: SEQUENCE(0.0).items != 2: " 652 + a0_0.length); 653 654 // 2.1 check if pkcs5PBES2(1 2 840 113549 1 5 13) 655 if (_getV(sHEX, a0_0[0]) != "2a864886f70d01050d") 656 throw new Error("this only supports pkcs5PBES2"); 657 658 // 2.2 pkcs5PBES2 param 659 var a0_0_1 = _getChildIdx(sHEX, a0_0[1]); 660 if (a0_0.length != 2) 661 throw new Error("malformed format: SEQUENCE(0.0.1).items != 2: " 662 + a0_0_1.length); 663 664 // 2.2.1 encryptionScheme 665 var a0_0_1_1 = _getChildIdx(sHEX, a0_0_1[1]); 666 if (a0_0_1_1.length != 2) 667 throw new Error("malformed format: " + 668 "SEQUENCE(0.0.1.1).items != 2: " + 669 a0_0_1_1.length); 670 if (_getV(sHEX, a0_0_1_1[0]) != "2a864886f70d0307") 671 throw "this only supports TripleDES"; 672 info.encryptionSchemeAlg = "TripleDES"; 673 674 // 2.2.1.1 IV of encryptionScheme 675 info.encryptionSchemeIV = _getV(sHEX, a0_0_1_1[1]); 676 677 // 2.2.2 keyDerivationFunc 678 var a0_0_1_0 = _getChildIdx(sHEX, a0_0_1[0]); 679 if (a0_0_1_0.length != 2) 680 throw new Error("malformed format: " + 681 "SEQUENCE(0.0.1.0).items != 2: " 682 + a0_0_1_0.length); 683 if (_getV(sHEX, a0_0_1_0[0]) != "2a864886f70d01050c") 684 throw new Error("this only supports pkcs5PBKDF2"); 685 686 // 2.2.2.1 pkcs5PBKDF2 param 687 var a0_0_1_0_1 = _getChildIdx(sHEX, a0_0_1_0[1]); 688 if (a0_0_1_0_1.length < 2) 689 throw new Error("malformed format: " + 690 "SEQUENCE(0.0.1.0.1).items < 2: " + 691 a0_0_1_0_1.length); 692 693 // 2.2.2.1.1 PBKDF2 salt 694 info.pbkdf2Salt = _getV(sHEX, a0_0_1_0_1[0]); 695 696 // 2.2.2.1.2 PBKDF2 iter 697 var iterNumHex = _getV(sHEX, a0_0_1_0_1[1]); 698 try { 699 info.pbkdf2Iter = parseInt(iterNumHex, 16); 700 } catch(ex) { 701 throw new Error("malformed format pbkdf2Iter: " + iterNumHex); 702 } 703 704 return info; 705 }, 706 707 /** 708 * generate PBKDF2 key hexstring with specified passcode and information (DEPRECATED) 709 * @name getPBKDF2KeyHexFromParam 710 * @memberOf KEYUTIL 711 * @function 712 * @param {Array} info result of {@link parseHexOfEncryptedPKCS8} which has preference of PKCS#8 file 713 * @param {String} passcode passcode to decrypto private key 714 * @return {String} hexadecimal string of PBKDF2 key 715 * @since pkcs5pkey 1.0.3 716 * @deprecated since jsrsasign 10.9.0 keyutil 1.3.0. Use {@link KEYUTIL.getDKFromPBES2Param} instead. 717 * 718 * @description 719 * As for info, this uses following properties: 720 * <ul> 721 * <li>info.pbkdf2Salt - hexadecimal string of PBKDF2 salt</li> 722 * <li>info.pkbdf2Iter - iteration count</li> 723 * </ul> 724 * Currently, this method only supports PKCS#5v2.0 with PBES2/PBDKF2 of HmacSHA1 and TripleDES. 725 * <ul> 726 * <li>keyDerivationFunc = pkcs5PBKDF2 with HmacSHA1</li> 727 * <li>encryptionScheme = des-EDE3-CBC(i.e. TripleDES</li> 728 * </ul> 729 * @example 730 * // to convert plain PKCS#5 private key to encrypted PKCS#8 private 731 * // key with PBKDF2 with TripleDES 732 * % openssl pkcs8 -in plain_p5.pem -topk8 -v2 des3 -out encrypted_p8.pem 733 */ 734 getPBKDF2KeyHexFromParam: function(info, passcode) { 735 var pbkdf2SaltWS = CryptoJS.enc.Hex.parse(info.pbkdf2Salt); 736 var pbkdf2Iter = info.pbkdf2Iter; 737 var pbkdf2KeyWS = CryptoJS.PBKDF2(passcode, 738 pbkdf2SaltWS, 739 { keySize: 192/32, iterations: pbkdf2Iter }); 740 var pbkdf2KeyHex = CryptoJS.enc.Hex.stringify(pbkdf2KeyWS); 741 return pbkdf2KeyHex; 742 }, 743 744 /* 745 * read PEM formatted encrypted PKCS#8 private key and returns hexadecimal string of plain PKCS#8 private key (DEPRECATED) 746 * @name getPlainPKCS8HexFromEncryptedPKCS8PEM 747 * @memberOf KEYUTIL 748 * @function 749 * @param {String} pkcs8PEM PEM formatted encrypted PKCS#8 private key 750 * @param {String} passcode passcode to decrypto private key 751 * @return {String} hexadecimal string of plain PKCS#8 private key 752 * @since pkcs5pkey 1.0.3 753 * @deprecated since jsrsasign 10.9.0 keyutil 1.3.0. Use {@link KEYUTIL.getPlainHexFromEncryptedPKCS8PEM} instead. 754 * 755 * @description 756 * Currently, this method only supports PKCS#5v2.0 with PBES2/PBDKF2 of HmacSHA1 and TripleDES. 757 * <ul> 758 * <li>keyDerivationFunc = pkcs5PBKDF2 with HmacSHA1</li> 759 * <li>encryptionScheme = des-EDE3-CBC(i.e. TripleDES</li> 760 * </ul> 761 * @example 762 * // to convert plain PKCS#5 private key to encrypted PKCS#8 private 763 * // key with PBKDF2 with TripleDES 764 * % openssl pkcs8 -in plain_p5.pem -topk8 -v2 -des3 -out encrypted_p8.pem 765 */ 766 _getPlainPKCS8HexFromEncryptedPKCS8PEM: function(pkcs8PEM, passcode) { 767 // 1. derHex - PKCS#8 private key encrypted by PBKDF2 768 var derHex = pemtohex(pkcs8PEM, "ENCRYPTED PRIVATE KEY"); 769 // 2. info - PKCS#5 PBES info 770 var info = this.parseHexOfEncryptedPKCS8(derHex); 771 // 3. hKey - PBKDF2 key 772 var pbkdf2KeyHex = KEYUTIL.getPBKDF2KeyHexFromParam(info, passcode); 773 // 4. decrypt ciphertext by PBKDF2 key 774 var encrypted = {}; 775 encrypted.ciphertext = CryptoJS.enc.Hex.parse(info.ciphertext); 776 var pbkdf2KeyWS = CryptoJS.enc.Hex.parse(pbkdf2KeyHex); 777 var des3IVWS = CryptoJS.enc.Hex.parse(info.encryptionSchemeIV); 778 var decWS = CryptoJS.TripleDES.decrypt(encrypted, pbkdf2KeyWS, { iv: des3IVWS }); 779 var decHex = CryptoJS.enc.Hex.stringify(decWS); 780 return decHex; 781 }, 782 783 /** 784 * parse ASN.1 hexadecimal encrypted PKCS#8 private key and return as JSON 785 * @name parsePBES2 786 * @memberOf KEYUTIL 787 * @function 788 * @param {string} hP8Prv hexadecimal encrypted PKCS#8 private key 789 * @return {object} parsed PBES2 parameters JSON object 790 * @since jsrsasign 10.9.0 keyutil 1.3.0 791 * @description 792 * This method parses ASN.1 hexadecimal encrypted PKCS#8 private key and returns as 793 * JSON object based on 794 * <a href="https://datatracker.ietf.org/doc/html/rfc8018" target="_blank">RFC 8018</a>. 795 * Currently following algorithms are supported: 796 * <ul> 797 * <li>prf(psudorandom function) - hmacWithSHA1,SHA224,SHA256,SHA384,SHA512</li> 798 * <li>encryptionScheme - des-EDE3-CBC,aes128-CBC,aes256-CBC</li> 799 * </ul> 800 * @see KEYUTIL.getDKFromPBES2Param 801 * 802 * @example 803 * KEYUTIL.parsePBES2("3082...") → 804 * { 805 * "prf": "hmacWithSHA256", 806 * "salt": "1234567890abcdef", 807 * "iter": 2048, 808 * "encalg": "aes256-CBC", 809 * "enciv": "12ab...", 810 * "enc": "34cd..." 811 * } 812 * 813 * // to convert plain PKCS#5 private key to encrypted PKCS#8 private 814 * // key with PBKDF2 with TripleDES 815 * % openssl pkcs8 -in plain_p5.pem -topk8 -v2 des3 -out encrypted_p8.pem 816 */ 817 parsePBES2: function(hP8Prv) { 818 var pASN = ASN1HEX.parse(hP8Prv); 819 if (aryval(pASN, "seq.0.seq.0.oid") != "pkcs5PBES2" || 820 aryval(pASN, "seq.0.seq.1.seq.0.seq.0.oid") != "pkcs5PBKDF2") { 821 throw new Error("not pkcs5PBES2 and pkcs5PBKDF2 used"); 822 } 823 var pASNKDF = aryval(pASN, "seq.0.seq.1.seq.0.seq.1.seq"); 824 if (pASNKDF == undefined) { 825 throw new Error("PBKDF2 parameter not found"); 826 } 827 var salt = aryval(pASNKDF, "0.octstr.hex"); 828 var hIter = aryval(pASNKDF, "1.int.hex"); 829 var prf = aryval(pASNKDF, "2.seq.0.oid", "hmacWithSHA1"); 830 831 var iter = -1; 832 try { 833 iter = parseInt(hIter, 16); 834 } catch(ex) { 835 throw new Error("iter not proper value"); 836 }; 837 838 var encalg = aryval(pASN, "seq.0.seq.1.seq.1.seq.0.oid"); 839 var enciv = aryval(pASN, "seq.0.seq.1.seq.1.seq.1.octstr.hex"); 840 var enc = aryval(pASN, "seq.1.octstr.hex"); 841 if (encalg == undefined || enciv == undefined || enc == undefined) 842 throw new Error("encalg, enciv or enc is undefined"); 843 844 var result = { 845 salt: salt, 846 iter: iter, 847 prf: prf, 848 encalg: encalg, 849 enciv: enciv, 850 enc: enc 851 }; 852 return result; 853 }, 854 855 /** 856 * get derived key from PBES2 parameters and passcode 857 * @name getDKFromPBES2Param 858 * @memberOf KEYUTIL 859 * @function 860 * @param {object} pPBES2 parsed PBES2 parameter by {@link KEYUTIL.parsePBES2} method 861 * @param {string} passcode password to derive the key 862 * @return {string} hexadecimal string of derived key 863 * @since jsrsasign 10.9.0 keyutil 1.3.0 864 * @see KEYUTIL.parsePBES2 865 * 866 * @description 867 * This method derives a key from a passcode and a PBES2 parameter by 868 * {@link KEYUTIL.parsePBES2}. 869 * Currently following algorithms are supported: 870 * <ul> 871 * <li>prf(psudorandom function) - hmacWithSHA1,SHA224,SHA256,SHA384,SHA512</li> 872 * <li>encryptionScheme - des-EDE3-CBC,aes128-CBC,aes256-CBC</li> 873 * </ul> 874 * 875 * @example 876 * pPBES2 = { 877 * "prf": "hmacWithSHA256", 878 * "salt": "1234567890abcdef", 879 * "iter": 2048, 880 * "encalg": "aes256-CBC", 881 * "enciv": "12ab...", 882 * "enc": "34cd..." 883 * } 884 * KEYUTIL.getDKFromPBES2Param(pPBES2, "passwd") → "3ab10fd..." 885 */ 886 getDKFromPBES2Param: function(pPBES2, passcode) { 887 var pHasher = { 888 "hmacWithSHA1": CryptoJS.algo.SHA1, 889 "hmacWithSHA224": CryptoJS.algo.SHA224, 890 "hmacWithSHA256": CryptoJS.algo.SHA256, 891 "hmacWithSHA384": CryptoJS.algo.SHA384, 892 "hmacWithSHA512": CryptoJS.algo.SHA512 893 }; 894 var pKeySize = { 895 "des-EDE3-CBC": 192/32, 896 "aes128-CBC": 128/32, 897 "aes256-CBC": 256/32, 898 }; 899 900 var hasher = pHasher[pPBES2.prf]; 901 if (hasher == undefined) 902 throw new Error("unsupported prf"); 903 904 var keysize = pKeySize[pPBES2.encalg]; 905 if (keysize == undefined) 906 throw new Error("unsupported encalg"); 907 908 var wSalt = CryptoJS.enc.Hex.parse(pPBES2.salt); 909 var iter = pPBES2.iter; 910 try { 911 var wKey = CryptoJS.PBKDF2(passcode, 912 wSalt, 913 { keySize: keysize, 914 iterations: iter, 915 hasher: hasher }); 916 return CryptoJS.enc.Hex.stringify(wKey); 917 } catch(ex) { 918 throw new Error("PBKDF2 error: " + ex + " " + JSON.stringify(pPBES2) + " " + passcode); 919 } 920 }, 921 922 /** 923 * get plaintext hexadecimal PKCS#8 private key from encrypted PKCS#8 PEM private key 924 * @name getPlainHexFromEncryptedPKCS8PEM 925 * @memberOf KEYUTIL 926 * @function 927 * @param {string} pkcs8PEM PEM string of encrypted PKCS#8 private key 928 * @param {string} passcode passcode to decrypt the private key 929 * @return {string} hexadecimal string of decrypted plaintext PKCS#8 private key 930 * @since jsrsasign 10.9.0 keyutil 1.3.0 931 * @see KEYUTIL.parsePBES2 932 * 933 * @description 934 * This will get a plaintext hexadecimal PKCS#8 private key from a 935 * encrypted PKCS#8 PEM private key. 936 * Currently following algorithms are supported: 937 * <ul> 938 * <li>prf(psudorandom function) - hmacWithSHA1,SHA224,SHA256,SHA384,SHA512</li> 939 * <li>encryptionScheme - des-EDE3-CBC,aes128-CBC,aes256-CBC</li> 940 * </ul> 941 * 942 * @example 943 * pem = "-----BEGIN ENCRYPTED PRIVATE KEY..."; 944 * KEYUTIL.getPlainHexFromEncryptedPKCS8PEM(pem, "passwd") → "3082..." 945 */ 946 getPlainHexFromEncryptedPKCS8PEM: function(pkcs8PEM, passcode) { 947 if (pkcs8PEM.indexOf("BEGIN ENCRYPTED PRIVATE KEY") == -1) 948 throw new Error("not Encrypted PKCS#8 PEM string"); 949 var hPBES2 = pemtohex(pkcs8PEM); 950 var pPBES2; 951 try { 952 pPBES2 = KEYUTIL.parsePBES2(hPBES2); 953 } catch(ex) { 954 throw new Error("malformed PBES2 format: " + ex.message); 955 } 956 var hKey = KEYUTIL.getDKFromPBES2Param(pPBES2, passcode); 957 return KJUR.crypto.Cipher.decrypt(pPBES2.enc, hKey, pPBES2.encalg, { iv: pPBES2.enciv }); 958 }, 959 960 /** 961 * get RSAKey/ECDSA private key object from encrypted PEM PKCS#8 private key 962 * @name getKeyFromEncryptedPKCS8PEM 963 * @memberOf KEYUTIL 964 * @function 965 * @param {String} pkcs8PEM string of PEM formatted PKCS#8 private key 966 * @param {String} passcode passcode string to decrypt key 967 * @return {Object} RSAKey or KJUR.crypto.ECDSA private key object 968 * @since pkcs5pkey 1.0.5 969 */ 970 getKeyFromEncryptedPKCS8PEM: function(pkcs8PEM, passcode) { 971 var prvKeyHex = this.getPlainHexFromEncryptedPKCS8PEM(pkcs8PEM, passcode); 972 var key = this.getKeyFromPlainPrivatePKCS8Hex(prvKeyHex); 973 return key; 974 }, 975 976 /** 977 * parse hexadecimal string of plain PKCS#8 private key 978 * @name parsePlainPrivatePKCS8Hex 979 * @memberOf KEYUTIL 980 * @function 981 * @param {String} pkcs8PrvHex hexadecimal string of PKCS#8 plain private key 982 * @return {Array} associative array of parsed key 983 * @since pkcs5pkey 1.0.5 984 * @description 985 * Resulted associative array has following properties: 986 * <ul> 987 * <li>algoid - hexadecimal string of OID of asymmetric key algorithm</li> 988 * <li>algparam - hexadecimal string of OID of ECC curve name or null</li> 989 * <li>keyidx - string starting index of key in pkcs8PrvHex</li> 990 * </ul> 991 */ 992 parsePlainPrivatePKCS8Hex: function(pkcs8PrvHex) { 993 var _ASN1HEX = ASN1HEX; 994 var _getChildIdx = _ASN1HEX.getChildIdx; 995 var _getV = _ASN1HEX.getV; 996 var result = {}; 997 result.algparam = null; 998 999 // 1. sequence 1000 if (pkcs8PrvHex.substr(0, 2) != "30") 1001 throw new Error("malformed plain PKCS8 private key(code:001)"); 1002 // not sequence 1003 1004 var a1 = _getChildIdx(pkcs8PrvHex, 0); 1005 if (a1.length < 3) 1006 throw new Error("malformed plain PKCS8 private key(code:002)"); 1007 // less elements 1008 1009 // 2. AlgID 1010 if (pkcs8PrvHex.substr(a1[1], 2) != "30") 1011 throw new Error("malformed PKCS8 private key(code:003)"); 1012 // AlgId not sequence 1013 1014 var a2 = _getChildIdx(pkcs8PrvHex, a1[1]); 1015 if (a2.length != 2) 1016 throw new Error("malformed PKCS8 private key(code:004)"); 1017 // AlgId not have two elements 1018 1019 // 2.1. AlgID OID 1020 if (pkcs8PrvHex.substr(a2[0], 2) != "06") 1021 throw new Error("malformed PKCS8 private key(code:005)"); 1022 // AlgId.oid is not OID 1023 1024 result.algoid = _getV(pkcs8PrvHex, a2[0]); 1025 1026 // 2.2. AlgID param 1027 if (pkcs8PrvHex.substr(a2[1], 2) == "06") { 1028 result.algparam = _getV(pkcs8PrvHex, a2[1]); 1029 } 1030 1031 // 3. Key index 1032 if (pkcs8PrvHex.substr(a1[2], 2) != "04") 1033 throw new Error("malformed PKCS8 private key(code:006)"); 1034 // not octet string 1035 1036 result.keyidx = _ASN1HEX.getVidx(pkcs8PrvHex, a1[2]); 1037 1038 return result; 1039 }, 1040 1041 /** 1042 * get RSAKey/ECDSA private key object from PEM plain PEM PKCS#8 private key 1043 * @name getKeyFromPlainPrivatePKCS8PEM 1044 * @memberOf KEYUTIL 1045 * @function 1046 * @param {String} pkcs8PEM string of plain PEM formatted PKCS#8 private key 1047 * @return {Object} RSAKey or KJUR.crypto.ECDSA private key object 1048 * @since pkcs5pkey 1.0.5 1049 */ 1050 getKeyFromPlainPrivatePKCS8PEM: function(prvKeyPEM) { 1051 var prvKeyHex = pemtohex(prvKeyPEM, "PRIVATE KEY"); 1052 var key = this.getKeyFromPlainPrivatePKCS8Hex(prvKeyHex); 1053 return key; 1054 }, 1055 1056 /** 1057 * get RSAKey/DSA/ECDSA private key object from HEX plain PEM PKCS#8 private key 1058 * @name getKeyFromPlainPrivatePKCS8Hex 1059 * @memberOf KEYUTIL 1060 * @function 1061 * @param {String} prvKeyHex hexadecimal string of plain PKCS#8 private key 1062 * @return {Object} RSAKey or KJUR.crypto.{DSA,ECDSA} private key object 1063 * @since pkcs5pkey 1.0.5 1064 */ 1065 getKeyFromPlainPrivatePKCS8Hex: function(prvKeyHex) { 1066 var p8 = this.parsePlainPrivatePKCS8Hex(prvKeyHex); 1067 var key; 1068 1069 if (p8.algoid == "2a864886f70d010101") { // RSA 1070 key = new RSAKey(); 1071 } else if (p8.algoid == "2a8648ce380401") { // DSA 1072 key = new KJUR.crypto.DSA(); 1073 } else if (p8.algoid == "2a8648ce3d0201") { // ECC 1074 key = new KJUR.crypto.ECDSA(); 1075 } else { 1076 throw new Error("unsupported private key algorithm"); 1077 } 1078 1079 key.readPKCS8PrvKeyHex(prvKeyHex); 1080 return key; 1081 }, 1082 1083 // === PKCS8 RSA Public Key ================================================ 1084 1085 /* 1086 * get RSAKey/DSA/ECDSA public key object from hexadecimal string of PKCS#8 public key 1087 * @name _getKeyFromPublicPKCS8Hex 1088 * @memberOf KEYUTIL 1089 * @function 1090 * @param {String} pkcsPub8Hex hexadecimal string of PKCS#8 public key 1091 * @return {Object} RSAKey or KJUR.crypto.{ECDSA,DSA} private key object 1092 * @since pkcs5pkey 1.0.5 1093 */ 1094 _getKeyFromPublicPKCS8Hex: function(h) { 1095 var key; 1096 var hOID = ASN1HEX.getVbyList(h, 0, [0, 0], "06"); 1097 1098 if (hOID === "2a864886f70d010101") { // oid=RSA 1099 key = new RSAKey(); 1100 } else if (hOID === "2a8648ce380401") { // oid=DSA 1101 key = new KJUR.crypto.DSA(); 1102 } else if (hOID === "2a8648ce3d0201") { // oid=ECPUB 1103 key = new KJUR.crypto.ECDSA(); 1104 } else { 1105 throw new Error("unsupported PKCS#8 public key hex"); 1106 } 1107 key.readPKCS8PubKeyHex(h); 1108 return key; 1109 }, 1110 1111 /** 1112 * parse hexadecimal string of plain PKCS#8 private key 1113 * @name parsePublicRawRSAKeyHex 1114 * @memberOf KEYUTIL 1115 * @function 1116 * @param {String} pubRawRSAHex hexadecimal string of ASN.1 encoded PKCS#8 public key 1117 * @return {Array} associative array of parsed key 1118 * @since pkcs5pkey 1.0.5 1119 * @description 1120 * Resulted associative array has following properties: 1121 * <ul> 1122 * <li>n - hexadecimal string of public key 1123 * <li>e - hexadecimal string of public exponent 1124 * </ul> 1125 */ 1126 parsePublicRawRSAKeyHex: function(pubRawRSAHex) { 1127 var _ASN1HEX = ASN1HEX; 1128 var _getChildIdx = _ASN1HEX.getChildIdx; 1129 var _getV = _ASN1HEX.getV; 1130 var result = {}; 1131 1132 // 1. Sequence 1133 if (pubRawRSAHex.substr(0, 2) != "30") 1134 throw new Error("malformed RSA key(code:001)"); // not sequence 1135 1136 var a1 = _getChildIdx(pubRawRSAHex, 0); 1137 if (a1.length != 2) 1138 throw new Error("malformed RSA key(code:002)"); // not 2 items in seq 1139 1140 // 2. public key "N" 1141 if (pubRawRSAHex.substr(a1[0], 2) != "02") 1142 throw new Error("malformed RSA key(code:003)"); // 1st item is not integer 1143 1144 result.n = _getV(pubRawRSAHex, a1[0]); 1145 1146 // 3. public key "E" 1147 if (pubRawRSAHex.substr(a1[1], 2) != "02") 1148 throw new Error("malformed RSA key(code:004)"); // 2nd item is not integer 1149 1150 result.e = _getV(pubRawRSAHex, a1[1]); 1151 1152 return result; 1153 }, 1154 1155 /** 1156 * parse hexadecimal string of PKCS#8 RSA/EC/DSA public key 1157 * @name parsePublicPKCS8Hex 1158 * @memberOf KEYUTIL 1159 * @function 1160 * @param {String} pkcs8PubHex hexadecimal string of PKCS#8 public key 1161 * @return {Hash} hash of key information 1162 * @description 1163 * Resulted hash has following attributes. 1164 * <ul> 1165 * <li>algoid - hexadecimal string of OID of asymmetric key algorithm</li> 1166 * <li>algparam - hexadecimal string of OID of ECC curve name, parameter SEQUENCE of DSA or null</li> 1167 * <li>key - hexadecimal string of public key</li> 1168 * </ul> 1169 */ 1170 parsePublicPKCS8Hex: function(pkcs8PubHex) { 1171 var _ASN1HEX = ASN1HEX; 1172 var _getChildIdx = _ASN1HEX.getChildIdx; 1173 var _getV = _ASN1HEX.getV; 1174 var result = {}; 1175 result.algparam = null; 1176 1177 // 1. AlgID and Key bit string 1178 var a1 = _getChildIdx(pkcs8PubHex, 0); 1179 if (a1.length != 2) 1180 throw new Error("outer DERSequence shall have 2 elements: " + a1.length); 1181 1182 // 2. AlgID 1183 var idxAlgIdTLV = a1[0]; 1184 if (pkcs8PubHex.substr(idxAlgIdTLV, 2) != "30") 1185 throw new Error("malformed PKCS8 public key(code:001)"); // AlgId not sequence 1186 1187 var a2 = _getChildIdx(pkcs8PubHex, idxAlgIdTLV); 1188 if (a2.length != 2) 1189 throw new Error("malformed PKCS8 public key(code:002)"); // AlgId not have two elements 1190 1191 // 2.1. AlgID OID 1192 if (pkcs8PubHex.substr(a2[0], 2) != "06") 1193 throw new Error("malformed PKCS8 public key(code:003)"); // AlgId.oid is not OID 1194 1195 result.algoid = _getV(pkcs8PubHex, a2[0]); 1196 1197 // 2.2. AlgID param 1198 if (pkcs8PubHex.substr(a2[1], 2) == "06") { // OID for EC 1199 result.algparam = _getV(pkcs8PubHex, a2[1]); 1200 } else if (pkcs8PubHex.substr(a2[1], 2) == "30") { // SEQ for DSA 1201 result.algparam = {}; 1202 result.algparam.p = _ASN1HEX.getVbyList(pkcs8PubHex, a2[1], [0], "02"); 1203 result.algparam.q = _ASN1HEX.getVbyList(pkcs8PubHex, a2[1], [1], "02"); 1204 result.algparam.g = _ASN1HEX.getVbyList(pkcs8PubHex, a2[1], [2], "02"); 1205 } 1206 1207 // 3. Key 1208 if (pkcs8PubHex.substr(a1[1], 2) != "03") 1209 throw new Error("malformed PKCS8 public key(code:004)"); // Key is not bit string 1210 1211 result.key = _getV(pkcs8PubHex, a1[1]).substr(2); 1212 1213 // 4. return result assoc array 1214 return result; 1215 }, 1216 }; 1217 }(); 1218 1219 // -- MAJOR PUBLIC METHODS ---------------------------------------------------- 1220 /** 1221 * get private or public key object from any arguments 1222 * @name getKey 1223 * @memberOf KEYUTIL 1224 * @function 1225 * @static 1226 * @param {Object} param parameter to get key object. see description in detail. 1227 * @param {String} passcode (OPTION) parameter to get key object. see description in detail. 1228 * @param {String} hextype (OPTOIN) parameter to get key object. see description in detail. 1229 * @return {Object} {@link RSAKey}, {@link KJUR.crypto.ECDSA} or {@link KJUR.crypto.ECDSA} object 1230 * @since keyutil 1.0.0 1231 * @description 1232 * This method gets private or public key object({@link RSAKey}, {@link KJUR.crypto.DSA} or {@link KJUR.crypto.ECDSA}) 1233 * for RSA, DSA and ECC. 1234 * Arguments for this methods depends on a key format you specify. 1235 * Following key representations are supported. 1236 * <ul> 1237 * <li>ECC private/public key object(as is): param=KJUR.crypto.ECDSA</li> 1238 * <li>DSA private/public key object(as is): param=KJUR.crypto.DSA</li> 1239 * <li>RSA private/public key object(as is): param=RSAKey </li> 1240 * <li>ECC private key parameters: param={d: d, curve: curveName}</li> 1241 * <li>RSA private key parameters: param={n: n, e: e, d: d, p: p, q: q, dp: dp, dq: dq, co: co}<br/> 1242 * NOTE: Each value shall be hexadecimal string of key spec.</li> 1243 * <li>DSA private key parameters: param={p: p, q: q, g: g, y: y, x: x}<br/> 1244 * NOTE: Each value shall be hexadecimal string of key spec.</li> 1245 * <li>ECC public key parameters: param={xy: xy, curve: curveName}<br/> 1246 * NOTE: ECC public key 'xy' shall be concatination of "04", x-bytes-hex and y-bytes-hex.</li> 1247 * <li>DSA public key parameters: param={p: p, q: q, g: g, y: y}<br/> 1248 * NOTE: Each value shall be hexadecimal string of key spec.</li> 1249 * <li>RSA public key parameters: param={n: n, e: e} </li> 1250 * <li>X.509v1/v3 PEM certificate (RSA/DSA/ECC): param=pemString</li> 1251 * <li>PKCS#8 hexadecimal RSA/ECC public key: param=pemString, null, "pkcs8pub"</li> 1252 * <li>PKCS#8 PEM RSA/DSA/ECC public key: param=pemString</li> 1253 * <li>PKCS#5 plain hexadecimal RSA private key: param=hexString, null, "pkcs5prv"</li> 1254 * <li>PKCS#5 plain PEM RSA/DSA/EC private key: param=pemString</li> 1255 * <li>PKCS#8 plain PEM RSA/EC private key: param=pemString</li> 1256 * <li>PKCS#5 encrypted PEM RSA/DSA/EC private key: param=pemString, passcode</li> 1257 * <li>PKCS#8 encrypted PEM RSA/EC private key: param=pemString, passcode</li> 1258 * </ul> 1259 * Please note following limitation on encrypted keys: 1260 * <ul> 1261 * <li>Encrypted PKCS#8 only supports PBKDF2/HmacSHA1/3DES</li> 1262 * <li>Encrypted PKCS#5 supports DES-CBC, DES-EDE3-CBC, AES-{128,192.256}-CBC</li> 1263 * <li>JWT plain ECC private/public key</li> 1264 * <li>JWT plain RSA public key</li> 1265 * <li>JWT plain RSA private key with P/Q/DP/DQ/COEFF</li> 1266 * <li>JWT plain RSA private key without P/Q/DP/DQ/COEFF (since jsrsasign 5.0.0)</li> 1267 * </ul> 1268 * NOTE1: <a href="https://tools.ietf.org/html/rfc7517">RFC 7517 JSON Web Key(JWK)</a> support for RSA/ECC private/public key from jsrsasign 4.8.1.<br/> 1269 * NOTE2: X509v1 support is added since jsrsasign 5.0.11. 1270 * 1271 * <h5>EXAMPLE</h5> 1272 * @example 1273 * // 1. loading private key from PEM string 1274 * keyObj = KEYUTIL.getKey("-----BEGIN RSA PRIVATE KEY..."); 1275 * keyObj = KEYUTIL.getKey("-----BEGIN RSA PRIVATE KEY..., "passcode"); 1276 * keyObj = KEYUTIL.getKey("-----BEGIN PRIVATE KEY..."); 1277 * keyObj = KEYUTIL.getKey("-----BEGIN PRIVATE KEY...", "passcode"); 1278 * keyObj = KEYUTIL.getKey("-----BEGIN EC PARAMETERS...-----BEGIN EC PRIVATE KEY..."); 1279 * // 2. loading public key from PEM string 1280 * keyObj = KEYUTIL.getKey("-----BEGIN PUBLIC KEY..."); 1281 * keyObj = KEYUTIL.getKey("-----BEGIN X509 CERTIFICATE..."); 1282 * // 3. loading hexadecimal PKCS#5/PKCS#8 key 1283 * keyObj = KEYUTIL.getKey("308205c1...", null, "pkcs8pub"); 1284 * keyObj = KEYUTIL.getKey("3082048b...", null, "pkcs5prv"); 1285 * // 4. loading JSON Web Key(JWK) 1286 * keyObj = KEYUTIL.getKey({kty: "RSA", n: "0vx7...", e: "AQAB"}); 1287 * keyObj = KEYUTIL.getKey({kty: "EC", crv: "P-256", 1288 * x: "MKBC...", y: "4Etl6...", d: "870Mb..."}); 1289 * // 5. bare hexadecimal key 1290 * keyObj = KEYUTIL.getKey({n: "75ab..", e: "010001"}); 1291 */ 1292 KEYUTIL.getKey = function(param, passcode, hextype) { 1293 var _ASN1HEX = ASN1HEX, 1294 _getChildIdx = _ASN1HEX.getChildIdx, 1295 _getV = _ASN1HEX.getV, 1296 _getVbyList = _ASN1HEX.getVbyList, 1297 _KJUR_crypto = KJUR.crypto, 1298 _KJUR_crypto_ECDSA = _KJUR_crypto.ECDSA, 1299 _KJUR_crypto_DSA = _KJUR_crypto.DSA, 1300 _RSAKey = RSAKey, 1301 _pemtohex = pemtohex, 1302 _KEYUTIL = KEYUTIL; 1303 1304 // 1. by key RSAKey/KJUR.crypto.ECDSA/KJUR.crypto.DSA object 1305 if (typeof _RSAKey != 'undefined' && param instanceof _RSAKey) 1306 return param; 1307 if (typeof _KJUR_crypto_ECDSA != 'undefined' && param instanceof _KJUR_crypto_ECDSA) 1308 return param; 1309 if (typeof _KJUR_crypto_DSA != 'undefined' && param instanceof _KJUR_crypto_DSA) 1310 return param; 1311 1312 // 2. by parameters of key 1313 1314 // 2.1. bare ECC 1315 // 2.1.1. bare ECC public key by hex values 1316 if (param.curve !== undefined && 1317 param.xy !== undefined && param.d === undefined) { 1318 return new _KJUR_crypto_ECDSA({pub: param.xy, curve: param.curve}); 1319 } 1320 1321 // 2.1.2. bare ECC private key by hex values 1322 if (param.curve !== undefined && param.d !== undefined) { 1323 return new _KJUR_crypto_ECDSA({prv: param.d, curve: param.curve}); 1324 } 1325 1326 // 2.2. bare RSA 1327 // 2.2.1. bare RSA public key by hex values 1328 if (param.kty === undefined && 1329 param.n !== undefined && param.e !== undefined && 1330 param.d === undefined) { 1331 var key = new _RSAKey(); 1332 key.setPublic(param.n, param.e); 1333 return key; 1334 } 1335 1336 // 2.2.2. bare RSA private key with P/Q/DP/DQ/COEFF by hex values 1337 if (param.kty === undefined && 1338 param.n !== undefined && 1339 param.e !== undefined && 1340 param.d !== undefined && 1341 param.p !== undefined && 1342 param.q !== undefined && 1343 param.dp !== undefined && 1344 param.dq !== undefined && 1345 param.co !== undefined && 1346 param.qi === undefined) { 1347 var key = new _RSAKey(); 1348 key.setPrivateEx(param.n, param.e, param.d, param.p, param.q, 1349 param.dp, param.dq, param.co); 1350 return key; 1351 } 1352 1353 // 2.2.3. bare RSA public key without P/Q/DP/DQ/COEFF by hex values 1354 if (param.kty === undefined && 1355 param.n !== undefined && 1356 param.e !== undefined && 1357 param.d !== undefined && 1358 param.p === undefined) { 1359 var key = new _RSAKey(); 1360 key.setPrivate(param.n, param.e, param.d); 1361 return key; 1362 } 1363 1364 // 2.3. bare DSA 1365 // 2.3.1. bare DSA public key by hex values 1366 if (param.p !== undefined && param.q !== undefined && 1367 param.g !== undefined && 1368 param.y !== undefined && param.x === undefined) { 1369 var key = new _KJUR_crypto_DSA(); 1370 key.setPublic(param.p, param.q, param.g, param.y); 1371 return key; 1372 } 1373 1374 // 2.3.2. bare DSA private key by hex values 1375 if (param.p !== undefined && param.q !== undefined && 1376 param.g !== undefined && 1377 param.y !== undefined && param.x !== undefined) { 1378 var key = new _KJUR_crypto_DSA(); 1379 key.setPrivate(param.p, param.q, param.g, param.y, param.x); 1380 return key; 1381 } 1382 1383 // 3. JWK 1384 // 3.1. JWK RSA 1385 // 3.1.1. JWK RSA public key by b64u values 1386 if (param.kty === "RSA" && 1387 param.n !== undefined && 1388 param.e !== undefined && 1389 param.d === undefined) { 1390 var key = new _RSAKey(); 1391 key.setPublic(b64utohex(param.n), b64utohex(param.e)); 1392 return key; 1393 } 1394 1395 // 3.1.2. JWK RSA private key with p/q/dp/dq/coeff by b64u values 1396 if (param.kty === "RSA" && 1397 param.n !== undefined && 1398 param.e !== undefined && 1399 param.d !== undefined && 1400 param.p !== undefined && 1401 param.q !== undefined && 1402 param.dp !== undefined && 1403 param.dq !== undefined && 1404 param.qi !== undefined) { 1405 var key = new _RSAKey(); 1406 key.setPrivateEx(b64utohex(param.n), 1407 b64utohex(param.e), 1408 b64utohex(param.d), 1409 b64utohex(param.p), 1410 b64utohex(param.q), 1411 b64utohex(param.dp), 1412 b64utohex(param.dq), 1413 b64utohex(param.qi)); 1414 return key; 1415 } 1416 1417 // 3.1.3. JWK RSA private key without p/q/dp/dq/coeff by b64u 1418 // since jsrsasign 5.0.0 keyutil 1.0.11 1419 if (param.kty === "RSA" && 1420 param.n !== undefined && 1421 param.e !== undefined && 1422 param.d !== undefined) { 1423 var key = new _RSAKey(); 1424 key.setPrivate(b64utohex(param.n), 1425 b64utohex(param.e), 1426 b64utohex(param.d)); 1427 return key; 1428 } 1429 1430 // 3.2. JWK ECC 1431 // 3.2.1. JWK ECC public key by b64u values 1432 if (param.kty === "EC" && 1433 param.crv !== undefined && 1434 param.x !== undefined && 1435 param.y !== undefined && 1436 param.d === undefined) { 1437 var ec = new _KJUR_crypto_ECDSA({"curve": param.crv}); 1438 var charlen = ec.ecparams.keycharlen; 1439 var hX = ("0000000000" + b64utohex(param.x)).slice(- charlen); 1440 var hY = ("0000000000" + b64utohex(param.y)).slice(- charlen); 1441 var hPub = "04" + hX + hY; 1442 ec.setPublicKeyHex(hPub); 1443 return ec; 1444 } 1445 1446 // 3.2.2. JWK ECC private key by b64u values 1447 if (param.kty === "EC" && 1448 param.crv !== undefined && 1449 param.x !== undefined && 1450 param.y !== undefined && 1451 param.d !== undefined) { 1452 var ec = new _KJUR_crypto_ECDSA({"curve": param.crv}); 1453 var charlen = ec.ecparams.keycharlen; 1454 var hX = ("0000000000" + b64utohex(param.x)).slice(- charlen); 1455 var hY = ("0000000000" + b64utohex(param.y)).slice(- charlen); 1456 var hPub = "04" + hX + hY; 1457 var hPrv = ("0000000000" + b64utohex(param.d)).slice(- charlen); 1458 ec.setPublicKeyHex(hPub); 1459 ec.setPrivateKeyHex(hPrv); 1460 return ec; 1461 } 1462 1463 // 4. (plain) hexadecimal data 1464 // 4.1. get private key by PKCS#5 plain RSA/DSA/ECDSA hexadecimal string 1465 if (hextype === "pkcs5prv") { 1466 var h = param, _ASN1HEX = ASN1HEX, a, key; 1467 a = _getChildIdx(h, 0); 1468 if (a.length === 9) { // RSA (INT x 9) 1469 key = new _RSAKey(); 1470 key.readPKCS5PrvKeyHex(h); 1471 } else if (a.length === 6) { // DSA (INT x 6) 1472 key = new _KJUR_crypto_DSA(); 1473 key.readPKCS5PrvKeyHex(h); 1474 } else if (a.length > 2 && // ECDSA (INT, OCT prv, [0] curve, [1] pub) 1475 h.substr(a[1], 2) === "04") { 1476 key = new _KJUR_crypto_ECDSA(); 1477 key.readPKCS5PrvKeyHex(h); 1478 } else { 1479 throw new Error("unsupported PKCS#1/5 hexadecimal key"); 1480 } 1481 1482 return key; 1483 } 1484 1485 // 4.2. get private key by PKCS#8 plain RSA/DSA/ECDSA hexadecimal string 1486 if (hextype === "pkcs8prv") { 1487 var key = _KEYUTIL.getKeyFromPlainPrivatePKCS8Hex(param); 1488 return key; 1489 } 1490 1491 // 4.3. get public key by PKCS#8 RSA/DSA/ECDSA hexadecimal string 1492 if (hextype === "pkcs8pub") { 1493 return _KEYUTIL._getKeyFromPublicPKCS8Hex(param); 1494 } 1495 1496 // 4.4. get public key by X.509 hexadecimal string for RSA/DSA/ECDSA 1497 if (hextype === "x509pub") { 1498 return X509.getPublicKeyFromCertHex(param); 1499 } 1500 1501 // 5. by PEM certificate (-----BEGIN ... CERTIFICATE----) 1502 if (param.indexOf("-END CERTIFICATE-", 0) != -1 || 1503 param.indexOf("-END X509 CERTIFICATE-", 0) != -1 || 1504 param.indexOf("-END TRUSTED CERTIFICATE-", 0) != -1) { 1505 return X509.getPublicKeyFromCertPEM(param); 1506 } 1507 1508 // 6. public key by PKCS#8 PEM string 1509 if (param.indexOf("-END PUBLIC KEY-") != -1) { 1510 var pubKeyHex = pemtohex(param, "PUBLIC KEY"); 1511 return _KEYUTIL._getKeyFromPublicPKCS8Hex(pubKeyHex); 1512 } 1513 1514 // 8.1 private key by plain PKCS#5 PEM RSA string 1515 // getKey("-----BEGIN RSA PRIVATE KEY-...") 1516 if (param.indexOf("-END RSA PRIVATE KEY-") != -1 && 1517 param.indexOf("4,ENCRYPTED") == -1) { 1518 var hex = _pemtohex(param, "RSA PRIVATE KEY"); 1519 return _KEYUTIL.getKey(hex, null, "pkcs5prv"); 1520 } 1521 1522 // 8.2. private key by plain PKCS#5 PEM DSA string 1523 if (param.indexOf("-END DSA PRIVATE KEY-") != -1 && 1524 param.indexOf("4,ENCRYPTED") == -1) { 1525 1526 var hKey = _pemtohex(param, "DSA PRIVATE KEY"); 1527 var p = _getVbyList(hKey, 0, [1], "02"); 1528 var q = _getVbyList(hKey, 0, [2], "02"); 1529 var g = _getVbyList(hKey, 0, [3], "02"); 1530 var y = _getVbyList(hKey, 0, [4], "02"); 1531 var x = _getVbyList(hKey, 0, [5], "02"); 1532 var key = new _KJUR_crypto_DSA(); 1533 key.setPrivate(new BigInteger(p, 16), 1534 new BigInteger(q, 16), 1535 new BigInteger(g, 16), 1536 new BigInteger(y, 16), 1537 new BigInteger(x, 16)); 1538 return key; 1539 } 1540 1541 // 8.3. private key by plain PKCS#5 PEM EC string 1542 if (param.indexOf("-END EC PRIVATE KEY-") != -1 && 1543 param.indexOf("4,ENCRYPTED") == -1) { 1544 var hex = _pemtohex(param, "EC PRIVATE KEY"); 1545 return _KEYUTIL.getKey(hex, null, "pkcs5prv"); 1546 } 1547 1548 // 10. private key by plain PKCS#8 PEM ECC/RSA string 1549 if (param.indexOf("-END PRIVATE KEY-") != -1) { 1550 return _KEYUTIL.getKeyFromPlainPrivatePKCS8PEM(param); 1551 } 1552 1553 // 11.1 private key by encrypted PKCS#5 PEM RSA string 1554 if (param.indexOf("-END RSA PRIVATE KEY-") != -1 && 1555 param.indexOf("4,ENCRYPTED") != -1) { 1556 var hPKey = _KEYUTIL.getDecryptedKeyHex(param, passcode); 1557 var rsaKey = new RSAKey(); 1558 rsaKey.readPKCS5PrvKeyHex(hPKey); 1559 return rsaKey; 1560 } 1561 1562 // 11.2. private key by encrypted PKCS#5 PEM ECDSA string 1563 if (param.indexOf("-END EC PRIVATE KEY-") != -1 && 1564 param.indexOf("4,ENCRYPTED") != -1) { 1565 var hKey = _KEYUTIL.getDecryptedKeyHex(param, passcode); 1566 1567 var key = _getVbyList(hKey, 0, [1], "04"); 1568 var curveNameOidHex = _getVbyList(hKey, 0, [2,0], "06"); 1569 var pubkey = _getVbyList(hKey, 0, [3,0], "03").substr(2); 1570 var curveName = ""; 1571 1572 if (KJUR.crypto.OID.oidhex2name[curveNameOidHex] !== undefined) { 1573 curveName = KJUR.crypto.OID.oidhex2name[curveNameOidHex]; 1574 } else { 1575 throw new Error("undefined OID(hex) in KJUR.crypto.OID: " + 1576 curveNameOidHex); 1577 } 1578 1579 var ec = new _KJUR_crypto_ECDSA({'curve': curveName}); 1580 ec.setPublicKeyHex(pubkey); 1581 ec.setPrivateKeyHex(key); 1582 ec.isPublic = false; 1583 return ec; 1584 } 1585 1586 // 11.3. private key by encrypted PKCS#5 PEM DSA string 1587 if (param.indexOf("-END DSA PRIVATE KEY-") != -1 && 1588 param.indexOf("4,ENCRYPTED") != -1) { 1589 var hKey = _KEYUTIL.getDecryptedKeyHex(param, passcode); 1590 var p = _getVbyList(hKey, 0, [1], "02"); 1591 var q = _getVbyList(hKey, 0, [2], "02"); 1592 var g = _getVbyList(hKey, 0, [3], "02"); 1593 var y = _getVbyList(hKey, 0, [4], "02"); 1594 var x = _getVbyList(hKey, 0, [5], "02"); 1595 var key = new _KJUR_crypto_DSA(); 1596 key.setPrivate(new BigInteger(p, 16), 1597 new BigInteger(q, 16), 1598 new BigInteger(g, 16), 1599 new BigInteger(y, 16), 1600 new BigInteger(x, 16)); 1601 return key; 1602 } 1603 1604 // 11. private key by encrypted PKCS#8 hexadecimal RSA/ECDSA string 1605 if (param.indexOf("-END ENCRYPTED PRIVATE KEY-") != -1) { 1606 return _KEYUTIL.getKeyFromEncryptedPKCS8PEM(param, passcode); 1607 } 1608 1609 throw new Error("not supported argument"); 1610 }; 1611 1612 /** 1613 * @name generateKeypair 1614 * @memberOf KEYUTIL 1615 * @function 1616 * @static 1617 * @param {String} alg 'RSA' or 'EC' 1618 * @param {Object} keylenOrCurve key length for RSA or curve name for EC 1619 * @return {Array} associative array of keypair which has prvKeyObj and pubKeyObj parameters 1620 * @since keyutil 1.0.1 1621 * @description 1622 * This method generates a key pair of public key algorithm. 1623 * The result will be an associative array which has following 1624 * parameters: 1625 * <ul> 1626 * <li>prvKeyObj - RSAKey or ECDSA object of private key</li> 1627 * <li>pubKeyObj - RSAKey or ECDSA object of public key</li> 1628 * </ul> 1629 * NOTE1: As for RSA algoirthm, public exponent has fixed 1630 * value '0x10001'. 1631 * NOTE2: As for EC algorithm, supported names of curve are 1632 * secp256r1, secp256k1, secp384r1 and secp521r1. 1633 * NOTE3: DSA is not supported yet. 1634 * @example 1635 * var rsaKeypair = KEYUTIL.generateKeypair("RSA", 1024); 1636 * var ecKeypair = KEYUTIL.generateKeypair("EC", "secp256r1"); 1637 * 1638 */ 1639 KEYUTIL.generateKeypair = function(alg, keylenOrCurve) { 1640 if (alg == "RSA") { 1641 var keylen = keylenOrCurve; 1642 var prvKey = new RSAKey(); 1643 prvKey.generate(keylen, '10001'); 1644 prvKey.isPrivate = true; 1645 prvKey.isPublic = true; 1646 1647 var pubKey = new RSAKey(); 1648 var hN = prvKey.n.toString(16); 1649 var hE = prvKey.e.toString(16); 1650 pubKey.setPublic(hN, hE); 1651 pubKey.isPrivate = false; 1652 pubKey.isPublic = true; 1653 1654 var result = {}; 1655 result.prvKeyObj = prvKey; 1656 result.pubKeyObj = pubKey; 1657 return result; 1658 } else if (alg == "EC") { 1659 var curve = keylenOrCurve; 1660 var ec = new KJUR.crypto.ECDSA({curve: curve}); 1661 var keypairHex = ec.generateKeyPairHex(); 1662 1663 var prvKey = new KJUR.crypto.ECDSA({curve: curve}); 1664 prvKey.setPublicKeyHex(keypairHex.ecpubhex); 1665 prvKey.setPrivateKeyHex(keypairHex.ecprvhex); 1666 prvKey.isPrivate = true; 1667 prvKey.isPublic = false; 1668 1669 var pubKey = new KJUR.crypto.ECDSA({curve: curve}); 1670 pubKey.setPublicKeyHex(keypairHex.ecpubhex); 1671 pubKey.isPrivate = false; 1672 pubKey.isPublic = true; 1673 1674 var result = {}; 1675 result.prvKeyObj = prvKey; 1676 result.pubKeyObj = pubKey; 1677 return result; 1678 } else { 1679 throw new Error("unknown algorithm: " + alg); 1680 } 1681 }; 1682 1683 /** 1684 * get PEM formatted private or public key file from a RSA/ECDSA/DSA key object 1685 * @name getPEM 1686 * @memberOf KEYUTIL 1687 * @function 1688 * @static 1689 * @param {Object} keyObjOrHex key object {@link RSAKey}, {@link KJUR.crypto.ECDSA} or {@link KJUR.crypto.DSA} to encode to 1690 * @param {String} formatType (OPTION) output format type of "PKCS1PRV", "PKCS5PRV" or "PKCS8PRV" for private key 1691 * @param {String} passwd (OPTION) password to protect private key 1692 * @param {String} encAlg (OPTION) encryption algorithm for PKCS#5. currently supports DES-CBC, DES-EDE3-CBC and AES-{128,192,256}-CBC 1693 * @param {String} hexType (OPTION) type of hex string (ex. pkcs5prv, pkcs8prv) 1694 * @param {String} ivsaltHex hexadecimal string of IV and salt (default generated random IV) 1695 * @since keyutil 1.0.4 1696 * 1697 * @description 1698 * <dl> 1699 * <dt><b>NOTE1:</b> 1700 * <dd> 1701 * PKCS#5 encrypted private key protection algorithm supports DES-CBC, 1702 * DES-EDE3-CBC and AES-{128,192,256}-CBC 1703 * <dt><b>NOTE2:</b> 1704 * <dd> 1705 * OpenSSL supports 1706 * <dt><b>NOTE3:</b> 1707 * <dd> 1708 * Parameter "ivsaltHex" supported since jsrsasign 8.0.0 keyutil 1.2.0. 1709 * </dl> 1710 * 1711 * @example 1712 * KEUUTIL.getPEM(publicKey) → generates PEM PKCS#8 public key 1713 * KEUUTIL.getPEM(privateKey) → generates PEM PKCS#8 plain private key by default 1714 * KEUUTIL.getPEM(privateKey, "PKCS1PRV") → generates PEM PKCS#1 plain private key 1715 * KEUUTIL.getPEM(privateKey, "PKCS5PRV", "pass") → generates PEM PKCS#5 encrypted private key 1716 * with DES-EDE3-CBC (DEFAULT) 1717 * KEUUTIL.getPEM(privateKey, "PKCS5PRV", "pass", "DES-CBC") → generates PEM PKCS#5 encrypted 1718 * private key with DES-CBC 1719 * KEUUTIL.getPEM(privateKey, "PKCS8PRV") → generates PEM PKCS#8 plain private key 1720 * KEUUTIL.getPEM(privateKey, "PKCS8PRV", "pass") → generates PEM PKCS#8 encrypted private key 1721 * with PBKDF2_HmacSHA1_3DES 1722 */ 1723 KEYUTIL.getPEM = function(keyObjOrHex, formatType, passwd, encAlg, hexType, ivsaltHex) { 1724 var _KJUR = KJUR, 1725 _KJUR_asn1 = _KJUR.asn1, 1726 _DERObjectIdentifier = _KJUR_asn1.DERObjectIdentifier, 1727 _DERInteger = _KJUR_asn1.DERInteger, 1728 _newObject = _KJUR_asn1.ASN1Util.newObject, 1729 _KJUR_asn1_x509 = _KJUR_asn1.x509, 1730 _SubjectPublicKeyInfo = _KJUR_asn1_x509.SubjectPublicKeyInfo, 1731 _KJUR_crypto = _KJUR.crypto, 1732 _DSA = _KJUR_crypto.DSA, 1733 _ECDSA = _KJUR_crypto.ECDSA, 1734 _RSAKey = RSAKey; 1735 1736 function _rsaprv2asn1obj(keyObjOrHex) { 1737 var asn1Obj = _newObject({ 1738 "seq": [ 1739 {"int": 0 }, 1740 {"int": {"bigint": keyObjOrHex.n}}, 1741 {"int": keyObjOrHex.e}, 1742 {"int": {"bigint": keyObjOrHex.d}}, 1743 {"int": {"bigint": keyObjOrHex.p}}, 1744 {"int": {"bigint": keyObjOrHex.q}}, 1745 {"int": {"bigint": keyObjOrHex.dmp1}}, 1746 {"int": {"bigint": keyObjOrHex.dmq1}}, 1747 {"int": {"bigint": keyObjOrHex.coeff}} 1748 ] 1749 }); 1750 return asn1Obj; 1751 }; 1752 1753 function _ecdsaprv2asn1obj(keyObjOrHex) { 1754 var asn1Obj2 = _newObject({ 1755 "seq": [ 1756 {"int": 1 }, 1757 {"octstr": {"hex": keyObjOrHex.prvKeyHex}}, 1758 {"tag": ['a0', true, {'oid': {'name': keyObjOrHex.curveName}}]}, 1759 {"tag": ['a1', true, {'bitstr': {'hex': '00' + keyObjOrHex.pubKeyHex}}]} 1760 ] 1761 }); 1762 return asn1Obj2; 1763 }; 1764 1765 function _dsaprv2asn1obj(keyObjOrHex) { 1766 var asn1Obj = _newObject({ 1767 "seq": [ 1768 {"int": 0 }, 1769 {"int": {"bigint": keyObjOrHex.p}}, 1770 {"int": {"bigint": keyObjOrHex.q}}, 1771 {"int": {"bigint": keyObjOrHex.g}}, 1772 {"int": {"bigint": keyObjOrHex.y}}, 1773 {"int": {"bigint": keyObjOrHex.x}} 1774 ] 1775 }); 1776 return asn1Obj; 1777 }; 1778 1779 // 1. public key 1780 1781 // x. PEM PKCS#8 public key of RSA/ECDSA/DSA public key object 1782 if (((_RSAKey !== undefined && keyObjOrHex instanceof _RSAKey) || 1783 (_DSA !== undefined && keyObjOrHex instanceof _DSA) || 1784 (_ECDSA !== undefined && keyObjOrHex instanceof _ECDSA)) && 1785 keyObjOrHex.isPublic == true && 1786 (formatType === undefined || formatType == "PKCS8PUB")) { 1787 var asn1Obj = new _SubjectPublicKeyInfo(keyObjOrHex); 1788 var asn1Hex = asn1Obj.tohex(); 1789 return hextopem(asn1Hex, "PUBLIC KEY"); 1790 } 1791 1792 // 2. private 1793 1794 // x. PEM PKCS#1 plain private key of RSA private key object 1795 if (formatType == "PKCS1PRV" && 1796 _RSAKey !== undefined && 1797 keyObjOrHex instanceof _RSAKey && 1798 (passwd === undefined || passwd == null) && 1799 keyObjOrHex.isPrivate == true) { 1800 1801 var asn1Obj = _rsaprv2asn1obj(keyObjOrHex); 1802 var asn1Hex = asn1Obj.tohex(); 1803 return hextopem(asn1Hex, "RSA PRIVATE KEY"); 1804 } 1805 1806 // x. PEM PKCS#1 plain private key of ECDSA private key object 1807 if (formatType == "PKCS1PRV" && 1808 _ECDSA !== undefined && 1809 keyObjOrHex instanceof _ECDSA && 1810 (passwd === undefined || passwd == null) && 1811 keyObjOrHex.isPrivate == true) { 1812 1813 var asn1Obj1 = 1814 new _DERObjectIdentifier({'name': keyObjOrHex.curveName}); 1815 var asn1Hex1 = asn1Obj1.tohex(); 1816 var asn1Obj2 = _ecdsaprv2asn1obj(keyObjOrHex); 1817 var asn1Hex2 = asn1Obj2.tohex(); 1818 1819 var s = ""; 1820 s += hextopem(asn1Hex1, "EC PARAMETERS"); 1821 s += hextopem(asn1Hex2, "EC PRIVATE KEY"); 1822 return s; 1823 } 1824 1825 // x. PEM PKCS#1 plain private key of DSA private key object 1826 if (formatType == "PKCS1PRV" && 1827 _DSA !== undefined && 1828 keyObjOrHex instanceof _DSA && 1829 (passwd === undefined || passwd == null) && 1830 keyObjOrHex.isPrivate == true) { 1831 1832 var asn1Obj = _dsaprv2asn1obj(keyObjOrHex); 1833 var asn1Hex = asn1Obj.tohex(); 1834 return hextopem(asn1Hex, "DSA PRIVATE KEY"); 1835 } 1836 1837 // 3. private 1838 1839 // x. PEM PKCS#5 encrypted private key of RSA private key object 1840 if (formatType == "PKCS5PRV" && 1841 _RSAKey !== undefined && 1842 keyObjOrHex instanceof _RSAKey && 1843 (passwd !== undefined && passwd != null) && 1844 keyObjOrHex.isPrivate == true) { 1845 1846 var asn1Obj = _rsaprv2asn1obj(keyObjOrHex); 1847 var asn1Hex = asn1Obj.tohex(); 1848 1849 if (encAlg === undefined) encAlg = "DES-EDE3-CBC"; 1850 return this.getEncryptedPKCS5PEMFromPrvKeyHex("RSA", asn1Hex, passwd, encAlg, ivsaltHex); 1851 } 1852 1853 // x. PEM PKCS#5 encrypted private key of ECDSA private key object 1854 if (formatType == "PKCS5PRV" && 1855 _ECDSA !== undefined && 1856 keyObjOrHex instanceof _ECDSA && 1857 (passwd !== undefined && passwd != null) && 1858 keyObjOrHex.isPrivate == true) { 1859 1860 var asn1Obj = _ecdsaprv2asn1obj(keyObjOrHex); 1861 var asn1Hex = asn1Obj.tohex(); 1862 1863 if (encAlg === undefined) encAlg = "DES-EDE3-CBC"; 1864 return this.getEncryptedPKCS5PEMFromPrvKeyHex("EC", asn1Hex, passwd, encAlg, ivsaltHex); 1865 } 1866 1867 // x. PEM PKCS#5 encrypted private key of DSA private key object 1868 if (formatType == "PKCS5PRV" && 1869 _DSA !== undefined && 1870 keyObjOrHex instanceof _DSA && 1871 (passwd !== undefined && passwd != null) && 1872 keyObjOrHex.isPrivate == true) { 1873 1874 var asn1Obj = _dsaprv2asn1obj(keyObjOrHex); 1875 var asn1Hex = asn1Obj.tohex(); 1876 1877 if (encAlg === undefined) encAlg = "DES-EDE3-CBC"; 1878 return this.getEncryptedPKCS5PEMFromPrvKeyHex("DSA", asn1Hex, passwd, encAlg, ivsaltHex); 1879 } 1880 1881 // x. ====================================================================== 1882 1883 var _getEncryptedPKCS8PEM = function(plainKeyHex, passcodeOrParam) { 1884 if (typeof passcodeOrParam == "string") { 1885 return KEYUTIL.getEncryptedPKCS8PEM(plainKeyHex, passcodeOrParam); 1886 } else if (typeof passcodeOrParam == "object" && aryval(passcodeOrParam, "passcode") != undefined) { 1887 var param = JSON.parse(JSON.stringify(passcodeOrParam)); 1888 var passcode = param.passcode; 1889 delete param.passcode; 1890 return KEYUTIL.getEncryptedPKCS8PEM(plainKeyHex, passcode, param); 1891 } 1892 }; 1893 1894 // x. PEM PKCS#8 plain private key of RSA private key object 1895 if (formatType == "PKCS8PRV" && 1896 _RSAKey != undefined && 1897 keyObjOrHex instanceof _RSAKey && 1898 keyObjOrHex.isPrivate == true) { 1899 1900 var keyObj = _rsaprv2asn1obj(keyObjOrHex); 1901 var keyHex = keyObj.tohex(); 1902 1903 var asn1Obj = _newObject({ 1904 "seq": [ 1905 {"int": 0}, 1906 {"seq": [{"oid": {"name": "rsaEncryption"}},{"null": true}]}, 1907 {"octstr": {"hex": keyHex}} 1908 ] 1909 }); 1910 var asn1Hex = asn1Obj.tohex(); 1911 1912 if (passwd === undefined || passwd == null) { 1913 return hextopem(asn1Hex, "PRIVATE KEY"); 1914 } else { 1915 return _getEncryptedPKCS8PEM(asn1Hex, passwd); 1916 } 1917 } 1918 1919 // x. PEM PKCS#8 plain private key of ECDSA private key object 1920 if (formatType == "PKCS8PRV" && 1921 _ECDSA !== undefined && 1922 keyObjOrHex instanceof _ECDSA && 1923 keyObjOrHex.isPrivate == true) { 1924 1925 var pKeyObj = { 1926 "seq": [ 1927 {"int": 1}, 1928 {"octstr": {"hex": keyObjOrHex.prvKeyHex}} 1929 ] 1930 }; 1931 if (typeof keyObjOrHex.pubKeyHex == "string") { 1932 pKeyObj.seq.push({"tag": ['a1', true, {"bitstr": {"hex": "00" + keyObjOrHex.pubKeyHex}}]}); 1933 } 1934 var keyObj = new _newObject(pKeyObj); 1935 var keyHex = keyObj.tohex(); 1936 1937 var asn1Obj = _newObject({ 1938 "seq": [ 1939 {"int": 0}, 1940 {"seq": [ 1941 {"oid": {"name": "ecPublicKey"}}, 1942 {"oid": {"name": keyObjOrHex.curveName}} 1943 ]}, 1944 {"octstr": {"hex": keyHex}} 1945 ] 1946 }); 1947 1948 var asn1Hex = asn1Obj.tohex(); 1949 if (passwd === undefined || passwd == null) { 1950 return hextopem(asn1Hex, "PRIVATE KEY"); 1951 } else { 1952 return _getEncryptedPKCS8PEM(asn1Hex, passwd); 1953 } 1954 } 1955 1956 // x. PEM PKCS#8 plain private key of DSA private key object 1957 if (formatType == "PKCS8PRV" && 1958 _DSA !== undefined && 1959 keyObjOrHex instanceof _DSA && 1960 keyObjOrHex.isPrivate == true) { 1961 1962 var keyObj = new _DERInteger({'bigint': keyObjOrHex.x}); 1963 var keyHex = keyObj.tohex(); 1964 1965 var asn1Obj = _newObject({ 1966 "seq": [ 1967 {"int": 0}, 1968 {"seq": [ 1969 {"oid": {"name": "dsa"}}, 1970 {"seq": [ 1971 {"int": {"bigint": keyObjOrHex.p}}, 1972 {"int": {"bigint": keyObjOrHex.q}}, 1973 {"int": {"bigint": keyObjOrHex.g}} 1974 ]} 1975 ]}, 1976 {"octstr": {"hex": keyHex}} 1977 ] 1978 }); 1979 1980 var asn1Hex = asn1Obj.tohex(); 1981 if (passwd === undefined || passwd == null) { 1982 return hextopem(asn1Hex, "PRIVATE KEY"); 1983 } else { 1984 return _getEncryptedPKCS8PEM(asn1Hex, passwd); 1985 } 1986 } 1987 1988 throw new Error("unsupported object nor format"); 1989 }; 1990 1991 // -- PUBLIC METHODS FOR CSR -------------------------------------------------- 1992 1993 /** 1994 * get RSAKey/DSA/ECDSA public key object from PEM formatted PKCS#10 CSR string 1995 * @name getKeyFromCSRPEM 1996 * @memberOf KEYUTIL 1997 * @function 1998 * @param {String} csrPEM PEM formatted PKCS#10 CSR string 1999 * @return {Object} RSAKey/DSA/ECDSA public key object 2000 * @since keyutil 1.0.5 2001 */ 2002 KEYUTIL.getKeyFromCSRPEM = function(csrPEM) { 2003 var csrHex = pemtohex(csrPEM, "CERTIFICATE REQUEST"); 2004 var key = KEYUTIL.getKeyFromCSRHex(csrHex); 2005 return key; 2006 }; 2007 2008 /** 2009 * get RSAKey/DSA/ECDSA public key object from hexadecimal string of PKCS#10 CSR 2010 * @name getKeyFromCSRHex 2011 * @memberOf KEYUTIL 2012 * @function 2013 * @param {String} csrHex hexadecimal string of PKCS#10 CSR 2014 * @return {Object} RSAKey/DSA/ECDSA public key object 2015 * @since keyutil 1.0.5 2016 */ 2017 KEYUTIL.getKeyFromCSRHex = function(csrHex) { 2018 var info = KEYUTIL.parseCSRHex(csrHex); 2019 var key = KEYUTIL.getKey(info.p8pubkeyhex, null, "pkcs8pub"); 2020 return key; 2021 }; 2022 2023 /** 2024 * parse hexadecimal string of PKCS#10 CSR (certificate signing request) 2025 * @name parseCSRHex 2026 * @memberOf KEYUTIL 2027 * @function 2028 * @param {String} csrHex hexadecimal string of PKCS#10 CSR 2029 * @return {Array} associative array of parsed CSR 2030 * @since keyutil 1.0.5 2031 * @description 2032 * Resulted associative array has following properties: 2033 * <ul> 2034 * <li>p8pubkeyhex - hexadecimal string of subject public key in PKCS#8</li> 2035 * </ul> 2036 */ 2037 KEYUTIL.parseCSRHex = function(csrHex) { 2038 var _ASN1HEX = ASN1HEX; 2039 var _getChildIdx = _ASN1HEX.getChildIdx; 2040 var _getTLV = _ASN1HEX.getTLV; 2041 var result = {}; 2042 var h = csrHex; 2043 2044 // 1. sequence 2045 if (h.substr(0, 2) != "30") 2046 throw new Error("malformed CSR(code:001)"); // not sequence 2047 2048 var a1 = _getChildIdx(h, 0); 2049 if (a1.length < 1) 2050 throw new Error("malformed CSR(code:002)"); // short length 2051 2052 // 2. 2nd sequence 2053 if (h.substr(a1[0], 2) != "30") 2054 throw new Error("malformed CSR(code:003)"); // not sequence 2055 2056 var a2 = _getChildIdx(h, a1[0]); 2057 if (a2.length < 3) 2058 throw new Error("malformed CSR(code:004)"); // 2nd seq short elem 2059 2060 result.p8pubkeyhex = _getTLV(h, a2[2]); 2061 2062 return result; 2063 }; 2064 2065 // -- ENCRYPTED PKCS#8 PRIVATE KEY GENERATION METHODS ------------------------ 2066 2067 // -- OTHER STATIC PUBLIC METHODS -------------------------------------------- 2068 2069 /** 2070 * get key ID by public key object for subject or authority key identifier 2071 * @name getKeyID 2072 * @memberof KEYUTIL 2073 * @function 2074 * @static 2075 * @param {Object} obj RSAKey/KJUR.crypto.ECDSA,DSA public key object or public key PEM string 2076 * @return hexadecimal string of public key identifier 2077 * @since keyutil 1.2.2 jsrsasign 5.0.16 2078 * @description 2079 * This static method generates a key identifier from a public key 2080 * by the method described in 2081 * <a href="https://tools.ietf.org/html/rfc5280#section-4.2.1.2" 2082 * target="_blank">RFC 5280 4.2.1.2. Subject Key Identifier (1)</a>. 2083 * @example 2084 * pubkeyobj = KEYUTIL.getKey(...); 2085 * KEYTUTIL.getKey(pubkeyobj) → "a612..." 2086 */ 2087 KEYUTIL.getKeyID = function(obj) { 2088 var _KEYUTIL = KEYUTIL; 2089 var _ASN1HEX = ASN1HEX; 2090 2091 if (typeof obj === "string" && obj.indexOf("BEGIN ") != -1) { 2092 obj = _KEYUTIL.getKey(obj); 2093 } 2094 2095 var p8hex = pemtohex(_KEYUTIL.getPEM(obj)); 2096 var idx = _ASN1HEX.getIdxbyList(p8hex, 0, [1]); // BITSTRING 2097 var hV = _ASN1HEX.getV(p8hex, idx).substring(2); // value without unused bit 2098 return KJUR.crypto.Util.hashHex(hV, "sha1"); 2099 } 2100 2101 /** 2102 * convert from certificate, public/private key object to RFC 7517 JSON Web Key(JWK)<br/> 2103 * @name getJWK 2104 * @memberOf KEYUTIL 2105 * @function 2106 * @static 2107 * @param {Object or string} keyinfo public/private key object, PEM key or PEM certificate 2108 * @param {boolean} nokid set true if you don't need kid (OPTION, DEFAULT=undefined) 2109 * @param {boolean} nox5c set true if you don't need x5c of certificate (OPTION, DEFAULT=undefined) 2110 * @param {boolean} nox5t set true if you don't need x5t of certificate (OPTION, DEFAULT=undefined) 2111 * @param {boolean} nox5t2 set true if you don't need x5c#S256 of certificate (OPTION, DEFAULT=undefined) 2112 * @return {Object} JWK object 2113 * @since keyutil 1.2.5 jsrsasign 10.5.1 2114 * @see RSAKey 2115 * @see KJUR.crypto.ECDSA 2116 * @see KJUR.crypto.DSA 2117 * 2118 * @description 2119 * This static method provides 2120 * <a href="https://datatracker.ietf.org/doc/html/rfc7517"> 2121 * RFC 7517 JSON Web Key(JWK) JSON</a> 2122 * object from following argument types: 2123 * <ul> 2124 * <li> 2125 * <b>JWK private key</b> 2126 * <ul> 2127 * <li>RSAKey or KJUR.crypto.{ECDSA,DSA} private key object</li> 2128 * <li>PKCS#5 or PKCS#8 plain PEM private key</li> 2129 * </ul> 2130 * </li> 2131 * <li> 2132 * <b>JWK public key</b> 2133 * <ul> 2134 * <li>RSAKey or KJUR.crypto.{ECDSA,DSA} public key object</li> 2135 * <li>PKCS#5 or PKCS#8 PEM public key</li> 2136 * <li>X509 certificate object</li> 2137 * <li>PEM certificate</li> 2138 * </ul> 2139 * </li> 2140 * </ul> 2141 * 2142 * @example 2143 * kp1 = KEYUTIL.generateKeypair("EC", "P-256"); 2144 * jwkPrv1 = KEYUTIL.getJWK(kp1.prvKeyObj); 2145 * jwkPub1 = KEYUTIL.getJWK(kp1.pubKeyObj); 2146 * 2147 * kp2 = KEYUTIL.generateKeypair("RSA", 2048); 2148 * jwkPrv2 = KEYUTIL.getJWK(kp2.prvKeyObj); 2149 * jwkPub2 = KEYUTIL.getJWK(kp2.pubKeyObj); 2150 * 2151 * // from PEM certificate 2152 * KEYUTIL.getJWK("-----BEGIN CERTIFICATE...") → 2153 * { 2154 * kty: "EC", crv: "P-521", x: "...", y: "...", 2155 * x5c: ["MI..."], 2156 * x5t: "...", 2157 * "x5t#S256": "...", 2158 * kid: "..." 2159 * } 2160 * 2161 * // from X509 object 2162 * x509obj = new X509("-----BEGIN CERTIFICATE..."); 2163 * KEYUTIL.getJWK(x509obj) → 2164 * { 2165 * kty: "EC", crv: "P-521", x: "...", y: "...", 2166 * ... 2167 * } 2168 * 2169 * // from PEM certificate without kid, x5t and x5t#S256 (i.e. only x5c) 2170 * KEYUTIL.getJWK("-----BEGIN CERTIFICATE...", true, false, true, true) → 2171 * { 2172 * kty: "EC", crv: "P-521", x: "...", y: "...", 2173 * x5c: ["MI..."] 2174 * } 2175 */ 2176 KEYUTIL.getJWK = function(keyinfo, nokid, nox5c, nox5t, nox5t2) { 2177 var keyObj; 2178 var jwk = {}; 2179 var hCert; 2180 var _hashHex = KJUR.crypto.Util.hashHex; 2181 2182 if (typeof keyinfo == "string") { 2183 keyObj = KEYUTIL.getKey(keyinfo); 2184 if (keyinfo.indexOf("CERTIFICATE") != -1) { 2185 hCert = pemtohex(keyinfo) 2186 } 2187 } else if (typeof keyinfo == "object") { 2188 if (keyinfo instanceof X509) { 2189 keyObj = keyinfo.getPublicKey(); 2190 hCert = keyinfo.hex; 2191 } else { 2192 keyObj = keyinfo; 2193 } 2194 } else { 2195 throw new Error("unsupported keyinfo type"); 2196 } 2197 2198 if (keyObj instanceof RSAKey && keyObj.isPrivate) { 2199 jwk.kty = "RSA"; 2200 jwk.n = hextob64u(keyObj.n.toString(16)); 2201 jwk.e = hextob64u(keyObj.e.toString(16)); 2202 jwk.d = hextob64u(keyObj.d.toString(16)); 2203 jwk.p = hextob64u(keyObj.p.toString(16)); 2204 jwk.q = hextob64u(keyObj.q.toString(16)); 2205 jwk.dp = hextob64u(keyObj.dmp1.toString(16)); 2206 jwk.dq = hextob64u(keyObj.dmq1.toString(16)); 2207 jwk.qi = hextob64u(keyObj.coeff.toString(16)); 2208 } else if (keyObj instanceof RSAKey && keyObj.isPublic) { 2209 jwk.kty = "RSA"; 2210 jwk.n = hextob64u(keyObj.n.toString(16)); 2211 jwk.e = hextob64u(keyObj.e.toString(16)); 2212 } else if (keyObj instanceof KJUR.crypto.ECDSA && keyObj.isPrivate) { 2213 var name = keyObj.getShortNISTPCurveName(); 2214 if (name !== "P-256" && name !== "P-384" && name !== "P-521") 2215 throw new Error("unsupported curve name for JWT: " + name); 2216 var xy = keyObj.getPublicKeyXYHex(); 2217 jwk.kty = "EC"; 2218 jwk.crv = name; 2219 jwk.x = hextob64u(xy.x); 2220 jwk.y = hextob64u(xy.y); 2221 jwk.d = hextob64u(keyObj.prvKeyHex); 2222 } else if (keyObj instanceof KJUR.crypto.ECDSA && keyObj.isPublic) { 2223 var name = keyObj.getShortNISTPCurveName(); 2224 if (name !== "P-256" && name !== "P-384" && name !== "P-521") 2225 throw new Error("unsupported curve name for JWT: " + name); 2226 var xy = keyObj.getPublicKeyXYHex(); 2227 jwk.kty = "EC"; 2228 jwk.crv = name; 2229 jwk.x = hextob64u(xy.x); 2230 jwk.y = hextob64u(xy.y); 2231 } 2232 if (jwk.kty == undefined) throw new Error("unsupported keyinfo"); 2233 2234 if ((! keyObj.isPrivate) && nokid != true) { 2235 jwk.kid = KJUR.jws.JWS.getJWKthumbprint(jwk); 2236 } 2237 2238 if (hCert != undefined && nox5c != true) { 2239 jwk.x5c = [hex2b64(hCert)]; 2240 } 2241 2242 if (hCert != undefined && nox5t != true) { 2243 jwk.x5t = b64tob64u(hex2b64(_hashHex(hCert, "sha1"))); 2244 } 2245 2246 if (hCert != undefined && nox5t2 != true) { 2247 jwk["x5t#S256"] = b64tob64u(hex2b64(_hashHex(hCert, "sha256"))); 2248 } 2249 2250 return jwk; 2251 }; 2252 2253 /** 2254 * convert from RSAKey/KJUR.crypto.ECDSA public/private key object to RFC 7517 JSON Web Key(JWK) (DEPRECATED)<br/> 2255 * @name getJWKFromKey 2256 * @memberOf KEYUTIL 2257 * @function 2258 * @static 2259 * @param {Object} RSAKey/KJUR.crypto.ECDSA public/private key object 2260 * @return {Object} JWK object 2261 * @since keyutil 1.0.13 jsrsasign 5.0.14 2262 * @deprecated since jsrsasign 10.5.1 keyutil 1.2.5 please use getJWK method 2263 * @see KEYUTIL.getJWK 2264 * 2265 * @description 2266 * This static method convert from RSAKey/KJUR.crypto.ECDSA public/private key object 2267 * to RFC 7517 JSON Web Key(JWK) 2268 * 2269 * @example 2270 * kp1 = KEYUTIL.generateKeypair("EC", "P-256"); 2271 * jwkPrv1 = KEYUTIL.getJWKFromKey(kp1.prvKeyObj); 2272 * jwkPub1 = KEYUTIL.getJWKFromKey(kp1.pubKeyObj); 2273 * 2274 * kp2 = KEYUTIL.generateKeypair("RSA", 2048); 2275 * jwkPrv2 = KEYUTIL.getJWKFromKey(kp2.prvKeyObj); 2276 * jwkPub2 = KEYUTIL.getJWKFromKey(kp2.pubKeyObj); 2277 * 2278 * // if you need RFC 7638 JWK thumprint as kid do like this: 2279 * jwkPub2.kid = KJUR.jws.JWS.getJWKthumbprint(jwkPub2); 2280 */ 2281 KEYUTIL.getJWKFromKey = function(keyObj) { 2282 return KEYUTIL.getJWK(keyObj, true, true, true, true); 2283 } 2284