1 /* keyutil-1.2.7.js (c) 2013-2022 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-2022 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.5.16 keyutil 1.2.7 (2022-Apr-08) 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 // === PKCS8 =============================================================== 396 397 /** 398 * generate PBKDF2 key hexstring with specified passcode and information 399 * @name parseHexOfEncryptedPKCS8 400 * @memberOf KEYUTIL 401 * @function 402 * @param {String} passcode passcode to decrypto private key 403 * @return {Array} info associative array of PKCS#8 parameters 404 * @since pkcs5pkey 1.0.3 405 * @description 406 * The associative array which is returned by this method has following properties: 407 * <ul> 408 * <li>info.pbkdf2Salt - hexadecimal string of PBKDF2 salt</li> 409 * <li>info.pkbdf2Iter - iteration count</li> 410 * <li>info.ciphertext - hexadecimal string of encrypted private key</li> 411 * <li>info.encryptionSchemeAlg - encryption algorithm name (currently TripleDES only)</li> 412 * <li>info.encryptionSchemeIV - initial vector for encryption algorithm</li> 413 * </ul> 414 * Currently, this method only supports PKCS#5v2.0 with PBES2/PBDKF2 of HmacSHA1 and TripleDES. 415 * <ul> 416 * <li>keyDerivationFunc = pkcs5PBKDF2 with HmacSHA1</li> 417 * <li>encryptionScheme = des-EDE3-CBC(i.e. TripleDES</li> 418 * </ul> 419 * @example 420 * // to convert plain PKCS#5 private key to encrypted PKCS#8 private 421 * // key with PBKDF2 with TripleDES 422 * % openssl pkcs8 -in plain_p5.pem -topk8 -v2 -des3 -out encrypted_p8.pem 423 */ 424 parseHexOfEncryptedPKCS8: function(sHEX) { 425 var _ASN1HEX = ASN1HEX; 426 var _getChildIdx = _ASN1HEX.getChildIdx; 427 var _getV = _ASN1HEX.getV; 428 var info = {}; 429 430 var a0 = _getChildIdx(sHEX, 0); 431 if (a0.length != 2) 432 throw new Error("malformed format: SEQUENCE(0).items != 2: " + 433 a0.length); 434 435 // 1. ciphertext 436 info.ciphertext = _getV(sHEX, a0[1]); 437 438 // 2. pkcs5PBES2 439 var a0_0 = _getChildIdx(sHEX, a0[0]); 440 if (a0_0.length != 2) 441 throw new Error("malformed format: SEQUENCE(0.0).items != 2: " 442 + a0_0.length); 443 444 // 2.1 check if pkcs5PBES2(1 2 840 113549 1 5 13) 445 if (_getV(sHEX, a0_0[0]) != "2a864886f70d01050d") 446 throw new Error("this only supports pkcs5PBES2"); 447 448 // 2.2 pkcs5PBES2 param 449 var a0_0_1 = _getChildIdx(sHEX, a0_0[1]); 450 if (a0_0.length != 2) 451 throw new Error("malformed format: SEQUENCE(0.0.1).items != 2: " 452 + a0_0_1.length); 453 454 // 2.2.1 encryptionScheme 455 var a0_0_1_1 = _getChildIdx(sHEX, a0_0_1[1]); 456 if (a0_0_1_1.length != 2) 457 throw new Error("malformed format: " + 458 "SEQUENCE(0.0.1.1).items != 2: " + 459 a0_0_1_1.length); 460 if (_getV(sHEX, a0_0_1_1[0]) != "2a864886f70d0307") 461 throw "this only supports TripleDES"; 462 info.encryptionSchemeAlg = "TripleDES"; 463 464 // 2.2.1.1 IV of encryptionScheme 465 info.encryptionSchemeIV = _getV(sHEX, a0_0_1_1[1]); 466 467 // 2.2.2 keyDerivationFunc 468 var a0_0_1_0 = _getChildIdx(sHEX, a0_0_1[0]); 469 if (a0_0_1_0.length != 2) 470 throw new Error("malformed format: " + 471 "SEQUENCE(0.0.1.0).items != 2: " 472 + a0_0_1_0.length); 473 if (_getV(sHEX, a0_0_1_0[0]) != "2a864886f70d01050c") 474 throw new Error("this only supports pkcs5PBKDF2"); 475 476 // 2.2.2.1 pkcs5PBKDF2 param 477 var a0_0_1_0_1 = _getChildIdx(sHEX, a0_0_1_0[1]); 478 if (a0_0_1_0_1.length < 2) 479 throw new Error("malformed format: " + 480 "SEQUENCE(0.0.1.0.1).items < 2: " + 481 a0_0_1_0_1.length); 482 483 // 2.2.2.1.1 PBKDF2 salt 484 info.pbkdf2Salt = _getV(sHEX, a0_0_1_0_1[0]); 485 486 // 2.2.2.1.2 PBKDF2 iter 487 var iterNumHex = _getV(sHEX, a0_0_1_0_1[1]); 488 try { 489 info.pbkdf2Iter = parseInt(iterNumHex, 16); 490 } catch(ex) { 491 throw new Error("malformed format pbkdf2Iter: " + iterNumHex); 492 } 493 494 return info; 495 }, 496 497 /** 498 * generate PBKDF2 key hexstring with specified passcode and information 499 * @name getPBKDF2KeyHexFromParam 500 * @memberOf KEYUTIL 501 * @function 502 * @param {Array} info result of {@link parseHexOfEncryptedPKCS8} which has preference of PKCS#8 file 503 * @param {String} passcode passcode to decrypto private key 504 * @return {String} hexadecimal string of PBKDF2 key 505 * @since pkcs5pkey 1.0.3 506 * @description 507 * As for info, this uses following properties: 508 * <ul> 509 * <li>info.pbkdf2Salt - hexadecimal string of PBKDF2 salt</li> 510 * <li>info.pkbdf2Iter - iteration count</li> 511 * </ul> 512 * Currently, this method only supports PKCS#5v2.0 with PBES2/PBDKF2 of HmacSHA1 and TripleDES. 513 * <ul> 514 * <li>keyDerivationFunc = pkcs5PBKDF2 with HmacSHA1</li> 515 * <li>encryptionScheme = des-EDE3-CBC(i.e. TripleDES</li> 516 * </ul> 517 * @example 518 * // to convert plain PKCS#5 private key to encrypted PKCS#8 private 519 * // key with PBKDF2 with TripleDES 520 * % openssl pkcs8 -in plain_p5.pem -topk8 -v2 -des3 -out encrypted_p8.pem 521 */ 522 getPBKDF2KeyHexFromParam: function(info, passcode) { 523 var pbkdf2SaltWS = CryptoJS.enc.Hex.parse(info.pbkdf2Salt); 524 var pbkdf2Iter = info.pbkdf2Iter; 525 var pbkdf2KeyWS = CryptoJS.PBKDF2(passcode, 526 pbkdf2SaltWS, 527 { keySize: 192/32, iterations: pbkdf2Iter }); 528 var pbkdf2KeyHex = CryptoJS.enc.Hex.stringify(pbkdf2KeyWS); 529 return pbkdf2KeyHex; 530 }, 531 532 /* 533 * read PEM formatted encrypted PKCS#8 private key and returns hexadecimal string of plain PKCS#8 private key 534 * @name getPlainPKCS8HexFromEncryptedPKCS8PEM 535 * @memberOf KEYUTIL 536 * @function 537 * @param {String} pkcs8PEM PEM formatted encrypted PKCS#8 private key 538 * @param {String} passcode passcode to decrypto private key 539 * @return {String} hexadecimal string of plain PKCS#8 private key 540 * @since pkcs5pkey 1.0.3 541 * @description 542 * Currently, this method only supports PKCS#5v2.0 with PBES2/PBDKF2 of HmacSHA1 and TripleDES. 543 * <ul> 544 * <li>keyDerivationFunc = pkcs5PBKDF2 with HmacSHA1</li> 545 * <li>encryptionScheme = des-EDE3-CBC(i.e. TripleDES</li> 546 * </ul> 547 * @example 548 * // to convert plain PKCS#5 private key to encrypted PKCS#8 private 549 * // key with PBKDF2 with TripleDES 550 * % openssl pkcs8 -in plain_p5.pem -topk8 -v2 -des3 -out encrypted_p8.pem 551 */ 552 _getPlainPKCS8HexFromEncryptedPKCS8PEM: function(pkcs8PEM, passcode) { 553 // 1. derHex - PKCS#8 private key encrypted by PBKDF2 554 var derHex = pemtohex(pkcs8PEM, "ENCRYPTED PRIVATE KEY"); 555 // 2. info - PKCS#5 PBES info 556 var info = this.parseHexOfEncryptedPKCS8(derHex); 557 // 3. hKey - PBKDF2 key 558 var pbkdf2KeyHex = KEYUTIL.getPBKDF2KeyHexFromParam(info, passcode); 559 // 4. decrypt ciphertext by PBKDF2 key 560 var encrypted = {}; 561 encrypted.ciphertext = CryptoJS.enc.Hex.parse(info.ciphertext); 562 var pbkdf2KeyWS = CryptoJS.enc.Hex.parse(pbkdf2KeyHex); 563 var des3IVWS = CryptoJS.enc.Hex.parse(info.encryptionSchemeIV); 564 var decWS = CryptoJS.TripleDES.decrypt(encrypted, pbkdf2KeyWS, { iv: des3IVWS }); 565 var decHex = CryptoJS.enc.Hex.stringify(decWS); 566 return decHex; 567 }, 568 569 /** 570 * get RSAKey/ECDSA private key object from encrypted PEM PKCS#8 private key 571 * @name getKeyFromEncryptedPKCS8PEM 572 * @memberOf KEYUTIL 573 * @function 574 * @param {String} pkcs8PEM string of PEM formatted PKCS#8 private key 575 * @param {String} passcode passcode string to decrypt key 576 * @return {Object} RSAKey or KJUR.crypto.ECDSA private key object 577 * @since pkcs5pkey 1.0.5 578 */ 579 getKeyFromEncryptedPKCS8PEM: function(pkcs8PEM, passcode) { 580 var prvKeyHex = this._getPlainPKCS8HexFromEncryptedPKCS8PEM(pkcs8PEM, passcode); 581 var key = this.getKeyFromPlainPrivatePKCS8Hex(prvKeyHex); 582 return key; 583 }, 584 585 /** 586 * parse hexadecimal string of plain PKCS#8 private key 587 * @name parsePlainPrivatePKCS8Hex 588 * @memberOf KEYUTIL 589 * @function 590 * @param {String} pkcs8PrvHex hexadecimal string of PKCS#8 plain private key 591 * @return {Array} associative array of parsed key 592 * @since pkcs5pkey 1.0.5 593 * @description 594 * Resulted associative array has following properties: 595 * <ul> 596 * <li>algoid - hexadecimal string of OID of asymmetric key algorithm</li> 597 * <li>algparam - hexadecimal string of OID of ECC curve name or null</li> 598 * <li>keyidx - string starting index of key in pkcs8PrvHex</li> 599 * </ul> 600 */ 601 parsePlainPrivatePKCS8Hex: function(pkcs8PrvHex) { 602 var _ASN1HEX = ASN1HEX; 603 var _getChildIdx = _ASN1HEX.getChildIdx; 604 var _getV = _ASN1HEX.getV; 605 var result = {}; 606 result.algparam = null; 607 608 // 1. sequence 609 if (pkcs8PrvHex.substr(0, 2) != "30") 610 throw new Error("malformed plain PKCS8 private key(code:001)"); 611 // not sequence 612 613 var a1 = _getChildIdx(pkcs8PrvHex, 0); 614 if (a1.length < 3) 615 throw new Error("malformed plain PKCS8 private key(code:002)"); 616 // less elements 617 618 // 2. AlgID 619 if (pkcs8PrvHex.substr(a1[1], 2) != "30") 620 throw new Error("malformed PKCS8 private key(code:003)"); 621 // AlgId not sequence 622 623 var a2 = _getChildIdx(pkcs8PrvHex, a1[1]); 624 if (a2.length != 2) 625 throw new Error("malformed PKCS8 private key(code:004)"); 626 // AlgId not have two elements 627 628 // 2.1. AlgID OID 629 if (pkcs8PrvHex.substr(a2[0], 2) != "06") 630 throw new Error("malformed PKCS8 private key(code:005)"); 631 // AlgId.oid is not OID 632 633 result.algoid = _getV(pkcs8PrvHex, a2[0]); 634 635 // 2.2. AlgID param 636 if (pkcs8PrvHex.substr(a2[1], 2) == "06") { 637 result.algparam = _getV(pkcs8PrvHex, a2[1]); 638 } 639 640 // 3. Key index 641 if (pkcs8PrvHex.substr(a1[2], 2) != "04") 642 throw new Error("malformed PKCS8 private key(code:006)"); 643 // not octet string 644 645 result.keyidx = _ASN1HEX.getVidx(pkcs8PrvHex, a1[2]); 646 647 return result; 648 }, 649 650 /** 651 * get RSAKey/ECDSA private key object from PEM plain PEM PKCS#8 private key 652 * @name getKeyFromPlainPrivatePKCS8PEM 653 * @memberOf KEYUTIL 654 * @function 655 * @param {String} pkcs8PEM string of plain PEM formatted PKCS#8 private key 656 * @return {Object} RSAKey or KJUR.crypto.ECDSA private key object 657 * @since pkcs5pkey 1.0.5 658 */ 659 getKeyFromPlainPrivatePKCS8PEM: function(prvKeyPEM) { 660 var prvKeyHex = pemtohex(prvKeyPEM, "PRIVATE KEY"); 661 var key = this.getKeyFromPlainPrivatePKCS8Hex(prvKeyHex); 662 return key; 663 }, 664 665 /** 666 * get RSAKey/DSA/ECDSA private key object from HEX plain PEM PKCS#8 private key 667 * @name getKeyFromPlainPrivatePKCS8Hex 668 * @memberOf KEYUTIL 669 * @function 670 * @param {String} prvKeyHex hexadecimal string of plain PKCS#8 private key 671 * @return {Object} RSAKey or KJUR.crypto.{DSA,ECDSA} private key object 672 * @since pkcs5pkey 1.0.5 673 */ 674 getKeyFromPlainPrivatePKCS8Hex: function(prvKeyHex) { 675 var p8 = this.parsePlainPrivatePKCS8Hex(prvKeyHex); 676 var key; 677 678 if (p8.algoid == "2a864886f70d010101") { // RSA 679 key = new RSAKey(); 680 } else if (p8.algoid == "2a8648ce380401") { // DSA 681 key = new KJUR.crypto.DSA(); 682 } else if (p8.algoid == "2a8648ce3d0201") { // ECC 683 key = new KJUR.crypto.ECDSA(); 684 } else { 685 throw new Error("unsupported private key algorithm"); 686 } 687 688 key.readPKCS8PrvKeyHex(prvKeyHex); 689 return key; 690 }, 691 692 // === PKCS8 RSA Public Key ================================================ 693 694 /* 695 * get RSAKey/DSA/ECDSA public key object from hexadecimal string of PKCS#8 public key 696 * @name _getKeyFromPublicPKCS8Hex 697 * @memberOf KEYUTIL 698 * @function 699 * @param {String} pkcsPub8Hex hexadecimal string of PKCS#8 public key 700 * @return {Object} RSAKey or KJUR.crypto.{ECDSA,DSA} private key object 701 * @since pkcs5pkey 1.0.5 702 */ 703 _getKeyFromPublicPKCS8Hex: function(h) { 704 var key; 705 var hOID = ASN1HEX.getVbyList(h, 0, [0, 0], "06"); 706 707 if (hOID === "2a864886f70d010101") { // oid=RSA 708 key = new RSAKey(); 709 } else if (hOID === "2a8648ce380401") { // oid=DSA 710 key = new KJUR.crypto.DSA(); 711 } else if (hOID === "2a8648ce3d0201") { // oid=ECPUB 712 key = new KJUR.crypto.ECDSA(); 713 } else { 714 throw new Error("unsupported PKCS#8 public key hex"); 715 } 716 key.readPKCS8PubKeyHex(h); 717 return key; 718 }, 719 720 /** 721 * parse hexadecimal string of plain PKCS#8 private key 722 * @name parsePublicRawRSAKeyHex 723 * @memberOf KEYUTIL 724 * @function 725 * @param {String} pubRawRSAHex hexadecimal string of ASN.1 encoded PKCS#8 public key 726 * @return {Array} associative array of parsed key 727 * @since pkcs5pkey 1.0.5 728 * @description 729 * Resulted associative array has following properties: 730 * <ul> 731 * <li>n - hexadecimal string of public key 732 * <li>e - hexadecimal string of public exponent 733 * </ul> 734 */ 735 parsePublicRawRSAKeyHex: function(pubRawRSAHex) { 736 var _ASN1HEX = ASN1HEX; 737 var _getChildIdx = _ASN1HEX.getChildIdx; 738 var _getV = _ASN1HEX.getV; 739 var result = {}; 740 741 // 1. Sequence 742 if (pubRawRSAHex.substr(0, 2) != "30") 743 throw new Error("malformed RSA key(code:001)"); // not sequence 744 745 var a1 = _getChildIdx(pubRawRSAHex, 0); 746 if (a1.length != 2) 747 throw new Error("malformed RSA key(code:002)"); // not 2 items in seq 748 749 // 2. public key "N" 750 if (pubRawRSAHex.substr(a1[0], 2) != "02") 751 throw new Error("malformed RSA key(code:003)"); // 1st item is not integer 752 753 result.n = _getV(pubRawRSAHex, a1[0]); 754 755 // 3. public key "E" 756 if (pubRawRSAHex.substr(a1[1], 2) != "02") 757 throw new Error("malformed RSA key(code:004)"); // 2nd item is not integer 758 759 result.e = _getV(pubRawRSAHex, a1[1]); 760 761 return result; 762 }, 763 764 /** 765 * parse hexadecimal string of PKCS#8 RSA/EC/DSA public key 766 * @name parsePublicPKCS8Hex 767 * @memberOf KEYUTIL 768 * @function 769 * @param {String} pkcs8PubHex hexadecimal string of PKCS#8 public key 770 * @return {Hash} hash of key information 771 * @description 772 * Resulted hash has following attributes. 773 * <ul> 774 * <li>algoid - hexadecimal string of OID of asymmetric key algorithm</li> 775 * <li>algparam - hexadecimal string of OID of ECC curve name, parameter SEQUENCE of DSA or null</li> 776 * <li>key - hexadecimal string of public key</li> 777 * </ul> 778 */ 779 parsePublicPKCS8Hex: function(pkcs8PubHex) { 780 var _ASN1HEX = ASN1HEX; 781 var _getChildIdx = _ASN1HEX.getChildIdx; 782 var _getV = _ASN1HEX.getV; 783 var result = {}; 784 result.algparam = null; 785 786 // 1. AlgID and Key bit string 787 var a1 = _getChildIdx(pkcs8PubHex, 0); 788 if (a1.length != 2) 789 throw new Error("outer DERSequence shall have 2 elements: " + a1.length); 790 791 // 2. AlgID 792 var idxAlgIdTLV = a1[0]; 793 if (pkcs8PubHex.substr(idxAlgIdTLV, 2) != "30") 794 throw new Error("malformed PKCS8 public key(code:001)"); // AlgId not sequence 795 796 var a2 = _getChildIdx(pkcs8PubHex, idxAlgIdTLV); 797 if (a2.length != 2) 798 throw new Error("malformed PKCS8 public key(code:002)"); // AlgId not have two elements 799 800 // 2.1. AlgID OID 801 if (pkcs8PubHex.substr(a2[0], 2) != "06") 802 throw new Error("malformed PKCS8 public key(code:003)"); // AlgId.oid is not OID 803 804 result.algoid = _getV(pkcs8PubHex, a2[0]); 805 806 // 2.2. AlgID param 807 if (pkcs8PubHex.substr(a2[1], 2) == "06") { // OID for EC 808 result.algparam = _getV(pkcs8PubHex, a2[1]); 809 } else if (pkcs8PubHex.substr(a2[1], 2) == "30") { // SEQ for DSA 810 result.algparam = {}; 811 result.algparam.p = _ASN1HEX.getVbyList(pkcs8PubHex, a2[1], [0], "02"); 812 result.algparam.q = _ASN1HEX.getVbyList(pkcs8PubHex, a2[1], [1], "02"); 813 result.algparam.g = _ASN1HEX.getVbyList(pkcs8PubHex, a2[1], [2], "02"); 814 } 815 816 // 3. Key 817 if (pkcs8PubHex.substr(a1[1], 2) != "03") 818 throw new Error("malformed PKCS8 public key(code:004)"); // Key is not bit string 819 820 result.key = _getV(pkcs8PubHex, a1[1]).substr(2); 821 822 // 4. return result assoc array 823 return result; 824 }, 825 }; 826 }(); 827 828 // -- MAJOR PUBLIC METHODS ---------------------------------------------------- 829 /** 830 * get private or public key object from any arguments 831 * @name getKey 832 * @memberOf KEYUTIL 833 * @function 834 * @static 835 * @param {Object} param parameter to get key object. see description in detail. 836 * @param {String} passcode (OPTION) parameter to get key object. see description in detail. 837 * @param {String} hextype (OPTOIN) parameter to get key object. see description in detail. 838 * @return {Object} {@link RSAKey}, {@link KJUR.crypto.ECDSA} or {@link KJUR.crypto.ECDSA} object 839 * @since keyutil 1.0.0 840 * @description 841 * This method gets private or public key object({@link RSAKey}, {@link KJUR.crypto.DSA} or {@link KJUR.crypto.ECDSA}) 842 * for RSA, DSA and ECC. 843 * Arguments for this methods depends on a key format you specify. 844 * Following key representations are supported. 845 * <ul> 846 * <li>ECC private/public key object(as is): param=KJUR.crypto.ECDSA</li> 847 * <li>DSA private/public key object(as is): param=KJUR.crypto.DSA</li> 848 * <li>RSA private/public key object(as is): param=RSAKey </li> 849 * <li>ECC private key parameters: param={d: d, curve: curveName}</li> 850 * <li>RSA private key parameters: param={n: n, e: e, d: d, p: p, q: q, dp: dp, dq: dq, co: co}<br/> 851 * NOTE: Each value shall be hexadecimal string of key spec.</li> 852 * <li>DSA private key parameters: param={p: p, q: q, g: g, y: y, x: x}<br/> 853 * NOTE: Each value shall be hexadecimal string of key spec.</li> 854 * <li>ECC public key parameters: param={xy: xy, curve: curveName}<br/> 855 * NOTE: ECC public key 'xy' shall be concatination of "04", x-bytes-hex and y-bytes-hex.</li> 856 * <li>DSA public key parameters: param={p: p, q: q, g: g, y: y}<br/> 857 * NOTE: Each value shall be hexadecimal string of key spec.</li> 858 * <li>RSA public key parameters: param={n: n, e: e} </li> 859 * <li>X.509v1/v3 PEM certificate (RSA/DSA/ECC): param=pemString</li> 860 * <li>PKCS#8 hexadecimal RSA/ECC public key: param=pemString, null, "pkcs8pub"</li> 861 * <li>PKCS#8 PEM RSA/DSA/ECC public key: param=pemString</li> 862 * <li>PKCS#5 plain hexadecimal RSA private key: param=hexString, null, "pkcs5prv"</li> 863 * <li>PKCS#5 plain PEM RSA/DSA/EC private key: param=pemString</li> 864 * <li>PKCS#8 plain PEM RSA/EC private key: param=pemString</li> 865 * <li>PKCS#5 encrypted PEM RSA/DSA/EC private key: param=pemString, passcode</li> 866 * <li>PKCS#8 encrypted PEM RSA/EC private key: param=pemString, passcode</li> 867 * </ul> 868 * Please note following limitation on encrypted keys: 869 * <ul> 870 * <li>Encrypted PKCS#8 only supports PBKDF2/HmacSHA1/3DES</li> 871 * <li>Encrypted PKCS#5 supports DES-CBC, DES-EDE3-CBC, AES-{128,192.256}-CBC</li> 872 * <li>JWT plain ECC private/public key</li> 873 * <li>JWT plain RSA public key</li> 874 * <li>JWT plain RSA private key with P/Q/DP/DQ/COEFF</li> 875 * <li>JWT plain RSA private key without P/Q/DP/DQ/COEFF (since jsrsasign 5.0.0)</li> 876 * </ul> 877 * 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/> 878 * NOTE2: X509v1 support is added since jsrsasign 5.0.11. 879 * 880 * <h5>EXAMPLE</h5> 881 * @example 882 * // 1. loading private key from PEM string 883 * keyObj = KEYUTIL.getKey("-----BEGIN RSA PRIVATE KEY..."); 884 * keyObj = KEYUTIL.getKey("-----BEGIN RSA PRIVATE KEY..., "passcode"); 885 * keyObj = KEYUTIL.getKey("-----BEGIN PRIVATE KEY..."); 886 * keyObj = KEYUTIL.getKey("-----BEGIN PRIVATE KEY...", "passcode"); 887 * keyObj = KEYUTIL.getKey("-----BEGIN EC PARAMETERS...-----BEGIN EC PRIVATE KEY..."); 888 * // 2. loading public key from PEM string 889 * keyObj = KEYUTIL.getKey("-----BEGIN PUBLIC KEY..."); 890 * keyObj = KEYUTIL.getKey("-----BEGIN X509 CERTIFICATE..."); 891 * // 3. loading hexadecimal PKCS#5/PKCS#8 key 892 * keyObj = KEYUTIL.getKey("308205c1...", null, "pkcs8pub"); 893 * keyObj = KEYUTIL.getKey("3082048b...", null, "pkcs5prv"); 894 * // 4. loading JSON Web Key(JWK) 895 * keyObj = KEYUTIL.getKey({kty: "RSA", n: "0vx7...", e: "AQAB"}); 896 * keyObj = KEYUTIL.getKey({kty: "EC", crv: "P-256", 897 * x: "MKBC...", y: "4Etl6...", d: "870Mb..."}); 898 * // 5. bare hexadecimal key 899 * keyObj = KEYUTIL.getKey({n: "75ab..", e: "010001"}); 900 */ 901 KEYUTIL.getKey = function(param, passcode, hextype) { 902 var _ASN1HEX = ASN1HEX, 903 _getChildIdx = _ASN1HEX.getChildIdx, 904 _getV = _ASN1HEX.getV, 905 _getVbyList = _ASN1HEX.getVbyList, 906 _KJUR_crypto = KJUR.crypto, 907 _KJUR_crypto_ECDSA = _KJUR_crypto.ECDSA, 908 _KJUR_crypto_DSA = _KJUR_crypto.DSA, 909 _RSAKey = RSAKey, 910 _pemtohex = pemtohex, 911 _KEYUTIL = KEYUTIL; 912 913 // 1. by key RSAKey/KJUR.crypto.ECDSA/KJUR.crypto.DSA object 914 if (typeof _RSAKey != 'undefined' && param instanceof _RSAKey) 915 return param; 916 if (typeof _KJUR_crypto_ECDSA != 'undefined' && param instanceof _KJUR_crypto_ECDSA) 917 return param; 918 if (typeof _KJUR_crypto_DSA != 'undefined' && param instanceof _KJUR_crypto_DSA) 919 return param; 920 921 // 2. by parameters of key 922 923 // 2.1. bare ECC 924 // 2.1.1. bare ECC public key by hex values 925 if (param.curve !== undefined && 926 param.xy !== undefined && param.d === undefined) { 927 return new _KJUR_crypto_ECDSA({pub: param.xy, curve: param.curve}); 928 } 929 930 // 2.1.2. bare ECC private key by hex values 931 if (param.curve !== undefined && param.d !== undefined) { 932 return new _KJUR_crypto_ECDSA({prv: param.d, curve: param.curve}); 933 } 934 935 // 2.2. bare RSA 936 // 2.2.1. bare RSA public key by hex values 937 if (param.kty === undefined && 938 param.n !== undefined && param.e !== undefined && 939 param.d === undefined) { 940 var key = new _RSAKey(); 941 key.setPublic(param.n, param.e); 942 return key; 943 } 944 945 // 2.2.2. bare RSA private key with P/Q/DP/DQ/COEFF by hex values 946 if (param.kty === undefined && 947 param.n !== undefined && 948 param.e !== undefined && 949 param.d !== undefined && 950 param.p !== undefined && 951 param.q !== undefined && 952 param.dp !== undefined && 953 param.dq !== undefined && 954 param.co !== undefined && 955 param.qi === undefined) { 956 var key = new _RSAKey(); 957 key.setPrivateEx(param.n, param.e, param.d, param.p, param.q, 958 param.dp, param.dq, param.co); 959 return key; 960 } 961 962 // 2.2.3. bare RSA public key without P/Q/DP/DQ/COEFF by hex values 963 if (param.kty === undefined && 964 param.n !== undefined && 965 param.e !== undefined && 966 param.d !== undefined && 967 param.p === undefined) { 968 var key = new _RSAKey(); 969 key.setPrivate(param.n, param.e, param.d); 970 return key; 971 } 972 973 // 2.3. bare DSA 974 // 2.3.1. bare DSA public key by hex values 975 if (param.p !== undefined && param.q !== undefined && 976 param.g !== undefined && 977 param.y !== undefined && param.x === undefined) { 978 var key = new _KJUR_crypto_DSA(); 979 key.setPublic(param.p, param.q, param.g, param.y); 980 return key; 981 } 982 983 // 2.3.2. bare DSA private key by hex values 984 if (param.p !== undefined && param.q !== undefined && 985 param.g !== undefined && 986 param.y !== undefined && param.x !== undefined) { 987 var key = new _KJUR_crypto_DSA(); 988 key.setPrivate(param.p, param.q, param.g, param.y, param.x); 989 return key; 990 } 991 992 // 3. JWK 993 // 3.1. JWK RSA 994 // 3.1.1. JWK RSA public key by b64u values 995 if (param.kty === "RSA" && 996 param.n !== undefined && 997 param.e !== undefined && 998 param.d === undefined) { 999 var key = new _RSAKey(); 1000 key.setPublic(b64utohex(param.n), b64utohex(param.e)); 1001 return key; 1002 } 1003 1004 // 3.1.2. JWK RSA private key with p/q/dp/dq/coeff by b64u values 1005 if (param.kty === "RSA" && 1006 param.n !== undefined && 1007 param.e !== undefined && 1008 param.d !== undefined && 1009 param.p !== undefined && 1010 param.q !== undefined && 1011 param.dp !== undefined && 1012 param.dq !== undefined && 1013 param.qi !== undefined) { 1014 var key = new _RSAKey(); 1015 key.setPrivateEx(b64utohex(param.n), 1016 b64utohex(param.e), 1017 b64utohex(param.d), 1018 b64utohex(param.p), 1019 b64utohex(param.q), 1020 b64utohex(param.dp), 1021 b64utohex(param.dq), 1022 b64utohex(param.qi)); 1023 return key; 1024 } 1025 1026 // 3.1.3. JWK RSA private key without p/q/dp/dq/coeff by b64u 1027 // since jsrsasign 5.0.0 keyutil 1.0.11 1028 if (param.kty === "RSA" && 1029 param.n !== undefined && 1030 param.e !== undefined && 1031 param.d !== undefined) { 1032 var key = new _RSAKey(); 1033 key.setPrivate(b64utohex(param.n), 1034 b64utohex(param.e), 1035 b64utohex(param.d)); 1036 return key; 1037 } 1038 1039 // 3.2. JWK ECC 1040 // 3.2.1. JWK ECC public key by b64u values 1041 if (param.kty === "EC" && 1042 param.crv !== undefined && 1043 param.x !== undefined && 1044 param.y !== undefined && 1045 param.d === undefined) { 1046 var ec = new _KJUR_crypto_ECDSA({"curve": param.crv}); 1047 var charlen = ec.ecparams.keycharlen; 1048 var hX = ("0000000000" + b64utohex(param.x)).slice(- charlen); 1049 var hY = ("0000000000" + b64utohex(param.y)).slice(- charlen); 1050 var hPub = "04" + hX + hY; 1051 ec.setPublicKeyHex(hPub); 1052 return ec; 1053 } 1054 1055 // 3.2.2. JWK ECC private key by b64u values 1056 if (param.kty === "EC" && 1057 param.crv !== undefined && 1058 param.x !== undefined && 1059 param.y !== undefined && 1060 param.d !== undefined) { 1061 var ec = new _KJUR_crypto_ECDSA({"curve": param.crv}); 1062 var charlen = ec.ecparams.keycharlen; 1063 var hX = ("0000000000" + b64utohex(param.x)).slice(- charlen); 1064 var hY = ("0000000000" + b64utohex(param.y)).slice(- charlen); 1065 var hPub = "04" + hX + hY; 1066 var hPrv = ("0000000000" + b64utohex(param.d)).slice(- charlen); 1067 ec.setPublicKeyHex(hPub); 1068 ec.setPrivateKeyHex(hPrv); 1069 return ec; 1070 } 1071 1072 // 4. (plain) hexadecimal data 1073 // 4.1. get private key by PKCS#5 plain RSA/DSA/ECDSA hexadecimal string 1074 if (hextype === "pkcs5prv") { 1075 var h = param, _ASN1HEX = ASN1HEX, a, key; 1076 a = _getChildIdx(h, 0); 1077 if (a.length === 9) { // RSA (INT x 9) 1078 key = new _RSAKey(); 1079 key.readPKCS5PrvKeyHex(h); 1080 } else if (a.length === 6) { // DSA (INT x 6) 1081 key = new _KJUR_crypto_DSA(); 1082 key.readPKCS5PrvKeyHex(h); 1083 } else if (a.length > 2 && // ECDSA (INT, OCT prv, [0] curve, [1] pub) 1084 h.substr(a[1], 2) === "04") { 1085 key = new _KJUR_crypto_ECDSA(); 1086 key.readPKCS5PrvKeyHex(h); 1087 } else { 1088 throw new Error("unsupported PKCS#1/5 hexadecimal key"); 1089 } 1090 1091 return key; 1092 } 1093 1094 // 4.2. get private key by PKCS#8 plain RSA/DSA/ECDSA hexadecimal string 1095 if (hextype === "pkcs8prv") { 1096 var key = _KEYUTIL.getKeyFromPlainPrivatePKCS8Hex(param); 1097 return key; 1098 } 1099 1100 // 4.3. get public key by PKCS#8 RSA/DSA/ECDSA hexadecimal string 1101 if (hextype === "pkcs8pub") { 1102 return _KEYUTIL._getKeyFromPublicPKCS8Hex(param); 1103 } 1104 1105 // 4.4. get public key by X.509 hexadecimal string for RSA/DSA/ECDSA 1106 if (hextype === "x509pub") { 1107 return X509.getPublicKeyFromCertHex(param); 1108 } 1109 1110 // 5. by PEM certificate (-----BEGIN ... CERTIFICATE----) 1111 if (param.indexOf("-END CERTIFICATE-", 0) != -1 || 1112 param.indexOf("-END X509 CERTIFICATE-", 0) != -1 || 1113 param.indexOf("-END TRUSTED CERTIFICATE-", 0) != -1) { 1114 return X509.getPublicKeyFromCertPEM(param); 1115 } 1116 1117 // 6. public key by PKCS#8 PEM string 1118 if (param.indexOf("-END PUBLIC KEY-") != -1) { 1119 var pubKeyHex = pemtohex(param, "PUBLIC KEY"); 1120 return _KEYUTIL._getKeyFromPublicPKCS8Hex(pubKeyHex); 1121 } 1122 1123 // 8.1 private key by plain PKCS#5 PEM RSA string 1124 // getKey("-----BEGIN RSA PRIVATE KEY-...") 1125 if (param.indexOf("-END RSA PRIVATE KEY-") != -1 && 1126 param.indexOf("4,ENCRYPTED") == -1) { 1127 var hex = _pemtohex(param, "RSA PRIVATE KEY"); 1128 return _KEYUTIL.getKey(hex, null, "pkcs5prv"); 1129 } 1130 1131 // 8.2. private key by plain PKCS#5 PEM DSA string 1132 if (param.indexOf("-END DSA PRIVATE KEY-") != -1 && 1133 param.indexOf("4,ENCRYPTED") == -1) { 1134 1135 var hKey = _pemtohex(param, "DSA PRIVATE KEY"); 1136 var p = _getVbyList(hKey, 0, [1], "02"); 1137 var q = _getVbyList(hKey, 0, [2], "02"); 1138 var g = _getVbyList(hKey, 0, [3], "02"); 1139 var y = _getVbyList(hKey, 0, [4], "02"); 1140 var x = _getVbyList(hKey, 0, [5], "02"); 1141 var key = new _KJUR_crypto_DSA(); 1142 key.setPrivate(new BigInteger(p, 16), 1143 new BigInteger(q, 16), 1144 new BigInteger(g, 16), 1145 new BigInteger(y, 16), 1146 new BigInteger(x, 16)); 1147 return key; 1148 } 1149 1150 // 8.3. private key by plain PKCS#5 PEM EC string 1151 if (param.indexOf("-END EC PRIVATE KEY-") != -1 && 1152 param.indexOf("4,ENCRYPTED") == -1) { 1153 var hex = _pemtohex(param, "EC PRIVATE KEY"); 1154 return _KEYUTIL.getKey(hex, null, "pkcs5prv"); 1155 } 1156 1157 // 10. private key by plain PKCS#8 PEM ECC/RSA string 1158 if (param.indexOf("-END PRIVATE KEY-") != -1) { 1159 return _KEYUTIL.getKeyFromPlainPrivatePKCS8PEM(param); 1160 } 1161 1162 // 11.1 private key by encrypted PKCS#5 PEM RSA string 1163 if (param.indexOf("-END RSA PRIVATE KEY-") != -1 && 1164 param.indexOf("4,ENCRYPTED") != -1) { 1165 var hPKey = _KEYUTIL.getDecryptedKeyHex(param, passcode); 1166 var rsaKey = new RSAKey(); 1167 rsaKey.readPKCS5PrvKeyHex(hPKey); 1168 return rsaKey; 1169 } 1170 1171 // 11.2. private key by encrypted PKCS#5 PEM ECDSA string 1172 if (param.indexOf("-END EC PRIVATE KEY-") != -1 && 1173 param.indexOf("4,ENCRYPTED") != -1) { 1174 var hKey = _KEYUTIL.getDecryptedKeyHex(param, passcode); 1175 1176 var key = _getVbyList(hKey, 0, [1], "04"); 1177 var curveNameOidHex = _getVbyList(hKey, 0, [2,0], "06"); 1178 var pubkey = _getVbyList(hKey, 0, [3,0], "03").substr(2); 1179 var curveName = ""; 1180 1181 if (KJUR.crypto.OID.oidhex2name[curveNameOidHex] !== undefined) { 1182 curveName = KJUR.crypto.OID.oidhex2name[curveNameOidHex]; 1183 } else { 1184 throw new Error("undefined OID(hex) in KJUR.crypto.OID: " + 1185 curveNameOidHex); 1186 } 1187 1188 var ec = new _KJUR_crypto_ECDSA({'curve': curveName}); 1189 ec.setPublicKeyHex(pubkey); 1190 ec.setPrivateKeyHex(key); 1191 ec.isPublic = false; 1192 return ec; 1193 } 1194 1195 // 11.3. private key by encrypted PKCS#5 PEM DSA string 1196 if (param.indexOf("-END DSA PRIVATE KEY-") != -1 && 1197 param.indexOf("4,ENCRYPTED") != -1) { 1198 var hKey = _KEYUTIL.getDecryptedKeyHex(param, passcode); 1199 var p = _getVbyList(hKey, 0, [1], "02"); 1200 var q = _getVbyList(hKey, 0, [2], "02"); 1201 var g = _getVbyList(hKey, 0, [3], "02"); 1202 var y = _getVbyList(hKey, 0, [4], "02"); 1203 var x = _getVbyList(hKey, 0, [5], "02"); 1204 var key = new _KJUR_crypto_DSA(); 1205 key.setPrivate(new BigInteger(p, 16), 1206 new BigInteger(q, 16), 1207 new BigInteger(g, 16), 1208 new BigInteger(y, 16), 1209 new BigInteger(x, 16)); 1210 return key; 1211 } 1212 1213 // 11. private key by encrypted PKCS#8 hexadecimal RSA/ECDSA string 1214 if (param.indexOf("-END ENCRYPTED PRIVATE KEY-") != -1) { 1215 return _KEYUTIL.getKeyFromEncryptedPKCS8PEM(param, passcode); 1216 } 1217 1218 throw new Error("not supported argument"); 1219 }; 1220 1221 /** 1222 * @name generateKeypair 1223 * @memberOf KEYUTIL 1224 * @function 1225 * @static 1226 * @param {String} alg 'RSA' or 'EC' 1227 * @param {Object} keylenOrCurve key length for RSA or curve name for EC 1228 * @return {Array} associative array of keypair which has prvKeyObj and pubKeyObj parameters 1229 * @since keyutil 1.0.1 1230 * @description 1231 * This method generates a key pair of public key algorithm. 1232 * The result will be an associative array which has following 1233 * parameters: 1234 * <ul> 1235 * <li>prvKeyObj - RSAKey or ECDSA object of private key</li> 1236 * <li>pubKeyObj - RSAKey or ECDSA object of public key</li> 1237 * </ul> 1238 * NOTE1: As for RSA algoirthm, public exponent has fixed 1239 * value '0x10001'. 1240 * NOTE2: As for EC algorithm, supported names of curve are 1241 * secp256r1, secp256k1, secp384r1 and secp521r1. 1242 * NOTE3: DSA is not supported yet. 1243 * @example 1244 * var rsaKeypair = KEYUTIL.generateKeypair("RSA", 1024); 1245 * var ecKeypair = KEYUTIL.generateKeypair("EC", "secp256r1"); 1246 * 1247 */ 1248 KEYUTIL.generateKeypair = function(alg, keylenOrCurve) { 1249 if (alg == "RSA") { 1250 var keylen = keylenOrCurve; 1251 var prvKey = new RSAKey(); 1252 prvKey.generate(keylen, '10001'); 1253 prvKey.isPrivate = true; 1254 prvKey.isPublic = true; 1255 1256 var pubKey = new RSAKey(); 1257 var hN = prvKey.n.toString(16); 1258 var hE = prvKey.e.toString(16); 1259 pubKey.setPublic(hN, hE); 1260 pubKey.isPrivate = false; 1261 pubKey.isPublic = true; 1262 1263 var result = {}; 1264 result.prvKeyObj = prvKey; 1265 result.pubKeyObj = pubKey; 1266 return result; 1267 } else if (alg == "EC") { 1268 var curve = keylenOrCurve; 1269 var ec = new KJUR.crypto.ECDSA({curve: curve}); 1270 var keypairHex = ec.generateKeyPairHex(); 1271 1272 var prvKey = new KJUR.crypto.ECDSA({curve: curve}); 1273 prvKey.setPublicKeyHex(keypairHex.ecpubhex); 1274 prvKey.setPrivateKeyHex(keypairHex.ecprvhex); 1275 prvKey.isPrivate = true; 1276 prvKey.isPublic = false; 1277 1278 var pubKey = new KJUR.crypto.ECDSA({curve: curve}); 1279 pubKey.setPublicKeyHex(keypairHex.ecpubhex); 1280 pubKey.isPrivate = false; 1281 pubKey.isPublic = true; 1282 1283 var result = {}; 1284 result.prvKeyObj = prvKey; 1285 result.pubKeyObj = pubKey; 1286 return result; 1287 } else { 1288 throw new Error("unknown algorithm: " + alg); 1289 } 1290 }; 1291 1292 /** 1293 * get PEM formatted private or public key file from a RSA/ECDSA/DSA key object 1294 * @name getPEM 1295 * @memberOf KEYUTIL 1296 * @function 1297 * @static 1298 * @param {Object} keyObjOrHex key object {@link RSAKey}, {@link KJUR.crypto.ECDSA} or {@link KJUR.crypto.DSA} to encode to 1299 * @param {String} formatType (OPTION) output format type of "PKCS1PRV", "PKCS5PRV" or "PKCS8PRV" for private key 1300 * @param {String} passwd (OPTION) password to protect private key 1301 * @param {String} encAlg (OPTION) encryption algorithm for PKCS#5. currently supports DES-CBC, DES-EDE3-CBC and AES-{128,192,256}-CBC 1302 * @param {String} hexType (OPTION) type of hex string (ex. pkcs5prv, pkcs8prv) 1303 * @param {String} ivsaltHex hexadecimal string of IV and salt (default generated random IV) 1304 * @since keyutil 1.0.4 1305 * @description 1306 * <dl> 1307 * <dt><b>NOTE1:</b> 1308 * <dd> 1309 * PKCS#5 encrypted private key protection algorithm supports DES-CBC, 1310 * DES-EDE3-CBC and AES-{128,192,256}-CBC 1311 * <dt><b>NOTE2:</b> 1312 * <dd> 1313 * OpenSSL supports 1314 * <dt><b>NOTE3:</b> 1315 * <dd> 1316 * Parameter "ivsaltHex" supported since jsrsasign 8.0.0 keyutil 1.2.0. 1317 * </dl> 1318 * @example 1319 * KEUUTIL.getPEM(publicKey) → generates PEM PKCS#8 public key 1320 * KEUUTIL.getPEM(privateKey) → generates PEM PKCS#8 plain private key by default 1321 * KEUUTIL.getPEM(privateKey, "PKCS1PRV") → generates PEM PKCS#1 plain private key 1322 * KEUUTIL.getPEM(privateKey, "PKCS5PRV", "pass") → generates PEM PKCS#5 encrypted private key 1323 * with DES-EDE3-CBC (DEFAULT) 1324 * KEUUTIL.getPEM(privateKey, "PKCS5PRV", "pass", "DES-CBC") → generates PEM PKCS#5 encrypted 1325 * private key with DES-CBC 1326 * KEUUTIL.getPEM(privateKey, "PKCS8PRV") → generates PEM PKCS#8 plain private key 1327 * KEUUTIL.getPEM(privateKey, "PKCS8PRV", "pass") → generates PEM PKCS#8 encrypted private key 1328 * with PBKDF2_HmacSHA1_3DES 1329 */ 1330 KEYUTIL.getPEM = function(keyObjOrHex, formatType, passwd, encAlg, hexType, ivsaltHex) { 1331 var _KJUR = KJUR, 1332 _KJUR_asn1 = _KJUR.asn1, 1333 _DERObjectIdentifier = _KJUR_asn1.DERObjectIdentifier, 1334 _DERInteger = _KJUR_asn1.DERInteger, 1335 _newObject = _KJUR_asn1.ASN1Util.newObject, 1336 _KJUR_asn1_x509 = _KJUR_asn1.x509, 1337 _SubjectPublicKeyInfo = _KJUR_asn1_x509.SubjectPublicKeyInfo, 1338 _KJUR_crypto = _KJUR.crypto, 1339 _DSA = _KJUR_crypto.DSA, 1340 _ECDSA = _KJUR_crypto.ECDSA, 1341 _RSAKey = RSAKey; 1342 1343 function _rsaprv2asn1obj(keyObjOrHex) { 1344 var asn1Obj = _newObject({ 1345 "seq": [ 1346 {"int": 0 }, 1347 {"int": {"bigint": keyObjOrHex.n}}, 1348 {"int": keyObjOrHex.e}, 1349 {"int": {"bigint": keyObjOrHex.d}}, 1350 {"int": {"bigint": keyObjOrHex.p}}, 1351 {"int": {"bigint": keyObjOrHex.q}}, 1352 {"int": {"bigint": keyObjOrHex.dmp1}}, 1353 {"int": {"bigint": keyObjOrHex.dmq1}}, 1354 {"int": {"bigint": keyObjOrHex.coeff}} 1355 ] 1356 }); 1357 return asn1Obj; 1358 }; 1359 1360 function _ecdsaprv2asn1obj(keyObjOrHex) { 1361 var asn1Obj2 = _newObject({ 1362 "seq": [ 1363 {"int": 1 }, 1364 {"octstr": {"hex": keyObjOrHex.prvKeyHex}}, 1365 {"tag": ['a0', true, {'oid': {'name': keyObjOrHex.curveName}}]}, 1366 {"tag": ['a1', true, {'bitstr': {'hex': '00' + keyObjOrHex.pubKeyHex}}]} 1367 ] 1368 }); 1369 return asn1Obj2; 1370 }; 1371 1372 function _dsaprv2asn1obj(keyObjOrHex) { 1373 var asn1Obj = _newObject({ 1374 "seq": [ 1375 {"int": 0 }, 1376 {"int": {"bigint": keyObjOrHex.p}}, 1377 {"int": {"bigint": keyObjOrHex.q}}, 1378 {"int": {"bigint": keyObjOrHex.g}}, 1379 {"int": {"bigint": keyObjOrHex.y}}, 1380 {"int": {"bigint": keyObjOrHex.x}} 1381 ] 1382 }); 1383 return asn1Obj; 1384 }; 1385 1386 // 1. public key 1387 1388 // x. PEM PKCS#8 public key of RSA/ECDSA/DSA public key object 1389 if (((_RSAKey !== undefined && keyObjOrHex instanceof _RSAKey) || 1390 (_DSA !== undefined && keyObjOrHex instanceof _DSA) || 1391 (_ECDSA !== undefined && keyObjOrHex instanceof _ECDSA)) && 1392 keyObjOrHex.isPublic == true && 1393 (formatType === undefined || formatType == "PKCS8PUB")) { 1394 var asn1Obj = new _SubjectPublicKeyInfo(keyObjOrHex); 1395 var asn1Hex = asn1Obj.tohex(); 1396 return hextopem(asn1Hex, "PUBLIC KEY"); 1397 } 1398 1399 // 2. private 1400 1401 // x. PEM PKCS#1 plain private key of RSA private key object 1402 if (formatType == "PKCS1PRV" && 1403 _RSAKey !== undefined && 1404 keyObjOrHex instanceof _RSAKey && 1405 (passwd === undefined || passwd == null) && 1406 keyObjOrHex.isPrivate == true) { 1407 1408 var asn1Obj = _rsaprv2asn1obj(keyObjOrHex); 1409 var asn1Hex = asn1Obj.tohex(); 1410 return hextopem(asn1Hex, "RSA PRIVATE KEY"); 1411 } 1412 1413 // x. PEM PKCS#1 plain private key of ECDSA private key object 1414 if (formatType == "PKCS1PRV" && 1415 _ECDSA !== undefined && 1416 keyObjOrHex instanceof _ECDSA && 1417 (passwd === undefined || passwd == null) && 1418 keyObjOrHex.isPrivate == true) { 1419 1420 var asn1Obj1 = 1421 new _DERObjectIdentifier({'name': keyObjOrHex.curveName}); 1422 var asn1Hex1 = asn1Obj1.tohex(); 1423 var asn1Obj2 = _ecdsaprv2asn1obj(keyObjOrHex); 1424 var asn1Hex2 = asn1Obj2.tohex(); 1425 1426 var s = ""; 1427 s += hextopem(asn1Hex1, "EC PARAMETERS"); 1428 s += hextopem(asn1Hex2, "EC PRIVATE KEY"); 1429 return s; 1430 } 1431 1432 // x. PEM PKCS#1 plain private key of DSA private key object 1433 if (formatType == "PKCS1PRV" && 1434 _DSA !== undefined && 1435 keyObjOrHex instanceof _DSA && 1436 (passwd === undefined || passwd == null) && 1437 keyObjOrHex.isPrivate == true) { 1438 1439 var asn1Obj = _dsaprv2asn1obj(keyObjOrHex); 1440 var asn1Hex = asn1Obj.tohex(); 1441 return hextopem(asn1Hex, "DSA PRIVATE KEY"); 1442 } 1443 1444 // 3. private 1445 1446 // x. PEM PKCS#5 encrypted private key of RSA private key object 1447 if (formatType == "PKCS5PRV" && 1448 _RSAKey !== undefined && 1449 keyObjOrHex instanceof _RSAKey && 1450 (passwd !== undefined && passwd != null) && 1451 keyObjOrHex.isPrivate == true) { 1452 1453 var asn1Obj = _rsaprv2asn1obj(keyObjOrHex); 1454 var asn1Hex = asn1Obj.tohex(); 1455 1456 if (encAlg === undefined) encAlg = "DES-EDE3-CBC"; 1457 return this.getEncryptedPKCS5PEMFromPrvKeyHex("RSA", asn1Hex, passwd, encAlg, ivsaltHex); 1458 } 1459 1460 // x. PEM PKCS#5 encrypted private key of ECDSA private key object 1461 if (formatType == "PKCS5PRV" && 1462 _ECDSA !== undefined && 1463 keyObjOrHex instanceof _ECDSA && 1464 (passwd !== undefined && passwd != null) && 1465 keyObjOrHex.isPrivate == true) { 1466 1467 var asn1Obj = _ecdsaprv2asn1obj(keyObjOrHex); 1468 var asn1Hex = asn1Obj.tohex(); 1469 1470 if (encAlg === undefined) encAlg = "DES-EDE3-CBC"; 1471 return this.getEncryptedPKCS5PEMFromPrvKeyHex("EC", asn1Hex, passwd, encAlg, ivsaltHex); 1472 } 1473 1474 // x. PEM PKCS#5 encrypted private key of DSA private key object 1475 if (formatType == "PKCS5PRV" && 1476 _DSA !== undefined && 1477 keyObjOrHex instanceof _DSA && 1478 (passwd !== undefined && passwd != null) && 1479 keyObjOrHex.isPrivate == true) { 1480 1481 var asn1Obj = _dsaprv2asn1obj(keyObjOrHex); 1482 var asn1Hex = asn1Obj.tohex(); 1483 1484 if (encAlg === undefined) encAlg = "DES-EDE3-CBC"; 1485 return this.getEncryptedPKCS5PEMFromPrvKeyHex("DSA", asn1Hex, passwd, encAlg, ivsaltHex); 1486 } 1487 1488 // x. ====================================================================== 1489 1490 var _getEncryptedPKCS8 = function(plainKeyHex, passcode) { 1491 var info = _getEencryptedPKCS8Info(plainKeyHex, passcode); 1492 //alert("iv=" + info.encryptionSchemeIV); 1493 //alert("info.ciphertext2[" + info.ciphertext.length + "=" + info.ciphertext); 1494 var asn1Obj = new _newObject({ 1495 "seq": [ 1496 {"seq": [ 1497 {"oid": {"name": "pkcs5PBES2"}}, 1498 {"seq": [ 1499 {"seq": [ 1500 {"oid": {"name": "pkcs5PBKDF2"}}, 1501 {"seq": [ 1502 {"octstr": {"hex": info.pbkdf2Salt}}, 1503 {"int": info.pbkdf2Iter} 1504 ]} 1505 ]}, 1506 {"seq": [ 1507 {"oid": {"name": "des-EDE3-CBC"}}, 1508 {"octstr": {"hex": info.encryptionSchemeIV}} 1509 ]} 1510 ]} 1511 ]}, 1512 {"octstr": {"hex": info.ciphertext}} 1513 ] 1514 }); 1515 return asn1Obj.tohex(); 1516 }; 1517 1518 var _getEencryptedPKCS8Info = function(plainKeyHex, passcode) { 1519 var pbkdf2Iter = 100; 1520 var pbkdf2SaltWS = CryptoJS.lib.WordArray.random(8); 1521 var encryptionSchemeAlg = "DES-EDE3-CBC"; 1522 var encryptionSchemeIVWS = CryptoJS.lib.WordArray.random(8); 1523 // PBKDF2 key 1524 var pbkdf2KeyWS = CryptoJS.PBKDF2(passcode, 1525 pbkdf2SaltWS, { "keySize": 192/32, 1526 "iterations": pbkdf2Iter }); 1527 // ENCRYPT 1528 var plainKeyWS = CryptoJS.enc.Hex.parse(plainKeyHex); 1529 var encryptedKeyHex = 1530 CryptoJS.TripleDES.encrypt(plainKeyWS, pbkdf2KeyWS, { "iv": encryptionSchemeIVWS }) + ""; 1531 1532 //alert("encryptedKeyHex=" + encryptedKeyHex); 1533 1534 var info = {}; 1535 info.ciphertext = encryptedKeyHex; 1536 //alert("info.ciphertext=" + info.ciphertext); 1537 info.pbkdf2Salt = CryptoJS.enc.Hex.stringify(pbkdf2SaltWS); 1538 info.pbkdf2Iter = pbkdf2Iter; 1539 info.encryptionSchemeAlg = encryptionSchemeAlg; 1540 info.encryptionSchemeIV = CryptoJS.enc.Hex.stringify(encryptionSchemeIVWS); 1541 return info; 1542 }; 1543 1544 // x. PEM PKCS#8 plain private key of RSA private key object 1545 if (formatType == "PKCS8PRV" && 1546 _RSAKey != undefined && 1547 keyObjOrHex instanceof _RSAKey && 1548 keyObjOrHex.isPrivate == true) { 1549 1550 var keyObj = _rsaprv2asn1obj(keyObjOrHex); 1551 var keyHex = keyObj.tohex(); 1552 1553 var asn1Obj = _newObject({ 1554 "seq": [ 1555 {"int": 0}, 1556 {"seq": [{"oid": {"name": "rsaEncryption"}},{"null": true}]}, 1557 {"octstr": {"hex": keyHex}} 1558 ] 1559 }); 1560 var asn1Hex = asn1Obj.tohex(); 1561 1562 if (passwd === undefined || passwd == null) { 1563 return hextopem(asn1Hex, "PRIVATE KEY"); 1564 } else { 1565 var asn1Hex2 = _getEncryptedPKCS8(asn1Hex, passwd); 1566 return hextopem(asn1Hex2, "ENCRYPTED PRIVATE KEY"); 1567 } 1568 } 1569 1570 // x. PEM PKCS#8 plain private key of ECDSA private key object 1571 if (formatType == "PKCS8PRV" && 1572 _ECDSA !== undefined && 1573 keyObjOrHex instanceof _ECDSA && 1574 keyObjOrHex.isPrivate == true) { 1575 1576 var pKeyObj = { 1577 "seq": [ 1578 {"int": 1}, 1579 {"octstr": {"hex": keyObjOrHex.prvKeyHex}} 1580 ] 1581 }; 1582 if (typeof keyObjOrHex.pubKeyHex == "string") { 1583 pKeyObj.seq.push({"tag": ['a1', true, {"bitstr": {"hex": "00" + keyObjOrHex.pubKeyHex}}]}); 1584 } 1585 var keyObj = new _newObject(pKeyObj); 1586 var keyHex = keyObj.tohex(); 1587 1588 var asn1Obj = _newObject({ 1589 "seq": [ 1590 {"int": 0}, 1591 {"seq": [ 1592 {"oid": {"name": "ecPublicKey"}}, 1593 {"oid": {"name": keyObjOrHex.curveName}} 1594 ]}, 1595 {"octstr": {"hex": keyHex}} 1596 ] 1597 }); 1598 1599 var asn1Hex = asn1Obj.tohex(); 1600 if (passwd === undefined || passwd == null) { 1601 return hextopem(asn1Hex, "PRIVATE KEY"); 1602 } else { 1603 var asn1Hex2 = _getEncryptedPKCS8(asn1Hex, passwd); 1604 return hextopem(asn1Hex2, "ENCRYPTED PRIVATE KEY"); 1605 } 1606 } 1607 1608 // x. PEM PKCS#8 plain private key of DSA private key object 1609 if (formatType == "PKCS8PRV" && 1610 _DSA !== undefined && 1611 keyObjOrHex instanceof _DSA && 1612 keyObjOrHex.isPrivate == true) { 1613 1614 var keyObj = new _DERInteger({'bigint': keyObjOrHex.x}); 1615 var keyHex = keyObj.tohex(); 1616 1617 var asn1Obj = _newObject({ 1618 "seq": [ 1619 {"int": 0}, 1620 {"seq": [ 1621 {"oid": {"name": "dsa"}}, 1622 {"seq": [ 1623 {"int": {"bigint": keyObjOrHex.p}}, 1624 {"int": {"bigint": keyObjOrHex.q}}, 1625 {"int": {"bigint": keyObjOrHex.g}} 1626 ]} 1627 ]}, 1628 {"octstr": {"hex": keyHex}} 1629 ] 1630 }); 1631 1632 var asn1Hex = asn1Obj.tohex(); 1633 if (passwd === undefined || passwd == null) { 1634 return hextopem(asn1Hex, "PRIVATE KEY"); 1635 } else { 1636 var asn1Hex2 = _getEncryptedPKCS8(asn1Hex, passwd); 1637 return hextopem(asn1Hex2, "ENCRYPTED PRIVATE KEY"); 1638 } 1639 } 1640 1641 throw new Error("unsupported object nor format"); 1642 }; 1643 1644 // -- PUBLIC METHODS FOR CSR -------------------------------------------------- 1645 1646 /** 1647 * get RSAKey/DSA/ECDSA public key object from PEM formatted PKCS#10 CSR string 1648 * @name getKeyFromCSRPEM 1649 * @memberOf KEYUTIL 1650 * @function 1651 * @param {String} csrPEM PEM formatted PKCS#10 CSR string 1652 * @return {Object} RSAKey/DSA/ECDSA public key object 1653 * @since keyutil 1.0.5 1654 */ 1655 KEYUTIL.getKeyFromCSRPEM = function(csrPEM) { 1656 var csrHex = pemtohex(csrPEM, "CERTIFICATE REQUEST"); 1657 var key = KEYUTIL.getKeyFromCSRHex(csrHex); 1658 return key; 1659 }; 1660 1661 /** 1662 * get RSAKey/DSA/ECDSA public key object from hexadecimal string of PKCS#10 CSR 1663 * @name getKeyFromCSRHex 1664 * @memberOf KEYUTIL 1665 * @function 1666 * @param {String} csrHex hexadecimal string of PKCS#10 CSR 1667 * @return {Object} RSAKey/DSA/ECDSA public key object 1668 * @since keyutil 1.0.5 1669 */ 1670 KEYUTIL.getKeyFromCSRHex = function(csrHex) { 1671 var info = KEYUTIL.parseCSRHex(csrHex); 1672 var key = KEYUTIL.getKey(info.p8pubkeyhex, null, "pkcs8pub"); 1673 return key; 1674 }; 1675 1676 /** 1677 * parse hexadecimal string of PKCS#10 CSR (certificate signing request) 1678 * @name parseCSRHex 1679 * @memberOf KEYUTIL 1680 * @function 1681 * @param {String} csrHex hexadecimal string of PKCS#10 CSR 1682 * @return {Array} associative array of parsed CSR 1683 * @since keyutil 1.0.5 1684 * @description 1685 * Resulted associative array has following properties: 1686 * <ul> 1687 * <li>p8pubkeyhex - hexadecimal string of subject public key in PKCS#8</li> 1688 * </ul> 1689 */ 1690 KEYUTIL.parseCSRHex = function(csrHex) { 1691 var _ASN1HEX = ASN1HEX; 1692 var _getChildIdx = _ASN1HEX.getChildIdx; 1693 var _getTLV = _ASN1HEX.getTLV; 1694 var result = {}; 1695 var h = csrHex; 1696 1697 // 1. sequence 1698 if (h.substr(0, 2) != "30") 1699 throw new Error("malformed CSR(code:001)"); // not sequence 1700 1701 var a1 = _getChildIdx(h, 0); 1702 if (a1.length < 1) 1703 throw new Error("malformed CSR(code:002)"); // short length 1704 1705 // 2. 2nd sequence 1706 if (h.substr(a1[0], 2) != "30") 1707 throw new Error("malformed CSR(code:003)"); // not sequence 1708 1709 var a2 = _getChildIdx(h, a1[0]); 1710 if (a2.length < 3) 1711 throw new Error("malformed CSR(code:004)"); // 2nd seq short elem 1712 1713 result.p8pubkeyhex = _getTLV(h, a2[2]); 1714 1715 return result; 1716 }; 1717 1718 // -- OTHER STATIC PUBLIC METHODS -------------------------------------------- 1719 1720 /** 1721 * get key ID by public key object for subject or authority key identifier 1722 * @name getKeyID 1723 * @memberof KEYUTIL 1724 * @function 1725 * @static 1726 * @param {Object} obj RSAKey/KJUR.crypto.ECDSA,DSA public key object or public key PEM string 1727 * @return hexadecimal string of public key identifier 1728 * @since keyutil 1.2.2 jsrsasign 5.0.16 1729 * @description 1730 * This static method generates a key identifier from a public key 1731 * by the method described in 1732 * <a href="https://tools.ietf.org/html/rfc5280#section-4.2.1.2" 1733 * target="_blank">RFC 5280 4.2.1.2. Subject Key Identifier (1)</a>. 1734 * @example 1735 * pubkeyobj = KEYUTIL.getKey(...); 1736 * KEYTUTIL.getKey(pubkeyobj) → "a612..." 1737 */ 1738 KEYUTIL.getKeyID = function(obj) { 1739 var _KEYUTIL = KEYUTIL; 1740 var _ASN1HEX = ASN1HEX; 1741 1742 if (typeof obj === "string" && obj.indexOf("BEGIN ") != -1) { 1743 obj = _KEYUTIL.getKey(obj); 1744 } 1745 1746 var p8hex = pemtohex(_KEYUTIL.getPEM(obj)); 1747 var idx = _ASN1HEX.getIdxbyList(p8hex, 0, [1]); // BITSTRING 1748 var hV = _ASN1HEX.getV(p8hex, idx).substring(2); // value without unused bit 1749 return KJUR.crypto.Util.hashHex(hV, "sha1"); 1750 } 1751 1752 /** 1753 * convert from certificate, public/private key object to RFC 7517 JSON Web Key(JWK)<br/> 1754 * @name getJWK 1755 * @memberOf KEYUTIL 1756 * @function 1757 * @static 1758 * @param {Object or string} keyinfo public/private key object, PEM key or PEM certificate 1759 * @param {boolean} nokid set true if you don't need kid (OPTION, DEFAULT=undefined) 1760 * @param {boolean} nox5c set true if you don't need x5c of certificate (OPTION, DEFAULT=undefined) 1761 * @param {boolean} nox5t set true if you don't need x5t of certificate (OPTION, DEFAULT=undefined) 1762 * @param {boolean} nox5t2 set true if you don't need x5c#S256 of certificate (OPTION, DEFAULT=undefined) 1763 * @return {Object} JWK object 1764 * @since keyutil 1.2.5 jsrsasign 10.5.1 1765 * @see RSAKey 1766 * @see KJUR.crypto.ECDSA 1767 * @see KJUR.crypto.DSA 1768 * 1769 * @description 1770 * This static method provides 1771 * <a href="https://datatracker.ietf.org/doc/html/rfc7517"> 1772 * RFC 7517 JSON Web Key(JWK) JSON</a> 1773 * object from following argument types: 1774 * <ul> 1775 * <li> 1776 * <b>JWK private key</b> 1777 * <ul> 1778 * <li>RSAKey or KJUR.crypto.{ECDSA,DSA} private key object</li> 1779 * <li>PKCS#5 or PKCS#8 plain PEM private key</li> 1780 * </ul> 1781 * </li> 1782 * <li> 1783 * <b>JWK public key</b> 1784 * <ul> 1785 * <li>RSAKey or KJUR.crypto.{ECDSA,DSA} public key object</li> 1786 * <li>PKCS#5 or PKCS#8 PEM public key</li> 1787 * <li>X509 certificate object</li> 1788 * <li>PEM certificate</li> 1789 * </ul> 1790 * </li> 1791 * </ul> 1792 * 1793 * @example 1794 * kp1 = KEYUTIL.generateKeypair("EC", "P-256"); 1795 * jwkPrv1 = KEYUTIL.getJWK(kp1.prvKeyObj); 1796 * jwkPub1 = KEYUTIL.getJWK(kp1.pubKeyObj); 1797 * 1798 * kp2 = KEYUTIL.generateKeypair("RSA", 2048); 1799 * jwkPrv2 = KEYUTIL.getJWK(kp2.prvKeyObj); 1800 * jwkPub2 = KEYUTIL.getJWK(kp2.pubKeyObj); 1801 * 1802 * // from PEM certificate 1803 * KEYUTIL.getJWK("-----BEGIN CERTIFICATE...") → 1804 * { 1805 * kty: "EC", crv: "P-521", x: "...", y: "...", 1806 * x5c: ["MI..."], 1807 * x5t: "...", 1808 * "x5t#S256": "...", 1809 * kid: "..." 1810 * } 1811 * 1812 * // from X509 object 1813 * x509obj = new X509("-----BEGIN CERTIFICATE..."); 1814 * KEYUTIL.getJWK(x509obj) → 1815 * { 1816 * kty: "EC", crv: "P-521", x: "...", y: "...", 1817 * ... 1818 * } 1819 * 1820 * // from PEM certificate without kid, x5t and x5t#S256 (i.e. only x5c) 1821 * KEYUTIL.getJWK("-----BEGIN CERTIFICATE...", true, false, true, true) → 1822 * { 1823 * kty: "EC", crv: "P-521", x: "...", y: "...", 1824 * x5c: ["MI..."] 1825 * } 1826 */ 1827 KEYUTIL.getJWK = function(keyinfo, nokid, nox5c, nox5t, nox5t2) { 1828 var keyObj; 1829 var jwk = {}; 1830 var hCert; 1831 var _hashHex = KJUR.crypto.Util.hashHex; 1832 1833 if (typeof keyinfo == "string") { 1834 keyObj = KEYUTIL.getKey(keyinfo); 1835 if (keyinfo.indexOf("CERTIFICATE") != -1) { 1836 hCert = pemtohex(keyinfo) 1837 } 1838 } else if (typeof keyinfo == "object") { 1839 if (keyinfo instanceof X509) { 1840 keyObj = keyinfo.getPublicKey(); 1841 hCert = keyinfo.hex; 1842 } else { 1843 keyObj = keyinfo; 1844 } 1845 } else { 1846 throw new Error("unsupported keyinfo type"); 1847 } 1848 1849 if (keyObj instanceof RSAKey && keyObj.isPrivate) { 1850 jwk.kty = "RSA"; 1851 jwk.n = hextob64u(keyObj.n.toString(16)); 1852 jwk.e = hextob64u(keyObj.e.toString(16)); 1853 jwk.d = hextob64u(keyObj.d.toString(16)); 1854 jwk.p = hextob64u(keyObj.p.toString(16)); 1855 jwk.q = hextob64u(keyObj.q.toString(16)); 1856 jwk.dp = hextob64u(keyObj.dmp1.toString(16)); 1857 jwk.dq = hextob64u(keyObj.dmq1.toString(16)); 1858 jwk.qi = hextob64u(keyObj.coeff.toString(16)); 1859 } else if (keyObj instanceof RSAKey && keyObj.isPublic) { 1860 jwk.kty = "RSA"; 1861 jwk.n = hextob64u(keyObj.n.toString(16)); 1862 jwk.e = hextob64u(keyObj.e.toString(16)); 1863 } else if (keyObj instanceof KJUR.crypto.ECDSA && keyObj.isPrivate) { 1864 var name = keyObj.getShortNISTPCurveName(); 1865 if (name !== "P-256" && name !== "P-384" && name !== "P-521") 1866 throw new Error("unsupported curve name for JWT: " + name); 1867 var xy = keyObj.getPublicKeyXYHex(); 1868 jwk.kty = "EC"; 1869 jwk.crv = name; 1870 jwk.x = hextob64u(xy.x); 1871 jwk.y = hextob64u(xy.y); 1872 jwk.d = hextob64u(keyObj.prvKeyHex); 1873 } else if (keyObj instanceof KJUR.crypto.ECDSA && keyObj.isPublic) { 1874 var name = keyObj.getShortNISTPCurveName(); 1875 if (name !== "P-256" && name !== "P-384" && name !== "P-521") 1876 throw new Error("unsupported curve name for JWT: " + name); 1877 var xy = keyObj.getPublicKeyXYHex(); 1878 jwk.kty = "EC"; 1879 jwk.crv = name; 1880 jwk.x = hextob64u(xy.x); 1881 jwk.y = hextob64u(xy.y); 1882 } 1883 if (jwk.kty == undefined) throw new Error("unsupported keyinfo"); 1884 1885 if ((! keyObj.isPrivate) && nokid != true) { 1886 jwk.kid = KJUR.jws.JWS.getJWKthumbprint(jwk); 1887 } 1888 1889 if (hCert != undefined && nox5c != true) { 1890 jwk.x5c = [hex2b64(hCert)]; 1891 } 1892 1893 if (hCert != undefined && nox5t != true) { 1894 jwk.x5t = b64tob64u(hex2b64(_hashHex(hCert, "sha1"))); 1895 } 1896 1897 if (hCert != undefined && nox5t2 != true) { 1898 jwk["x5t#S256"] = b64tob64u(hex2b64(_hashHex(hCert, "sha256"))); 1899 } 1900 1901 return jwk; 1902 }; 1903 1904 /** 1905 * convert from RSAKey/KJUR.crypto.ECDSA public/private key object to RFC 7517 JSON Web Key(JWK) (DEPRECATED)<br/> 1906 * @name getJWKFromKey 1907 * @memberOf KEYUTIL 1908 * @function 1909 * @static 1910 * @param {Object} RSAKey/KJUR.crypto.ECDSA public/private key object 1911 * @return {Object} JWK object 1912 * @since keyutil 1.0.13 jsrsasign 5.0.14 1913 * @deprecated since jsrsasign 10.5.1 keyutil 1.2.5 please use getJWK method 1914 * @see KEYUTIL.getJWK 1915 * 1916 * @description 1917 * This static method convert from RSAKey/KJUR.crypto.ECDSA public/private key object 1918 * to RFC 7517 JSON Web Key(JWK) 1919 * 1920 * @example 1921 * kp1 = KEYUTIL.generateKeypair("EC", "P-256"); 1922 * jwkPrv1 = KEYUTIL.getJWKFromKey(kp1.prvKeyObj); 1923 * jwkPub1 = KEYUTIL.getJWKFromKey(kp1.pubKeyObj); 1924 * 1925 * kp2 = KEYUTIL.generateKeypair("RSA", 2048); 1926 * jwkPrv2 = KEYUTIL.getJWKFromKey(kp2.prvKeyObj); 1927 * jwkPub2 = KEYUTIL.getJWKFromKey(kp2.pubKeyObj); 1928 * 1929 * // if you need RFC 7638 JWK thumprint as kid do like this: 1930 * jwkPub2.kid = KJUR.jws.JWS.getJWKthumbprint(jwkPub2); 1931 */ 1932 KEYUTIL.getJWKFromKey = function(keyObj) { 1933 return KEYUTIL.getJWK(keyObj, true, true, true, true); 1934 } 1935