def __init__(self, name, secret="", sshkeyname=""): """ is secret == "" then will use the ssh-agent to generate a secret """ JSBASE.__init__(self) if sshkeyname: self.logger.debug("sshkeyname for nacl:%s"%sshkeyname) pass elif j.tools.configmanager.keyname: self.logger.debug("get config from git repo, keyname='%s'"% j.tools.configmanager.keyname) sshkeyname = j.tools.configmanager.keyname else: sshkeyname = j.core.state.configGetFromDict("myconfig", "sshkeyname") self.logger.debug("get config from system, keyname:'%s'"%sshkeyname) self.sshkeyname = sshkeyname self._agent = None if isinstance(secret, str): secret = secret.encode() self.name = name self.path = j.tools.configmanager.path self.logger.debug("NACL uses path:'%s'"%self.path) # get/create the secret seed self.path_secretseed = "%s/%s.seed" % (self.path, self.name) if not j.sal.fs.exists(self.path_secretseed): secretseed = self.hash32(nacl.utils.random( nacl.secret.SecretBox.KEY_SIZE)) self.file_write_hex(self.path_secretseed, secretseed) else: secretseed = self.file_read_hex(self.path_secretseed) # this creates a unique encryption box # the secret needs 3 components: the passphrase(secret), the # secretseed means the repo & a loaded ssh-agent with your ssh key secret2 = self.hash32(secretseed + secret + self.sign_with_ssh_key(secretseed + secret)) # self._box is a temp encryption box which only exists while this # process runs # create temp box encrypt/decr (this to not keep secret in mem) self._box = nacl.secret.SecretBox( nacl.utils.random(nacl.secret.SecretBox.KEY_SIZE)) self.secret = self._box.encrypt( secret2, nacl.utils.random(nacl.secret.SecretBox.NONCE_SIZE)) secret = "" secret2 = "" secretseed = "" self.path_privatekey = "%s/%s.priv" % (self.path, self.name) if not j.sal.fs.exists(self.path_privatekey): self._keys_generate() self._privkey = "" self._pubkey = "" self._signingkey = "" self._signingkey_pub = ""
def _get_nacl_secret_box(secret, hmac_secret): if isinstance(secret, text_type): secret = secret.encode("utf-8") if isinstance(hmac_secret, text_type): hmac_secret = hmac_secret.encode("utf-8") secret_key = Hkdf(b"", hmac_secret).expand(secret) box = nacl.secret.SecretBox(secret_key) return box
def configure(self, privkey_words=None, secret=None, sshagent_use=None, interactive=False, generate=False): """ secret is used to encrypt/decrypt the private key when stored on local filesystem privkey_words is used to put the private key back will ask for the details of the configuration :param: sshagent_use is True, will derive the secret from the private key of the ssh-agent if only 1 ssh key loaded secret needs to be None at that point :param: secret only used when sshagent not used, will be stored encrypted in redis sha256 is used on the secret as specified above before storing/encrypting/decrypting the private key :param: generate if True and interactive is False then will autogenerate a key :return: None """ self._log_debug("NACL uses path:'%s'" % self._path) self.privkey = None j.application.interactive = j.application.interactive or interactive # create dir where the secret will be to encrypt the secret j.sal.fs.createDir(j.core.tools.text_replace("{DIR_VAR}/logs")) j.sal.fs.remove(self._path_encryptor_for_secret) redis_key = "secret_%s" % self.name if j.core.db is None: j.clients.redis.core_get() j.core.db.delete(redis_key) if j.application.interactive and sshagent_use is None: sshagent_use = j.tools.console.askYesNo( "do you want to use ssh-agent for secret key in jumpscale?") if sshagent_use is False: if secret is None: secret = j.tools.console.askPassword( "Provide a strong secret which will be used to encrypt/decrypt your private key" ) if secret.strip() in [""]: self._error_raise("Secret cannot be empty") secret = self._hash(secret) # will create a dummy file with a random key which will encrypt the secret key = nacl.utils.random(nacl.secret.SecretBox.KEY_SIZE) j.sal.fs.writeFile(self._path_encryptor_for_secret, key) self._box = nacl.secret.SecretBox(key) if isinstance(secret, str): secret = secret.encode() r = self._box.encrypt(secret) j.core.db.set(redis_key, r) # create path where the files for nacl will be j.sal.fs.createDir(self._path) self.load(die=False) if self.privkey is None: if j.application.interactive: # means we did not find a priv key yet self._ask_privkey_words() elif generate: self._keys_generate() self.load(die=False) if self.privkey is None: # none of the methods worked self._error_raise( "could not generate/load a private key, please use 'kosmos --init' to fix." )