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