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