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