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