bash 如何在不回显的情况下从 shell 脚本获取密码

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3980668/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 19:47:29  来源:igfitidea点击:

How to get a password from a shell script without echoing

bashshellscriptingsh

提问by BD at Rivenhill

I have a script that automates a process that needs access to a password protected system. The system is accessed via a command-line program that accepts the user password as an argument.

我有一个脚本可以自动执行需要访问密码保护系统的过程。该系统通过接受用户密码作为参数的命令行程序访问。

I would like to prompt the user to type in their password, assign it to a shell variable, and then use that variable to construct the command line of the accessing program (which will of course produce stream output that I will process).

我想提示用户输入他们的密码,将其分配给一个 shell 变量,然后使用该变量来构建访问程序的命令行(这当然会产生我将处理的流输出)。

I am a reasonably competent shell programmer in Bourne/Bash, but I don't know how to accept the user input without having it echo to the terminal (or maybe having it echoed using '*' characters).

我是 Bourne/Bash 中相当称职的 shell 程序员,但我不知道如何在不回显到终端的情况下接受用户输入(或者可能使用 '*' 字符回显)。

Can anyone help with this?

有人能帮忙吗?

回答by wsware

Here is another way to do it:

这是另一种方法:

#!/bin/bash
# Read Password
echo -n Password: 
read -s password
echo
# Run Command
echo $password

The read -swill turn off echo for you. Just replace the echoon the last line with the command you want to run.

read -s将关闭回声你。只需用echo您要运行的命令替换最后一行的 。

回答by thecloud

A POSIX compliant answer. Notice the use of /bin/shinstead of /bin/bash. (It does work with bash, but it does not requirebash.)

符合 POSIX 标准的答案。注意使用/bin/sh代替/bin/bash。(它确实适用于 bash,但它不需要bash。)

#!/bin/sh
stty -echo
printf "Password: "
read PASSWORD
stty echo
printf "\n"

回答by smendola

One liner:

一个班轮:

read -s -p "Password: " password

Under Linux (and cygwin) this form works in bash and sh. It may not be standard Unix sh, though.

在 Linux(和 cygwin)下,这种形式适用于 bash 和 sh。不过,它可能不是标准的 Unix sh。

For more info and options, in bash, type "help read".

有关更多信息和选项,请在 bash 中键入“help read”。

$ help read
read: read [-ers] [-a array] [-d delim] [-i text] [-n nchars] [-N nchars] [-p prompt] [-t timeout] [-u fd] [name ...]
Read a line from the standard input and split it into fields.
  ...
  -p prompt output the string PROMPT without a trailing newline before
            attempting to read
  ...
  -s                do not echo input coming from a terminal

回答by Susam Pal

The -soption of readis not defined in the POSIX standard. See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/read.html. I wanted something that would work for any POSIX shell, so I wrote a little function that uses sttyto disable echo.

-s选项read在 POSIX 标准中没有定义。请参阅http://pubs.opengroup.org/onlinepubs/9699919799/utilities/read.html。我想要一些适用于任何 POSIX shell 的东西,所以我写了一个stty用来禁用 echo的小函数。

#!/bin/sh

# Read secret string
read_secret()
{
    # Disable echo.
    stty -echo

    # Set up trap to ensure echo is enabled before exiting if the script
    # is terminated while echo is disabled.
    trap 'stty echo' EXIT

    # Read secret.
    read "$@"

    # Enable echo.
    stty echo
    trap - EXIT

    # Print a newline because the newline entered by the user after
    # entering the passcode is not echoed. This ensures that the
    # next line of output begins at a new line.
    echo
}

This function behaves quite similar to the readcommand. Here is a simple usage of readfollowed by similar usage of read_secret. The input to read_secretappears empty because it was not echoed to the terminal.

此函数的行为与read命令非常相似。这是一个简单的用法,read然后是类似的用法read_secret。输入read_secret显示为空,因为它没有回显到终端。

[susam@cube ~]$ read a b c
foo \bar baz \qux
[susam@cube ~]$ echo a=$a b=$b c=$c
a=foo b=bar c=baz qux
[susam@cube ~]$ unset a b c
[susam@cube ~]$ read_secret a b c

[susam@cube ~]$ echo a=$a b=$b c=$c
a=foo b=bar c=baz qux
[susam@cube ~]$ unset a b c

