Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I'm writing a bash script, and need to ask user for his password and pass it to openssl. Whilst openssl 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?

share|improve this question
    
combination of GnuPG and PinEntry can be used here gnupg.org/related_software/pinentry/index.en.html –  Nikhil Mulley Jan 14 '12 at 12:37

3 Answers 3

up vote 7 down vote accepted

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
share|improve this answer
    
As I understand from another your answer, in the bash version with env:PASS is safe too. –  Corvus Jan 15 '12 at 6:32
    
printf '%s\n' "$PASS" isn't safe. Somebody can read the command line with ps for example. –  Corvus Jan 15 '12 at 6:38
1  
@user14284 No, and no. env:PASS is not safe because the password would appear in the environment of the openssl process (it wouldn't appear in the environment of the bash process, but that's not enough). Using printf is safe because it's a bash built-in. –  Gilles Jan 15 '12 at 17:01

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

)
share|improve this answer

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
share|improve this answer
    
This 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.) –  Gilles Jan 15 '12 at 2:25
    
Thanks @Gilles, looked at the docs and saw my blunder, updated answer with a different approach. –  bdowning Jan 15 '12 at 12:54

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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