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