1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 """
20 L{DSSKey}
21 """
22
23 from Crypto.PublicKey import DSA
24 from Crypto.Hash import SHA
25
26 from paramiko.common import *
27 from paramiko import util
28 from paramiko.ssh_exception import SSHException
29 from paramiko.message import Message
30 from paramiko.ber import BER, BERException
31 from paramiko.pkey import PKey
32
33
35 """
36 Representation of a DSS key which can be used to sign an verify SSH2
37 data.
38 """
39
40 - def __init__(self, msg=None, data=None, filename=None, password=None, vals=None, file_obj=None):
41 self.p = None
42 self.q = None
43 self.g = None
44 self.y = None
45 self.x = None
46 if file_obj is not None:
47 self._from_private_key(file_obj, password)
48 return
49 if filename is not None:
50 self._from_private_key_file(filename, password)
51 return
52 if (msg is None) and (data is not None):
53 msg = Message(data)
54 if vals is not None:
55 self.p, self.q, self.g, self.y = vals
56 else:
57 if msg is None:
58 raise SSHException('Key object may not be empty')
59 if msg.get_string() != 'ssh-dss':
60 raise SSHException('Invalid key')
61 self.p = msg.get_mpint()
62 self.q = msg.get_mpint()
63 self.g = msg.get_mpint()
64 self.y = msg.get_mpint()
65 self.size = util.bit_length(self.p)
66
75
77 h = hash(self.get_name())
78 h = h * 37 + hash(self.p)
79 h = h * 37 + hash(self.q)
80 h = h * 37 + hash(self.g)
81 h = h * 37 + hash(self.y)
82
83 return hash(h)
84
87
90
92 return self.x is not None
93
95 digest = SHA.new(data).digest()
96 dss = DSA.construct((long(self.y), long(self.g), long(self.p), long(self.q), long(self.x)))
97
98 qsize = len(util.deflate_long(self.q, 0))
99 while True:
100 k = util.inflate_long(rpool.get_bytes(qsize), 1)
101 if (k > 2) and (k < self.q):
102 break
103 r, s = dss.sign(util.inflate_long(digest, 1), k)
104 m = Message()
105 m.add_string('ssh-dss')
106
107 rstr = util.deflate_long(r, 0)
108 sstr = util.deflate_long(s, 0)
109 if len(rstr) < 20:
110 rstr = '\x00' * (20 - len(rstr)) + rstr
111 if len(sstr) < 20:
112 sstr = '\x00' * (20 - len(sstr)) + sstr
113 m.add_string(rstr + sstr)
114 return m
115
117 if len(str(msg)) == 40:
118
119 sig = str(msg)
120 else:
121 kind = msg.get_string()
122 if kind != 'ssh-dss':
123 return 0
124 sig = msg.get_string()
125
126
127 sigR = util.inflate_long(sig[:20], 1)
128 sigS = util.inflate_long(sig[20:], 1)
129 sigM = util.inflate_long(SHA.new(data).digest(), 1)
130
131 dss = DSA.construct((long(self.y), long(self.g), long(self.p), long(self.q)))
132 return dss.verify(sigM, (sigR, sigS))
133
135 if self.x is None:
136 raise SSHException('Not enough key information')
137 keylist = [ 0, self.p, self.q, self.g, self.y, self.x ]
138 try:
139 b = BER()
140 b.encode(keylist)
141 except BERException:
142 raise SSHException('Unable to create ber encoding of key')
143 return str(b)
144
146 self._write_private_key_file('DSA', filename, self._encode_key(), password)
147
149 self._write_private_key('DSA', file_obj, self._encode_key(), password)
150
151 - def generate(bits=1024, progress_func=None):
152 """
153 Generate a new private DSS key. This factory function can be used to
154 generate a new host key or authentication key.
155
156 @param bits: number of bits the generated key should be.
157 @type bits: int
158 @param progress_func: an optional function to call at key points in
159 key generation (used by C{pyCrypto.PublicKey}).
160 @type progress_func: function
161 @return: new private key
162 @rtype: L{DSSKey}
163 """
164 randpool.stir()
165 dsa = DSA.generate(bits, randpool.get_bytes, progress_func)
166 key = DSSKey(vals=(dsa.p, dsa.q, dsa.g, dsa.y))
167 key.x = dsa.x
168 return key
169 generate = staticmethod(generate)
170
171
172
173
174
176 data = self._read_private_key_file('DSA', filename, password)
177 self._decode_key(data)
178
180 data = self._read_private_key('DSA', file_obj, password)
181 self._decode_key(data)
182
184
185
186 try:
187 keylist = BER(data).decode()
188 except BERException, x:
189 raise SSHException('Unable to parse key file: ' + str(x))
190 if (type(keylist) is not list) or (len(keylist) < 6) or (keylist[0] != 0):
191 raise SSHException('not a valid DSA private key file (bad ber encoding)')
192 self.p = keylist[1]
193 self.q = keylist[2]
194 self.g = keylist[3]
195 self.y = keylist[4]
196 self.x = keylist[5]
197 self.size = util.bit_length(self.p)
198