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