Changing a secret key's passphrase?

349 views
Skip to first unread message

Josh Kupershmidt

unread,
Apr 11, 2011, 6:14:48 PM4/11/11
to python...@googlegroups.com
Hi all,

I am trying to figure out how to change the passphrase on a secret key
from within a Python script, preferably using gnupg. I've got a
temporary directory with my private/public keys, like this:

$ gpg --list-secret-keys --homedir "/tmp/tmpqQsHe9/"
/tmp/tmpqQsHe9//secring.gpg
---------------------------
sec 1024D/991EE5E5 2011-04-08
uid Josh Kupershmidt (test key) <jkuper...@perimeterusa.com>
ssb 2048g/439B5EA3 2011-04-08

One peculiarity I've noticed is that the various --passphrase flags to
gpg seem to be used for both the existing and new passphrase. For
instance, if I run:

$ gpg --passphrase="abc123" --homedir "/tmp/tmpqQsHe9" --edit-key
C8DB0952991EE5E5 passwd

I see output which suggests that gpg has used "abc123" at the prompt
for "You need a passphrase to unlock the secret key for.." as well as
the prompt for "Enter the new passphrase for this secret key." This
(mis?)feature of gpg seems to be making it difficult for me to add in
a change_password() function to gnupg.py. When I try to set things up
to use --passphrase or --passphrase-fd, I can't specify my own new
passphrase.

I'm guessing there's a way to use _handle_io() or a similar function
to pipe in exactly what I need to gpg, so that I can specify both old
and new passwords, but I can't seem to get things right. (I've found
some Perl code in the Crypt::GPG module's keypass() function which
appears to work this way.) Any advice would be appreciated, as I'm new
to the gnupg and subprocess modules.

Thanks,
Josh

Vinay Sajip

unread,
Apr 12, 2011, 8:11:51 AM4/12/11
to python-gnupg
Hi Josh,

On Apr 11, 11:14 pm, Josh Kupershmidt <schmi...@gmail.com> wrote:
> I am trying to figure out how to change the passphrase on a secret key
> from within a Python script, preferably using gnupg. I've got a
> [snip]
> I'm guessing there's a way to use _handle_io() or a similar function
> to pipe in exactly what I need to gpg, so that I can specify both old
> and new passwords, but I can't seem to get things right. (I've found
> some Perl code in the Crypt::GPG module's keypass() function which
> appears to work this way.) Any advice would be appreciated, as I'm new
> to the gnupg and subprocess modules.

To do this properly, you have to interact with the GPG subprocess,
ideally using a state machine approach: this is why I haven't
implemented this sort of key-editing functionality, since doing it
properly is not straightforward.

You'd need to create an edit_key method which took a similar approach
to the other methods, create an EditKey class comparable to Crypt,
Verify etc. and implement the handle_status method to do what was
necessary to manage the interaction with the GPG executable. To deal
correctly with all possible scenarios of such an interaction would
(probably) require a (perhaps simple) state machine.

GPG is pretty good about outputting the relevant prompts on its
stderr, but I've found that different versions of GPG behave slightly
differently (e.g. the specifics of some prompts and status messages
changed between 1.4.9 and 1.4.11), which makes providing a generic
solution require more time than I've currently got available :-(

However, if you're using a single version of GnuPG on a single
platform, then you will probably be able to implement a solution. A
quick glance of the Perl code (Google code search was my friend) shows
that this is the approach taken by the Perl module: look for a
specific prompt, send the appropriate value on GPG's stdin, etc. It
may be necessary to specify --command-fd explicitly.

Regards,

Vinay Sajip

Josh Kupershmidt

unread,
Apr 14, 2011, 9:00:08 PM4/14/11
to python...@googlegroups.com, Vinay Sajip
On Tue, Apr 12, 2011 at 8:11 AM, Vinay Sajip <vinay...@yahoo.co.uk> wrote:
> However, if you're using a single version of GnuPG on a single
> platform, then you will probably be able to implement a solution. A
> quick glance of the Perl code (Google code search was my friend) shows
> that this is the approach taken by the Perl module: look for a
> specific prompt, send the appropriate value on GPG's stdin, etc. It
> may be necessary to specify --command-fd explicitly.

Yeah, luckily I only need this to work on a single platform. I think
the --command-fd was the key bit I was missing. I still haven't had a
chance to figure out the proper way to do back-and-forth communication
with a gpg process launched with subprocess.Popen(), but at least I
see how to pipe in everything I need now, e.g.

echo -e "abc123\ndef345\ndef345\nsave\n | gpg --command-fd 0 ...
--edit-key passwd"

appears to work, and I should hopefully be able to figure out how to
make the rest work in a less ugly fashion.

Thanks for all the tips,
Josh

Reply all
Reply to author
Forward
0 new messages