I'm writing a python script to generate SSH keys for users. After generating them using ssh-keygen, I'd like to use puttygen to create a .ppk file. Unfortunately, puttygen doesn't allow the passphrase to be provided on the commandline - therefore I'm trying to pipe them into its stdin using popen. It always complains of a 'wrong passphrase', but entering the commands at the commandline and entering the passphrase there works fine - the problem is something in my popen technique. puttygen prompts three times for a passphrase - once to read the openssh-generated key, and twice for the key for the new file. Puttygen reports an error after the first prompt, so the problem is with my attempt to send the passphrase to the subprocess.
The platform is Ubuntu 11.10, python 2.7, latest openssh and putty-tools packages. Here's a chopped-out script to illustrate the problem I'm having:
#!/usr/bin/python
import sys, os, subprocess
KEYGEN = "/usr/bin/ssh-keygen -t rsa -b 4096 -f id_rsa -N passphrase"
PUTTYGEN = "/usr/bin/puttygen id_rsa -P -O private -o test.ppk"
phrase = "passphrase"
try:
os.unlink('id_rsa')
except:
pass
try:
os.unlink('id_rsa.pub')
except:
pass
try:
os.unlink('test.ppk')
except:
pass
## generate the public and private keys
subprocess.call(KEYGEN.split(' '))
## convert key to PuTTY format
p = subprocess.Popen(PUTTYGEN.split(' '),
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
## Two techniques I've tried - also tried variations on CR/LF. No luck.
if False:
o, e = p.communicate(phrase + '\n' + phrase + '\n' + phrase + '\n')
#o, e = p.communicate(phrase + '\r' + phrase + '\r' + phrase + '\r')
#o, e = p.communicate(phrase + '\r\n' + phrase + '\r\n' + phrase + '\r\n')
print o
print e
else:
p.stdin.write(phrase + '\n')
p.stdin.write(phrase + '\n')
p.stdin.write(phrase + '\n')
print p.stdout.read()
print p.stderr.read()
p.stdin.close()
p.wait()
It seems like puttygen reads all three passphrases as first one. The simplest solution is to insert
between
puttygen (0.69 in my case) has new options: '--old-passphrase file' - specify file containing old key passphrase, '--new-passphrase file' - specify file containing new key passphrase. It answers the passphrase via 'stdin' issue.