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