Safe way to pass password for >1 programs in bash
Solution 1
Pass the password on a separate file descriptor from the input (twice, once for encryption and once for decryption). Do not export PASS
to the environment.
read -sp 'Enter password. ' PASS
printf '%s\n' "$PASS" |
openssl enc -d -aes-256-cbc -kfile /dev/stdin -in file.old |
sed ... | {
printf '%s\n' "$PASS" |
openssl enc -e -aes-256-cbc -kfile /dev/stdin -in /dev/fd/3 -out file;
} 3<&0
If your system doesn't have /dev/fd
, you can use the -pass
argument to tell openssl
to read the passphrase from an open file descriptor.
printf '%s\n' "$PASS" | {
printf '%s\n' "$PASS" |
openssl enc -d -aes-256-cbc -pass fd:0 -in file.old |
tr a-z A-Z | tee /dev/tty | {
openssl enc -e -aes-256-cbc -pass fd:3 -out file; }
} 3<&0
Solution 2
Using Bash it can be done without using printf '%s\n' "$PASS"
by associating a so-called here string with file descriptors using the Bash builtin exec
command.
For more information see: Shell script password security of command-line parameters.
(
# sample code to edit password-protected file with openssl
# user should have to enter password only once
# password should not become visible using the ps command
echo hello > tmp.file
#env -i bash --norc # clean up environment
set +o history
unset PASS || exit 1
read -sp 'Enter password. ' PASS; echo
# encrypt file and protect it by given password
exec 3<<<"$PASS"
openssl enc -e -aes-256-cbc -pass fd:3 -in tmp.file -out file
cp file{,.old}
# decode | edit | encode
exec 3<<<"$PASS" 4<<<"$PASS"
openssl enc -d -aes-256-cbc -pass fd:3 -in file.old |
sed 's/l/L/g' |
openssl enc -e -aes-256-cbc -pass fd:4 -out file
exec 3<<<"$PASS"
openssl enc -d -aes-256-cbc -pass fd:3 -in file
rm -P tmp.file file.old
unset PASS
)
Solution 3
Sorry, my previous answer was from openssl man, not the openssl enc docs.
This solution is not a pipeline, but I believe this solution prevents the password from being visible to ps.
Using a here document, only openssl sees the text of the password.
As long as you're certain to eliminate the intermediate file, no trace remains.
Maybe someone can help do this in a pipeline and eliminate the intermediate file?
# cp file{,.old} don't need this anymore since intermediate becomes same
read -sp 'Enter password. ' PASS; echo
#no need to export, env's are readable, as mentioned
# decode into intermediate file
openssl <<HERE 2>&1 >/dev/null
enc -d -aes-256-cbc -k "$PASS" -in file -out intermediate
HERE
# edit intermediate
# encode intermediate back into file
openssl <<HERE 2>&1 >/dev/null
enc -e -aes-256-cbc -k "$PASS" -in intermediate -out file
HERE
unset PASS
rm -f intermediate
Related videos on Youtube
clerksx
Hi there! I work on Linux kernel memory management and also help maintain systemd. You can find me at: chrisdown.name GitHub LinkedIn
Updated on September 18, 2022Comments
-
clerksx about 1 year
I'm writing a
bash
script, and need to ask user for his password and pass it toopenssl
. Whilstopenssl
can read the password itself, I need for two runs of the program and don't want to ask the user twice. Here is the script:cp file{,.old} read -sp 'Enter password. ' PASS; echo export PASS # decode | edit | encode openssl enc -d -aes-256-cbc -k "$PASS" -in file.old | \ sed ... | openssl enc -e -aes-256-cbc -k "$PASS" -out file unset PASS
This is not safe as the password is easily available by looking at the command line; somebody can read it using
ps
, for example.openssl
can read a password from an environment variable, so I can replace-k "$PASS"
with-pass env:PASS
, but it's still not safe; the environment variables of any process can be read freely (again,ps
can do it).So, how can I safely pass the password to the two
openssl
instances?-
Admin almost 12 yearscombination of GnuPG and PinEntry can be used here gnupg.org/related_software/pinentry/index.en.html
-
-
Gilles 'SO- stop being evil' almost 12 yearsThis would be a better answer if it explained how to use the switch. It's not wrong (except that the
enc
command has no-kn
switch, at least on current versions, it's-pass
), but not very informative. (The downvote isn't mine.) -
Admin almost 12 years
-
Admin almost 12 years
printf '%s\n' "$PASS"
isn't safe. Somebody can read the command line withps
for example. -
bsd almost 12 yearsThanks @Gilles, looked at the docs and saw my blunder, updated answer with a different approach.
-
Gilles 'SO- stop being evil' almost 12 years@user14284 No, and no.
env:PASS
is not safe because the password would appear in the environment of theopenssl
process (it wouldn't appear in the environment of thebash
process, but that's not enough). Usingprintf
is safe because it's a bash built-in. -
gaoithe almost 4 yearsecho is a bash built in, so would not a simple echo command be safe?
echo $PASS | openssl ...
. It would not appear in ps listing. The only place you can get pass would be in bash process memory. I think ? -
Gilles 'SO- stop being evil' almost 4 years@gaoithe Yes,
echo
would be safe for the same reasonprintf
is safe (andprintf
would not be safe in a shell where it is not built in). The reason I useprintf
and notecho
is thatecho
may mangle backslashes (depending on the bash options).