Search code examples
shellunixencryptioncommand-linegnupg

GPG change symmetric encryption password


I'm trying to figure out a way to change the password of a file that is symmetrically encrypted by GPG without using a temporary file or a shell variable. I know I could do this in a shell function with a variable but I'd like to do it on the command line if possible.

I think this should be possible because GPG will encrypt incoming streams with gpg --symmetric -o example.gpg and because GPG will send decrypted output to STDOUT with gpg --decrypt.

But this doesn't work properly:

gpg --decrypt example.gpg | gpg --symmetric -o new.gpg

I think my understanding of the shell order of operations and redirection is wrong. Especially because the shell output has more than one Enter passphrase: prompts at a time.

Here is the initial interactive response after entering the piped commands:

localhost ~% gpg --decrypt example.gpg | gpg --symmetric -o example.gpg
gpg: CAST5 encrypted data
Enter passphrase: Enter passphrase

After that, I get a variety of password prompts... sometimes I am asked for the decryption password, then I can type the new password in visible plain text, then the new password confirmation which is hidden. Sometimes, I get the new password dialogue before I am asked for the decryption password.

I think there is a race condition.

Any advice?


Solution

  • Solution:

    You need to non-interactively tell the first gpg command what the decryption passphrase is.

    • With gpg2 (most modern Linux distros ship with this) it could look like this:

      gpg --decrypt --batch --passphrase 'original passwd' example.gpg  | gpg --symmetric -o new_example.gpg
      
    • With gpg1, you would use --no-use-agent instead of --batch, e.g.:

      gpg -d --no-use-agent --passphrase 'original passwd' example.gpg  | gpg -co new_example.gpg
      

    Note: Depending on your version of gpg and how it's configured, you might also have to specify the passphrase in the same way for the second gpg command.

    Root cause:

    When you put together a commandline with pipes, your shell starts all the commands at the same time after setting up pipes to connect each one (to allow stdout of each command to be sent to stdin of the next).

    Extra warnings:

    1. Do not write to the same file you're reading from. It will almost never work out how you want.

    2. On a multi-user system it's a bad idea to use gpg's --passphrase option, since it makes the passphrase available for inspection by anyone on the system (anyone can run a ps command and see the passphrase while the gpg command is running). Furthermore, the passphrase is then saved in your shell history. Yikes. If that's a problem, use --passphrase-fd or --passphrase-file.