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