1
# -*- test-case-name: twisted.conch.test.test_ckeygen -*-
2
# Copyright (c) 2001-2008 Twisted Matrix Laboratories.
3
# See LICENSE for details.
6
Implementation module for the `ckeygen` command.
9
import sys, os, getpass, socket
10
if getpass.getpass == getpass.unix_getpass:
12
import termios # hack around broken termios
13
termios.tcgetattr, termios.tcsetattr
14
except (ImportError, AttributeError):
15
sys.modules['termios'] = None
18
from twisted.conch.ssh import keys
19
from twisted.python import filepath, log, usage, randbytes
22
class GeneralOptions(usage.Options):
23
synopsis = """Usage: ckeygen [options]
26
longdesc = "ckeygen manipulates public/private keys in various ways."
28
optParameters = [['bits', 'b', 1024, 'Number of bits in the key to create.'],
29
['filename', 'f', None, 'Filename of the key file.'],
30
['type', 't', None, 'Specify type of key to create.'],
31
['comment', 'C', None, 'Provide new comment.'],
32
['newpass', 'N', None, 'Provide new passphrase.'],
33
['pass', 'P', None, 'Provide old passphrase']]
35
optFlags = [['fingerprint', 'l', 'Show fingerprint of key file.'],
36
['changepass', 'p', 'Change passphrase of private key file.'],
37
['quiet', 'q', 'Quiet.'],
38
['showpub', 'y', 'Read private key file and print public key.']]
40
#zsh_altArgDescr = {"bits":"Number of bits in the key (default: 1024)"}
41
#zsh_multiUse = ["foo", "bar"]
42
#zsh_mutuallyExclusive = [("foo", "bar"), ("bar", "baz")]
43
zsh_actions = {"type":"(rsa dsa)"}
44
#zsh_actionDescr = {"logfile":"log file name", "random":"random seed"}
47
options = GeneralOptions()
49
options.parseOptions(sys.argv[1:])
50
except usage.UsageError, u:
55
log.deferr = handleError # HACK
57
if options['type'] == 'rsa':
58
generateRSAkey(options)
59
elif options['type'] == 'dsa':
60
generateDSAkey(options)
62
sys.exit('Key type was %s, must be one of: rsa, dsa' % options['type'])
63
elif options['fingerprint']:
64
printFingerprint(options)
65
elif options['changepass']:
66
changePassPhrase(options)
67
elif options['showpub']:
68
displayPublicKey(options)
74
from twisted.python import failure
77
log.err(failure.Failure())
81
def generateRSAkey(options):
82
from Crypto.PublicKey import RSA
83
print 'Generating public/private rsa key pair.'
84
key = RSA.generate(int(options['bits']), randbytes.secureRandom)
85
_saveKey(key, options)
87
def generateDSAkey(options):
88
from Crypto.PublicKey import DSA
89
print 'Generating public/private dsa key pair.'
90
key = DSA.generate(int(options['bits']), randbytes.secureRandom)
91
_saveKey(key, options)
94
def printFingerprint(options):
95
if not options['filename']:
96
filename = os.path.expanduser('~/.ssh/id_rsa')
97
options['filename'] = raw_input('Enter file in which the key is (%s): ' % filename)
98
if os.path.exists(options['filename']+'.pub'):
99
options['filename'] += '.pub'
101
key = keys.Key.fromFile(options['filename'])
107
os.path.basename(options['filename']))
111
def changePassPhrase(options):
112
if not options['filename']:
113
filename = os.path.expanduser('~/.ssh/id_rsa')
114
options['filename'] = raw_input('Enter file in which the key is (%s): ' % filename)
116
key = keys.getPrivateKeyObject(options['filename'])
117
except keys.BadKeyError, e:
118
if e.args[0] != 'encrypted key with no passphrase':
121
if not options['pass']:
122
options['pass'] = getpass.getpass('Enter old passphrase: ')
123
key = keys.getPrivateKeyObject(options['filename'], passphrase = options['pass'])
124
if not options['newpass']:
126
p1 = getpass.getpass('Enter new passphrase (empty for no passphrase): ')
127
p2 = getpass.getpass('Enter same passphrase again: ')
130
print 'Passphrases do not match. Try again.'
131
options['newpass'] = p1
132
open(options['filename'], 'w').write(
133
keys.makePrivateKeyString(key, passphrase=options['newpass']))
134
print 'Your identification has been saved with the new passphrase.'
136
def displayPublicKey(options):
137
if not options['filename']:
138
filename = os.path.expanduser('~/.ssh/id_rsa')
139
options['filename'] = raw_input('Enter file in which the key is (%s): ' % filename)
141
key = keys.getPrivateKeyObject(options['filename'])
142
except keys.BadKeyError, e:
143
if e.args[0] != 'encrypted key with no passphrase':
146
if not options['pass']:
147
options['pass'] = getpass.getpass('Enter passphrase: ')
148
key = keys.getPrivateKeyObject(options['filename'], passphrase = options['pass'])
149
print keys.makePublicKeyString(key)
151
def _saveKey(key, options):
152
if not options['filename']:
153
kind = keys.objectType(key)
154
kind = {'ssh-rsa':'rsa','ssh-dss':'dsa'}[kind]
155
filename = os.path.expanduser('~/.ssh/id_%s'%kind)
156
options['filename'] = raw_input('Enter file in which to save the key (%s): '%filename).strip() or filename
157
if os.path.exists(options['filename']):
158
print '%s already exists.' % options['filename']
159
yn = raw_input('Overwrite (y/n)? ')
160
if yn[0].lower() != 'y':
162
if not options['pass']:
164
p1 = getpass.getpass('Enter passphrase (empty for no passphrase): ')
165
p2 = getpass.getpass('Enter same passphrase again: ')
168
print 'Passphrases do not match. Try again.'
171
keyObj = keys.Key(key)
172
comment = '%s@%s' % (getpass.getuser(), socket.gethostname())
174
filepath.FilePath(options['filename']).setContent(
175
keyObj.toString('openssh', options['pass']))
176
os.chmod(options['filename'], 33152)
178
filepath.FilePath(options['filename'] + '.pub').setContent(
179
keyObj.public().toString('openssh', comment))
181
print 'Your identification has been saved in %s' % options['filename']
182
print 'Your public key has been saved in %s.pub' % options['filename']
183
print 'The key fingerprint is:'
184
print keyObj.fingerprint()
186
if __name__ == '__main__':