/*! keyutil-1.0.12.js (c) 2013-2015 Kenji Urushima | kjur.github.com/jsrsasign/license */ /* * keyutil.js - key utility for PKCS#1/5/8 PEM, RSA/DSA/ECDSA key object * * Copyright (c) 2013-2015 Kenji Urushima (kenji.urushima@gmail.com) * * This software is licensed under the terms of the MIT License. * http://kjur.github.com/jsrsasign/license * * The above copyright and license notice shall be * included in all copies or substantial portions of the Software. */ /** * @fileOverview * @name keyutil-1.0.js * @author Kenji Urushima kenji.urushima@gmail.com * @version keyutil 1.0.12 (2015-Oct-14) * @since jsrsasign 4.1.4 * @license MIT License */ /** * @name KEYUTIL * @class class for RSA/ECC/DSA key utility * @description *
* {@link KEYUTIL} class is an update of former {@link PKCS5PKEY} class. * So for now, {@link PKCS5PKEY} is deprecated class. * {@link KEYUTIL} class has following features: *
*
key loading - {@link KEYUTIL.getKey} *
* * NOTE1: Encrypted PKCS#8 only supports PBKDF2/HmacSHA1/3DES
* NOTE2: Encrypted PKCS#5 supports DES-CBC, DES-EDE3-CBC, AES-{128,192.256}-CBC
* *
exporting key - {@link KEYUTIL.getPEM} *
* {@link KEYUTIL.getPEM} method supports following formats: * * *
keypair generation - {@link KEYUTIL.generateKeypair} * * NOTE: {@link KJUR.crypto.DSA} is not yet supported. *
* * @example * // 1. loading PEM private key * var key = KEYUTIL.getKey(pemPKCS1PrivateKey); * var key = KEYUTIL.getKey(pemPKCS5EncryptedPrivateKey, "passcode"); * var key = KEYUTIL.getKey(pemPKC85PlainPrivateKey); * var key = KEYUTIL.getKey(pemPKC85EncryptedPrivateKey, "passcode"); * // 2. loading PEM public key * var key = KEYUTIL.getKey(pemPKCS8PublicKey); * var key = KEYUTIL.getKey(pemX509Certificate); * // 3. exporting private key * var pem = KEYUTIL.getPEM(privateKeyObj, "PKCS1PRV"); * var pem = KEYUTIL.getPEM(privateKeyObj, "PKCS5PRV", "passcode"); // DES-EDE3-CBC by default * var pem = KEYUTIL.getPEM(privateKeyObj, "PKCS5PRV", "passcode", "DES-CBC"); * var pem = KEYUTIL.getPEM(privateKeyObj, "PKCS8PRV"); * var pem = KEYUTIL.getPEM(privateKeyObj, "PKCS8PRV", "passcode"); * // 4. exporting public key * var pem = KEYUTIL.getPEM(publicKeyObj); */ /* * DEPRECATED METHODS * GET PKCS8 * KEYUTIL.getRSAKeyFromPlainPKCS8PEM * KEYUTIL.getRSAKeyFromPlainPKCS8Hex * KEYUTIL.getRSAKeyFromEncryptedPKCS8PEM * P8 UTIL (make internal use) * KEYUTIL.getPlainPKCS8HexFromEncryptedPKCS8PEM * GET PKCS8 PUB * KEYUTIL.getKeyFromPublicPKCS8PEM * KEYUTIL.getKeyFromPublicPKCS8Hex * KEYUTIL.getRSAKeyFromPublicPKCS8PEM * KEYUTIL.getRSAKeyFromPublicPKCS8Hex * GET PKCS5 * KEYUTIL.getRSAKeyFromEncryptedPKCS5PEM * PUT PKCS5 * KEYUTIL.getEncryptedPKCS5PEMFromRSAKey * OTHER METHODS (FOR INTERNAL?) * KEYUTIL.getHexFromPEM * KEYUTIL.getDecryptedKeyHexByKeyIV */ var KEYUTIL = function() { // ***************************************************************** // *** PRIVATE PROPERTIES AND METHODS ******************************* // ***************************************************************** // shared key decryption ------------------------------------------ var decryptAES = function(dataHex, keyHex, ivHex) { return decryptGeneral(CryptoJS.AES, dataHex, keyHex, ivHex); }; var decrypt3DES = function(dataHex, keyHex, ivHex) { return decryptGeneral(CryptoJS.TripleDES, dataHex, keyHex, ivHex); }; var decryptDES = function(dataHex, keyHex, ivHex) { return decryptGeneral(CryptoJS.DES, dataHex, keyHex, ivHex); }; var decryptGeneral = function(f, dataHex, keyHex, ivHex) { var data = CryptoJS.enc.Hex.parse(dataHex); var key = CryptoJS.enc.Hex.parse(keyHex); var iv = CryptoJS.enc.Hex.parse(ivHex); var encrypted = {}; encrypted.key = key; encrypted.iv = iv; encrypted.ciphertext = data; var decrypted = f.decrypt(encrypted, key, { iv: iv }); return CryptoJS.enc.Hex.stringify(decrypted); }; // shared key decryption ------------------------------------------ var encryptAES = function(dataHex, keyHex, ivHex) { return encryptGeneral(CryptoJS.AES, dataHex, keyHex, ivHex); }; var encrypt3DES = function(dataHex, keyHex, ivHex) { return encryptGeneral(CryptoJS.TripleDES, dataHex, keyHex, ivHex); }; var encryptDES = function(dataHex, keyHex, ivHex) { return encryptGeneral(CryptoJS.DES, dataHex, keyHex, ivHex); }; var encryptGeneral = function(f, dataHex, keyHex, ivHex) { var data = CryptoJS.enc.Hex.parse(dataHex); var key = CryptoJS.enc.Hex.parse(keyHex); var iv = CryptoJS.enc.Hex.parse(ivHex); var encryptedHex = f.encrypt(data, key, { iv: iv }); var encryptedWA = CryptoJS.enc.Hex.parse(encryptedHex.toString()); var encryptedB64 = CryptoJS.enc.Base64.stringify(encryptedWA); return encryptedB64; }; // other methods and properties ---------------------------------------- var ALGLIST = { 'AES-256-CBC': { 'proc': decryptAES, 'eproc': encryptAES, keylen: 32, ivlen: 16 }, 'AES-192-CBC': { 'proc': decryptAES, 'eproc': encryptAES, keylen: 24, ivlen: 16 }, 'AES-128-CBC': { 'proc': decryptAES, 'eproc': encryptAES, keylen: 16, ivlen: 16 }, 'DES-EDE3-CBC': { 'proc': decrypt3DES, 'eproc': encrypt3DES, keylen: 24, ivlen: 8 }, 'DES-CBC': { 'proc': decryptDES, 'eproc': encryptDES, keylen: 8, ivlen: 8 } }; var getFuncByName = function(algName) { return ALGLIST[algName]['proc']; }; var _generateIvSaltHex = function(numBytes) { var wa = CryptoJS.lib.WordArray.random(numBytes); var hex = CryptoJS.enc.Hex.stringify(wa); return hex; }; var _parsePKCS5PEM = function(sPKCS5PEM) { var info = {}; if (sPKCS5PEM.match(new RegExp("DEK-Info: ([^,]+),([0-9A-Fa-f]+)", "m"))) { info.cipher = RegExp.$1; info.ivsalt = RegExp.$2; } if (sPKCS5PEM.match(new RegExp("-----BEGIN ([A-Z]+) PRIVATE KEY-----"))) { info.type = RegExp.$1; } var i1 = -1; var lenNEWLINE = 0; if (sPKCS5PEM.indexOf("\r\n\r\n") != -1) { i1 = sPKCS5PEM.indexOf("\r\n\r\n"); lenNEWLINE = 2; } if (sPKCS5PEM.indexOf("\n\n") != -1) { i1 = sPKCS5PEM.indexOf("\n\n"); lenNEWLINE = 1; } var i2 = sPKCS5PEM.indexOf("-----END"); if (i1 != -1 && i2 != -1) { var s = sPKCS5PEM.substring(i1 + lenNEWLINE * 2, i2 - lenNEWLINE); s = s.replace(/\s+/g, ''); info.data = s; } return info; }; var _getKeyAndUnusedIvByPasscodeAndIvsalt = function(algName, passcode, ivsaltHex) { //alert("ivsaltHex(2) = " + ivsaltHex); var saltHex = ivsaltHex.substring(0, 16); //alert("salt = " + saltHex); var salt = CryptoJS.enc.Hex.parse(saltHex); var data = CryptoJS.enc.Utf8.parse(passcode); //alert("salt = " + salt); //alert("data = " + data); var nRequiredBytes = ALGLIST[algName]['keylen'] + ALGLIST[algName]['ivlen']; var hHexValueJoined = ''; var hLastValue = null; //alert("nRequiredBytes = " + nRequiredBytes); for (;;) { var h = CryptoJS.algo.MD5.create(); if (hLastValue != null) { h.update(hLastValue); } h.update(data); h.update(salt); hLastValue = h.finalize(); hHexValueJoined = hHexValueJoined + CryptoJS.enc.Hex.stringify(hLastValue); //alert("joined = " + hHexValueJoined); if (hHexValueJoined.length >= nRequiredBytes * 2) { break; } } var result = {}; result.keyhex = hHexValueJoined.substr(0, ALGLIST[algName]['keylen'] * 2); result.ivhex = hHexValueJoined.substr(ALGLIST[algName]['keylen'] * 2, ALGLIST[algName]['ivlen'] * 2); return result; }; /* * @param {String} privateKeyB64 base64 string of encrypted private key * @param {String} sharedKeyAlgName algorithm name of shared key encryption * @param {String} sharedKeyHex hexadecimal string of shared key to encrypt * @param {String} ivsaltHex hexadecimal string of IV and salt * @param {String} hexadecimal string of decrypted private key */ var _decryptKeyB64 = function(privateKeyB64, sharedKeyAlgName, sharedKeyHex, ivsaltHex) { var privateKeyWA = CryptoJS.enc.Base64.parse(privateKeyB64); var privateKeyHex = CryptoJS.enc.Hex.stringify(privateKeyWA); var f = ALGLIST[sharedKeyAlgName]['proc']; var decryptedKeyHex = f(privateKeyHex, sharedKeyHex, ivsaltHex); return decryptedKeyHex; }; /* * @param {String} privateKeyHex hexadecimal string of private key * @param {String} sharedKeyAlgName algorithm name of shared key encryption * @param {String} sharedKeyHex hexadecimal string of shared key to encrypt * @param {String} ivsaltHex hexadecimal string of IV and salt * @param {String} base64 string of encrypted private key */ var _encryptKeyHex = function(privateKeyHex, sharedKeyAlgName, sharedKeyHex, ivsaltHex) { var f = ALGLIST[sharedKeyAlgName]['eproc']; var encryptedKeyB64 = f(privateKeyHex, sharedKeyHex, ivsaltHex); return encryptedKeyB64; }; // ***************************************************************** // *** PUBLIC PROPERTIES AND METHODS ******************************* // ***************************************************************** return { // -- UTILITY METHODS ------------------------------------------------------------ /** * decrypt private key by shared key * @name version * @memberOf KEYUTIL * @property {String} version * @description version string of KEYUTIL class */ version: "1.0.0", /** * get hexacedimal string of PEM format * @name getHexFromPEM * @memberOf KEYUTIL * @function * @param {String} sPEM PEM formatted string * @param {String} sHead PEM header string without BEGIN/END * @return {String} hexadecimal string data of PEM contents * @since pkcs5pkey 1.0.5 */ getHexFromPEM: function(sPEM, sHead) { var s = sPEM; if (s.indexOf("-----BEGIN ") == -1) { throw "can't find PEM header: " + sHead; } if (typeof sHead == "string" && sHead != "") { s = s.replace("-----BEGIN " + sHead + "-----", ""); s = s.replace("-----END " + sHead + "-----", ""); } else { s = s.replace(/-----BEGIN [^-]+-----/, ''); s = s.replace(/-----END [^-]+-----/, ''); } var sB64 = s.replace(/\s+/g, ''); var dataHex = b64tohex(sB64); return dataHex; }, /** * decrypt private key by shared key * @name getDecryptedKeyHexByKeyIV * @memberOf KEYUTIL * @function * @param {String} encryptedKeyHex hexadecimal string of encrypted private key * @param {String} algName name of symmetric key algorithm (ex. 'DES-EBE3-CBC') * @param {String} sharedKeyHex hexadecimal string of symmetric key * @param {String} ivHex hexadecimal string of initial vector(IV). * @return {String} hexadecimal string of decrypted privated key */ getDecryptedKeyHexByKeyIV: function(encryptedKeyHex, algName, sharedKeyHex, ivHex) { var f1 = getFuncByName(algName); return f1(encryptedKeyHex, sharedKeyHex, ivHex); }, /** * parse PEM formatted passcode protected PKCS#5 private key * @name parsePKCS5PEM * @memberOf KEYUTIL * @function * @param {String} sEncryptedPEM PEM formatted protected passcode protected PKCS#5 private key * @return {Hash} hash of key information * @description * Resulted hash has following attributes. * * */ parsePKCS5PEM: function(sPKCS5PEM) { return _parsePKCS5PEM(sPKCS5PEM); }, /** * the same function as OpenSSL EVP_BytsToKey to generate shared key and IV * @name getKeyAndUnusedIvByPasscodeAndIvsalt * @memberOf KEYUTIL * @function * @param {String} algName name of symmetric key algorithm (ex. 'DES-EBE3-CBC') * @param {String} passcode passcode to decrypt private key (ex. 'password') * @param {String} hexadecimal string of IV. heading 8 bytes will be used for passcode salt * @return {Hash} hash of key and unused IV (ex. {keyhex:2fe3..., ivhex:3fad..}) */ getKeyAndUnusedIvByPasscodeAndIvsalt: function(algName, passcode, ivsaltHex) { return _getKeyAndUnusedIvByPasscodeAndIvsalt(algName, passcode, ivsaltHex); }, decryptKeyB64: function(privateKeyB64, sharedKeyAlgName, sharedKeyHex, ivsaltHex) { return _decryptKeyB64(privateKeyB64, sharedKeyAlgName, sharedKeyHex, ivsaltHex); }, /** * decrypt PEM formatted protected PKCS#5 private key with passcode * @name getDecryptedKeyHex * @memberOf KEYUTIL * @function * @param {String} sEncryptedPEM PEM formatted protected passcode protected PKCS#5 private key * @param {String} passcode passcode to decrypt private key (ex. 'password') * @return {String} hexadecimal string of decrypted RSA priavte key */ getDecryptedKeyHex: function(sEncryptedPEM, passcode) { // 1. parse pem var info = _parsePKCS5PEM(sEncryptedPEM); var publicKeyAlgName = info.type; var sharedKeyAlgName = info.cipher; var ivsaltHex = info.ivsalt; var privateKeyB64 = info.data; //alert("ivsaltHex = " + ivsaltHex); // 2. generate shared key var sharedKeyInfo = _getKeyAndUnusedIvByPasscodeAndIvsalt(sharedKeyAlgName, passcode, ivsaltHex); var sharedKeyHex = sharedKeyInfo.keyhex; //alert("sharedKeyHex = " + sharedKeyHex); // 3. decrypt private key var decryptedKey = _decryptKeyB64(privateKeyB64, sharedKeyAlgName, sharedKeyHex, ivsaltHex); return decryptedKey; }, /** * (DEPRECATED) read PEM formatted encrypted PKCS#5 private key and returns RSAKey object * @name getRSAKeyFromEncryptedPKCS5PEM * @memberOf KEYUTIL * @function * @param {String} sEncryptedP5PEM PEM formatted encrypted PKCS#5 private key * @param {String} passcode passcode to decrypt private key * @return {RSAKey} loaded RSAKey object of RSA private key * @since pkcs5pkey 1.0.2 * @deprecated From jsrsasign 4.2.1 please use {@link KEYUTIL.getKey#}. */ getRSAKeyFromEncryptedPKCS5PEM: function(sEncryptedP5PEM, passcode) { var hPKey = this.getDecryptedKeyHex(sEncryptedP5PEM, passcode); var rsaKey = new RSAKey(); rsaKey.readPrivateKeyFromASN1HexString(hPKey); return rsaKey; }, /* * get PEM formatted encrypted PKCS#5 private key from hexadecimal string of plain private key * @name getEncryptedPKCS5PEMFromPrvKeyHex * @memberOf KEYUTIL * @function * @param {String} pemHeadAlg algorithm name in the pem header (i.e. RSA,EC or DSA) * @param {String} hPrvKey hexadecimal string of plain private key * @param {String} passcode pass code to protect private key (ex. password) * @param {String} sharedKeyAlgName algorithm name to protect private key (ex. AES-256-CBC) * @param {String} ivsaltHex hexadecimal string of IV and salt * @return {String} string of PEM formatted encrypted PKCS#5 private key * @since pkcs5pkey 1.0.2 * @description *
* generate PEM formatted encrypted PKCS#5 private key by hexadecimal string encoded * ASN.1 object of plain RSA private key. * Following arguments can be omitted. * * NOTE1: DES-CBC, DES-EDE3-CBC, AES-{128,192.256}-CBC algorithm are supported. * @example * var pem = * KEYUTIL.getEncryptedPKCS5PEMFromPrvKeyHex(plainKeyHex, "password"); * var pem2 = * KEYUTIL.getEncryptedPKCS5PEMFromPrvKeyHex(plainKeyHex, "password", "AES-128-CBC"); * var pem3 = * KEYUTIL.getEncryptedPKCS5PEMFromPrvKeyHex(plainKeyHex, "password", "AES-128-CBC", "1f3d02..."); */ getEncryptedPKCS5PEMFromPrvKeyHex: function(pemHeadAlg, hPrvKey, passcode, sharedKeyAlgName, ivsaltHex) { var sPEM = ""; // 1. set sharedKeyAlgName if undefined (default AES-256-CBC) if (typeof sharedKeyAlgName == "undefined" || sharedKeyAlgName == null) { sharedKeyAlgName = "AES-256-CBC"; } if (typeof ALGLIST[sharedKeyAlgName] == "undefined") throw "KEYUTIL unsupported algorithm: " + sharedKeyAlgName; // 2. set ivsaltHex if undefined if (typeof ivsaltHex == "undefined" || ivsaltHex == null) { var ivlen = ALGLIST[sharedKeyAlgName]['ivlen']; var randIV = _generateIvSaltHex(ivlen); ivsaltHex = randIV.toUpperCase(); } // 3. get shared key //alert("ivsalthex=" + ivsaltHex); var sharedKeyInfo = _getKeyAndUnusedIvByPasscodeAndIvsalt(sharedKeyAlgName, passcode, ivsaltHex); var sharedKeyHex = sharedKeyInfo.keyhex; // alert("sharedKeyHex = " + sharedKeyHex); // 3. get encrypted Key in Base64 var encryptedKeyB64 = _encryptKeyHex(hPrvKey, sharedKeyAlgName, sharedKeyHex, ivsaltHex); var pemBody = encryptedKeyB64.replace(/(.{64})/g, "$1\r\n"); var sPEM = "-----BEGIN " + pemHeadAlg + " PRIVATE KEY-----\r\n"; sPEM += "Proc-Type: 4,ENCRYPTED\r\n"; sPEM += "DEK-Info: " + sharedKeyAlgName + "," + ivsaltHex + "\r\n"; sPEM += "\r\n"; sPEM += pemBody; sPEM += "\r\n-----END " + pemHeadAlg + " PRIVATE KEY-----\r\n"; return sPEM; }, /** * (DEPRECATED) get PEM formatted encrypted PKCS#5 private key from RSAKey object of private key * @name getEncryptedPKCS5PEMFromRSAKey * @memberOf KEYUTIL * @function * @param {RSAKey} pKey RSAKey object of private key * @param {String} passcode pass code to protect private key (ex. password) * @param {String} alg algorithm name to protect private key (default AES-256-CBC) * @param {String} ivsaltHex hexadecimal string of IV and salt (default generated random IV) * @return {String} string of PEM formatted encrypted PKCS#5 private key * @since pkcs5pkey 1.0.2 * @deprecated From jsrsasign 4.2.1 please use {@link KEYUTIL.getPEM#}. * @description *
* generate PEM formatted encrypted PKCS#5 private key by * {@link RSAKey} object of RSA private key and passcode. * Following argument can be omitted. * * @example * var pkey = new RSAKey(); * pkey.generate(1024, '10001'); // generate 1024bit RSA private key with public exponent 'x010001' * var pem = KEYUTIL.getEncryptedPKCS5PEMFromRSAKey(pkey, "password"); */ getEncryptedPKCS5PEMFromRSAKey: function(pKey, passcode, alg, ivsaltHex) { var version = new KJUR.asn1.DERInteger({'int': 0}); var n = new KJUR.asn1.DERInteger({'bigint': pKey.n}); var e = new KJUR.asn1.DERInteger({'int': pKey.e}); var d = new KJUR.asn1.DERInteger({'bigint': pKey.d}); var p = new KJUR.asn1.DERInteger({'bigint': pKey.p}); var q = new KJUR.asn1.DERInteger({'bigint': pKey.q}); var dmp1 = new KJUR.asn1.DERInteger({'bigint': pKey.dmp1}); var dmq1 = new KJUR.asn1.DERInteger({'bigint': pKey.dmq1}); var coeff = new KJUR.asn1.DERInteger({'bigint': pKey.coeff}); var seq = new KJUR.asn1.DERSequence({'array': [version, n, e, d, p, q, dmp1, dmq1, coeff]}); var hex = seq.getEncodedHex(); return this.getEncryptedPKCS5PEMFromPrvKeyHex("RSA", hex, passcode, alg, ivsaltHex); }, /** * generate RSAKey and PEM formatted encrypted PKCS#5 private key * @name newEncryptedPKCS5PEM * @memberOf KEYUTIL * @function * @param {String} passcode pass code to protect private key (ex. password) * @param {Integer} keyLen key bit length of RSA key to be generated. (default 1024) * @param {String} hPublicExponent hexadecimal string of public exponent (default 10001) * @param {String} alg shared key algorithm to encrypt private key (default AES-258-CBC) * @return {String} string of PEM formatted encrypted PKCS#5 private key * @since pkcs5pkey 1.0.2 * @example * var pem1 = KEYUTIL.newEncryptedPKCS5PEM("password"); // RSA1024bit/10001/AES-256-CBC * var pem2 = KEYUTIL.newEncryptedPKCS5PEM("password", 512); // RSA 512bit/10001/AES-256-CBC * var pem3 = KEYUTIL.newEncryptedPKCS5PEM("password", 512, '3'); // RSA 512bit/ 3/AES-256-CBC */ newEncryptedPKCS5PEM: function(passcode, keyLen, hPublicExponent, alg) { if (typeof keyLen == "undefined" || keyLen == null) { keyLen = 1024; } if (typeof hPublicExponent == "undefined" || hPublicExponent == null) { hPublicExponent = '10001'; } var pKey = new RSAKey(); pKey.generate(keyLen, hPublicExponent); var pem = null; if (typeof alg == "undefined" || alg == null) { pem = this.getEncryptedPKCS5PEMFromRSAKey(pKey, passcode); } else { pem = this.getEncryptedPKCS5PEMFromRSAKey(pKey, passcode, alg); } return pem; }, // === PKCS8 =============================================================== /** * (DEPRECATED) read PEM formatted unencrypted PKCS#8 private key and returns RSAKey object * @name getRSAKeyFromPlainPKCS8PEM * @memberOf KEYUTIL * @function * @param {String} pkcs8PEM PEM formatted unencrypted PKCS#8 private key * @return {RSAKey} loaded RSAKey object of RSA private key * @since pkcs5pkey 1.0.1 * @deprecated From jsrsasign 4.2.1 please use {@link KEYUTIL.getKey#}. */ getRSAKeyFromPlainPKCS8PEM: function(pkcs8PEM) { if (pkcs8PEM.match(/ENCRYPTED/)) throw "pem shall be not ENCRYPTED"; var prvKeyHex = this.getHexFromPEM(pkcs8PEM, "PRIVATE KEY"); var rsaKey = this.getRSAKeyFromPlainPKCS8Hex(prvKeyHex); return rsaKey; }, /** * (DEPRECATED) provide hexadecimal string of unencrypted PKCS#8 private key and returns RSAKey object * @name getRSAKeyFromPlainPKCS8Hex * @memberOf KEYUTIL * @function * @param {String} prvKeyHex hexadecimal string of unencrypted PKCS#8 private key * @return {RSAKey} loaded RSAKey object of RSA private key * @since pkcs5pkey 1.0.3 * @deprecated From jsrsasign 4.2.1 please use {@link KEYUTIL.getKey#}. */ getRSAKeyFromPlainPKCS8Hex: function(prvKeyHex) { var a1 = ASN1HEX.getPosArrayOfChildren_AtObj(prvKeyHex, 0); if (a1.length != 3) throw "outer DERSequence shall have 3 elements: " + a1.length; var algIdTLV =ASN1HEX.getHexOfTLV_AtObj(prvKeyHex, a1[1]); if (algIdTLV != "300d06092a864886f70d0101010500") // AlgId rsaEncryption throw "PKCS8 AlgorithmIdentifier is not rsaEnc: " + algIdTLV; var algIdTLV = ASN1HEX.getHexOfTLV_AtObj(prvKeyHex, a1[1]); var octetStr = ASN1HEX.getHexOfTLV_AtObj(prvKeyHex, a1[2]); var p5KeyHex = ASN1HEX.getHexOfV_AtObj(octetStr, 0); //alert(p5KeyHex); var rsaKey = new RSAKey(); rsaKey.readPrivateKeyFromASN1HexString(p5KeyHex); return rsaKey; }, /** * generate PBKDF2 key hexstring with specified passcode and information * @name parseHexOfEncryptedPKCS8 * @memberOf KEYUTIL * @function * @param {String} passcode passcode to decrypto private key * @return {Array} info associative array of PKCS#8 parameters * @since pkcs5pkey 1.0.3 * @description * The associative array which is returned by this method has following properties: * * Currently, this method only supports PKCS#5v2.0 with PBES2/PBDKF2 of HmacSHA1 and TripleDES. * * @example * // to convert plain PKCS#5 private key to encrypted PKCS#8 private * // key with PBKDF2 with TripleDES * % openssl pkcs8 -in plain_p5.pem -topk8 -v2 -des3 -out encrypted_p8.pem */ parseHexOfEncryptedPKCS8: function(sHEX) { var info = {}; var a0 = ASN1HEX.getPosArrayOfChildren_AtObj(sHEX, 0); if (a0.length != 2) throw "malformed format: SEQUENCE(0).items != 2: " + a0.length; // 1. ciphertext info.ciphertext = ASN1HEX.getHexOfV_AtObj(sHEX, a0[1]); // 2. pkcs5PBES2 var a0_0 = ASN1HEX.getPosArrayOfChildren_AtObj(sHEX, a0[0]); if (a0_0.length != 2) throw "malformed format: SEQUENCE(0.0).items != 2: " + a0_0.length; // 2.1 check if pkcs5PBES2(1 2 840 113549 1 5 13) if (ASN1HEX.getHexOfV_AtObj(sHEX, a0_0[0]) != "2a864886f70d01050d") throw "this only supports pkcs5PBES2"; // 2.2 pkcs5PBES2 param var a0_0_1 = ASN1HEX.getPosArrayOfChildren_AtObj(sHEX, a0_0[1]); if (a0_0.length != 2) throw "malformed format: SEQUENCE(0.0.1).items != 2: " + a0_0_1.length; // 2.2.1 encryptionScheme var a0_0_1_1 = ASN1HEX.getPosArrayOfChildren_AtObj(sHEX, a0_0_1[1]); if (a0_0_1_1.length != 2) throw "malformed format: SEQUENCE(0.0.1.1).items != 2: " + a0_0_1_1.length; if (ASN1HEX.getHexOfV_AtObj(sHEX, a0_0_1_1[0]) != "2a864886f70d0307") throw "this only supports TripleDES"; info.encryptionSchemeAlg = "TripleDES"; // 2.2.1.1 IV of encryptionScheme info.encryptionSchemeIV = ASN1HEX.getHexOfV_AtObj(sHEX, a0_0_1_1[1]); // 2.2.2 keyDerivationFunc var a0_0_1_0 = ASN1HEX.getPosArrayOfChildren_AtObj(sHEX, a0_0_1[0]); if (a0_0_1_0.length != 2) throw "malformed format: SEQUENCE(0.0.1.0).items != 2: " + a0_0_1_0.length; if (ASN1HEX.getHexOfV_AtObj(sHEX, a0_0_1_0[0]) != "2a864886f70d01050c") throw "this only supports pkcs5PBKDF2"; // 2.2.2.1 pkcs5PBKDF2 param var a0_0_1_0_1 = ASN1HEX.getPosArrayOfChildren_AtObj(sHEX, a0_0_1_0[1]); if (a0_0_1_0_1.length < 2) throw "malformed format: SEQUENCE(0.0.1.0.1).items < 2: " + a0_0_1_0_1.length; // 2.2.2.1.1 PBKDF2 salt info.pbkdf2Salt = ASN1HEX.getHexOfV_AtObj(sHEX, a0_0_1_0_1[0]); // 2.2.2.1.2 PBKDF2 iter var iterNumHex = ASN1HEX.getHexOfV_AtObj(sHEX, a0_0_1_0_1[1]); try { info.pbkdf2Iter = parseInt(iterNumHex, 16); } catch(ex) { throw "malformed format pbkdf2Iter: " + iterNumHex; } return info; }, /** * generate PBKDF2 key hexstring with specified passcode and information * @name getPBKDF2KeyHexFromParam * @memberOf KEYUTIL * @function * @param {Array} info result of {@link parseHexOfEncryptedPKCS8} which has preference of PKCS#8 file * @param {String} passcode passcode to decrypto private key * @return {String} hexadecimal string of PBKDF2 key * @since pkcs5pkey 1.0.3 * @description * As for info, this uses following properties: * * Currently, this method only supports PKCS#5v2.0 with PBES2/PBDKF2 of HmacSHA1 and TripleDES. * * @example * // to convert plain PKCS#5 private key to encrypted PKCS#8 private * // key with PBKDF2 with TripleDES * % openssl pkcs8 -in plain_p5.pem -topk8 -v2 -des3 -out encrypted_p8.pem */ getPBKDF2KeyHexFromParam: function(info, passcode) { var pbkdf2SaltWS = CryptoJS.enc.Hex.parse(info.pbkdf2Salt); var pbkdf2Iter = info.pbkdf2Iter; var pbkdf2KeyWS = CryptoJS.PBKDF2(passcode, pbkdf2SaltWS, { keySize: 192/32, iterations: pbkdf2Iter }); var pbkdf2KeyHex = CryptoJS.enc.Hex.stringify(pbkdf2KeyWS); return pbkdf2KeyHex; }, /** * read PEM formatted encrypted PKCS#8 private key and returns hexadecimal string of plain PKCS#8 private key * @name getPlainPKCS8HexFromEncryptedPKCS8PEM * @memberOf KEYUTIL * @function * @param {String} pkcs8PEM PEM formatted encrypted PKCS#8 private key * @param {String} passcode passcode to decrypto private key * @return {String} hexadecimal string of plain PKCS#8 private key * @since pkcs5pkey 1.0.3 * @description * Currently, this method only supports PKCS#5v2.0 with PBES2/PBDKF2 of HmacSHA1 and TripleDES. * * @example * // to convert plain PKCS#5 private key to encrypted PKCS#8 private * // key with PBKDF2 with TripleDES * % openssl pkcs8 -in plain_p5.pem -topk8 -v2 -des3 -out encrypted_p8.pem */ getPlainPKCS8HexFromEncryptedPKCS8PEM: function(pkcs8PEM, passcode) { // 1. derHex - PKCS#8 private key encrypted by PBKDF2 var derHex = this.getHexFromPEM(pkcs8PEM, "ENCRYPTED PRIVATE KEY"); // 2. info - PKCS#5 PBES info var info = this.parseHexOfEncryptedPKCS8(derHex); // 3. hKey - PBKDF2 key var pbkdf2KeyHex = KEYUTIL.getPBKDF2KeyHexFromParam(info, passcode); // 4. decrypt ciphertext by PBKDF2 key var encrypted = {}; encrypted.ciphertext = CryptoJS.enc.Hex.parse(info.ciphertext); var pbkdf2KeyWS = CryptoJS.enc.Hex.parse(pbkdf2KeyHex); var des3IVWS = CryptoJS.enc.Hex.parse(info.encryptionSchemeIV); var decWS = CryptoJS.TripleDES.decrypt(encrypted, pbkdf2KeyWS, { iv: des3IVWS }); var decHex = CryptoJS.enc.Hex.stringify(decWS); return decHex; }, /** * (DEPRECATED) read PEM formatted encrypted PKCS#8 private key and returns RSAKey object * @name getRSAKeyFromEncryptedPKCS8PEM * @memberOf KEYUTIL * @function * @param {String} pkcs8PEM PEM formatted encrypted PKCS#8 private key * @param {String} passcode passcode to decrypto private key * @return {RSAKey} loaded RSAKey object of RSA private key * @since pkcs5pkey 1.0.3 * @deprecated From jsrsasign 4.2.1 please use {@link KEYUTIL.getKey#}. * @description * Currently, this method only supports PKCS#5v2.0 with PBES2/PBDKF2 of HmacSHA1 and TripleDES. * * @example * // to convert plain PKCS#5 private key to encrypted PKCS#8 private * // key with PBKDF2 with TripleDES * % openssl pkcs8 -in plain_p5.pem -topk8 -v2 -des3 -out encrypted_p8.pem */ getRSAKeyFromEncryptedPKCS8PEM: function(pkcs8PEM, passcode) { var prvKeyHex = this.getPlainPKCS8HexFromEncryptedPKCS8PEM(pkcs8PEM, passcode); var rsaKey = this.getRSAKeyFromPlainPKCS8Hex(prvKeyHex); return rsaKey; }, /** * get RSAKey/ECDSA private key object from encrypted PEM PKCS#8 private key * @name getKeyFromEncryptedPKCS8PEM * @memberOf KEYUTIL * @function * @param {String} pkcs8PEM string of PEM formatted PKCS#8 private key * @param {String} passcode passcode string to decrypt key * @return {Object} RSAKey or KJUR.crypto.ECDSA private key object * @since pkcs5pkey 1.0.5 */ getKeyFromEncryptedPKCS8PEM: function(pkcs8PEM, passcode) { var prvKeyHex = this.getPlainPKCS8HexFromEncryptedPKCS8PEM(pkcs8PEM, passcode); var key = this.getKeyFromPlainPrivatePKCS8Hex(prvKeyHex); return key; }, /** * parse hexadecimal string of plain PKCS#8 private key * @name parsePlainPrivatePKCS8Hex * @memberOf KEYUTIL * @function * @param {String} pkcs8PrvHex hexadecimal string of PKCS#8 plain private key * @return {Array} associative array of parsed key * @since pkcs5pkey 1.0.5 * @description * Resulted associative array has following properties: * */ parsePlainPrivatePKCS8Hex: function(pkcs8PrvHex) { var result = {}; result.algparam = null; // 1. sequence if (pkcs8PrvHex.substr(0, 2) != "30") throw "malformed plain PKCS8 private key(code:001)"; // not sequence var a1 = ASN1HEX.getPosArrayOfChildren_AtObj(pkcs8PrvHex, 0); if (a1.length != 3) throw "malformed plain PKCS8 private key(code:002)"; // 2. AlgID if (pkcs8PrvHex.substr(a1[1], 2) != "30") throw "malformed PKCS8 private key(code:003)"; // AlgId not sequence var a2 = ASN1HEX.getPosArrayOfChildren_AtObj(pkcs8PrvHex, a1[1]); if (a2.length != 2) throw "malformed PKCS8 private key(code:004)"; // AlgId not have two elements // 2.1. AlgID OID if (pkcs8PrvHex.substr(a2[0], 2) != "06") throw "malformed PKCS8 private key(code:005)"; // AlgId.oid is not OID result.algoid = ASN1HEX.getHexOfV_AtObj(pkcs8PrvHex, a2[0]); // 2.2. AlgID param if (pkcs8PrvHex.substr(a2[1], 2) == "06") { result.algparam = ASN1HEX.getHexOfV_AtObj(pkcs8PrvHex, a2[1]); } // 3. Key index if (pkcs8PrvHex.substr(a1[2], 2) != "04") throw "malformed PKCS8 private key(code:006)"; // not octet string result.keyidx = ASN1HEX.getStartPosOfV_AtObj(pkcs8PrvHex, a1[2]); return result; }, /** * get RSAKey/ECDSA private key object from PEM plain PEM PKCS#8 private key * @name getKeyFromPlainPrivatePKCS8PEM * @memberOf KEYUTIL * @function * @param {String} pkcs8PEM string of plain PEM formatted PKCS#8 private key * @return {Object} RSAKey or KJUR.crypto.ECDSA private key object * @since pkcs5pkey 1.0.5 */ getKeyFromPlainPrivatePKCS8PEM: function(prvKeyPEM) { var prvKeyHex = this.getHexFromPEM(prvKeyPEM, "PRIVATE KEY"); var key = this.getKeyFromPlainPrivatePKCS8Hex(prvKeyHex); return key; }, /** * get RSAKey/ECDSA private key object from HEX plain PEM PKCS#8 private key * @name getKeyFromPlainPrivatePKCS8Hex * @memberOf KEYUTIL * @function * @param {String} prvKeyHex hexadecimal string of plain PKCS#8 private key * @return {Object} RSAKey or KJUR.crypto.ECDSA private key object * @since pkcs5pkey 1.0.5 */ getKeyFromPlainPrivatePKCS8Hex: function(prvKeyHex) { var p8 = this.parsePlainPrivatePKCS8Hex(prvKeyHex); if (p8.algoid == "2a864886f70d010101") { // RSA this.parsePrivateRawRSAKeyHexAtObj(prvKeyHex, p8); var k = p8.key; var key = new RSAKey(); key.setPrivateEx(k.n, k.e, k.d, k.p, k.q, k.dp, k.dq, k.co); return key; } else if (p8.algoid == "2a8648ce3d0201") { // ECC this.parsePrivateRawECKeyHexAtObj(prvKeyHex, p8); if (KJUR.crypto.OID.oidhex2name[p8.algparam] === undefined) throw "KJUR.crypto.OID.oidhex2name undefined: " + p8.algparam; var curveName = KJUR.crypto.OID.oidhex2name[p8.algparam]; var key = new KJUR.crypto.ECDSA({'curve': curveName}); key.setPublicKeyHex(p8.pubkey); key.setPrivateKeyHex(p8.key); key.isPublic = false; return key; } else if (p8.algoid == "2a8648ce380401") { // DSA var hP = ASN1HEX.getVbyList(prvKeyHex, 0, [1,1,0], "02"); var hQ = ASN1HEX.getVbyList(prvKeyHex, 0, [1,1,1], "02"); var hG = ASN1HEX.getVbyList(prvKeyHex, 0, [1,1,2], "02"); var hX = ASN1HEX.getVbyList(prvKeyHex, 0, [2,0], "02"); var biP = new BigInteger(hP, 16); var biQ = new BigInteger(hQ, 16); var biG = new BigInteger(hG, 16); var biX = new BigInteger(hX, 16); var key = new KJUR.crypto.DSA(); key.setPrivate(biP, biQ, biG, null, biX); return key; } else { throw "unsupported private key algorithm"; } }, // === PKCS8 RSA Public Key ================================================ /** * (DEPRECATED) read PEM formatted PKCS#8 public key and returns RSAKey object * @name getRSAKeyFromPublicPKCS8PEM * @memberOf KEYUTIL * @function * @param {String} pkcs8PubPEM PEM formatted PKCS#8 public key * @return {RSAKey} loaded RSAKey object of RSA public key * @since pkcs5pkey 1.0.4 * @deprecated From jsrsasign 4.2.1 please use {@link KEYUTIL.getKey#}. */ getRSAKeyFromPublicPKCS8PEM: function(pkcs8PubPEM) { var pubKeyHex = this.getHexFromPEM(pkcs8PubPEM, "PUBLIC KEY"); var rsaKey = this.getRSAKeyFromPublicPKCS8Hex(pubKeyHex); return rsaKey; }, /** * (DEPRECATED) get RSAKey/ECDSA public key object from PEM PKCS#8 public key * @name getKeyFromPublicPKCS8PEM * @memberOf KEYUTIL * @function * @param {String} pkcsPub8PEM string of PEM formatted PKCS#8 public key * @return {Object} RSAKey or KJUR.crypto.ECDSA private key object * @since pkcs5pkey 1.0.5 * @deprecated From jsrsasign 4.2.1 please use {@link KEYUTIL.getKey#}. */ getKeyFromPublicPKCS8PEM: function(pkcs8PubPEM) { var pubKeyHex = this.getHexFromPEM(pkcs8PubPEM, "PUBLIC KEY"); var key = this.getKeyFromPublicPKCS8Hex(pubKeyHex); return key; }, /** * (DEPRECATED) get RSAKey/DSA/ECDSA public key object from hexadecimal string of PKCS#8 public key * @name getKeyFromPublicPKCS8Hex * @memberOf KEYUTIL * @function * @param {String} pkcsPub8Hex hexadecimal string of PKCS#8 public key * @return {Object} RSAKey or KJUR.crypto.{ECDSA,DSA} private key object * @since pkcs5pkey 1.0.5 * @deprecated From jsrsasign 4.2.1 please use {@link KEYUTIL.getKey#}. */ getKeyFromPublicPKCS8Hex: function(pkcs8PubHex) { var p8 = this.parsePublicPKCS8Hex(pkcs8PubHex); if (p8.algoid == "2a864886f70d010101") { // RSA var aRSA = this.parsePublicRawRSAKeyHex(p8.key); var key = new RSAKey(); key.setPublic(aRSA.n, aRSA.e); return key; } else if (p8.algoid == "2a8648ce3d0201") { // ECC if (KJUR.crypto.OID.oidhex2name[p8.algparam] === undefined) throw "KJUR.crypto.OID.oidhex2name undefined: " + p8.algparam; var curveName = KJUR.crypto.OID.oidhex2name[p8.algparam]; var key = new KJUR.crypto.ECDSA({'curve': curveName, 'pub': p8.key}); return key; } else if (p8.algoid == "2a8648ce380401") { // DSA 1.2.840.10040.4.1 var param = p8.algparam; var y = ASN1HEX.getHexOfV_AtObj(p8.key, 0); var key = new KJUR.crypto.DSA(); key.setPublic(new BigInteger(param.p, 16), new BigInteger(param.q, 16), new BigInteger(param.g, 16), new BigInteger(y, 16)); return key; } else { throw "unsupported public key algorithm"; } }, /** * parse hexadecimal string of plain PKCS#8 private key * @name parsePublicRawRSAKeyHex * @memberOf KEYUTIL * @function * @param {String} pubRawRSAHex hexadecimal string of ASN.1 encoded PKCS#8 public key * @return {Array} associative array of parsed key * @since pkcs5pkey 1.0.5 * @description * Resulted associative array has following properties: * */ parsePublicRawRSAKeyHex: function(pubRawRSAHex) { var result = {}; // 1. Sequence if (pubRawRSAHex.substr(0, 2) != "30") throw "malformed RSA key(code:001)"; // not sequence var a1 = ASN1HEX.getPosArrayOfChildren_AtObj(pubRawRSAHex, 0); if (a1.length != 2) throw "malformed RSA key(code:002)"; // not 2 items in seq // 2. public key "N" if (pubRawRSAHex.substr(a1[0], 2) != "02") throw "malformed RSA key(code:003)"; // 1st item is not integer result.n = ASN1HEX.getHexOfV_AtObj(pubRawRSAHex, a1[0]); // 3. public key "E" if (pubRawRSAHex.substr(a1[1], 2) != "02") throw "malformed RSA key(code:004)"; // 2nd item is not integer result.e = ASN1HEX.getHexOfV_AtObj(pubRawRSAHex, a1[1]); return result; }, /** * parse hexadecimal string of RSA private key * @name parsePrivateRawRSAKeyHexAtObj * @memberOf KEYUTIL * @function * @param {String} pkcs8PrvHex hexadecimal string of PKCS#8 private key concluding RSA private key * @return {Array} info associative array to add parsed RSA private key information * @since pkcs5pkey 1.0.5 * @description * Following properties are added to associative array 'info' * */ parsePrivateRawRSAKeyHexAtObj: function(pkcs8PrvHex, info) { var keyIdx = info.keyidx; // 1. sequence if (pkcs8PrvHex.substr(keyIdx, 2) != "30") throw "malformed RSA private key(code:001)"; // not sequence var a1 = ASN1HEX.getPosArrayOfChildren_AtObj(pkcs8PrvHex, keyIdx); if (a1.length != 9) throw "malformed RSA private key(code:002)"; // not sequence // 2. RSA key info.key = {}; info.key.n = ASN1HEX.getHexOfV_AtObj(pkcs8PrvHex, a1[1]); info.key.e = ASN1HEX.getHexOfV_AtObj(pkcs8PrvHex, a1[2]); info.key.d = ASN1HEX.getHexOfV_AtObj(pkcs8PrvHex, a1[3]); info.key.p = ASN1HEX.getHexOfV_AtObj(pkcs8PrvHex, a1[4]); info.key.q = ASN1HEX.getHexOfV_AtObj(pkcs8PrvHex, a1[5]); info.key.dp = ASN1HEX.getHexOfV_AtObj(pkcs8PrvHex, a1[6]); info.key.dq = ASN1HEX.getHexOfV_AtObj(pkcs8PrvHex, a1[7]); info.key.co = ASN1HEX.getHexOfV_AtObj(pkcs8PrvHex, a1[8]); }, /** * parse hexadecimal string of ECC private key * @name parsePrivateRawECKeyHexAtObj * @memberOf KEYUTIL * @function * @param {String} pkcs8PrvHex hexadecimal string of PKCS#8 private key concluding EC private key * @return {Array} info associative array to add parsed ECC private key information * @since pkcs5pkey 1.0.5 * @description * Following properties are added to associative array 'info' * */ parsePrivateRawECKeyHexAtObj: function(pkcs8PrvHex, info) { var keyIdx = info.keyidx; var key = ASN1HEX.getVbyList(pkcs8PrvHex, keyIdx, [1], "04"); var pubkey = ASN1HEX.getVbyList(pkcs8PrvHex, keyIdx, [2,0], "03").substr(2); info.key = key; info.pubkey = pubkey; }, /** * parse hexadecimal string of PKCS#8 RSA/EC/DSA public key * @name parsePublicPKCS8Hex * @memberOf KEYUTIL * @function * @param {String} pkcs8PubHex hexadecimal string of PKCS#8 public key * @return {Hash} hash of key information * @description * Resulted hash has following attributes. * */ parsePublicPKCS8Hex: function(pkcs8PubHex) { var result = {}; result.algparam = null; // 1. AlgID and Key bit string var a1 = ASN1HEX.getPosArrayOfChildren_AtObj(pkcs8PubHex, 0); if (a1.length != 2) throw "outer DERSequence shall have 2 elements: " + a1.length; // 2. AlgID var idxAlgIdTLV = a1[0]; if (pkcs8PubHex.substr(idxAlgIdTLV, 2) != "30") throw "malformed PKCS8 public key(code:001)"; // AlgId not sequence var a2 = ASN1HEX.getPosArrayOfChildren_AtObj(pkcs8PubHex, idxAlgIdTLV); if (a2.length != 2) throw "malformed PKCS8 public key(code:002)"; // AlgId not have two elements // 2.1. AlgID OID if (pkcs8PubHex.substr(a2[0], 2) != "06") throw "malformed PKCS8 public key(code:003)"; // AlgId.oid is not OID result.algoid = ASN1HEX.getHexOfV_AtObj(pkcs8PubHex, a2[0]); // 2.2. AlgID param if (pkcs8PubHex.substr(a2[1], 2) == "06") { // OID for EC result.algparam = ASN1HEX.getHexOfV_AtObj(pkcs8PubHex, a2[1]); } else if (pkcs8PubHex.substr(a2[1], 2) == "30") { // SEQ for DSA result.algparam = {}; result.algparam.p = ASN1HEX.getVbyList(pkcs8PubHex, a2[1], [0], "02"); result.algparam.q = ASN1HEX.getVbyList(pkcs8PubHex, a2[1], [1], "02"); result.algparam.g = ASN1HEX.getVbyList(pkcs8PubHex, a2[1], [2], "02"); } // 3. Key if (pkcs8PubHex.substr(a1[1], 2) != "03") throw "malformed PKCS8 public key(code:004)"; // Key is not bit string result.key = ASN1HEX.getHexOfV_AtObj(pkcs8PubHex, a1[1]).substr(2); // 4. return result assoc array return result; }, /** * (DEPRECATED) provide hexadecimal string of unencrypted PKCS#8 private key and returns RSAKey object * @name getRSAKeyFromPublicPKCS8Hex * @memberOf KEYUTIL * @function * @param {String} pkcs8PubHex hexadecimal string of unencrypted PKCS#8 public key * @return {RSAKey} loaded RSAKey object of RSA public key * @since pkcs5pkey 1.0.4 * @deprecated From jsrsasign 4.2.1 please use {@link KEYUTIL.getKey#}. */ getRSAKeyFromPublicPKCS8Hex: function(pkcs8PubHex) { var a1 = ASN1HEX.getPosArrayOfChildren_AtObj(pkcs8PubHex, 0); if (a1.length != 2) throw "outer DERSequence shall have 2 elements: " + a1.length; var algIdTLV =ASN1HEX.getHexOfTLV_AtObj(pkcs8PubHex, a1[0]); if (algIdTLV != "300d06092a864886f70d0101010500") // AlgId rsaEncryption throw "PKCS8 AlgorithmId is not rsaEncryption"; if (pkcs8PubHex.substr(a1[1], 2) != "03") throw "PKCS8 Public Key is not BITSTRING encapslated."; var idxPub = ASN1HEX.getStartPosOfV_AtObj(pkcs8PubHex, a1[1]) + 2; // 2 for unused bit if (pkcs8PubHex.substr(idxPub, 2) != "30") throw "PKCS8 Public Key is not SEQUENCE."; var a2 = ASN1HEX.getPosArrayOfChildren_AtObj(pkcs8PubHex, idxPub); if (a2.length != 2) throw "inner DERSequence shall have 2 elements: " + a2.length; if (pkcs8PubHex.substr(a2[0], 2) != "02") throw "N is not ASN.1 INTEGER"; if (pkcs8PubHex.substr(a2[1], 2) != "02") throw "E is not ASN.1 INTEGER"; var hN = ASN1HEX.getHexOfV_AtObj(pkcs8PubHex, a2[0]); var hE = ASN1HEX.getHexOfV_AtObj(pkcs8PubHex, a2[1]); var pubKey = new RSAKey(); pubKey.setPublic(hN, hE); return pubKey; }, //addAlgorithm: function(functionObject, algName, keyLen, ivLen) { //} }; }(); // -- MAJOR PUBLIC METHODS ------------------------------------------------------- /** * get private or public key object from any arguments * @name getKey * @memberOf KEYUTIL * @function * @static * @param {Object} param parameter to get key object. see description in detail. * @param {String} passcode (OPTION) parameter to get key object. see description in detail. * @param {String} hextype (OPTOIN) parameter to get key object. see description in detail. * @return {Object} {@link RSAKey}, {@link KJUR.crypto.ECDSA} or {@link KJUR.crypto.ECDSA} object * @since keyutil 1.0.0 * @description * This method gets private or public key object({@link RSAKey}, {@link KJUR.crypto.DSA} or {@link KJUR.crypto.ECDSA}) * for RSA, DSA and ECC. * Arguments for this methods depends on a key format you specify. * Following key representations are supported. * * Please note following limitation on encrypted keys: * * NOTE1: RFC 7517 JSON Web Key(JWK) support for RSA/ECC private/public key from jsrsasign 4.8.1.
* NOTE2: X509v1 support is added since jsrsasign 5.0.11. * *
EXAMPLE
* @example * // 1. loading private key from PEM string * keyObj = KEYUTIL.getKey("-----BEGIN RSA PRIVATE KEY..."); * keyObj = KEYUTIL.getKey("-----BEGIN RSA PRIVATE KEY..., "passcode"); * keyObj = KEYUTIL.getKey("-----BEGIN PRIVATE KEY..."); * keyObj = KEYUTIL.getKey("-----BEGIN PRIVATE KEY...", "passcode"); * // 2. loading public key from PEM string * keyObj = KEYUTIL.getKey("-----BEGIN PUBLIC KEY..."); * keyObj = KEYUTIL.getKey("-----BEGIN X509 CERTIFICATE..."); * // 3. loading hexadecimal PKCS#5/PKCS#8 key * keyObj = KEYUTIL.getKey("308205c1...", null, "pkcs8pub"); * keyObj = KEYUTIL.getKey("3082048b...", null, "pkcs5prv"); * // 4. loading JSON Web Key(JWK) * keyObj = KEYUTIL.getKey({kty: "RSA", n: "0vx7...", e: "AQAB"}); * keyObj = KEYUTIL.getKey({kty: "EC", crv: "P-256", * x: "MKBC...", y: "4Etl6...", d: "870Mb..."}); * // 5. bare hexadecimal key * keyObj = KEYUTIL.getKey({n: "75ab..", e: "010001"}); */ KEYUTIL.getKey = function(param, passcode, hextype) { // 1. by key RSAKey/KJUR.crypto.ECDSA/KJUR.crypto.DSA object if (typeof RSAKey != 'undefined' && param instanceof RSAKey) return param; if (typeof KJUR.crypto.ECDSA != 'undefined' && param instanceof KJUR.crypto.ECDSA) return param; if (typeof KJUR.crypto.DSA != 'undefined' && param instanceof KJUR.crypto.DSA) return param; // 2. by parameters of key // 2.1. bare ECC // 2.1.1. bare ECC public key by hex values if (param.curve !== undefined && param.xy !== undefined && param.d === undefined) { return new KJUR.crypto.ECDSA({pub: param.xy, curve: param.curve}); } // 2.1.2. bare ECC private key by hex values if (param.curve !== undefined && param.d !== undefined) { return new KJUR.crypto.ECDSA({prv: param.d, curve: param.curve}); } // 2.2. bare RSA // 2.2.1. bare RSA public key by hex values if (param.kty === undefined && param.n !== undefined && param.e !== undefined && param.d === undefined) { var key = new RSAKey(); key.setPublic(param.n, param.e); return key; } // 2.2.2. bare RSA private key with P/Q/DP/DQ/COEFF by hex values if (param.kty === undefined && param.n !== undefined && param.e !== undefined && param.d !== undefined && param.p !== undefined && param.q !== undefined && param.dp !== undefined && param.dq !== undefined && param.co !== undefined && param.qi === undefined) { var key = new RSAKey(); key.setPrivateEx(param.n, param.e, param.d, param.p, param.q, param.dp, param.dq, param.co); return key; } // 2.2.3. bare RSA public key without P/Q/DP/DQ/COEFF by hex values if (param.kty === undefined && param.n !== undefined && param.e !== undefined && param.d !== undefined && param.p === undefined) { var key = new RSAKey(); key.setPrivate(param.n, param.e, param.d); return key; } // 2.3. bare DSA // 2.3.1. bare DSA public key by hex values if (param.p !== undefined && param.q !== undefined && param.g !== undefined && param.y !== undefined && param.x === undefined) { var key = new KJUR.crypto.DSA(); key.setPublic(param.p, param.q, param.g, param.y); return key; } // 2.3.2. bare DSA private key by hex values if (param.p !== undefined && param.q !== undefined && param.g !== undefined && param.y !== undefined && param.x !== undefined) { var key = new KJUR.crypto.DSA(); key.setPrivate(param.p, param.q, param.g, param.y, param.x); return key; } // 3. JWK // 3.1. JWK RSA // 3.1.1. JWK RSA public key by b64u values if (param.kty === "RSA" && param.n !== undefined && param.e !== undefined && param.d === undefined) { var key = new RSAKey(); key.setPublic(b64utohex(param.n), b64utohex(param.e)); return key; } // 3.1.2. JWK RSA private key with p/q/dp/dq/coeff by b64u values if (param.kty === "RSA" && param.n !== undefined && param.e !== undefined && param.d !== undefined && param.p !== undefined && param.q !== undefined && param.dp !== undefined && param.dq !== undefined && param.qi !== undefined) { var key = new RSAKey(); key.setPrivateEx(b64utohex(param.n), b64utohex(param.e), b64utohex(param.d), b64utohex(param.p), b64utohex(param.q), b64utohex(param.dp), b64utohex(param.dq), b64utohex(param.qi)); return key; } // 3.1.3. JWK RSA private key without p/q/dp/dq/coeff by b64u // since jsrsasign 5.0.0 keyutil 1.0.11 if (param.kty === "RSA" && param.n !== undefined && param.e !== undefined && param.d !== undefined) { var key = new RSAKey(); key.setPrivate(b64utohex(param.n), b64utohex(param.e), b64utohex(param.d)); return key; } // 3.2. JWK ECC // 3.2.1. JWK ECC public key by b64u values if (param.kty === "EC" && param.crv !== undefined && param.x !== undefined && param.y !== undefined && param.d === undefined) { var ec = new KJUR.crypto.ECDSA({"curve": param.crv}); var charlen = ec.ecparams.keylen / 4; var hX = ("0000000000" + b64utohex(param.x)).slice(- charlen); var hY = ("0000000000" + b64utohex(param.y)).slice(- charlen); var hPub = "04" + hX + hY; ec.setPublicKeyHex(hPub); return ec; } // 3.2.2. JWK ECC private key by b64u values if (param.kty === "EC" && param.crv !== undefined && param.x !== undefined && param.y !== undefined && param.d !== undefined) { var ec = new KJUR.crypto.ECDSA({"curve": param.crv}); var charlen = ec.ecparams.keylen / 4; var hPrv = ("0000000000" + b64utohex(param.d)).slice(- charlen); ec.setPrivateKeyHex(hPrv); return ec; } // 4. by PEM certificate (-----BEGIN ... CERTIFITE----) if (param.indexOf("-END CERTIFICATE-", 0) != -1 || param.indexOf("-END X509 CERTIFICATE-", 0) != -1 || param.indexOf("-END TRUSTED CERTIFICATE-", 0) != -1) { return X509.getPublicKeyFromCertPEM(param); } // 4. public key by PKCS#8 hexadecimal string if (hextype === "pkcs8pub") { return KEYUTIL.getKeyFromPublicPKCS8Hex(param); } // 5. public key by PKCS#8 PEM string if (param.indexOf("-END PUBLIC KEY-") != -1) { return KEYUTIL.getKeyFromPublicPKCS8PEM(param); } // 6. private key by PKCS#5 plain hexadecimal RSA string if (hextype === "pkcs5prv") { var key = new RSAKey(); key.readPrivateKeyFromASN1HexString(param); return key; } // 7. private key by plain PKCS#5 hexadecimal RSA string if (hextype === "pkcs5prv") { var key = new RSAKey(); key.readPrivateKeyFromASN1HexString(param); return key; } // 8. private key by plain PKCS#5 PEM RSA string // getKey("-----BEGIN RSA PRIVATE KEY-...") if (param.indexOf("-END RSA PRIVATE KEY-") != -1 && param.indexOf("4,ENCRYPTED") == -1) { var hex = KEYUTIL.getHexFromPEM(param, "RSA PRIVATE KEY"); return KEYUTIL.getKey(hex, null, "pkcs5prv"); } // 8.2. private key by plain PKCS#5 PEM DSA string if (param.indexOf("-END DSA PRIVATE KEY-") != -1 && param.indexOf("4,ENCRYPTED") == -1) { var hKey = this.getHexFromPEM(param, "DSA PRIVATE KEY"); var p = ASN1HEX.getVbyList(hKey, 0, [1], "02"); var q = ASN1HEX.getVbyList(hKey, 0, [2], "02"); var g = ASN1HEX.getVbyList(hKey, 0, [3], "02"); var y = ASN1HEX.getVbyList(hKey, 0, [4], "02"); var x = ASN1HEX.getVbyList(hKey, 0, [5], "02"); var key = new KJUR.crypto.DSA(); key.setPrivate(new BigInteger(p, 16), new BigInteger(q, 16), new BigInteger(g, 16), new BigInteger(y, 16), new BigInteger(x, 16)); return key; } // 9. private key by plain PKCS#8 PEM ECC/RSA string if (param.indexOf("-END PRIVATE KEY-") != -1) { return KEYUTIL.getKeyFromPlainPrivatePKCS8PEM(param); } // 10. private key by encrypted PKCS#5 PEM RSA string if (param.indexOf("-END RSA PRIVATE KEY-") != -1 && param.indexOf("4,ENCRYPTED") != -1) { return KEYUTIL.getRSAKeyFromEncryptedPKCS5PEM(param, passcode); } // 10.2. private key by encrypted PKCS#5 PEM ECDSA string if (param.indexOf("-END EC PRIVATE KEY-") != -1 && param.indexOf("4,ENCRYPTED") != -1) { var hKey = KEYUTIL.getDecryptedKeyHex(param, passcode); var key = ASN1HEX.getVbyList(hKey, 0, [1], "04"); var curveNameOidHex = ASN1HEX.getVbyList(hKey, 0, [2,0], "06"); var pubkey = ASN1HEX.getVbyList(hKey, 0, [3,0], "03").substr(2); var curveName = ""; if (KJUR.crypto.OID.oidhex2name[curveNameOidHex] !== undefined) { curveName = KJUR.crypto.OID.oidhex2name[curveNameOidHex]; } else { throw "undefined OID(hex) in KJUR.crypto.OID: " + curveNameOidHex; } var ec = new KJUR.crypto.ECDSA({'name': curveName}); ec.setPublicKeyHex(pubkey); ec.setPrivateKeyHex(key); ec.isPublic = false; return ec; } // 10.3. private key by encrypted PKCS#5 PEM DSA string if (param.indexOf("-END DSA PRIVATE KEY-") != -1 && param.indexOf("4,ENCRYPTED") != -1) { var hKey = KEYUTIL.getDecryptedKeyHex(param, passcode); var p = ASN1HEX.getVbyList(hKey, 0, [1], "02"); var q = ASN1HEX.getVbyList(hKey, 0, [2], "02"); var g = ASN1HEX.getVbyList(hKey, 0, [3], "02"); var y = ASN1HEX.getVbyList(hKey, 0, [4], "02"); var x = ASN1HEX.getVbyList(hKey, 0, [5], "02"); var key = new KJUR.crypto.DSA(); key.setPrivate(new BigInteger(p, 16), new BigInteger(q, 16), new BigInteger(g, 16), new BigInteger(y, 16), new BigInteger(x, 16)); return key; } // 11. private key by encrypted PKCS#8 hexadecimal RSA/ECDSA string if (param.indexOf("-END ENCRYPTED PRIVATE KEY-") != -1) { return KEYUTIL.getKeyFromEncryptedPKCS8PEM(param, passcode); } throw "not supported argument"; }; /** * @name generateKeypair * @memberOf KEYUTIL * @function * @static * @param {String} alg 'RSA' or 'EC' * @param {Object} keylenOrCurve key length for RSA or curve name for EC * @return {Array} associative array of keypair which has prvKeyObj and pubKeyObj parameters * @since keyutil 1.0.1 * @description * This method generates a key pair of public key algorithm. * The result will be an associative array which has following * parameters: * * NOTE1: As for RSA algoirthm, public exponent has fixed * value '0x10001'. * NOTE2: As for EC algorithm, supported names of curve are * secp256r1, secp256k1 and secp384r1. * NOTE3: DSA is not supported yet. * @example * var rsaKeypair = KEYUTIL.generateKeypair("RSA", 1024); * var ecKeypair = KEYUTIL.generateKeypair("EC", "secp256r1"); * */ KEYUTIL.generateKeypair = function(alg, keylenOrCurve) { if (alg == "RSA") { var keylen = keylenOrCurve; var prvKey = new RSAKey(); prvKey.generate(keylen, '10001'); prvKey.isPrivate = true; prvKey.isPublic = true; var pubKey = new RSAKey(); var hN = prvKey.n.toString(16); var hE = prvKey.e.toString(16); pubKey.setPublic(hN, hE); pubKey.isPrivate = false; pubKey.isPublic = true; var result = {}; result.prvKeyObj = prvKey; result.pubKeyObj = pubKey; return result; } else if (alg == "EC") { var curve = keylenOrCurve; var ec = new KJUR.crypto.ECDSA({curve: curve}); var keypairHex = ec.generateKeyPairHex(); var prvKey = new KJUR.crypto.ECDSA({curve: curve}); prvKey.setPrivateKeyHex(keypairHex.ecprvhex); prvKey.isPrivate = true; prvKey.isPublic = false; var pubKey = new KJUR.crypto.ECDSA({curve: curve}); pubKey.setPublicKeyHex(keypairHex.ecpubhex); pubKey.isPrivate = false; pubKey.isPublic = true; var result = {}; result.prvKeyObj = prvKey; result.pubKeyObj = pubKey; return result; } else { throw "unknown algorithm: " + alg; } }; /** * get PEM formatted private or public key file from a RSA/ECDSA/DSA key object * @name getPEM * @memberOf KEYUTIL * @function * @static * @param {Object} keyObjOrHex key object {@link RSAKey}, {@link KJUR.crypto.ECDSA} or {@link KJUR.crypto.DSA} to encode to * @param {String} formatType (OPTION) output format type of "PKCS1PRV", "PKCS5PRV" or "PKCS8PRV" for private key * @param {String} passwd (OPTION) password to protect private key * @param {String} encAlg (OPTION) encryption algorithm for PKCS#5. currently supports DES-CBC, DES-EDE3-CBC and AES-{128,192,256}-CBC * @since keyutil 1.0.4 * @description *
*
NOTE1: *
* PKCS#5 encrypted private key protection algorithm supports DES-CBC, * DES-EDE3-CBC and AES-{128,192,256}-CBC *
NOTE2: *
* OpenSSL supports *
* @example * KEUUTIL.getPEM(publicKey) => generates PEM PKCS#8 public key * KEUUTIL.getPEM(privateKey, "PKCS1PRV") => generates PEM PKCS#1 plain private key * KEUUTIL.getPEM(privateKey, "PKCS5PRV", "pass") => generates PEM PKCS#5 encrypted private key * with DES-EDE3-CBC (DEFAULT) * KEUUTIL.getPEM(privateKey, "PKCS5PRV", "pass", "DES-CBC") => generates PEM PKCS#5 encrypted * private key with DES-CBC * KEUUTIL.getPEM(privateKey, "PKCS8PRV") => generates PEM PKCS#8 plain private key * KEUUTIL.getPEM(privateKey, "PKCS8PRV", "pass") => generates PEM PKCS#8 encrypted private key * with PBKDF2_HmacSHA1_3DES */ KEYUTIL.getPEM = function(keyObjOrHex, formatType, passwd, encAlg, hexType) { var ns1 = KJUR.asn1; var ns2 = KJUR.crypto; function _rsaprv2asn1obj(keyObjOrHex) { var asn1Obj = KJUR.asn1.ASN1Util.newObject({ "seq": [ {"int": 0 }, {"int": {"bigint": keyObjOrHex.n}}, {"int": keyObjOrHex.e}, {"int": {"bigint": keyObjOrHex.d}}, {"int": {"bigint": keyObjOrHex.p}}, {"int": {"bigint": keyObjOrHex.q}}, {"int": {"bigint": keyObjOrHex.dmp1}}, {"int": {"bigint": keyObjOrHex.dmq1}}, {"int": {"bigint": keyObjOrHex.coeff}} ] }); return asn1Obj; }; function _ecdsaprv2asn1obj(keyObjOrHex) { var asn1Obj2 = KJUR.asn1.ASN1Util.newObject({ "seq": [ {"int": 1 }, {"octstr": {"hex": keyObjOrHex.prvKeyHex}}, {"tag": ['a0', true, {'oid': {'name': keyObjOrHex.curveName}}]}, {"tag": ['a1', true, {'bitstr': {'hex': '00' + keyObjOrHex.pubKeyHex}}]} ] }); return asn1Obj2; }; function _dsaprv2asn1obj(keyObjOrHex) { var asn1Obj = KJUR.asn1.ASN1Util.newObject({ "seq": [ {"int": 0 }, {"int": {"bigint": keyObjOrHex.p}}, {"int": {"bigint": keyObjOrHex.q}}, {"int": {"bigint": keyObjOrHex.g}}, {"int": {"bigint": keyObjOrHex.y}}, {"int": {"bigint": keyObjOrHex.x}} ] }); return asn1Obj; }; // 1. public key // x. PEM PKCS#8 public key of RSA/ECDSA/DSA public key object if (((typeof RSAKey != "undefined" && keyObjOrHex instanceof RSAKey) || (typeof ns2.DSA != "undefined" && keyObjOrHex instanceof ns2.DSA) || (typeof ns2.ECDSA != "undefined" && keyObjOrHex instanceof ns2.ECDSA)) && keyObjOrHex.isPublic == true && (formatType === undefined || formatType == "PKCS8PUB")) { var asn1Obj = new KJUR.asn1.x509.SubjectPublicKeyInfo(keyObjOrHex); var asn1Hex = asn1Obj.getEncodedHex(); return ns1.ASN1Util.getPEMStringFromHex(asn1Hex, "PUBLIC KEY"); } // 2. private // x. PEM PKCS#1 plain private key of RSA private key object if (formatType == "PKCS1PRV" && typeof RSAKey != "undefined" && keyObjOrHex instanceof RSAKey && (passwd === undefined || passwd == null) && keyObjOrHex.isPrivate == true) { var asn1Obj = _rsaprv2asn1obj(keyObjOrHex); var asn1Hex = asn1Obj.getEncodedHex(); return ns1.ASN1Util.getPEMStringFromHex(asn1Hex, "RSA PRIVATE KEY"); } // x. PEM PKCS#1 plain private key of ECDSA private key object if (formatType == "PKCS1PRV" && typeof RSAKey != "undefined" && keyObjOrHex instanceof KJUR.crypto.ECDSA && (passwd === undefined || passwd == null) && keyObjOrHex.isPrivate == true) { var asn1Obj1 = new KJUR.asn1.DERObjectIdentifier({'name': keyObjOrHex.curveName}); var asn1Hex1 = asn1Obj1.getEncodedHex(); var asn1Obj2 = _ecdsaprv2asn1obj(keyObjOrHex); var asn1Hex2 = asn1Obj2.getEncodedHex(); var s = ""; s += ns1.ASN1Util.getPEMStringFromHex(asn1Hex1, "EC PARAMETERS"); s += ns1.ASN1Util.getPEMStringFromHex(asn1Hex2, "EC PRIVATE KEY"); return s; } // x. PEM PKCS#1 plain private key of DSA private key object if (formatType == "PKCS1PRV" && typeof KJUR.crypto.DSA != "undefined" && keyObjOrHex instanceof KJUR.crypto.DSA && (passwd === undefined || passwd == null) && keyObjOrHex.isPrivate == true) { var asn1Obj = _dsaprv2asn1obj(keyObjOrHex); var asn1Hex = asn1Obj.getEncodedHex(); return ns1.ASN1Util.getPEMStringFromHex(asn1Hex, "DSA PRIVATE KEY"); } // 3. private // x. PEM PKCS#5 encrypted private key of RSA private key object if (formatType == "PKCS5PRV" && typeof RSAKey != "undefined" && keyObjOrHex instanceof RSAKey && (passwd !== undefined && passwd != null) && keyObjOrHex.isPrivate == true) { var asn1Obj = _rsaprv2asn1obj(keyObjOrHex); var asn1Hex = asn1Obj.getEncodedHex(); if (encAlg === undefined) encAlg = "DES-EDE3-CBC"; return this.getEncryptedPKCS5PEMFromPrvKeyHex("RSA", asn1Hex, passwd, encAlg); } // x. PEM PKCS#5 encrypted private key of ECDSA private key object if (formatType == "PKCS5PRV" && typeof KJUR.crypto.ECDSA != "undefined" && keyObjOrHex instanceof KJUR.crypto.ECDSA && (passwd !== undefined && passwd != null) && keyObjOrHex.isPrivate == true) { var asn1Obj = _ecdsaprv2asn1obj(keyObjOrHex); var asn1Hex = asn1Obj.getEncodedHex(); if (encAlg === undefined) encAlg = "DES-EDE3-CBC"; return this.getEncryptedPKCS5PEMFromPrvKeyHex("EC", asn1Hex, passwd, encAlg); } // x. PEM PKCS#5 encrypted private key of DSA private key object if (formatType == "PKCS5PRV" && typeof KJUR.crypto.DSA != "undefined" && keyObjOrHex instanceof KJUR.crypto.DSA && (passwd !== undefined && passwd != null) && keyObjOrHex.isPrivate == true) { var asn1Obj = _dsaprv2asn1obj(keyObjOrHex); var asn1Hex = asn1Obj.getEncodedHex(); if (encAlg === undefined) encAlg = "DES-EDE3-CBC"; return this.getEncryptedPKCS5PEMFromPrvKeyHex("DSA", asn1Hex, passwd, encAlg); } // x. ====================================================================== var _getEncryptedPKCS8 = function(plainKeyHex, passcode) { var info = _getEencryptedPKCS8Info(plainKeyHex, passcode); //alert("iv=" + info.encryptionSchemeIV); //alert("info.ciphertext2[" + info.ciphertext.length + "=" + info.ciphertext); var asn1Obj = new KJUR.asn1.ASN1Util.newObject({ "seq": [ {"seq": [ {"oid": {"name": "pkcs5PBES2"}}, {"seq": [ {"seq": [ {"oid": {"name": "pkcs5PBKDF2"}}, {"seq": [ {"octstr": {"hex": info.pbkdf2Salt}}, {"int": info.pbkdf2Iter} ]} ]}, {"seq": [ {"oid": {"name": "des-EDE3-CBC"}}, {"octstr": {"hex": info.encryptionSchemeIV}} ]} ]} ]}, {"octstr": {"hex": info.ciphertext}} ] }); return asn1Obj.getEncodedHex(); }; var _getEencryptedPKCS8Info = function(plainKeyHex, passcode) { var pbkdf2Iter = 100; var pbkdf2SaltWS = CryptoJS.lib.WordArray.random(8); var encryptionSchemeAlg = "DES-EDE3-CBC"; var encryptionSchemeIVWS = CryptoJS.lib.WordArray.random(8); // PBKDF2 key var pbkdf2KeyWS = CryptoJS.PBKDF2(passcode, pbkdf2SaltWS, { "keySize": 192/32, "iterations": pbkdf2Iter }); // ENCRYPT var plainKeyWS = CryptoJS.enc.Hex.parse(plainKeyHex); var encryptedKeyHex = CryptoJS.TripleDES.encrypt(plainKeyWS, pbkdf2KeyWS, { "iv": encryptionSchemeIVWS }) + ""; //alert("encryptedKeyHex=" + encryptedKeyHex); var info = {}; info.ciphertext = encryptedKeyHex; //alert("info.ciphertext=" + info.ciphertext); info.pbkdf2Salt = CryptoJS.enc.Hex.stringify(pbkdf2SaltWS); info.pbkdf2Iter = pbkdf2Iter; info.encryptionSchemeAlg = encryptionSchemeAlg; info.encryptionSchemeIV = CryptoJS.enc.Hex.stringify(encryptionSchemeIVWS); return info; }; // x. PEM PKCS#8 plain private key of RSA private key object if (formatType == "PKCS8PRV" && typeof RSAKey != "undefined" && keyObjOrHex instanceof RSAKey && keyObjOrHex.isPrivate == true) { var keyObj = _rsaprv2asn1obj(keyObjOrHex); var keyHex = keyObj.getEncodedHex(); var asn1Obj = KJUR.asn1.ASN1Util.newObject({ "seq": [ {"int": 0}, {"seq": [{"oid": {"name": "rsaEncryption"}},{"null": true}]}, {"octstr": {"hex": keyHex}} ] }); var asn1Hex = asn1Obj.getEncodedHex(); if (passwd === undefined || passwd == null) { return ns1.ASN1Util.getPEMStringFromHex(asn1Hex, "PRIVATE KEY"); } else { var asn1Hex2 = _getEncryptedPKCS8(asn1Hex, passwd); return ns1.ASN1Util.getPEMStringFromHex(asn1Hex2, "ENCRYPTED PRIVATE KEY"); } } // x. PEM PKCS#8 plain private key of ECDSA private key object if (formatType == "PKCS8PRV" && typeof KJUR.crypto.ECDSA != "undefined" && keyObjOrHex instanceof KJUR.crypto.ECDSA && keyObjOrHex.isPrivate == true) { var keyObj = new KJUR.asn1.ASN1Util.newObject({ "seq": [ {"int": 1}, {"octstr": {"hex": keyObjOrHex.prvKeyHex}}, {"tag": ['a1', true, {"bitstr": {"hex": "00" + keyObjOrHex.pubKeyHex}}]} ] }); var keyHex = keyObj.getEncodedHex(); var asn1Obj = KJUR.asn1.ASN1Util.newObject({ "seq": [ {"int": 0}, {"seq": [ {"oid": {"name": "ecPublicKey"}}, {"oid": {"name": keyObjOrHex.curveName}} ]}, {"octstr": {"hex": keyHex}} ] }); var asn1Hex = asn1Obj.getEncodedHex(); if (passwd === undefined || passwd == null) { return ns1.ASN1Util.getPEMStringFromHex(asn1Hex, "PRIVATE KEY"); } else { var asn1Hex2 = _getEncryptedPKCS8(asn1Hex, passwd); return ns1.ASN1Util.getPEMStringFromHex(asn1Hex2, "ENCRYPTED PRIVATE KEY"); } } // x. PEM PKCS#8 plain private key of DSA private key object if (formatType == "PKCS8PRV" && typeof KJUR.crypto.DSA != "undefined" && keyObjOrHex instanceof KJUR.crypto.DSA && keyObjOrHex.isPrivate == true) { var keyObj = new KJUR.asn1.DERInteger({'bigint': keyObjOrHex.x}); var keyHex = keyObj.getEncodedHex(); var asn1Obj = KJUR.asn1.ASN1Util.newObject({ "seq": [ {"int": 0}, {"seq": [ {"oid": {"name": "dsa"}}, {"seq": [ {"int": {"bigint": keyObjOrHex.p}}, {"int": {"bigint": keyObjOrHex.q}}, {"int": {"bigint": keyObjOrHex.g}} ]} ]}, {"octstr": {"hex": keyHex}} ] }); var asn1Hex = asn1Obj.getEncodedHex(); if (passwd === undefined || passwd == null) { return ns1.ASN1Util.getPEMStringFromHex(asn1Hex, "PRIVATE KEY"); } else { var asn1Hex2 = _getEncryptedPKCS8(asn1Hex, passwd); return ns1.ASN1Util.getPEMStringFromHex(asn1Hex2, "ENCRYPTED PRIVATE KEY"); } } throw "unsupported object nor format"; }; // -- PUBLIC METHODS FOR CSR ------------------------------------------------------- /** * get RSAKey/DSA/ECDSA public key object from PEM formatted PKCS#10 CSR string * @name getKeyFromCSRPEM * @memberOf KEYUTIL * @function * @param {String} csrPEM PEM formatted PKCS#10 CSR string * @return {Object} RSAKey/DSA/ECDSA public key object * @since keyutil 1.0.5 */ KEYUTIL.getKeyFromCSRPEM = function(csrPEM) { var csrHex = KEYUTIL.getHexFromPEM(csrPEM, "CERTIFICATE REQUEST"); var key = KEYUTIL.getKeyFromCSRHex(csrHex); return key; }; /** * get RSAKey/DSA/ECDSA public key object from hexadecimal string of PKCS#10 CSR * @name getKeyFromCSRHex * @memberOf KEYUTIL * @function * @param {String} csrHex hexadecimal string of PKCS#10 CSR * @return {Object} RSAKey/DSA/ECDSA public key object * @since keyutil 1.0.5 */ KEYUTIL.getKeyFromCSRHex = function(csrHex) { var info = KEYUTIL.parseCSRHex(csrHex); var key = KEYUTIL.getKey(info.p8pubkeyhex, null, "pkcs8pub"); return key; }; /** * parse hexadecimal string of PKCS#10 CSR (certificate signing request) * @name parseCSRHex * @memberOf KEYUTIL * @function * @param {String} csrHex hexadecimal string of PKCS#10 CSR * @return {Array} associative array of parsed CSR * @since keyutil 1.0.5 * @description * Resulted associative array has following properties: * */ KEYUTIL.parseCSRHex = function(csrHex) { var result = {}; var h = csrHex; // 1. sequence if (h.substr(0, 2) != "30") throw "malformed CSR(code:001)"; // not sequence var a1 = ASN1HEX.getPosArrayOfChildren_AtObj(h, 0); if (a1.length < 1) throw "malformed CSR(code:002)"; // short length // 2. 2nd sequence if (h.substr(a1[0], 2) != "30") throw "malformed CSR(code:003)"; // not sequence var a2 = ASN1HEX.getPosArrayOfChildren_AtObj(h, a1[0]); if (a2.length < 3) throw "malformed CSR(code:004)"; // 2nd seq short elem result.p8pubkeyhex = ASN1HEX.getHexOfTLV_AtObj(h, a2[2]); return result; };