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