1 /*! pkcs5pkey-1.0.5.js (c) 2013 Kenji Urushima | kjur.github.com/jsrsasign/license
  2  */
  3 /*
  4  * pkcs5pkey.js - reading passcode protected PKCS#5 PEM formatted RSA private key
  5  *
  6  * Copyright (c) 2013 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 pkcs5pkey-1.0.js
 17  * @author Kenji Urushima kenji.urushima@gmail.com
 18  * @version pkcs5pkey 1.0.5 (2013-Aug-20)
 19  * @since jsrsasign 2.0.0
 20  * @license <a href="http://kjur.github.io/jsrsasign/license/">MIT License</a>
 21  */
 22 
 23 /**
 24  * @name PKCS5PKEY
 25  * @class class for PKCS#5 and PKCS#8 private key 
 26  * @deprecated Since jsrsasign 4.1.3. Please use KEYUTIL class.
 27  * @description 
 28  * <br/>
 29  * {@link PKCS5PKEY} class has following features:
 30  * <ul>
 31  * <li>read and parse PEM formatted encrypted PKCS#5 private key
 32  * <li>generate PEM formatted encrypted PKCS#5 private key
 33  * <li>read and parse PEM formatted plain PKCS#8 private key
 34  * <li>read and parse PEM formatted encrypted PKCS#8 private key by PBKDF2/HmacSHA1/3DES
 35  * </ul>
 36  * Currently supports only RSA private key and
 37  * following symmetric key algorithms to protect private key.
 38  * <ul>
 39  * <li>DES-EDE3-CBC</li>
 40  * <li>AES-256-CBC</li>
 41  * <li>AES-192-CBC</li>
 42  * <li>AES-128-CBC</li>
 43  * </ul>
 44  * 
 45  * <h5>METHOD SUMMARY</h5>
 46  * <dl>
 47  * <dt><b>PKCS8 PRIVATE KEY METHODS</b><dd>
 48  * <ul>
 49  * <li>{@link PKCS5PKEY.getRSAKeyFromPlainPKCS8PEM} - convert plain PKCS8 PEM to RSAKey object</li>
 50  * <li>{@link PKCS5PKEY.getRSAKeyFromPlainPKCS8Hex} - convert plain PKCS8 hexadecimal data to RSAKey object</li>
 51  * <li>{@link PKCS5PKEY.getRSAKeyFromEncryptedPKCS8PEM} - convert encrypted PKCS8 PEM to RSAKey object</li>
 52  * <li>{@link PKCS5PKEY.getPlainPKCS8HexFromEncryptedPKCS8PEM} - convert encrypted PKCS8 PEM to plain PKCS8 Hex</li>
 53  * </ul>
 54  * <dt><b>PKCS5 PRIVATE KEY METHODS</b><dd>
 55  * <ul>
 56  * <li>{@link PKCS5PKEY.getRSAKeyFromEncryptedPKCS5PEM} - convert encrypted PKCS5 PEM to RSAKey object</li>
 57  * <li>{@link PKCS5PKEY.getEncryptedPKCS5PEMFromRSAKey} - convert RSAKey object to encryped PKCS5 PEM</li>
 58  * <li>{@link PKCS5PKEY.newEncryptedPKCS5PEM} - generate RSAKey and its encrypted PKCS5 PEM</li>
 59  * </ul>
 60  * <dt><b>PKCS8 PUBLIC KEY METHODS</b><dd>
 61  * <ul>
 62  * <li>{@link PKCS5PKEY.getKeyFromPublicPKCS8PEM} - convert encrypted PKCS8 PEM to RSAKey/ECDSA object</li>
 63  * <li>{@link PKCS5PKEY.getKeyFromPublicPKCS8Hex} - convert encrypted PKCS8 Hex to RSAKey/ECDSA object</li>
 64  * <li>{@link PKCS5PKEY.getRSAKeyFromPublicPKCS8PEM} - convert encrypted PKCS8 PEM to RSAKey object</li>
 65  * <li>{@link PKCS5PKEY.getRSAKeyFromPublicPKCS8Hex} - convert encrypted PKCS8 Hex to RSAKey object</li>
 66  * </ul>
 67  * <dt><b>UTITILIY METHODS</b><dd>
 68  * <ul>
 69  * <li>{@link PKCS5PKEY.getHexFromPEM} - convert PEM string to hexadecimal data</li>
 70  * <li>{@link PKCS5PKEY.getDecryptedKeyHexByKeyIV} - decrypt key by sharedKey and IV</li>
 71  * </ul>
 72  * </dl>
 73  * 
 74  * @example
 75  * Here is an example of PEM formatted encrypted PKCS#5 private key.
 76  * -----BEGIN RSA PRIVATE KEY-----
 77  * Proc-Type: 4,ENCRYPTED
 78  * DEK-Info: AES-256-CBC,40555967F759530864FE022E257DE34E
 79  *
 80  * jV7uXajRw4cccDaliagcqiLOiQEUCe19l761pXRxzgQP+DH4rCi12T4puTdZyy6l
 81  *          ...(snip)...
 82  * qxLS+BASmyGm4DME6m+kltZ12LXwPgNU6+d+XQ4NXSA=
 83  *-----END RSA PRIVATE KEY-----
 84  */
 85 var PKCS5PKEY = function() {
 86     // *****************************************************************
 87     // *** PRIVATE PROPERTIES AND METHODS *******************************
 88     // *****************************************************************
 89     // shared key decryption ------------------------------------------
 90     var decryptAES = function(dataHex, keyHex, ivHex) {
 91 	return decryptGeneral(CryptoJS.AES, dataHex, keyHex, ivHex);
 92     };
 93 
 94     var decrypt3DES = function(dataHex, keyHex, ivHex) {
 95 	return decryptGeneral(CryptoJS.TripleDES, dataHex, keyHex, ivHex);
 96     };
 97 
 98     var decryptGeneral = function(f, dataHex, keyHex, ivHex) {
 99 	var data = CryptoJS.enc.Hex.parse(dataHex);
100 	var key = CryptoJS.enc.Hex.parse(keyHex);
101 	var iv = CryptoJS.enc.Hex.parse(ivHex);
102 	var encrypted = {};
103 	encrypted.key = key;
104 	encrypted.iv = iv;
105 	encrypted.ciphertext = data;
106 	var decrypted = f.decrypt(encrypted, key, { iv: iv });
107 	return CryptoJS.enc.Hex.stringify(decrypted);
108     };
109 
110     // shared key decryption ------------------------------------------
111     var encryptAES = function(dataHex, keyHex, ivHex) {
112 	return encryptGeneral(CryptoJS.AES, dataHex, keyHex, ivHex);
113     };
114 
115     var encrypt3DES = function(dataHex, keyHex, ivHex) {
116 	return encryptGeneral(CryptoJS.TripleDES, dataHex, keyHex, ivHex);
117     };
118 
119     var encryptGeneral = function(f, dataHex, keyHex, ivHex) {
120 	var data = CryptoJS.enc.Hex.parse(dataHex);
121 	var key = CryptoJS.enc.Hex.parse(keyHex);
122 	var iv = CryptoJS.enc.Hex.parse(ivHex);
123 	var msg = {};
124 	var encryptedHex = f.encrypt(data, key, { iv: iv });
125         var encryptedWA = CryptoJS.enc.Hex.parse(encryptedHex.toString());
126         var encryptedB64 = CryptoJS.enc.Base64.stringify(encryptedWA);
127 	return encryptedB64;
128     };
129 
130     // other methods and properties ----------------------------------------
131     var ALGLIST = {
132 	'AES-256-CBC': { 'proc': decryptAES, 'eproc': encryptAES, keylen: 32, ivlen: 16 },
133 	'AES-192-CBC': { 'proc': decryptAES, 'eproc': encryptAES, keylen: 24, ivlen: 16 },
134 	'AES-128-CBC': { 'proc': decryptAES, 'eproc': encryptAES, keylen: 16, ivlen: 16 },
135 	'DES-EDE3-CBC': { 'proc': decrypt3DES, 'eproc': encrypt3DES, keylen: 24, ivlen: 8 }
136     };
137 
138     var getFuncByName = function(algName) {
139 	return ALGLIST[algName]['proc'];
140     };
141 
142     var _generateIvSaltHex = function(numBytes) {
143 	var wa = CryptoJS.lib.WordArray.random(numBytes);
144 	var hex = CryptoJS.enc.Hex.stringify(wa);
145 	return hex;
146     };
147 
148     var _parsePKCS5PEM = function(sPKCS5PEM) {
149 	var info = {};
150 	if (sPKCS5PEM.match(new RegExp("DEK-Info: ([^,]+),([0-9A-Fa-f]+)", "m"))) {
151 	    info.cipher = RegExp.$1;
152 	    info.ivsalt = RegExp.$2;
153 	}
154 	if (sPKCS5PEM.match(new RegExp("-----BEGIN ([A-Z]+) PRIVATE KEY-----"))) {
155 	    info.type = RegExp.$1;
156 	}
157 	var i1 = -1;
158 	var lenNEWLINE = 0;
159 	if (sPKCS5PEM.indexOf("\r\n\r\n") != -1) {
160 	    i1 = sPKCS5PEM.indexOf("\r\n\r\n");
161 	    lenNEWLINE = 2;
162 	}
163 	if (sPKCS5PEM.indexOf("\n\n") != -1) {
164 	    i1 = sPKCS5PEM.indexOf("\n\n");
165 	    lenNEWLINE = 1;
166 	}
167 	var i2 = sPKCS5PEM.indexOf("-----END");
168 	if (i1 != -1 && i2 != -1) {
169 	    var s = sPKCS5PEM.substring(i1 + lenNEWLINE * 2, i2 - lenNEWLINE);
170 	    s = s.replace(/\s+/g, '');
171 	    info.data = s;
172 	}
173 	return info;
174     };
175 
176     var _getKeyAndUnusedIvByPasscodeAndIvsalt = function(algName, passcode, ivsaltHex) {
177 	//alert("ivsaltHex(2) = " + ivsaltHex);
178 	var saltHex = ivsaltHex.substring(0, 16);
179 	//alert("salt = " + saltHex);
180 	    
181 	var salt = CryptoJS.enc.Hex.parse(saltHex);
182 	var data = CryptoJS.enc.Utf8.parse(passcode);
183 	//alert("salt = " + salt);
184 	//alert("data = " + data);
185 
186 	var nRequiredBytes = ALGLIST[algName]['keylen'] + ALGLIST[algName]['ivlen'];
187 	var hHexValueJoined = '';
188 	var hLastValue = null;
189 	//alert("nRequiredBytes = " + nRequiredBytes);
190 	for (;;) {
191 	    var h = CryptoJS.algo.MD5.create();
192 	    if (hLastValue != null) {
193 		h.update(hLastValue);
194 	    }
195 	    h.update(data);
196 	    h.update(salt);
197 	    hLastValue = h.finalize();
198 	    hHexValueJoined = hHexValueJoined + CryptoJS.enc.Hex.stringify(hLastValue);
199 	    //alert("joined = " + hHexValueJoined);
200 	    if (hHexValueJoined.length >= nRequiredBytes * 2) {
201 		break;
202 	    }
203 	}
204 	var result = {};
205 	result.keyhex = hHexValueJoined.substr(0, ALGLIST[algName]['keylen'] * 2);
206 	result.ivhex = hHexValueJoined.substr(ALGLIST[algName]['keylen'] * 2, ALGLIST[algName]['ivlen'] * 2);
207 	return result;
208     };
209 
210     /*
211      * @param {String} privateKeyB64 base64 string of encrypted private key
212      * @param {String} sharedKeyAlgName algorithm name of shared key encryption
213      * @param {String} sharedKeyHex hexadecimal string of shared key to encrypt
214      * @param {String} ivsaltHex hexadecimal string of IV and salt
215      * @param {String} hexadecimal string of decrypted private key
216      */
217     var _decryptKeyB64 = function(privateKeyB64, sharedKeyAlgName, sharedKeyHex, ivsaltHex) {
218 	var privateKeyWA = CryptoJS.enc.Base64.parse(privateKeyB64);
219 	var privateKeyHex = CryptoJS.enc.Hex.stringify(privateKeyWA);
220 	var f = ALGLIST[sharedKeyAlgName]['proc'];
221 	var decryptedKeyHex = f(privateKeyHex, sharedKeyHex, ivsaltHex);
222 	return decryptedKeyHex;
223     };
224     
225     /*
226      * @param {String} privateKeyHex hexadecimal string of private key
227      * @param {String} sharedKeyAlgName algorithm name of shared key encryption
228      * @param {String} sharedKeyHex hexadecimal string of shared key to encrypt
229      * @param {String} ivsaltHex hexadecimal string of IV and salt
230      * @param {String} base64 string of encrypted private key
231      */
232     var _encryptKeyHex = function(privateKeyHex, sharedKeyAlgName, sharedKeyHex, ivsaltHex) {
233 	var f = ALGLIST[sharedKeyAlgName]['eproc'];
234 	var encryptedKeyB64 = f(privateKeyHex, sharedKeyHex, ivsaltHex);
235 	return encryptedKeyB64;
236     };
237 
238     // *****************************************************************
239     // *** PUBLIC PROPERTIES AND METHODS *******************************
240     // *****************************************************************
241     return {
242         // -- UTILITY METHODS ------------------------------------------------------------
243 	/**
244          * decrypt private key by shared key
245 	 * @name version
246 	 * @memberOf PKCS5PKEY
247 	 * @property {String} version
248 	 * @description version string of PKCS5PKEY class
249 	 */
250 	version: "1.0.5",
251 
252 	/**
253          * get hexacedimal string of PEM format
254 	 * @name getHexFromPEM
255 	 * @memberOf PKCS5PKEY
256 	 * @function
257 	 * @param {String} sPEM PEM formatted string
258 	 * @param {String} sHead PEM header string without BEGIN/END
259 	 * @return {String} hexadecimal string data of PEM contents
260 	 * @since pkcs5pkey 1.0.5
261 	 */
262         getHexFromPEM: function(sPEM, sHead) {
263 	    var s = sPEM;
264 	    if (s.indexOf("BEGIN " + sHead) == -1) {
265 		throw "can't find PEM header: " + sHead;
266 	    }
267 	    s = s.replace("-----BEGIN " + sHead + "-----", "");
268 	    s = s.replace("-----END " + sHead + "-----", "");
269 	    var sB64 = s.replace(/\s+/g, '');
270             var dataHex = b64tohex(sB64);
271 	    return dataHex;
272 	},
273 
274 	/**
275          * decrypt private key by shared key
276 	 * @name getDecryptedKeyHexByKeyIV
277 	 * @memberOf PKCS5PKEY
278 	 * @function
279 	 * @param {String} encryptedKeyHex hexadecimal string of encrypted private key
280 	 * @param {String} algName name of symmetric key algorithm (ex. 'DES-EBE3-CBC')
281 	 * @param {String} sharedKeyHex hexadecimal string of symmetric key
282 	 * @param {String} ivHex hexadecimal string of initial vector(IV).
283 	 * @return {String} hexadecimal string of decrypted privated key
284 	 */
285 	getDecryptedKeyHexByKeyIV: function(encryptedKeyHex, algName, sharedKeyHex, ivHex) {
286 	    var f1 = getFuncByName(algName);
287 	    return f1(encryptedKeyHex, sharedKeyHex, ivHex);
288 	},
289 
290 	/**
291          * parse PEM formatted passcode protected PKCS#5 private key
292 	 * @name parsePKCS5PEM
293 	 * @memberOf PKCS5PKEY
294 	 * @function
295 	 * @param {String} sEncryptedPEM PEM formatted protected passcode protected PKCS#5 private key
296 	 * @return {Hash} hash of key information
297 	 * @description
298          * Resulted hash has following attributes.
299 	 * <ul>
300 	 * <li>cipher - symmetric key algorithm name (ex. 'DES-EBE3-CBC', 'AES-256-CBC')</li>
301 	 * <li>ivsalt - IV used for decrypt. Its heading 8 bytes will be used for passcode salt.</li>
302 	 * <li>type - asymmetric key algorithm name of private key described in PEM header.</li>
303 	 * <li>data - base64 encoded encrypted private key.</li>
304 	 * </ul>
305          *
306 	 */
307         parsePKCS5PEM: function(sPKCS5PEM) {
308 	    return _parsePKCS5PEM(sPKCS5PEM);
309 	},
310 
311 	/**
312          * the same function as OpenSSL EVP_BytsToKey to generate shared key and IV
313 	 * @name getKeyAndUnusedIvByPasscodeAndIvsalt
314 	 * @memberOf PKCS5PKEY
315 	 * @function
316 	 * @param {String} algName name of symmetric key algorithm (ex. 'DES-EBE3-CBC')
317 	 * @param {String} passcode passcode to decrypt private key (ex. 'password')
318 	 * @param {String} hexadecimal string of IV. heading 8 bytes will be used for passcode salt
319 	 * @return {Hash} hash of key and unused IV (ex. {keyhex:2fe3..., ivhex:3fad..})
320 	 */
321 	getKeyAndUnusedIvByPasscodeAndIvsalt: function(algName, passcode, ivsaltHex) {
322 	    return _getKeyAndUnusedIvByPasscodeAndIvsalt(algName, passcode, ivsaltHex);
323 	},
324 
325         decryptKeyB64: function(privateKeyB64, sharedKeyAlgName, sharedKeyHex, ivsaltHex) {
326 	    return _decryptKeyB64(privateKeyB64, sharedKeyAlgName, sharedKeyHex, ivsaltHex);
327         },
328 
329 	/**
330          * decrypt PEM formatted protected PKCS#5 private key with passcode
331 	 * @name getDecryptedKeyHex
332 	 * @memberOf PKCS5PKEY
333 	 * @function
334 	 * @param {String} sEncryptedPEM PEM formatted protected passcode protected PKCS#5 private key
335 	 * @param {String} passcode passcode to decrypt private key (ex. 'password')
336 	 * @return {String} hexadecimal string of decrypted RSA priavte key
337 	 */
338 	getDecryptedKeyHex: function(sEncryptedPEM, passcode) {
339 	    // 1. parse pem
340 	    var info = _parsePKCS5PEM(sEncryptedPEM);
341 	    var publicKeyAlgName = info.type;
342 	    var sharedKeyAlgName = info.cipher;
343 	    var ivsaltHex = info.ivsalt;
344 	    var privateKeyB64 = info.data;
345 	    //alert("ivsaltHex = " + ivsaltHex);
346 
347 	    // 2. generate shared key
348 	    var sharedKeyInfo = _getKeyAndUnusedIvByPasscodeAndIvsalt(sharedKeyAlgName, passcode, ivsaltHex);
349 	    var sharedKeyHex = sharedKeyInfo.keyhex;
350 	    //alert("sharedKeyHex = " + sharedKeyHex);
351 
352 	    // 3. decrypt private key
353             var decryptedKey = _decryptKeyB64(privateKeyB64, sharedKeyAlgName, sharedKeyHex, ivsaltHex);
354 	    return decryptedKey;
355 	},
356 
357 	/**
358          * read PEM formatted encrypted PKCS#5 private key and returns RSAKey object
359 	 * @name getRSAKeyFromEncryptedPKCS5PEM
360 	 * @memberOf PKCS5PKEY
361 	 * @function
362 	 * @param {String} sEncryptedP5PEM PEM formatted encrypted PKCS#5 private key
363 	 * @param {String} passcode passcode to decrypt private key
364 	 * @return {RSAKey} loaded RSAKey object of RSA private key
365          * @since pkcs5pkey 1.0.2
366 	 */
367 	getRSAKeyFromEncryptedPKCS5PEM: function(sEncryptedP5PEM, passcode) {
368 	    var hPKey = this.getDecryptedKeyHex(sEncryptedP5PEM, passcode);
369 	    var rsaKey = new RSAKey();
370 	    rsaKey.readPrivateKeyFromASN1HexString(hPKey);
371 	    return rsaKey;
372 	},
373 
374 	/**
375          * get PEM formatted encrypted PKCS#5 private key from hexadecimal string of plain private key
376 	 * @name getEryptedPKCS5PEMFromPrvKeyHex
377 	 * @memberOf PKCS5PKEY
378 	 * @function
379 	 * @param {String} hPrvKey hexadecimal string of plain private key
380 	 * @param {String} passcode pass code to protect private key (ex. password)
381 	 * @param {String} sharedKeyAlgName algorithm name to protect private key (ex. AES-256-CBC)
382 	 * @param {String} ivsaltHex hexadecimal string of IV and salt
383 	 * @return {String} string of PEM formatted encrypted PKCS#5 private key
384          * @since pkcs5pkey 1.0.2
385 	 * @description
386 	 * <br/>
387 	 * generate PEM formatted encrypted PKCS#5 private key by hexadecimal string encoded
388 	 * ASN.1 object of plain RSA private key.
389 	 * Following arguments can be omitted.
390 	 * <ul>
391 	 * <li>alg - AES-256-CBC will be used if omitted.</li>
392 	 * <li>ivsaltHex - automatically generate IV and salt which length depends on algorithm</li>
393 	 * </ul>
394 	 * @example
395 	 * var pem = 
396          *   PKCS5PKEY.getEryptedPKCS5PEMFromPrvKeyHex(plainKeyHex, "password");
397 	 * var pem2 = 
398          *   PKCS5PKEY.getEryptedPKCS5PEMFromPrvKeyHex(plainKeyHex, "password", "AES-128-CBC");
399 	 * var pem3 = 
400          *   PKCS5PKEY.getEryptedPKCS5PEMFromPrvKeyHex(plainKeyHex, "password", "AES-128-CBC", "1f3d02...");
401 	 */
402 	getEryptedPKCS5PEMFromPrvKeyHex: function(hPrvKey, passcode, sharedKeyAlgName, ivsaltHex) {
403 	    var sPEM = "";
404 
405 	    // 1. set sharedKeyAlgName if undefined (default AES-256-CBC)
406 	    if (typeof sharedKeyAlgName == "undefined" || sharedKeyAlgName == null) {
407 		sharedKeyAlgName = "AES-256-CBC";
408 	    }
409 	    if (typeof ALGLIST[sharedKeyAlgName] == "undefined")
410 		throw "PKCS5PKEY unsupported algorithm: " + sharedKeyAlgName;
411 
412 	    // 2. set ivsaltHex if undefined
413 	    if (typeof ivsaltHex == "undefined" || ivsaltHex == null) {
414 		var ivlen = ALGLIST[sharedKeyAlgName]['ivlen'];
415 		var randIV = _generateIvSaltHex(ivlen);
416 		ivsaltHex = randIV.toUpperCase();
417 	    }
418 
419 	    // 3. get shared key
420             //alert("ivsalthex=" + ivsaltHex);
421 	    var sharedKeyInfo = _getKeyAndUnusedIvByPasscodeAndIvsalt(sharedKeyAlgName, passcode, ivsaltHex);
422 	    var sharedKeyHex = sharedKeyInfo.keyhex;
423 	    // alert("sharedKeyHex = " + sharedKeyHex);
424 
425             // 3. get encrypted Key in Base64
426             var encryptedKeyB64 = _encryptKeyHex(hPrvKey, sharedKeyAlgName, sharedKeyHex, ivsaltHex);
427 
428 	    var pemBody = encryptedKeyB64.replace(/(.{64})/g, "$1\r\n");
429 	    var sPEM = "-----BEGIN RSA PRIVATE KEY-----\r\n";
430 	    sPEM += "Proc-Type: 4,ENCRYPTED\r\n";
431 	    sPEM += "DEK-Info: " + sharedKeyAlgName + "," + ivsaltHex + "\r\n";
432 	    sPEM += "\r\n";
433 	    sPEM += pemBody;
434 	    sPEM += "\r\n-----END RSA PRIVATE KEY-----\r\n";
435 
436 	    return sPEM;
437         },
438 
439 	/**
440          * get PEM formatted encrypted PKCS#5 private key from RSAKey object of private key
441 	 * @name getEryptedPKCS5PEMFromRSAKey
442 	 * @memberOf PKCS5PKEY
443 	 * @function
444 	 * @param {RSAKey} pKey RSAKey object of private key
445 	 * @param {String} passcode pass code to protect private key (ex. password)
446 	 * @param {String} alg algorithm name to protect private key (default AES-256-CBC)
447 	 * @param {String} ivsaltHex hexadecimal string of IV and salt (default generated random IV)
448 	 * @return {String} string of PEM formatted encrypted PKCS#5 private key
449          * @since pkcs5pkey 1.0.2
450 	 * @description
451 	 * <br/>
452 	 * generate PEM formatted encrypted PKCS#5 private key by
453 	 * {@link RSAKey} object of RSA private key and passcode.
454 	 * Following argument can be omitted.
455 	 * <ul>
456 	 * <li>alg - AES-256-CBC will be used if omitted.</li>
457 	 * <li>ivsaltHex - automatically generate IV and salt which length depends on algorithm</li>
458 	 * </ul>
459 	 * @example
460 	 * var pkey = new RSAKey();
461 	 * pkey.generate(1024, '10001'); // generate 1024bit RSA private key with public exponent 'x010001'
462 	 * var pem = PKCS5PKEY.getEryptedPKCS5PEMFromRSAKey(pkey, "password");
463 	 */
464         getEryptedPKCS5PEMFromRSAKey: function(pKey, passcode, alg, ivsaltHex) {
465 	    var version = new KJUR.asn1.DERInteger({'int': 0});
466 	    var n = new KJUR.asn1.DERInteger({'bigint': pKey.n});
467 	    var e = new KJUR.asn1.DERInteger({'int': pKey.e});
468 	    var d = new KJUR.asn1.DERInteger({'bigint': pKey.d});
469 	    var p = new KJUR.asn1.DERInteger({'bigint': pKey.p});
470 	    var q = new KJUR.asn1.DERInteger({'bigint': pKey.q});
471 	    var dmp1 = new KJUR.asn1.DERInteger({'bigint': pKey.dmp1});
472 	    var dmq1 = new KJUR.asn1.DERInteger({'bigint': pKey.dmq1});
473 	    var coeff = new KJUR.asn1.DERInteger({'bigint': pKey.coeff});
474 	    var seq = new KJUR.asn1.DERSequence({'array': [version, n, e, d, p, q, dmp1, dmq1, coeff]});
475 	    var hex = seq.getEncodedHex();
476 	    return this.getEryptedPKCS5PEMFromPrvKeyHex(hex, passcode, alg, ivsaltHex);
477         },
478 
479 	/**
480          * generate RSAKey and PEM formatted encrypted PKCS#5 private key
481 	 * @name newEncryptedPKCS5PEM
482 	 * @memberOf PKCS5PKEY
483 	 * @function
484 	 * @param {String} passcode pass code to protect private key (ex. password)
485 	 * @param {Integer} keyLen key bit length of RSA key to be generated. (default 1024)
486 	 * @param {String} hPublicExponent hexadecimal string of public exponent (default 10001)
487 	 * @param {String} alg shared key algorithm to encrypt private key (default AES-258-CBC)
488 	 * @return {String} string of PEM formatted encrypted PKCS#5 private key
489          * @since pkcs5pkey 1.0.2
490 	 * @example
491 	 * var pem1 = PKCS5PKEY.newEncryptedPKCS5PEM("password");           // RSA1024bit/10001/AES-256-CBC
492 	 * var pem2 = PKCS5PKEY.newEncryptedPKCS5PEM("password", 512);      // RSA 512bit/10001/AES-256-CBC
493 	 * var pem3 = PKCS5PKEY.newEncryptedPKCS5PEM("password", 512, '3'); // RSA 512bit/    3/AES-256-CBC
494 	 */
495 	newEncryptedPKCS5PEM: function(passcode, keyLen, hPublicExponent, alg) {
496 	    if (typeof keyLen == "undefined" || keyLen == null) {
497 		keyLen = 1024;
498 	    }
499 	    if (typeof hPublicExponent == "undefined" || hPublicExponent == null) {
500 		hPublicExponent = '10001';
501 	    }
502 	    var pKey = new RSAKey();
503 	    pKey.generate(keyLen, hPublicExponent);
504 	    var pem = null;
505 	    if (typeof alg == "undefined" || alg == null) {
506 		pem = this.getEncryptedPKCS5PEMFromRSAKey(pkey, passcode);
507 	    } else {
508 		pem = this.getEncryptedPKCS5PEMFromRSAKey(pkey, passcode, alg);
509 	    }
510 	    return pem;
511         },
512 
513 	// === PKCS8 ===============================================================
514 
515 	/**
516          * read PEM formatted unencrypted PKCS#8 private key and returns RSAKey object
517 	 * @name getRSAKeyFromPlainPKCS8PEM
518 	 * @memberOf PKCS5PKEY
519 	 * @function
520 	 * @param {String} pkcs8PEM PEM formatted unencrypted PKCS#8 private key
521 	 * @return {RSAKey} loaded RSAKey object of RSA private key
522          * @since pkcs5pkey 1.0.1
523 	 */
524         getRSAKeyFromPlainPKCS8PEM: function(pkcs8PEM) {
525             if (pkcs8PEM.match(/ENCRYPTED/))
526                 throw "pem shall be not ENCRYPTED";
527             var prvKeyHex = this.getHexFromPEM(pkcs8PEM, "PRIVATE KEY");
528             var rsaKey = this.getRSAKeyFromPlainPKCS8Hex(prvKeyHex);
529 	    return rsaKey;
530         },
531 
532 	/**
533          * provide hexadecimal string of unencrypted PKCS#8 private key and returns RSAKey object
534 	 * @name getRSAKeyFromPlainPKCS8Hex
535 	 * @memberOf PKCS5PKEY
536 	 * @function
537 	 * @param {String} prvKeyHex hexadecimal string of unencrypted PKCS#8 private key
538 	 * @return {RSAKey} loaded RSAKey object of RSA private key
539          * @since pkcs5pkey 1.0.3
540 	 */
541         getRSAKeyFromPlainPKCS8Hex: function(prvKeyHex) {
542 	    var a1 = ASN1HEX.getPosArrayOfChildren_AtObj(prvKeyHex, 0);
543 	    if (a1.length != 3)
544 		throw "outer DERSequence shall have 3 elements: " + a1.length;
545             var algIdTLV =ASN1HEX.getHexOfTLV_AtObj(prvKeyHex, a1[1]);
546 	    if (algIdTLV != "300d06092a864886f70d0101010500") // AlgId rsaEncryption
547 		throw "PKCS8 AlgorithmIdentifier is not rsaEnc: " + algIdTLV;
548             var algIdTLV = ASN1HEX.getHexOfTLV_AtObj(prvKeyHex, a1[1]);
549 	    var octetStr = ASN1HEX.getHexOfTLV_AtObj(prvKeyHex, a1[2]);
550 	    var p5KeyHex = ASN1HEX.getHexOfV_AtObj(octetStr, 0);
551             //alert(p5KeyHex);
552 	    var rsaKey = new RSAKey();
553 	    rsaKey.readPrivateKeyFromASN1HexString(p5KeyHex);
554 	    return rsaKey;
555         },
556 
557 	/**
558          * generate PBKDF2 key hexstring with specified passcode and information
559 	 * @name parseHexOfEncryptedPKCS8
560 	 * @memberOf PKCS5PKEY
561 	 * @function
562 	 * @param {String} passcode passcode to decrypto private key
563 	 * @return {Array} info associative array of PKCS#8 parameters
564          * @since pkcs5pkey 1.0.3
565 	 * @description
566 	 * The associative array which is returned by this method has following properties:
567 	 * <ul>
568 	 * <li>info.pbkdf2Salt - hexadecimal string of PBKDF2 salt</li>
569 	 * <li>info.pkbdf2Iter - iteration count</li>
570 	 * <li>info.ciphertext - hexadecimal string of encrypted private key</li>
571 	 * <li>info.encryptionSchemeAlg - encryption algorithm name (currently TripleDES only)</li>
572 	 * <li>info.encryptionSchemeIV - initial vector for encryption algorithm</li>
573 	 * </ul>
574 	 * Currently, this method only supports PKCS#5v2.0 with PBES2/PBDKF2 of HmacSHA1 and TripleDES.
575 	 * <ul>
576 	 * <li>keyDerivationFunc = pkcs5PBKDF2 with HmacSHA1</li>
577 	 * <li>encryptionScheme = des-EDE3-CBC(i.e. TripleDES</li>
578 	 * </ul>
579 	 * @example
580 	 * // to convert plain PKCS#5 private key to encrypted PKCS#8 private
581 	 * // key with PBKDF2 with TripleDES
582 	 * % openssl pkcs8 -in plain_p5.pem -topk8 -v2 -des3 -out encrypted_p8.pem
583 	 */
584         parseHexOfEncryptedPKCS8: function(sHEX) {
585             var info = {};
586 	    
587 	    var a0 = ASN1HEX.getPosArrayOfChildren_AtObj(sHEX, 0);
588 	    if (a0.length != 2)
589 		throw "malformed format: SEQUENCE(0).items != 2: " + a0.length;
590 
591 	    // 1. ciphertext
592 	    info.ciphertext = ASN1HEX.getHexOfV_AtObj(sHEX, a0[1]);
593 
594 	    // 2. pkcs5PBES2
595 	    var a0_0 = ASN1HEX.getPosArrayOfChildren_AtObj(sHEX, a0[0]); 
596 	    if (a0_0.length != 2)
597 		throw "malformed format: SEQUENCE(0.0).items != 2: " + a0_0.length;
598 
599 	    // 2.1 check if pkcs5PBES2(1 2 840 113549 1 5 13)
600 	    if (ASN1HEX.getHexOfV_AtObj(sHEX, a0_0[0]) != "2a864886f70d01050d")
601 		throw "this only supports pkcs5PBES2";
602 
603 	    // 2.2 pkcs5PBES2 param
604             var a0_0_1 = ASN1HEX.getPosArrayOfChildren_AtObj(sHEX, a0_0[1]); 
605 	    if (a0_0.length != 2)
606 		throw "malformed format: SEQUENCE(0.0.1).items != 2: " + a0_0_1.length;
607 
608 	    // 2.2.1 encryptionScheme
609 	    var a0_0_1_1 = ASN1HEX.getPosArrayOfChildren_AtObj(sHEX, a0_0_1[1]); 
610 	    if (a0_0_1_1.length != 2)
611 		throw "malformed format: SEQUENCE(0.0.1.1).items != 2: " + a0_0_1_1.length;
612 	    if (ASN1HEX.getHexOfV_AtObj(sHEX, a0_0_1_1[0]) != "2a864886f70d0307")
613 		throw "this only supports TripleDES";
614 	    info.encryptionSchemeAlg = "TripleDES";
615 
616 	    // 2.2.1.1 IV of encryptionScheme
617 	    info.encryptionSchemeIV = ASN1HEX.getHexOfV_AtObj(sHEX, a0_0_1_1[1]);
618 
619 	    // 2.2.2 keyDerivationFunc
620 	    var a0_0_1_0 = ASN1HEX.getPosArrayOfChildren_AtObj(sHEX, a0_0_1[0]); 
621 	    if (a0_0_1_0.length != 2)
622 		throw "malformed format: SEQUENCE(0.0.1.0).items != 2: " + a0_0_1_0.length;
623 	    if (ASN1HEX.getHexOfV_AtObj(sHEX, a0_0_1_0[0]) != "2a864886f70d01050c")
624 		throw "this only supports pkcs5PBKDF2";
625 
626 	    // 2.2.2.1 pkcs5PBKDF2 param
627 	    var a0_0_1_0_1 = ASN1HEX.getPosArrayOfChildren_AtObj(sHEX, a0_0_1_0[1]); 
628 	    if (a0_0_1_0_1.length < 2)
629 		throw "malformed format: SEQUENCE(0.0.1.0.1).items < 2: " + a0_0_1_0_1.length;
630 
631 	    // 2.2.2.1.1 PBKDF2 salt
632 	    info.pbkdf2Salt = ASN1HEX.getHexOfV_AtObj(sHEX, a0_0_1_0_1[0]);
633 
634 	    // 2.2.2.1.2 PBKDF2 iter
635 	    var iterNumHex = ASN1HEX.getHexOfV_AtObj(sHEX, a0_0_1_0_1[1]);
636 	    try {
637 		info.pbkdf2Iter = parseInt(iterNumHex, 16);
638 	    } catch(ex) {
639 		throw "malformed format pbkdf2Iter: " + iterNumHex;
640 	    }
641 
642 	    return info;
643 	},
644 
645 	/**
646          * generate PBKDF2 key hexstring with specified passcode and information
647 	 * @name getPBKDF2KeyHexFromParam
648 	 * @memberOf PKCS5PKEY
649 	 * @function
650 	 * @param {Array} info result of {@link parseHexOfEncryptedPKCS8} which has preference of PKCS#8 file
651 	 * @param {String} passcode passcode to decrypto private key
652 	 * @return {String} hexadecimal string of PBKDF2 key
653          * @since pkcs5pkey 1.0.3
654 	 * @description
655 	 * As for info, this uses following properties:
656 	 * <ul>
657 	 * <li>info.pbkdf2Salt - hexadecimal string of PBKDF2 salt</li>
658 	 * <li>info.pkbdf2Iter - iteration count</li>
659 	 * </ul>
660 	 * Currently, this method only supports PKCS#5v2.0 with PBES2/PBDKF2 of HmacSHA1 and TripleDES.
661 	 * <ul>
662 	 * <li>keyDerivationFunc = pkcs5PBKDF2 with HmacSHA1</li>
663 	 * <li>encryptionScheme = des-EDE3-CBC(i.e. TripleDES</li>
664 	 * </ul>
665 	 * @example
666 	 * // to convert plain PKCS#5 private key to encrypted PKCS#8 private
667 	 * // key with PBKDF2 with TripleDES
668 	 * % openssl pkcs8 -in plain_p5.pem -topk8 -v2 -des3 -out encrypted_p8.pem
669 	 */
670 	getPBKDF2KeyHexFromParam: function(info, passcode) {
671 	    var pbkdf2SaltWS = CryptoJS.enc.Hex.parse(info.pbkdf2Salt);
672 	    var pbkdf2Iter = info.pbkdf2Iter;
673 	    var pbkdf2KeyWS = CryptoJS.PBKDF2(passcode, 
674 					      pbkdf2SaltWS, 
675 					      { keySize: 192/32, iterations: pbkdf2Iter });
676 	    var pbkdf2KeyHex = CryptoJS.enc.Hex.stringify(pbkdf2KeyWS);
677 	    return pbkdf2KeyHex;
678 	},
679 
680 	/**
681          * read PEM formatted encrypted PKCS#8 private key and returns hexadecimal string of plain PKCS#8 private key
682 	 * @name getPlainPKCS8HexFromEncryptedPKCS8PEM
683 	 * @memberOf PKCS5PKEY
684 	 * @function
685 	 * @param {String} pkcs8PEM PEM formatted encrypted PKCS#8 private key
686 	 * @param {String} passcode passcode to decrypto private key
687 	 * @return {String} hexadecimal string of plain PKCS#8 private key
688          * @since pkcs5pkey 1.0.3
689 	 * @description
690 	 * Currently, this method only supports PKCS#5v2.0 with PBES2/PBDKF2 of HmacSHA1 and TripleDES.
691 	 * <ul>
692 	 * <li>keyDerivationFunc = pkcs5PBKDF2 with HmacSHA1</li>
693 	 * <li>encryptionScheme = des-EDE3-CBC(i.e. TripleDES</li>
694 	 * </ul>
695 	 * @example
696 	 * // to convert plain PKCS#5 private key to encrypted PKCS#8 private
697 	 * // key with PBKDF2 with TripleDES
698 	 * % openssl pkcs8 -in plain_p5.pem -topk8 -v2 -des3 -out encrypted_p8.pem
699 	 */
700 	getPlainPKCS8HexFromEncryptedPKCS8PEM: function(pkcs8PEM, passcode) {
701 	    // 1. derHex - PKCS#8 private key encrypted by PBKDF2
702             var derHex = this.getHexFromPEM(pkcs8PEM, "ENCRYPTED PRIVATE KEY");
703 	    // 2. info - PKCS#5 PBES info
704 	    var info = this.parseHexOfEncryptedPKCS8(derHex);
705 	    // 3. hKey - PBKDF2 key
706 	    var pbkdf2KeyHex = PKCS5PKEY.getPBKDF2KeyHexFromParam(info, passcode);
707 	    // 4. decrypt ciphertext by PBKDF2 key
708 	    var encrypted = {};
709 	    encrypted.ciphertext = CryptoJS.enc.Hex.parse(info.ciphertext);
710 	    var pbkdf2KeyWS = CryptoJS.enc.Hex.parse(pbkdf2KeyHex);
711 	    var des3IVWS = CryptoJS.enc.Hex.parse(info.encryptionSchemeIV);
712 	    var decWS = CryptoJS.TripleDES.decrypt(encrypted, pbkdf2KeyWS, { iv: des3IVWS });
713 	    var decHex = CryptoJS.enc.Hex.stringify(decWS);
714 	    return decHex;
715 	},
716 
717 	/**
718          * read PEM formatted encrypted PKCS#8 private key and returns RSAKey object
719 	 * @name getRSAKeyFromEncryptedPKCS8PEM
720 	 * @memberOf PKCS5PKEY
721 	 * @function
722 	 * @param {String} pkcs8PEM PEM formatted encrypted PKCS#8 private key
723 	 * @param {String} passcode passcode to decrypto private key
724 	 * @return {RSAKey} loaded RSAKey object of RSA 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         getRSAKeyFromEncryptedPKCS8PEM: function(pkcs8PEM, passcode) {
738 	    var prvKeyHex = this.getPlainPKCS8HexFromEncryptedPKCS8PEM(pkcs8PEM, passcode);
739 	    var rsaKey = this.getRSAKeyFromPlainPKCS8Hex(prvKeyHex);
740 	    return rsaKey;
741         },
742 
743 	/**
744          * get RSAKey/ECDSA private key object from encrypted PEM PKCS#8 private key
745 	 * @name getKeyFromEncryptedPKCS8PEM
746 	 * @memberOf PKCS5PKEY
747 	 * @function
748 	 * @param {String} pkcs8PEM string of PEM formatted PKCS#8 private key
749 	 * @param {String} passcode passcode string to decrypt key
750 	 * @return {Object} RSAKey or KJUR.crypto.ECDSA private key object
751 	 * @since pkcs5pkey 1.0.5
752 	 */
753         getKeyFromEncryptedPKCS8PEM: function(pkcs8PEM, passcode) {
754 	    var prvKeyHex = this.getPlainPKCS8HexFromEncryptedPKCS8PEM(pkcs8PEM, passcode);
755 	    var key = this.getKeyFromPlainPrivatePKCS8Hex(prvKeyHex);
756 	    return key;
757         },
758 
759 	/**
760          * parse hexadecimal string of plain PKCS#8 private key
761 	 * @name parsePlainPrivatePKCS8Hex
762 	 * @memberOf PKCS5PKEY
763 	 * @function
764 	 * @param {String} pkcs8PrvHex hexadecimal string of PKCS#8 plain private key
765 	 * @return {Array} associative array of parsed key
766 	 * @since pkcs5pkey 1.0.5
767 	 * @description
768 	 * Resulted associative array has following properties:
769 	 * <ul>
770 	 * <li>algoid - hexadecimal string of OID of asymmetric key algorithm</li>
771 	 * <li>algparam - hexadecimal string of OID of ECC curve name or null</li>
772 	 * <li>keyidx - string starting index of key in pkcs8PrvHex</li>
773 	 * </ul>
774 	 */
775 	parsePlainPrivatePKCS8Hex: function(pkcs8PrvHex) {
776 	    var result = {};
777 	    result.algparam = null;
778 
779 	    // 1. sequence
780 	    if (pkcs8PrvHex.substr(0, 2) != "30")
781 		throw "malformed plain PKCS8 private key(code:001)"; // not sequence
782 
783 	    var a1 = ASN1HEX.getPosArrayOfChildren_AtObj(pkcs8PrvHex, 0);
784 	    if (a1.length != 3)
785 		throw "malformed plain PKCS8 private key(code:002)";
786 
787 	    // 2. AlgID
788             if (pkcs8PrvHex.substr(a1[1], 2) != "30")
789                 throw "malformed PKCS8 private key(code:003)"; // AlgId not sequence
790 
791             var a2 = ASN1HEX.getPosArrayOfChildren_AtObj(pkcs8PrvHex, a1[1]);
792             if (a2.length != 2)
793                 throw "malformed PKCS8 private key(code:004)"; // AlgId not have two elements
794 
795 	    // 2.1. AlgID OID
796 	    if (pkcs8PrvHex.substr(a2[0], 2) != "06")
797 		throw "malformed PKCS8 private key(code:005)"; // AlgId.oid is not OID
798 
799 	    result.algoid = ASN1HEX.getHexOfV_AtObj(pkcs8PrvHex, a2[0]);
800 
801 	    // 2.2. AlgID param
802 	    if (pkcs8PrvHex.substr(a2[1], 2) == "06") {
803 		result.algparam = ASN1HEX.getHexOfV_AtObj(pkcs8PrvHex, a2[1]);
804 	    }
805 
806 	    // 3. Key index
807 	    if (pkcs8PrvHex.substr(a1[2], 2) != "04")
808 		throw "malformed PKCS8 private key(code:006)"; // not octet string
809 
810 	    result.keyidx = ASN1HEX.getStartPosOfV_AtObj(pkcs8PrvHex, a1[2]);
811 
812 	    return result;
813         },
814 
815 	/**
816          * get RSAKey/ECDSA private key object from PEM plain PEM PKCS#8 private key
817 	 * @name getKeyFromPlainPrivatePKCS8PEM
818 	 * @memberOf PKCS5PKEY
819 	 * @function
820 	 * @param {String} pkcs8PEM string of plain PEM formatted PKCS#8 private key
821 	 * @return {Object} RSAKey or KJUR.crypto.ECDSA private key object
822 	 * @since pkcs5pkey 1.0.5
823 	 */
824 	getKeyFromPlainPrivatePKCS8PEM: function(prvKeyPEM) {
825 	    var prvKeyHex = this.getHexFromPEM(prvKeyPEM, "PRIVATE KEY");
826 	    var key = this.getKeyFromPlainPrivatePKCS8Hex(prvKeyHex);
827 	    return key;
828 	},
829 
830 	/**
831          * get RSAKey/ECDSA private key object from HEX plain PEM PKCS#8 private key
832 	 * @name getKeyFromPlainPrivatePKCS8Hex
833 	 * @memberOf PKCS5PKEY
834 	 * @function
835 	 * @param {String} prvKeyHex hexadecimal string of plain PKCS#8 private key
836 	 * @return {Object} RSAKey or KJUR.crypto.ECDSA private key object
837 	 * @since pkcs5pkey 1.0.5
838 	 */
839 	getKeyFromPlainPrivatePKCS8Hex: function(prvKeyHex) {
840 	    var p8 = this.parsePlainPrivatePKCS8Hex(prvKeyHex);
841 	    
842 	    if (p8.algoid == "2a864886f70d010101") { // RSA
843 		this.parsePrivateRawRSAKeyHexAtObj(prvKeyHex, p8);
844 		var k = p8.key;
845 		var key = new RSAKey();
846 		key.setPrivateEx(k.n, k.e, k.d, k.p, k.q, k.dp, k.dq, k.co);
847 		return key;
848 	    } else if (p8.algoid == "2a8648ce3d0201") { // ECC
849 		this.parsePrivateRawECKeyHexAtObj(prvKeyHex, p8);
850 		if (KJUR.crypto.OID.oidhex2name[p8.algparam] === undefined)
851 		    throw "KJUR.crypto.OID.oidhex2name undefined: " + p8.algparam;
852 		var curveName = KJUR.crypto.OID.oidhex2name[p8.algparam];
853 		var key = new KJUR.crypto.ECDSA({'curve': curveName, 'prv': p8.key});
854 		return key;
855 	    } else {
856 		throw "unsupported private key algorithm";
857 	    }
858 	},
859 
860 	// === PKCS8 RSA Public Key ================================================
861 	/**
862          * read PEM formatted PKCS#8 public key and returns RSAKey object
863 	 * @name getRSAKeyFromPublicPKCS8PEM
864 	 * @memberOf PKCS5PKEY
865 	 * @function
866 	 * @param {String} pkcs8PubPEM PEM formatted PKCS#8 public key
867 	 * @return {RSAKey} loaded RSAKey object of RSA public key
868          * @since pkcs5pkey 1.0.4
869 	 */
870         getRSAKeyFromPublicPKCS8PEM: function(pkcs8PubPEM) {
871             var pubKeyHex = this.getHexFromPEM(pkcs8PubPEM, "PUBLIC KEY");
872             var rsaKey = this.getRSAKeyFromPublicPKCS8Hex(pubKeyHex);
873 	    return rsaKey;
874 	},
875 
876 	/**
877          * get RSAKey/ECDSA public key object from PEM PKCS#8 public key
878 	 * @name getKeyFromPublicPKCS8PEM
879 	 * @memberOf PKCS5PKEY
880 	 * @function
881 	 * @param {String} pkcsPub8PEM string of PEM formatted PKCS#8 public key
882 	 * @return {Object} RSAKey or KJUR.crypto.ECDSA private key object
883 	 * @since pkcs5pkey 1.0.5
884 	 */
885         getKeyFromPublicPKCS8PEM: function(pkcs8PubPEM) {
886             var pubKeyHex = this.getHexFromPEM(pkcs8PubPEM, "PUBLIC KEY");
887             var key = this.getKeyFromPublicPKCS8Hex(pubKeyHex);
888 	    return key;
889 	},
890 
891 	/**
892          * get RSAKey/ECDSA public key object from hexadecimal string of PKCS#8 public key
893 	 * @name getKeyFromPublicPKCS8Hex
894 	 * @memberOf PKCS5PKEY
895 	 * @function
896 	 * @param {String} pkcsPub8Hex hexadecimal string of PKCS#8 public key
897 	 * @return {Object} RSAKey or KJUR.crypto.ECDSA private key object
898 	 * @since pkcs5pkey 1.0.5
899 	 */
900         getKeyFromPublicPKCS8Hex: function(pkcs8PubHex) {
901 	    var p8 = this.parsePublicPKCS8Hex(pkcs8PubHex);
902 	    
903 	    if (p8.algoid == "2a864886f70d010101") { // RSA
904 		var aRSA = this.parsePublicRawRSAKeyHex(p8.key);
905 		var key = new RSAKey();
906 		key.setPublic(aRSA.n, aRSA.e);
907 		return key;
908 	    } else if (p8.algoid == "2a8648ce3d0201") { // ECC
909 		if (KJUR.crypto.OID.oidhex2name[p8.algparam] === undefined)
910 		    throw "KJUR.crypto.OID.oidhex2name undefined: " + p8.algparam;
911 		var curveName = KJUR.crypto.OID.oidhex2name[p8.algparam];
912 		var key = new KJUR.crypto.ECDSA({'curve': curveName, 'pub': p8.key});
913 		return key;
914 	    } else {
915 		throw "unsupported public key algorithm";
916 	    }
917 	},
918 
919 	/**
920          * parse hexadecimal string of plain PKCS#8 private key
921 	 * @name parsePublicRawRSAKeyHex
922 	 * @memberOf PKCS5PKEY
923 	 * @function
924 	 * @param {String} pubRawRSAHex hexadecimal string of ASN.1 encoded PKCS#8 public key
925 	 * @return {Array} associative array of parsed key
926 	 * @since pkcs5pkey 1.0.5
927 	 * @description
928 	 * Resulted associative array has following properties:
929 	 * <ul>
930 	 * <li>n - hexadecimal string of public key
931 	 * <li>e - hexadecimal string of public exponent
932 	 * </ul>
933 	 */
934 	parsePublicRawRSAKeyHex: function(pubRawRSAHex) {
935 	    var result = {};
936 	    
937 	    // 1. Sequence
938 	    if (pubRawRSAHex.substr(0, 2) != "30")
939 		throw "malformed RSA key(code:001)"; // not sequence
940 	    
941 	    var a1 = ASN1HEX.getPosArrayOfChildren_AtObj(pubRawRSAHex, 0);
942 	    if (a1.length != 2)
943 		throw "malformed RSA key(code:002)"; // not 2 items in seq
944 
945 	    // 2. public key "N"
946 	    if (pubRawRSAHex.substr(a1[0], 2) != "02")
947 		throw "malformed RSA key(code:003)"; // 1st item is not integer
948 
949 	    result.n = ASN1HEX.getHexOfV_AtObj(pubRawRSAHex, a1[0]);
950 
951 	    // 3. public key "E"
952 	    if (pubRawRSAHex.substr(a1[1], 2) != "02")
953 		throw "malformed RSA key(code:004)"; // 2nd item is not integer
954 
955 	    result.e = ASN1HEX.getHexOfV_AtObj(pubRawRSAHex, a1[1]);
956 
957 	    return result;
958 	},
959 
960 	/**
961          * parse hexadecimal string of RSA private key
962 	 * @name parsePrivateRawRSAKeyHexAtObj
963 	 * @memberOf PKCS5PKEY
964 	 * @function
965 	 * @param {String} pkcs8PrvHex hexadecimal string of PKCS#8 private key concluding RSA private key
966 	 * @return {Array} info associative array to add parsed RSA private key information
967 	 * @since pkcs5pkey 1.0.5
968 	 * @description
969 	 * Following properties are added to associative array 'info'
970 	 * <ul>
971 	 * <li>n - hexadecimal string of public key
972 	 * <li>e - hexadecimal string of public exponent
973 	 * <li>d - hexadecimal string of private key
974 	 * <li>p - hexadecimal string
975 	 * <li>q - hexadecimal string
976 	 * <li>dp - hexadecimal string
977 	 * <li>dq - hexadecimal string
978 	 * <li>co - hexadecimal string
979 	 * </ul>
980 	 */
981 	parsePrivateRawRSAKeyHexAtObj: function(pkcs8PrvHex, info) {
982 	    var keyIdx = info.keyidx;
983 	    
984 	    // 1. sequence
985 	    if (pkcs8PrvHex.substr(keyIdx, 2) != "30")
986 		throw "malformed RSA private key(code:001)"; // not sequence
987 
988 	    var a1 = ASN1HEX.getPosArrayOfChildren_AtObj(pkcs8PrvHex, keyIdx);
989 	    if (a1.length != 9)
990 		throw "malformed RSA private key(code:002)"; // not sequence
991 
992 	    // 2. RSA key
993 	    info.key = {};
994 	    info.key.n = ASN1HEX.getHexOfV_AtObj(pkcs8PrvHex, a1[1]);
995 	    info.key.e = ASN1HEX.getHexOfV_AtObj(pkcs8PrvHex, a1[2]);
996 	    info.key.d = ASN1HEX.getHexOfV_AtObj(pkcs8PrvHex, a1[3]);
997 	    info.key.p = ASN1HEX.getHexOfV_AtObj(pkcs8PrvHex, a1[4]);
998 	    info.key.q = ASN1HEX.getHexOfV_AtObj(pkcs8PrvHex, a1[5]);
999 	    info.key.dp = ASN1HEX.getHexOfV_AtObj(pkcs8PrvHex, a1[6]);
1000 	    info.key.dq = ASN1HEX.getHexOfV_AtObj(pkcs8PrvHex, a1[7]);
1001 	    info.key.co = ASN1HEX.getHexOfV_AtObj(pkcs8PrvHex, a1[8]);
1002 	},
1003 
1004 	/**
1005          * parse hexadecimal string of ECC private key
1006 	 * @name parsePrivateRawECKeyHexAtObj
1007 	 * @memberOf PKCS5PKEY
1008 	 * @function
1009 	 * @param {String} pkcs8PrvHex hexadecimal string of PKCS#8 private key concluding EC private key
1010 	 * @return {Array} info associative array to add parsed ECC private key information
1011 	 * @since pkcs5pkey 1.0.5
1012 	 * @description
1013 	 * Following properties are added to associative array 'info'
1014 	 * <ul>
1015 	 * <li>key - hexadecimal string of ECC private key
1016 	 * </ul>
1017 	 */
1018 	parsePrivateRawECKeyHexAtObj: function(pkcs8PrvHex, info) {
1019 	    var keyIdx = info.keyidx;
1020 	    
1021 	    // 1. sequence
1022 	    if (pkcs8PrvHex.substr(keyIdx, 2) != "30")
1023 		throw "malformed ECC private key(code:001)"; // not sequence
1024 
1025 	    var a1 = ASN1HEX.getPosArrayOfChildren_AtObj(pkcs8PrvHex, keyIdx);
1026 	    if (a1.length != 3)
1027 		throw "malformed ECC private key(code:002)"; // not sequence
1028 
1029 	    // 2. EC private key
1030 	    if (pkcs8PrvHex.substr(a1[1], 2) != "04")
1031 		throw "malformed ECC private key(code:003)"; // not octetstring
1032 
1033 	    info.key = ASN1HEX.getHexOfV_AtObj(pkcs8PrvHex, a1[1]);
1034 	},
1035 
1036 	/**
1037          * parse hexadecimal string of PKCS#8 public key
1038 	 * @name parsePublicPKCS8Hex
1039 	 * @memberOf PKCS5PKEY
1040 	 * @function
1041 	 * @param {String} pkcs8PubHex hexadecimal string of PKCS#8 public key
1042 	 * @return {Hash} hash of key information
1043 	 * @description
1044          * Resulted hash has following attributes.
1045 	 * <ul>
1046 	 * <li>algoid - hexadecimal string of OID of asymmetric key algorithm</li>
1047 	 * <li>algparam - hexadecimal string of OID of ECC curve name or null</li>
1048 	 * <li>key - hexadecimal string of public key</li>
1049 	 * </ul>
1050 	 */
1051         parsePublicPKCS8Hex: function(pkcs8PubHex) {
1052 	    var result = {};
1053 	    result.algparam = null;
1054 
1055             // 1. AlgID and Key bit string
1056 	    var a1 = ASN1HEX.getPosArrayOfChildren_AtObj(pkcs8PubHex, 0);
1057 	    if (a1.length != 2)
1058 		throw "outer DERSequence shall have 2 elements: " + a1.length;
1059 
1060             // 2. AlgID
1061             var idxAlgIdTLV = a1[0];
1062             if (pkcs8PubHex.substr(idxAlgIdTLV, 2) != "30")
1063                 throw "malformed PKCS8 public key(code:001)"; // AlgId not sequence
1064 
1065             var a2 = ASN1HEX.getPosArrayOfChildren_AtObj(pkcs8PubHex, idxAlgIdTLV);
1066             if (a2.length != 2)
1067                 throw "malformed PKCS8 public key(code:002)"; // AlgId not have two elements
1068 
1069 	    // 2.1. AlgID OID
1070 	    if (pkcs8PubHex.substr(a2[0], 2) != "06")
1071 		throw "malformed PKCS8 public key(code:003)"; // AlgId.oid is not OID
1072 
1073 	    result.algoid = ASN1HEX.getHexOfV_AtObj(pkcs8PubHex, a2[0]);
1074 
1075 	    // 2.2. AlgID param
1076 	    if (pkcs8PubHex.substr(a2[1], 2) == "06") {
1077 		result.algparam = ASN1HEX.getHexOfV_AtObj(pkcs8PubHex, a2[1]);
1078 	    }
1079 
1080 	    // 3. Key
1081 	    if (pkcs8PubHex.substr(a1[1], 2) != "03")
1082 		throw "malformed PKCS8 public key(code:004)"; // Key is not bit string
1083 
1084 	    result.key = ASN1HEX.getHexOfV_AtObj(pkcs8PubHex, a1[1]).substr(2);
1085             
1086 	    // 4. return result assoc array
1087 	    return result;
1088         },
1089 
1090 	/**
1091          * provide hexadecimal string of unencrypted PKCS#8 private key and returns RSAKey object
1092 	 * @name getRSAKeyFromPublicPKCS8Hex
1093 	 * @memberOf PKCS5PKEY
1094 	 * @function
1095 	 * @param {String} pkcs8PubHex hexadecimal string of unencrypted PKCS#8 public key
1096 	 * @return {RSAKey} loaded RSAKey object of RSA public key
1097          * @since pkcs5pkey 1.0.4
1098 	 */
1099         getRSAKeyFromPublicPKCS8Hex: function(pkcs8PubHex) {
1100 	    var a1 = ASN1HEX.getPosArrayOfChildren_AtObj(pkcs8PubHex, 0);
1101 	    if (a1.length != 2)
1102 		throw "outer DERSequence shall have 2 elements: " + a1.length;
1103 
1104             var algIdTLV =ASN1HEX.getHexOfTLV_AtObj(pkcs8PubHex, a1[0]);
1105 	    if (algIdTLV != "300d06092a864886f70d0101010500") // AlgId rsaEncryption
1106 		throw "PKCS8 AlgorithmId is not rsaEncryption";
1107 	    
1108 	    if (pkcs8PubHex.substr(a1[1], 2) != "03")
1109 		throw "PKCS8 Public Key is not BITSTRING encapslated.";
1110 
1111 	    var idxPub = ASN1HEX.getStartPosOfV_AtObj(pkcs8PubHex, a1[1]) + 2; // 2 for unused bit
1112 	    
1113 	    if (pkcs8PubHex.substr(idxPub, 2) != "30")
1114 		throw "PKCS8 Public Key is not SEQUENCE.";
1115 
1116 	    var a2 = ASN1HEX.getPosArrayOfChildren_AtObj(pkcs8PubHex, idxPub);
1117 	    if (a2.length != 2)
1118 		throw "inner DERSequence shall have 2 elements: " + a2.length;
1119 
1120 	    if (pkcs8PubHex.substr(a2[0], 2) != "02") 
1121 		throw "N is not ASN.1 INTEGER";
1122 	    if (pkcs8PubHex.substr(a2[1], 2) != "02") 
1123 		throw "E is not ASN.1 INTEGER";
1124 		
1125 	    var hN = ASN1HEX.getHexOfV_AtObj(pkcs8PubHex, a2[0]);
1126 	    var hE = ASN1HEX.getHexOfV_AtObj(pkcs8PubHex, a2[1]);
1127 
1128 	    var pubKey = new RSAKey();
1129 	    pubKey.setPublic(hN, hE);
1130 	    
1131 	    return pubKey;
1132 	},
1133 
1134 	//addAlgorithm: function(functionObject, algName, keyLen, ivLen) {
1135 	//}
1136     };
1137 }();
1138