3

I had written a shell script that will connect with the Database to perform some operations

This is my sample code

#!/usr/bin/ksh
. /home/ram/.profile

sqlplus username/pwd@TNS<<EOF
select sysdate from dual;
exit;
EOF

I am using this code in AIX system , I want the pwd to be encrypted.

Is there any command in shell , I heard crypt command is having some security problems

Programs for breaking crypt(1) encryption are widely available. Bob Baldwin's Crypt Breaker's Workbench,[2] which was written in 1984-1985, is an interactive tool that provides successive plaintext guesses that must be corrected by the user. Peter Selinger's unixcrypt-breaker[3] uses a simple statistical model to guess plausible plaintexts, and does not require user interaction. (source-wikipedia ).

Even though I tried crypt command in my AIX , but it throws error

[shell-ksh]$uname    
AIX
[shell-ksh]$crypt
ksh: crypt: command not found
[shell-ksh]$echo $SHELL
/usr/bin/ksh

I like to know about any secure method to encrypt the password in shell ?

3
  • 1
    Not sure you understand what "encrypted" means. sqlplus requires a plain text password, so will need eventually to "de-crypt" the password which means having the de-cryption key in your script or somewhere available (recursive mode on: unless you want to crypt the encryption key ...) – Ouki Mar 24 '14 at 11:41
  • ya but instead of plain text password , we can use some function to fill the password , eg decrypt($pwd) there would be better – Jeyanthinath Mar 24 '14 at 15:53
  • 1
    And in that function you will need to have the decrypt key in plain text. Regarding crypt, it has been removed from AIX with 5.x. – Ouki Mar 24 '14 at 16:19
1

Instead of hard coding the password in your shell script, you can use the oracle password repository to use the password in your shell script.

This tool uses a simple file to stores the passwords encrypted. You can secure this file to make it non-accessible for others. The tool can be found here. You can see the installation steps of this tool from here.

1
  • 1
    such tools are called "password manager" on Debian: cpm, fpm2, gringotts, keepass2, pass and more... – user55518 Mar 24 '14 at 17:35
1

Assuming your user and pass are stored in user.txt and pass.txt

Encrypt with:

$ openssl aes-256-cbc -salt -in user.txt -out user.txt.enc -pass file:pass.txt

Decrypt with:

$ openssl aes-256-cbc -d -salt -in user.txt.enc -out user.txt.dec -pass file:pass.txt

In order to have more secure encryption you can try to use you own complex salt with -S "your complex string". However this might be sufficient for most uses.

0

You might look at using an SSH tunnel. You can setup the database to listen on a local port and allow a user to connect without a password on that port (reject all connections other than 127.0.0.1 on a specific interface) and then use SSH to negotiate a tunnel to that port. You then use certificate authentication to connect to SSH, this is both harder to spoof and there are no hard coded passwords. If this script is something that should operate on a cron job it can execute as a service account that runs with a nologin shell.

What your worrying about at that point is SSH key management and there are many tools to assist with this. The only people locally who could get to the private key are users with root access and in that case, your encrypted password store isn't safe from them either.

Another benefit is that the script can be placed under remote version control and the authentication is left to being an implementation detail, not something that can be extracted from the script should the code leak beyond the machine it's implemented on.

A few databases already support certificate auth (Postgresql for instance), but using SSH tunnel would work for any database that has a command line client. I've used this for scripted backups of MySQL and Postgresql, it works like a charm.

0

I had a similar problem wanting to have a simple, yet secure solution to store encrypted secrets in shell scripts. The best solution I came up with was to store the encrypted passwords in the home directory of my user and then read them into my scripts. The root user on a machine could potentially access the secrets, but otherwise they were safe. This has the nice benefit of allowing you to distribute or store the script in a code repository without having to expose your credentials.

This solution has evolved overtime into a shell script that my company (Plyint - https://plyint.com) maintains. You can download the shell script, encpass.sh, over on github at https://github.com/plyint/encpass.sh.

Essentially what it does is create an AES 256-bit key for each script (or user-defined bucket) and then encrypts any secrets for that script in a hidden folder under your home directory that only your user can access. When the keys are not in use it also provides a lock command to encrypt the keys themselves with a password.

Pasted below is the lite version of the code, but you can download the full version over on github. It has an MIT License, so you can use and distribute it in commercial settings.

 #!/bin/sh
 ################################################################################
 # Copyright (c) 2020 Plyint, LLC <contact@plyint.com>. 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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.