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