[security] Hide/encrypt password in bash file to stop accidentally seeing it

Sorry if this has been asked before, I did check but couldn't find anything...

Is there a function in Unix to encrypt and decrypt a password in a batch file so that I can pipe it into some other commands in a bash file?

I realise that doing this provides no real security, it is more to stop someone accidentally seeing the password if they are looking at the script over my shoulder :)

I'm running on Red Hat 5.3.

I have a script which does something similar to this:

serverControl.sh -u admin -p myPassword -c shutdown

and I would like to do something like this:

password = decrypt("fgsfkageaivgea", "aDecryptionKey")
serverControl.sh -u admin -p $password -c shutdown

This doesn't protect the password in any way, but does stop someone from accidentally seeing it over my shoulder.

This question is related to security bash unix passwords

The answer is


  • indent it off the edge of your screen (assuming you don't use line wrapping and you have a consistant editor width)

or

  • store it in a separate file and read it in.

I used base64 for the overcoming the same problem, i.e. people can see my password over my shoulder.

Here is what I did - I created a new "db_auth.cfg" file and created parameters with one being my db password. I set the permission as 750 for the file.

DB_PASSWORD=Z29vZ2xl

In my shell script I used the "source" command to get the file and then decode it back to use in my script.

source path_to_the_file/db_auth.cfg
DB_PASSWORD=$(eval echo ${DB_PASSWORD} | base64 --decode)

I hope this helps.


You should be able to use crypt, mcrypt, or gpg to meet your needs. They all support a number of algorithms. crypt is a bit outdated though.

More info:


Another solution, without regard to security (I also think it is better to keep the credentials in another file or in a database) is to encrypt the password with gpg and insert it in the script.

I use a password-less gpg key pair that I keep in a usb. (Note: When you export this key pair don't use --armor, export them in binary format).

First encrypt your password:

EDIT: Put a space before this command, so it is not recorded by the bash history.

echo -n "pAssw0rd" | gpg --armor --no-default-keyring --keyring /media/usb/key.pub --recipient [email protected] --encrypt

That will be print out the gpg encrypted password in the standart output. Copy the whole message and add this to the script:

password=$(gpg --batch --quiet --no-default-keyring --secret-keyring /media/usb/key.priv --decrypt <<EOF 
-----BEGIN PGP MESSAGE-----

hQEMA0CjbyauRLJ8AQgAkZT5gK8TrdH6cZEy+Ufl0PObGZJ1YEbshacZb88RlRB9
h2z+s/Bso5HQxNd5tzkwulvhmoGu6K6hpMXM3mbYl07jHF4qr+oWijDkdjHBVcn5
0mkpYO1riUf0HXIYnvCZq/4k/ajGZRm8EdDy2JIWuwiidQ18irp07UUNO+AB9mq8
5VXUjUN3tLTexg4sLZDKFYGRi4fyVrYKGsi0i5AEHKwn5SmTb3f1pa5yXbv68eYE
lCVfy51rBbG87UTycZ3gFQjf1UkNVbp0WV+RPEM9JR7dgR+9I8bKCuKLFLnGaqvc
beA3A6eMpzXQqsAg6GGo3PW6fMHqe1ZCvidi6e4a/dJDAbHq0XWp93qcwygnWeQW
Ozr1hr5mCa+QkUSymxiUrRncRhyqSP0ok5j4rjwSJu9vmHTEUapiyQMQaEIF2e2S
/NIWGg==
=uriR
-----END PGP MESSAGE-----
EOF)

In this way only if the usb is mounted in the system the password can be decrypted. Of course you can also import the keys into the system (less secure, or no security at all) or you can protect the private key with password (so it can not be automated).


Although this is not a built in Unix solution, I've implemented a solution for this using a shell script that can be included in whatever shell script you are using. This is usable on POSIX compliant setups. (sh, bash, ksh, zsh) The full description is available in the github repo -> https://github.com/plyint/encpass.sh. This solution will auto-generate a key for your script and store the key and your password (or other secrets) in a hidden directory under your user (i.e. ~/.encpass).

In your script you just need to source encpass.sh and then call the get_secret method. For example:

#!/bin/sh
. encpass.sh
password=$(get_secret)

Pasted below is lite version of the code for encpass.sh(you can get the full version over on github) for easier visibility:

 #!/bin/sh
 ################################################################################
 # Copyright (c) 2020 Plyint, LLC <[email protected]>. All Rights Reserved.
 # This file is licensed under the MIT License (MIT). 
 # Please see LICENSE.txt for more information.
 # 
 # DESCRIPTION: 
 # This script allows a user to encrypt a password (or any other secret) at 
 # runtime and then use it, decrypted, within a script.  This prevents shoulder 
 # surfing passwords and avoids storing the password in plain text, which could 
 # inadvertently be sent to or discovered by an individual at a later date.
 #
 # This script generates an AES 256 bit symmetric key for each script (or user-
 # defined bucket) that stores secrets.  This key will then be used to encrypt 
 # all secrets for that script or bucket.  encpass.sh sets up a directory 
 # (.encpass) under the user's home directory where keys and secrets will be 
 # stored.
 #
 # For further details, see README.md or run "./encpass ?" from the command line.
 #
 ################################################################################

 encpass_checks() {
    [ -n "$ENCPASS_CHECKS" ] && return

    if [ -z "$ENCPASS_HOME_DIR" ]; then
        ENCPASS_HOME_DIR="$HOME/.encpass"
    fi
    [ ! -d "$ENCPASS_HOME_DIR" ] && mkdir -m 700 "$ENCPASS_HOME_DIR"

    if [ -f "$ENCPASS_HOME_DIR/.extension" ]; then
        # Extension enabled, load it...
        ENCPASS_EXTENSION="$(cat "$ENCPASS_HOME_DIR/.extension")"
        ENCPASS_EXT_FILE="encpass-$ENCPASS_EXTENSION.sh"
        if [ -f "./extensions/$ENCPASS_EXTENSION/$ENCPASS_EXT_FILE" ]; then
            # shellcheck source=/dev/null
          . "./extensions/$ENCPASS_EXTENSION/$ENCPASS_EXT_FILE"
        elif [ ! -z "$(command -v encpass-"$ENCPASS_EXTENSION".sh)" ]; then 
            # shellcheck source=/dev/null
            . "$(command -v encpass-$ENCPASS_EXTENSION.sh)"
        else
            encpass_die "Error: Extension $ENCPASS_EXTENSION could not be found."
        fi

        # Extension specific checks, mandatory function for extensions
        encpass_"${ENCPASS_EXTENSION}"_checks
    else
        # Use default OpenSSL implementation
        if [ ! -x "$(command -v openssl)" ]; then
            echo "Error: OpenSSL is not installed or not accessible in the current path." \
                "Please install it and try again." >&2
            exit 1
        fi

        [ ! -d "$ENCPASS_HOME_DIR/keys" ] && mkdir -m 700 "$ENCPASS_HOME_DIR/keys"
        [ ! -d "$ENCPASS_HOME_DIR/secrets" ] && mkdir -m 700 "$ENCPASS_HOME_DIR/secrets"
        [ ! -d "$ENCPASS_HOME_DIR/exports" ] && mkdir -m 700 "$ENCPASS_HOME_DIR/exports"

    fi

   ENCPASS_CHECKS=1
 }

 # Checks if the enabled extension has implented the passed function and if so calls it
 encpass_ext_func() {
   [ ! -z "$ENCPASS_EXTENSION" ] && ENCPASS_EXT_FUNC="$(command -v "encpass_${ENCPASS_EXTENSION}_$1")" || return
    [ ! -z "$ENCPASS_EXT_FUNC" ] && shift && $ENCPASS_EXT_FUNC "$@" 
 }

 # Initializations performed when the script is included by another script
 encpass_include_init() {
    encpass_ext_func "include_init" "$@"
    [ ! -z "$ENCPASS_EXT_FUNC" ] && return

    if [ -n "$1" ] && [ -n "$2" ]; then
        ENCPASS_BUCKET=$1
        ENCPASS_SECRET_NAME=$2
    elif [ -n "$1" ]; then
        if [ -z "$ENCPASS_BUCKET" ]; then
          ENCPASS_BUCKET=$(basename "$0")
        fi
        ENCPASS_SECRET_NAME=$1
    else
        ENCPASS_BUCKET=$(basename "$0")
        ENCPASS_SECRET_NAME="password"
    fi
 }

 encpass_generate_private_key() {
    ENCPASS_KEY_DIR="$ENCPASS_HOME_DIR/keys/$ENCPASS_BUCKET"

    [ ! -d "$ENCPASS_KEY_DIR" ] && mkdir -m 700 "$ENCPASS_KEY_DIR"

    if [ ! -f "$ENCPASS_KEY_DIR/private.key" ]; then
        (umask 0377 && printf "%s" "$(openssl rand -hex 32)" >"$ENCPASS_KEY_DIR/private.key")
    fi
 }

 encpass_set_private_key_abs_name() {
    ENCPASS_PRIVATE_KEY_ABS_NAME="$ENCPASS_HOME_DIR/keys/$ENCPASS_BUCKET/private.key"
    [ ! -n "$1" ] && [ ! -f "$ENCPASS_PRIVATE_KEY_ABS_NAME" ] && encpass_generate_private_key
 }

 encpass_set_secret_abs_name() {
    ENCPASS_SECRET_ABS_NAME="$ENCPASS_HOME_DIR/secrets/$ENCPASS_BUCKET/$ENCPASS_SECRET_NAME.enc"
    [ ! -n "$1" ] && [ ! -f "$ENCPASS_SECRET_ABS_NAME" ] && set_secret
 }

 encpass_rmfifo() {
    trap - EXIT
    kill "$1" 2>/dev/null
    rm -f "$2"
 }

 encpass_mkfifo() {
    fifo="$ENCPASS_HOME_DIR/$1.$$"
    mkfifo -m 600 "$fifo" || encpass_die "Error: unable to create named pipe"
    printf '%s\n' "$fifo"
 }

 get_secret() {
    encpass_checks
    encpass_ext_func "get_secret" "$@"; [ ! -z "$ENCPASS_EXT_FUNC" ] && return

    [ "$(basename "$0")" != "encpass.sh" ] && encpass_include_init "$1" "$2"

    encpass_set_private_key_abs_name
    encpass_set_secret_abs_name
    encpass_decrypt_secret "$@"
 }

 set_secret() {
    encpass_checks

    encpass_ext_func "set_secret" "$@"; [ ! -z "$ENCPASS_EXT_FUNC" ] && return

    if [ "$1" != "reuse" ] || { [ -z "$ENCPASS_SECRET_INPUT" ] && [ -z "$ENCPASS_CSECRET_INPUT" ]; }; then
        echo "Enter $ENCPASS_SECRET_NAME:" >&2
        stty -echo
        read -r ENCPASS_SECRET_INPUT
        stty echo
        echo "Confirm $ENCPASS_SECRET_NAME:" >&2
        stty -echo
        read -r ENCPASS_CSECRET_INPUT
        stty echo

        # Use named pipe to securely pass secret to openssl
        fifo="$(encpass_mkfifo set_secret_fifo)"
    fi

    if [ "$ENCPASS_SECRET_INPUT" = "$ENCPASS_CSECRET_INPUT" ]; then
        encpass_set_private_key_abs_name
        ENCPASS_SECRET_DIR="$ENCPASS_HOME_DIR/secrets/$ENCPASS_BUCKET"

        [ ! -d "$ENCPASS_SECRET_DIR" ] && mkdir -m 700 "$ENCPASS_SECRET_DIR"

        # Generate IV and create secret file
        printf "%s" "$(openssl rand -hex 16)" > "$ENCPASS_SECRET_DIR/$ENCPASS_SECRET_NAME.enc"
        ENCPASS_OPENSSL_IV="$(cat "$ENCPASS_SECRET_DIR/$ENCPASS_SECRET_NAME.enc")"

        echo "$ENCPASS_SECRET_INPUT" > "$fifo" &
        # Allow expansion now so PID is set
        # shellcheck disable=SC2064
        trap "encpass_rmfifo $! $fifo" EXIT HUP TERM INT TSTP

        # Append encrypted secret to IV in the secret file
        openssl enc -aes-256-cbc -e -a -iv "$ENCPASS_OPENSSL_IV" \
            -K "$(cat "$ENCPASS_HOME_DIR/keys/$ENCPASS_BUCKET/private.key")" \
            -in "$fifo" 1>> "$ENCPASS_SECRET_DIR/$ENCPASS_SECRET_NAME.enc"
    else
        encpass_die "Error: secrets do not match.  Please try again."
    fi
 }

 encpass_decrypt_secret() {
    encpass_ext_func "decrypt_secret" "$@"; [ ! -z "$ENCPASS_EXT_FUNC" ] && return

    if [ -f "$ENCPASS_PRIVATE_KEY_ABS_NAME" ]; then
        ENCPASS_DECRYPT_RESULT="$(dd if="$ENCPASS_SECRET_ABS_NAME" ibs=1 skip=32 2> /dev/null | openssl enc -aes-256-cbc \
            -d -a -iv "$(head -c 32 "$ENCPASS_SECRET_ABS_NAME")" -K "$(cat "$ENCPASS_PRIVATE_KEY_ABS_NAME")" 2> /dev/null)"
        if [ ! -z "$ENCPASS_DECRYPT_RESULT" ]; then
            echo "$ENCPASS_DECRYPT_RESULT"
        else
            # If a failed unlock command occurred and the user tries to show the secret
            # Present either a locked or failed decrypt error.
            if [ -f "$ENCPASS_HOME_DIR/keys/$ENCPASS_BUCKET/private.lock" ]; then 
            echo "**Locked**"
            else
                # The locked file wasn't present as expected.  Let's display a failure
            echo "Error: Failed to decrypt"
            fi
        fi
    elif [ -f "$ENCPASS_HOME_DIR/keys/$ENCPASS_BUCKET/private.lock" ]; then
        echo "**Locked**"
    else
        echo "Error: Unable to decrypt. The key file \"$ENCPASS_PRIVATE_KEY_ABS_NAME\" is not present."
    fi
 }

 encpass_die() {
   echo "$@" >&2
   exit 1
 }
 #LITE

Following line in above code is not working

DB_PASSWORD=$(eval echo ${DB_PASSWORD} | base64 --decode)

Correct line is:

DB_PASSWORD=`echo $PASSWORD|base64 -d`

And save the password in other file as PASSWORD.


There's a more convenient way to store passwords in a script but you will have to encrypt and obfuscate the script so that it cannot be read. In order to successfully encrypt and obfuscate a shell script and actually have that script be executable, try copying and pasting it here:

http://www.kinglazy.com/shell-script-encryption-kinglazy-shieldx.htm

On the above page, all you have to do is submit your script and give the script a proper name, then hit the download button. A zip file will be generated for you. Right click on the download link and copy the URL you're provided. Then, go to your UNIX box and perform the following steps.

Installation:

1. wget link-to-the-zip-file
2. unzip the-newly-downloaded-zip-file
3. cd /tmp/KingLazySHIELD
4. ./install.sh /var/tmp/KINGLAZY/SHIELDX-(your-script-name) /home/(your-username) -force

What the above install command will do for you is:

  1. Install the encrypted version of your script in the directory /var/tmp/KINGLAZY/SHIELDX-(your-script-name).
  2. It'll place a link to this encrypted script in whichever directory you specify in replacement of /home/(your-username) - that way, it allows you to easily access the script without having to type the absolute path.
  3. Ensures NO ONE can modify the script - Any attempts to modify the encrypted script will render it inoperable...until those attempts are stopped or removed. It can even be configured to notify you whenever someone tries to do anything with the script other than run it...i.e. hacking or modification attempts.
  4. Ensures absolutely NO ONE can make copies of it. No one can copy your script to a secluded location and try to screw around with it to see how it works. All copies of the script must be links to the original location which you specified during install (step 4).

NOTE:

This does not work for interactive scripts that prompts and waits on the user for a response. The values that are expected from the user should be hard-coded into the script. The encryption ensures no one can actually see those values so you need not worry about that.

RELATION:

The solution provided in this post answers your problem in the sense that it encrypts the actual script containing the password that you wanted to have encrypted. You get to leave the password as is (unencrypted) but the script that the password is in is so deeply obfuscated and encrypted that you can rest assured no one will be able to see it. And if attempts are made to try to pry into the script, you will receive email notifications about them.


Examples related to security

Monitoring the Full Disclosure mailinglist Two Page Login with Spring Security 3.2.x How to prevent a browser from storing passwords JWT authentication for ASP.NET Web API How to use a client certificate to authenticate and authorize in a Web API Disable-web-security in Chrome 48+ When you use 'badidea' or 'thisisunsafe' to bypass a Chrome certificate/HSTS error, does it only apply for the current site? How does Content Security Policy (CSP) work? How to prevent Screen Capture in Android Default SecurityProtocol in .NET 4.5

Examples related to bash

Comparing a variable with a string python not working when redirecting from bash script Zipping a file in bash fails How do I prevent Conda from activating the base environment by default? Get first line of a shell command's output Fixing a systemd service 203/EXEC failure (no such file or directory) /bin/sh: apt-get: not found VSCode Change Default Terminal Run bash command on jenkins pipeline How to check if the docker engine and a docker container are running? How to switch Python versions in Terminal?

Examples related to unix

Docker CE on RHEL - Requires: container-selinux >= 2.9 What does `set -x` do? How to find files modified in last x minutes (find -mmin does not work as expected) sudo: npm: command not found How to sort a file in-place How to read a .properties file which contains keys that have a period character using Shell script gpg decryption fails with no secret key error Loop through a comma-separated shell variable Best way to find os name and version in Unix/Linux platform Resource u'tokenizers/punkt/english.pickle' not found

Examples related to passwords

Your password does not satisfy the current policy requirements Laravel Password & Password_Confirmation Validation Default password of mysql in ubuntu server 16.04 mcrypt is deprecated, what is the alternative? What is the default root pasword for MySQL 5.7 MySQL user DB does not have password columns - Installing MySQL on OSX Changing an AIX password via script? Hide password with "•••••••" in a textField How to create a laravel hashed password Enter export password to generate a P12 certificate