Here is another that uses the -roption to preserve the backslashes in the input. This works because the read_secretfunction defined above passes all arguments it receives to the readcommand.

这是另一个使用-r选项保留输入中的反斜杠的方法。这是有效的,因为read_secret上面定义的函数将它接收到的所有参数传递给read命令。

[susam@cube ~]$ read -r a b c
foo \bar baz \qux
[susam@cube ~]$ echo a=$a b=$b c=$c
a=foo b=\bar c=baz \qux
[susam@cube ~]$ unset a b c
[susam@cube ~]$ read_secret -r a b c

[susam@cube ~]$ echo a=$a b=$b c=$c
a=foo b=\bar c=baz \qux
[susam@cube ~]$ unset a b c

Finally, here is an example that shows how to use the read_secretfunction to read a password in a POSIX compliant manner.

最后,这是一个示例,展示了如何使用该read_secret函数以符合 POSIX 的方式读取密码。

printf "Password: "
read_secret password
# Do something with $password here ...

回答by Manuel

I found to be the the askpasscommand useful

我发现这个askpass命令很有用

password=$(/lib/cryptsetup/askpass "Give a password")

Every input character is replaced by *. See: Give a password ****

每个输入字符都被 * 替换。见:给一个密码****

回答by Ignacio Vazquez-Abrams

Turn echooff using stty, then back on again after.

echo使用 关闭stty,然后再次打开。

回答by Pascal Chardon

You can also prompt for a password without setting a variable in the current shell by doing something like this:

您还可以通过执行以下操作来提示输入密码而不在当前 shell 中设置变量:

$(read -s;echo $REPLY)

For instance:

例如:

my-command --set password=$(read -sp "Password: ";echo $REPLY)

You can add several of these prompted values with line break, doing this:

您可以使用换行符添加这些提示值中的几个,这样做:

my-command --set user=$(read -sp "`echo $'\n '`User: ";echo $REPLY) --set password=$(read -sp "`echo $'\n '`Password: ";echo $REPLY)

回答by Alexander Nick

For anyone needing to prompt for a password, you may be interested in using encpass.sh. This is a script I wrote for similar purposes of capturing a secret at runtime and then encrypting it for subsequent occasions. Subsequent runs do not prompt for the password as it will just use the encrypted value from disk.

对于需要提示输入密码的任何人,您可能对使用encpass.sh感兴趣。这是我为类似目的而编写的脚本,在运行时捕获秘密,然后在随后的场合对其进行加密。后续运行不会提示输入密码,因为它只会使用磁盘中的加密值。

It stores the encrypted passwords in a hidden folder under the user's home directory or in a custom folder that you can define through the environment variable ENCPASS_HOME_DIR. It is designed to be POSIX compliant and has an MIT License, so it can be used even in corporate enterprise environments. My company, Plyint LLC, maintains the script and occasionally releases updates. Pull requests are also welcome, if you find an issue. :)

它将加密的密码存储在用户主目录下的隐藏文件夹中,或存储在您可以通过环境变量 ENCPASS_HOME_DIR 定义的自定义文件夹中。它被设计为符合 POSIX 标准并拥有 MIT 许可证,因此它甚至可以在公司企业环境中使用。我的公司Plyint LLC维护脚本并偶尔发布更新。如果您发现问题,也欢迎拉取请求。:)

To use it in your scripts simply source encpass.sh in your script and call the get_secret function. I'm including a copy of the script below for easy visibility.

要在脚本中使用它,只需在脚本中源 encpass.sh 并调用 get_secret 函数。为了便于查看,我在下面包含了脚本的副本。

#!/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() {
    if [ -n "$ENCPASS_CHECKS" ]; then
        return
    fi

    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

    if [ -z "$ENCPASS_HOME_DIR" ]; then
        ENCPASS_HOME_DIR=$(encpass_get_abs_filename ~)/.encpass
    fi

    if [ ! -d "$ENCPASS_HOME_DIR" ]; then
        mkdir -m 700 "$ENCPASS_HOME_DIR"
        mkdir -m 700 "$ENCPASS_HOME_DIR/keys"
        mkdir -m 700 "$ENCPASS_HOME_DIR/secrets"
    fi

    if [ "$(basename "
echo "password123" | md5sum  | cut -d '-' -f 1 > /tmp/secret
")" != "encpass.sh" ]; then encpass_include_init "" "" fi ENCPASS_CHECKS=1 } # Initializations performed when the script is included by another script encpass_include_init() { if [ -n "" ] && [ -n "" ]; then ENCPASS_BUCKET= ENCPASS_SECRET_NAME= elif [ -n "" ]; then ENCPASS_BUCKET=$(basename "
#!/bin/bash

