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