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