PASSWORD_FILE="/tmp/secret"
MD5_HASH=$(cat /tmp/secret)
PASSWORD_WRONG=1


while [ $PASSWORD_WRONG -eq 1 ]
 do
    echo "Enter your password:"
    read -s ENTERED_PASSWORD
    if [ "$MD5_HASH" != "$(echo $ENTERED_PASSWORD | md5sum | cut -d '-' -f 1)" ]; then
        echo "Access Deniend: Incorrenct password!. Try again"
    else
        echo "Access Granted"
        PASSWORD_WRONG=0
    fi
done
") ENCPASS_SECRET_NAME= else ENCPASS_BUCKET=$(basename "
echo "password123" | md5sum  | cut -d '-' -f 1 > /tmp/secret
") ENCPASS_SECRET_NAME="password" fi } encpass_generate_private_key() { ENCPASS_KEY_DIR="$ENCPASS_HOME_DIR/keys/$ENCPASS_BUCKET" if [ ! -d "$ENCPASS_KEY_DIR" ]; then mkdir -m 700 "$ENCPASS_KEY_DIR" fi if [ ! -f "$ENCPASS_KEY_DIR/private.key" ]; then (umask 0377 && printf "%s" "$(openssl rand -hex 32)" >"$ENCPASS_KEY_DIR/private.key") fi } encpass_get_private_key_abs_name() { ENCPASS_PRIVATE_KEY_ABS_NAME="$ENCPASS_HOME_DIR/keys/$ENCPASS_BUCKET/private.key" if [ "" != "nogenerate" ]; then if [ ! -f "$ENCPASS_PRIVATE_KEY_ABS_NAME" ]; then encpass_generate_private_key fi fi } encpass_get_secret_abs_name() { ENCPASS_SECRET_ABS_NAME="$ENCPASS_HOME_DIR/secrets/$ENCPASS_BUCKET/$ENCPASS_SECRET_NAME.enc" if [ "" != "nocreate" ]; then if [ ! -f "$ENCPASS_SECRET_ABS_NAME" ]; then set_secret "" "" fi fi } get_secret() { encpass_checks "" "" encpass_get_private_key_abs_name encpass_get_secret_abs_name "" "" encpass_decrypt_secret } set_secret() { encpass_checks "" "" if [ "" != "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 fi if [ "$ENCPASS_SECRET_INPUT" = "$ENCPASS_CSECRET_INPUT" ]; then encpass_get_private_key_abs_name ENCPASS_SECRET_DIR="$ENCPASS_HOME_DIR/secrets/$ENCPASS_BUCKET" if [ ! -d "$ENCPASS_SECRET_DIR" ]; then mkdir -m 700 "$ENCPASS_SECRET_DIR" fi 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" | openssl enc -aes-256-cbc -e -a -iv \ "$ENCPASS_OPENSSL_IV" -K \ "$(cat "$ENCPASS_HOME_DIR/keys/$ENCPASS_BUCKET/private.key")" 1>> \ "$ENCPASS_SECRET_DIR/$ENCPASS_SECRET_NAME.enc" else echo "Error: secrets do not match. Please try again." >&2 exit 1 fi } encpass_get_abs_filename() { # : relative filename filename="" parentdir="$(dirname "${filename}")" if [ -d "${filename}" ]; then cd "${filename}" && pwd elif [ -d "${parentdir}" ]; then echo "$(cd "${parentdir}" && pwd)/$(basename "${filename}")" fi } encpass_decrypt_secret() { 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 locked or decrypt command 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 } ########################################################## # COMMAND LINE MANAGEMENT SUPPORT # ------------------------------- # If you don't need to manage the secrets for the scripts # with encpass.sh you can delete all code below this point # in order to significantly reduce the size of encpass.sh. # This is useful if you want to bundle encpass.sh with # your existing scripts and just need the retrieval # functions. ########################################################## encpass_show_secret() { encpass_checks ENCPASS_BUCKET= encpass_get_private_key_abs_name "nogenerate" if [ ! -z "" ]; then ENCPASS_SECRET_NAME= encpass_get_secret_abs_name "" "" "nocreate" if [ -z "$ENCPASS_SECRET_ABS_NAME" ]; then echo "No secret named found for bucket ." exit 1 fi encpass_decrypt_secret else ENCPASS_FILE_LIST=$(ls -1 "$ENCPASS_HOME_DIR"/secrets/"") for ENCPASS_F in $ENCPASS_FILE_LIST; do ENCPASS_SECRET_NAME=$(basename "$ENCPASS_F" .enc) encpass_get_secret_abs_name "" "$ENCPASS_SECRET_NAME" "nocreate" if [ -z "$ENCPASS_SECRET_ABS_NAME" ]; then echo "No secret named $ENCPASS_SECRET_NAME found for bucket ." exit 1 fi echo "$ENCPASS_SECRET_NAME = $(encpass_decrypt_secret)" done fi } encpass_getche() { old=$(stty -g) stty raw min 1 time 0 printf '%s' "$(dd bs=1 count=1 2>/dev/null)" stty "$old" } encpass_remove() { if [ ! -n "$ENCPASS_FORCE_REMOVE" ]; then if [ ! -z "$ENCPASS_SECRET" ]; then printf "Are you sure you want to remove the secret \"%s\" from bucket \"%s\"? [y/N]" "$ENCPASS_SECRET" "$ENCPASS_BUCKET" else printf "Are you sure you want to remove the bucket \"%s?\" [y/N]" "$ENCPASS_BUCKET" fi ENCPASS_CONFIRM="$(encpass_getche)" printf "\n" if [ "$ENCPASS_CONFIRM" != "Y" ] && [ "$ENCPASS_CONFIRM" != "y" ]; then exit 0 fi fi if [ ! -z "$ENCPASS_SECRET" ]; then rm -f "" printf "Secret \"%s\" removed from bucket \"%s\".\n" "$ENCPASS_SECRET" "$ENCPASS_BUCKET" else rm -Rf "$ENCPASS_HOME_DIR/keys/$ENCPASS_BUCKET" rm -Rf "$ENCPASS_HOME_DIR/secrets/$ENCPASS_BUCKET" printf "Bucket \"%s\" removed.\n" "$ENCPASS_BUCKET" fi } encpass_save_err() { if read -r x; then { printf "%s\n" "$x"; cat; } > "" elif [ "$x" != "" ]; then printf "%s" "$x" > "" fi } encpass_help() { less << EOF NAME: encpass.sh - Use encrypted passwords in shell scripts DESCRIPTION: A lightweight solution for using encrypted passwords in shell scripts using OpenSSL. It 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, within a script, 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. Subsequent calls to retrieve a secret will not prompt for a secret to be entered as the file with the encrypted value already exists. Note: By default, encpass.sh sets up a directory (.encpass) under the user's home directory where keys and secrets will be stored. This directory can be overridden by setting the environment variable ENCPASS_HOME_DIR to a directory of your choice. ~/.encpass (or the directory specified by ENCPASS_HOME_DIR) will contain the following subdirectories: - keys (Holds the private key for each script/bucket) - secrets (Holds the secrets stored for each script/bucket) USAGE: To use the encpass.sh script in an existing shell script, source the script and then call the get_secret function. Example: #!/bin/sh . encpass.sh password=$(get_secret) When no arguments are passed to the get_secret function, then the bucket name is set to the name of the script and the secret name is set to "password". There are 2 other ways to call get_secret: Specify the secret name: Ex: $(get_secret user) - bucket name = <script name> - secret name = "user" Specify both the secret name and bucket name: Ex: $(get_secret personal user) - bucket name = "personal" - secret name = "user" encpass.sh also provides a command line interface to manage the secrets. To invoke a command, pass it as an argument to encpass.sh from the shell. $ encpass.sh [COMMAND] See the COMMANDS section below for a list of available commands. Wildcard handling is implemented for secret and bucket names. This enables performing operations like adding/removing a secret to/from multiple buckets at once. COMMANDS: add [-f] <bucket> <secret> Add a secret to the specified bucket. The bucket will be created if it does not already exist. If a secret with the same name already exists for the specified bucket, then the user will be prompted to confirm overwriting the value. If the -f option is passed, then the add operation will perform a forceful overwrite of the value. (i.e. no prompt) list|ls [<bucket>] Display the names of the secrets held in the bucket. If no bucket is specified, then the names of all existing buckets will be displayed. lock Locks all keys used by encpass.sh using a password. The user will be prompted to enter a password and confirm it. A user should take care to securely store the password. If the password is lost then keys can not be unlocked. When keys are locked, secrets can not be retrieved. (e.g. the output of the values in the "show" command will be encrypted/garbage) remove|rm [-f] <bucket> [<secret>] Remove a secret from the specified bucket. If only a bucket is specified then the entire bucket (i.e. all secrets and keys) will be removed. By default the user is asked to confirm the removal of the secret or the bucket. If the -f option is passed then a forceful removal will be performed. (i.e. no prompt) show [<bucket>] [<secret>] Show the unencrypted value of the secret from the specified bucket. If no secret is specified then all secrets for the bucket are displayed. update <bucket> <secret> Updates a secret in the specified bucket. This command is similar to using an "add -f" command, but it has a safety check to only proceed if the specified secret exists. If the secret, does not already exist, then an error will be reported. There is no forceable update implemented. Use "add -f" for any required forceable update scenarios. unlock Unlocks all the keys for encpass.sh. The user will be prompted to enter the password and confirm it. dir Prints out the current value of the ENCPASS_HOME_DIR environment variable. help|--help|usage|--usage|? Display this help message. EOF } # Subcommands for cli support case "" in add ) shift while getopts ":f" ENCPASS_OPTS; do case "$ENCPASS_OPTS" in f ) ENCPASS_FORCE_ADD=1;; esac done encpass_checks if [ -n "$ENCPASS_FORCE_ADD" ]; then shift $((OPTIND-1)) fi if [ ! -z "" ] && [ ! -z "" ]; then # Allow globbing # shellcheck disable=SC2027,SC2086 ENCPASS_ADD_LIST="$(ls -1d "$ENCPASS_HOME_DIR/secrets/""" 2>/dev/null)" if [ -z "$ENCPASS_ADD_LIST" ]; then ENCPASS_ADD_LIST="" fi for ENCPASS_ADD_F in $ENCPASS_ADD_LIST; do ENCPASS_ADD_DIR="$(basename "$ENCPASS_ADD_F")" ENCPASS_BUCKET="$ENCPASS_ADD_DIR" if [ ! -n "$ENCPASS_FORCE_ADD" ] && [ -f "$ENCPASS_ADD_F/.enc" ]; then echo "Warning: A secret with the name \"\" already exists for bucket $ENCPASS_BUCKET." echo "Would you like to overwrite the value? [y/N]" ENCPASS_CONFIRM="$(encpass_getche)" if [ "$ENCPASS_CONFIRM" != "Y" ] && [ "$ENCPASS_CONFIRM" != "y" ]; then continue fi fi ENCPASS_SECRET_NAME="" echo "Adding secret \"$ENCPASS_SECRET_NAME\" to bucket \"$ENCPASS_BUCKET\"..." set_secret "$ENCPASS_BUCKET" "$ENCPASS_SECRET_NAME" "reuse" done else echo "Error: A bucket name and secret name must be provided when adding a secret." exit 1 fi ;; update ) shift encpass_checks if [ ! -z "" ] && [ ! -z "" ]; then ENCPASS_SECRET_NAME="" # Allow globbing # shellcheck disable=SC2027,SC2086 ENCPASS_UPDATE_LIST="$(ls -1d "$ENCPASS_HOME_DIR/secrets/""" 2>/dev/null)" for ENCPASS_UPDATE_F in $ENCPASS_UPDATE_LIST; do # Allow globbing # shellcheck disable=SC2027,SC2086 if [ -f "$ENCPASS_UPDATE_F/"".enc" ]; then ENCPASS_UPDATE_DIR="$(basename "$ENCPASS_UPDATE_F")" ENCPASS_BUCKET="$ENCPASS_UPDATE_DIR" echo "Updating secret \"$ENCPASS_SECRET_NAME\" to bucket \"$ENCPASS_BUCKET\"..." set_secret "$ENCPASS_BUCKET" "$ENCPASS_SECRET_NAME" "reuse" else echo "Error: A secret with the name \"\" does not exist for bucket ." exit 1 fi done else echo "Error: A bucket name and secret name must be provided when updating a secret." exit 1 fi ;; rm|remove ) shift encpass_checks while getopts ":f" ENCPASS_OPTS; do case "$ENCPASS_OPTS" in f ) ENCPASS_FORCE_REMOVE=1;; esac done if [ -n "$ENCPASS_FORCE_REMOVE" ]; then shift $((OPTIND-1)) fi if [ -z "" ]; then echo "Error: A bucket must be specified for removal." fi # Allow globbing # shellcheck disable=SC2027,SC2086 ENCPASS_REMOVE_BKT_LIST="$(ls -1d "$ENCPASS_HOME_DIR/secrets/""" 2>/dev/null)" if [ ! -z "$ENCPASS_REMOVE_BKT_LIST" ]; then for ENCPASS_REMOVE_B in $ENCPASS_REMOVE_BKT_LIST; do ENCPASS_BUCKET="$(basename "$ENCPASS_REMOVE_B")" if [ ! -z "" ]; then # Removing secrets for a specified bucket # Allow globbing # shellcheck disable=SC2027,SC2086 ENCPASS_REMOVE_LIST="$(ls -1p "$ENCPASS_REMOVE_B/"".enc" 2>/dev/null)" if [ -z "$ENCPASS_REMOVE_LIST" ]; then echo "Error: No secrets found for in bucket $ENCPASS_BUCKET." exit 1 fi for ENCPASS_REMOVE_F in $ENCPASS_REMOVE_LIST; do ENCPASS_SECRET="" encpass_remove "$ENCPASS_REMOVE_F" done else # Removing a specified bucket encpass_remove fi done else echo "Error: The bucket named does not exist." exit 1 fi ;; show ) shift encpass_checks if [ -z "" ]; then ENCPASS_SHOW_DIR="*" else ENCPASS_SHOW_DIR= fi if [ ! -z "" ]; then # Allow globbing # shellcheck disable=SC2027,SC2086 if [ -f "$(encpass_get_abs_filename "$ENCPASS_HOME_DIR/secrets/$ENCPASS_SHOW_DIR/"".enc")" ]; then encpass_show_secret "$ENCPASS_SHOW_DIR" "" fi else # Allow globbing # shellcheck disable=SC2027,SC2086 ENCPASS_SHOW_LIST="$(ls -1d "$ENCPASS_HOME_DIR/secrets/"$ENCPASS_SHOW_DIR"" 2>/dev/null)" if [ -z "$ENCPASS_SHOW_LIST" ]; then if [ "$ENCPASS_SHOW_DIR" = "*" ]; then echo "Error: No buckets exist." else echo "Error: Bucket does not exist." fi exit 1 fi for ENCPASS_SHOW_F in $ENCPASS_SHOW_LIST; do ENCPASS_SHOW_DIR="$(basename "$ENCPASS_SHOW_F")" echo "$ENCPASS_SHOW_DIR:" encpass_show_secret "$ENCPASS_SHOW_DIR" echo " " done fi ;; ls|list ) shift encpass_checks if [ ! -z "" ]; then # Allow globbing # shellcheck disable=SC2027,SC2086 ENCPASS_FILE_LIST="$(ls -1p "$ENCPASS_HOME_DIR/secrets/""" 2>/dev/null)" if [ -z "$ENCPASS_FILE_LIST" ]; then # Allow globbing # shellcheck disable=SC2027,SC2086 ENCPASS_DIR_EXISTS="$(ls -d "$ENCPASS_HOME_DIR/secrets/""" 2>/dev/null)" if [ ! -z "$ENCPASS_DIR_EXISTS" ]; then echo "Bucket is empty." else echo "Error: Bucket does not exist." fi exit 1 fi ENCPASS_NL="" for ENCPASS_F in $ENCPASS_FILE_LIST; do if [ -d "${ENCPASS_F%:}" ]; then printf "$ENCPASS_NL%s\n" "$(basename "$ENCPASS_F")" ENCPASS_NL="\n" else printf "%s\n" "$(basename "$ENCPASS_F" .enc)" fi done else # Allow globbing # shellcheck disable=SC2027,SC2086 ENCPASS_BUCKET_LIST="$(ls -1p "$ENCPASS_HOME_DIR/secrets/""" 2>/dev/null)" for ENCPASS_C in $ENCPASS_BUCKET_LIST; do if [ -d "${ENCPASS_C%:}" ]; then printf "\n%s" "\n$(basename "$ENCPASS_C")" else basename "$ENCPASS_C" .enc fi done fi ;; lock ) shift encpass_checks echo "************************!!!WARNING!!!*************************" >&2 echo "* You are about to lock your keys with a password. *" >&2 echo "* You will not be able to use your secrets again until you *" >&2 echo "* unlock the keys with the same password. It is important *" >&2 echo "* that you securely store the password, so you can recall it *" >&2 echo "* in the future. If you forget your password you will no *" >&2 echo "* longer be able to access your secrets. *" >&2 echo "************************!!!WARNING!!!*************************" >&2 printf "\n%s\n" "About to lock keys held in directory $ENCPASS_HOME_DIR/keys/" printf "\nEnter Password to lock keys:" >&2 stty -echo read -r ENCPASS_KEY_PASS printf "\nConfirm Password:" >&2 read -r ENCPASS_CKEY_PASS printf "\n" stty echo if [ -z "$ENCPASS_KEY_PASS" ]; then echo "Error: You must supply a password value." exit 1 fi if [ "$ENCPASS_KEY_PASS" = "$ENCPASS_CKEY_PASS" ]; then ENCPASS_NUM_KEYS_LOCKED=0 ENCPASS_KEYS_LIST="$(ls -1d "$ENCPASS_HOME_DIR/keys/"*"/" 2>/dev/null)" for ENCPASS_KEY_F in $ENCPASS_KEYS_LIST; do if [ -d "${ENCPASS_KEY_F%:}" ]; then ENCPASS_KEY_NAME="$(basename "$ENCPASS_KEY_F")" ENCPASS_KEY_VALUE="" if [ -f "$ENCPASS_KEY_F/private.key" ]; then ENCPASS_KEY_VALUE="$(cat "$ENCPASS_KEY_F/private.key")" if [ ! -f "$ENCPASS_KEY_F/private.lock" ]; then echo "Locking key $ENCPASS_KEY_NAME..." else echo "Error: The key $ENCPASS_KEY_NAME appears to have been previously locked." echo " The current key file may hold a bad value. Exiting to avoid encrypting" echo " a bad value and overwriting the lock file." exit 1 fi else echo "Error: Private key file ${ENCPASS_KEY_F}private.key missing for bucket $ENCPASS_KEY_NAME." exit 1 fi if [ ! -z "$ENCPASS_KEY_VALUE" ]; then openssl enc -aes-256-cbc -pbkdf2 -iter 10000 -salt -in "$ENCPASS_KEY_F/private.key" -out "$ENCPASS_KEY_F/private.lock" -k "$ENCPASS_KEY_PASS" if [ -f "$ENCPASS_KEY_F/private.key" ] && [ -f "$ENCPASS_KEY_F/private.lock" ]; then # Both the key and lock file exist. We can remove the key file now rm -f "$ENCPASS_KEY_F/private.key" echo "Locked key $ENCPASS_KEY_NAME." ENCPASS_NUM_KEYS_LOCKED=$(( ENCPASS_NUM_KEYS_LOCKED + 1 )) else echo "Error: The key fle and/or lock file were not found as expected for key $ENCPASS_KEY_NAME." fi else echo "Error: No key value found for the $ENCPASS_KEY_NAME key." exit 1 fi fi done echo "Locked $ENCPASS_NUM_KEYS_LOCKED keys." else echo "Error: Passwords do not match." fi ;; unlock ) shift encpass_checks printf "%s\n" "About to unlock keys held in the $ENCPASS_HOME_DIR/keys/ directory." printf "\nEnter Password to unlock keys: " >&2 stty -echo read -r ENCPASS_KEY_PASS printf "\n" stty echo if [ ! -z "$ENCPASS_KEY_PASS" ]; then ENCPASS_NUM_KEYS_UNLOCKED=0 ENCPASS_KEYS_LIST="$(ls -1d "$ENCPASS_HOME_DIR/keys/"*"/" 2>/dev/null)" for ENCPASS_KEY_F in $ENCPASS_KEYS_LIST; do if [ -d "${ENCPASS_KEY_F%:}" ]; then ENCPASS_KEY_NAME="$(basename "$ENCPASS_KEY_F")" echo "Unlocking key $ENCPASS_KEY_NAME..." if [ -f "$ENCPASS_KEY_F/private.key" ] && [ ! -f "$ENCPASS_KEY_F/private.lock" ]; then echo "Error: Key $ENCPASS_KEY_NAME appears to be unlocked already." exit 1 fi if [ -f "$ENCPASS_KEY_F/private.lock" ]; then # Remove the failed file in case previous decryption attempts were unsuccessful rm -f "$ENCPASS_KEY_F/failed" 2>/dev/null # Decrypt key. Log any failure to the "failed" file. openssl enc -aes-256-cbc -d -pbkdf2 -iter 10000 -salt \ -in "$ENCPASS_KEY_F/private.lock" -out "$ENCPASS_KEY_F/private.key" \ -k "$ENCPASS_KEY_PASS" 2>&1 | encpass_save_err "$ENCPASS_KEY_F/failed" if [ ! -f "$ENCPASS_KEY_F/failed" ]; then # No failure has occurred. if [ -f "$ENCPASS_KEY_F/private.key" ] && [ -f "$ENCPASS_KEY_F/private.lock" ]; then # Both the key and lock file exist. We can remove the lock file now. rm -f "$ENCPASS_KEY_F/private.lock" echo "Unlocked key $ENCPASS_KEY_NAME." ENCPASS_NUM_KEYS_UNLOCKED=$(( ENCPASS_NUM_KEYS_UNLOCKED + 1 )) else echo "Error: The key file and/or lock file were not found as expected for key $ENCPASS_KEY_NAME." fi else printf "Error: Failed to unlock key %s.\n" "$ENCPASS_KEY_NAME" printf " Please view %sfailed for details.\n" "$ENCPASS_KEY_F" fi else echo "Error: No lock file found for the $ENCPASS_KEY_NAME key." fi fi done echo "Unlocked $ENCPASS_NUM_KEYS_UNLOCKED keys." else echo "No password entered." fi ;; dir ) shift encpass_checks echo "ENCPASS_HOME_DIR=$ENCPASS_HOME_DIR" ;; help|--help|usage|--usage|\? ) encpass_checks encpass_help ;; * ) if [ ! -z "" ]; then echo "Command not recognized. See \"encpass.sh help\" for a list commands." exit 1 fi ;; esac

回答by Hassan Farid

This link is help in defining, * How to read password from use without echo-ing it back to terminal * How to replace each character with * -character.

此链接有助于定义, * 如何从使用中读取密码而不将其回显回终端 * 如何用 * - 字符替换每个字符。

https://www.tutorialkart.com/bash-shell-scripting/bash-read-username-and-password/

https://www.tutorialkart.com/bash-shell-scripting/bash-read-username-and-password/

回答by Chol Nhial

First of all, if anyone is going to store any password in a file, I would make sure it's hashed. It's not the best security, but at least it will not be in plain text.

首先,如果有人要在文件中存储任何密码,我会确保它是散列的。这不是最好的安全性,但至少它不会是纯文本。

  1. First, create the password and hash it:

    #!/bin/bash
    
    PASSWORD_FILE="/tmp/secret"
    MD5_HASH=$(cat /tmp/secret)
    PASSWORD_WRONG=1
    
    
    while [ $PASSWORD_WRONG -eq 1 ]
     do
        echo "Enter your password:"
        read -s ENTERED_PASSWORD
        if [ "$MD5_HASH" != "$(echo $ENTERED_PASSWORD | md5sum | cut -d '-' -f 1)" ]; then
            echo "Access Deniend: Incorrenct password!. Try again"
        else
            echo "Access Granted"
            PASSWORD_WRONG=0
        fi
    done
    
  2. Now, create your program to use the hash. In this case, this little program receives user input for a password without echoing, and then converts it to hash to be compared with the stored hash. If it matches the stored hash, then access is granted:

    ##代码##
  1. 首先,创建密码并散列它:

    ##代码##
  2. 现在,创建您的程序以使用哈希。在这种情况下,这个小程序在不回显的情况下接收用户输入的密码,然后将其转换为哈希值,以便与存储的哈希值进行比较。如果它与存储的哈希匹配,则授予访问权限:

    ##代码##