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