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