root / trunk / twisted / conch / scripts / ckeygen.py

Revision 25457, 6.7 kB (checked in by exarkun, 8 months ago)

Merge hashlib-2763-3

Author: wsanchez, exarkun
Reviewer: exarkun, mwhudson
Fixes: #2763

Replace uses of md5 and sha modules in Twisted with use of a new twisted.python.hashlib
module which transparently uses the new hashlib standard library module if it is available
or falls back to md5 and sha if not.

Line 
1 # -*- test-case-name: twisted.conch.test.test_ckeygen -*-
2 # Copyright (c) 2001-2008 Twisted Matrix Laboratories.
3 # See LICENSE for details.
4
5 """
6 Implementation module for the `ckeygen` command.
7 """
8
9 import sys, os, getpass, socket
10 if getpass.getpass == getpass.unix_getpass:
11     try:
12         import termios # hack around broken termios
13         termios.tcgetattr, termios.tcsetattr
14     except (ImportError, AttributeError):
15         sys.modules['termios'] = None
16         reload(getpass)
17
18 from twisted.conch.ssh import keys
19 from twisted.python import filepath, log, usage, randbytes
20
21
22 class GeneralOptions(usage.Options):
23     synopsis = """Usage:    ckeygen [options]
24  """
25
26     optParameters = [['bits', 'b', 1024, 'Number of bits in the key to create.'],
27                      ['filename', 'f', None, 'Filename of the key file.'],
28                      ['type', 't', None, 'Specify type of key to create.'],
29                      ['comment', 'C', None, 'Provide new comment.'],
30                      ['newpass', 'N', None, 'Provide new passphrase.'],
31                      ['pass', 'P', None, 'Provide old passphrase']]
32
33     optFlags = [['fingerprint', 'l', 'Show fingerprint of key file.'],
34                 ['changepass', 'p', 'Change passphrase of private key file.'],
35                 ['quiet', 'q', 'Quiet.'],
36                 ['showpub', 'y', 'Read private key file and print public key.']]
37
38     #zsh_altArgDescr = {"bits":"Number of bits in the key (default: 1024)"}
39     #zsh_multiUse = ["foo", "bar"]
40     #zsh_mutuallyExclusive = [("foo", "bar"), ("bar", "baz")]
41     zsh_actions = {"type":"(rsa dsa)"}
42     #zsh_actionDescr = {"logfile":"log file name", "random":"random seed"}
43
44 def run():
45     options = GeneralOptions()
46     try:
47         options.parseOptions(sys.argv[1:])
48     except usage.UsageError, u:
49         print 'ERROR: %s' % u
50         options.opt_help()
51         sys.exit(1)
52     log.discardLogs()
53     log.deferr = handleError # HACK
54     if options['type']:
55         if options['type'] == 'rsa':
56             generateRSAkey(options)
57         elif options['type'] == 'dsa':
58             generateDSAkey(options)
59         else:
60             sys.exit('Key type was %s, must be one of: rsa, dsa' % options['type'])
61     elif options['fingerprint']:
62         printFingerprint(options)
63     elif options['changepass']:
64         changePassPhrase(options)
65     elif options['showpub']:
66         displayPublicKey(options)
67     else:
68         options.opt_help()
69         sys.exit(1)
70
71 def handleError():
72     from twisted.python import failure
73     global exitStatus
74     exitStatus = 2
75     log.err(failure.Failure())
76     reactor.stop()
77     raise
78
79 def generateRSAkey(options):
80     from Crypto.PublicKey import RSA
81     print 'Generating public/private rsa key pair.'
82     key = RSA.generate(int(options['bits']), randbytes.secureRandom)
83     _saveKey(key, options)
84
85 def generateDSAkey(options):
86     from Crypto.PublicKey import DSA
87     print 'Generating public/private dsa key pair.'
88     key = DSA.generate(int(options['bits']), randbytes.secureRandom)
89     _saveKey(key, options)
90
91
92 def printFingerprint(options):
93     if not options['filename']:
94         filename = os.path.expanduser('~/.ssh/id_rsa')
95         options['filename'] = raw_input('Enter file in which the key is (%s): ' % filename)
96     if os.path.exists(options['filename']+'.pub'):
97         options['filename'] += '.pub'
98     try:
99         key = keys.Key.fromFile(options['filename'])
100         obj = key.keyObject
101         string = key.blob()
102         print '%s %s %s' % (
103             obj.size() + 1,
104             key.fingerprint(),
105             os.path.basename(options['filename']))
106     except:
107         sys.exit('bad key')
108
109 def changePassPhrase(options):
110     if not options['filename']:
111         filename = os.path.expanduser('~/.ssh/id_rsa')
112         options['filename'] = raw_input('Enter file in which the key is (%s): ' % filename)
113     try:
114         key = keys.getPrivateKeyObject(options['filename'])
115     except keys.BadKeyError, e:
116         if e.args[0] != 'encrypted key with no passphrase':
117             raise
118         else:
119             if not options['pass']:
120                 options['pass'] = getpass.getpass('Enter old passphrase: ')
121             key = keys.getPrivateKeyObject(options['filename'], passphrase = options['pass'])
122     if not options['newpass']:
123         while 1:
124             p1 = getpass.getpass('Enter new passphrase (empty for no passphrase): ')
125             p2 = getpass.getpass('Enter same passphrase again: ')
126             if p1 == p2:
127                 break
128             print 'Passphrases do not match.  Try again.'
129         options['newpass'] = p1
130     open(options['filename'], 'w').write(
131     keys.makePrivateKeyString(key, passphrase=options['newpass']))
132     print 'Your identification has been saved with the new passphrase.'
133
134 def displayPublicKey(options):
135     if not options['filename']:
136         filename = os.path.expanduser('~/.ssh/id_rsa')
137         options['filename'] = raw_input('Enter file in which the key is (%s): ' % filename)
138     try:
139         key = keys.getPrivateKeyObject(options['filename'])
140     except keys.BadKeyError, e:
141         if e.args[0] != 'encrypted key with no passphrase':
142             raise
143         else:
144             if not options['pass']:
145                 options['pass'] = getpass.getpass('Enter passphrase: ')
146             key = keys.getPrivateKeyObject(options['filename'], passphrase = options['pass'])
147     print keys.makePublicKeyString(key)
148
149 def _saveKey(key, options):
150     if not options['filename']:
151         kind = keys.objectType(key)
152         kind = {'ssh-rsa':'rsa','ssh-dss':'dsa'}[kind]
153         filename = os.path.expanduser('~/.ssh/id_%s'%kind)
154         options['filename'] = raw_input('Enter file in which to save the key (%s): '%filename).strip() or filename
155     if os.path.exists(options['filename']):
156         print '%s already exists.' % options['filename']
157         yn = raw_input('Overwrite (y/n)? ')
158         if yn[0].lower() != 'y':
159             sys.exit()
160     if not options['pass']:
161         while 1:
162             p1 = getpass.getpass('Enter passphrase (empty for no passphrase): ')
163             p2 = getpass.getpass('Enter same passphrase again: ')
164             if p1 == p2:
165                 break
166             print 'Passphrases do not match.  Try again.'
167         options['pass'] = p1
168
169     keyObj = keys.Key(key)
170     comment = '%s@%s' % (getpass.getuser(), socket.gethostname())
171
172     filepath.FilePath(options['filename']).setContent(
173         keyObj.toString('openssh', options['pass']))
174     os.chmod(options['filename'], 33152)
175
176     filepath.FilePath(options['filename'] + '.pub').setContent(
177         keyObj.public().toString('openssh', comment))
178
179     print 'Your identification has been saved in %s' % options['filename']
180     print 'Your public key has been saved in %s.pub' % options['filename']
181     print 'The key fingerprint is:'
182     print keyObj.fingerprint()
183
184 if __name__ == '__main__':
185     run()
186
Note: See TracBrowser for help on using the browser.