1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 """
20 DSS keys.
21 """
22
23 import os
24 from hashlib import sha1
25
26 from Crypto.PublicKey import DSA
27
28 from paramiko import util
29 from paramiko.common import zero_byte
30 from paramiko.py3compat import long
31 from paramiko.ssh_exception import SSHException
32 from paramiko.message import Message
33 from paramiko.ber import BER, BERException
34 from paramiko.pkey import PKey
35
36
38 """
39 Representation of a DSS key which can be used to sign an verify SSH2
40 data.
41 """
42
43 - def __init__(self, msg=None, data=None, filename=None, password=None, vals=None, file_obj=None):
44 self.p = None
45 self.q = None
46 self.g = None
47 self.y = None
48 self.x = None
49 if file_obj is not None:
50 self._from_private_key(file_obj, password)
51 return
52 if filename is not None:
53 self._from_private_key_file(filename, password)
54 return
55 if (msg is None) and (data is not None):
56 msg = Message(data)
57 if vals is not None:
58 self.p, self.q, self.g, self.y = vals
59 else:
60 if msg is None:
61 raise SSHException('Key object may not be empty')
62 if msg.get_text() != 'ssh-dss':
63 raise SSHException('Invalid key')
64 self.p = msg.get_mpint()
65 self.q = msg.get_mpint()
66 self.g = msg.get_mpint()
67 self.y = msg.get_mpint()
68 self.size = util.bit_length(self.p)
69
78
81
83 h = hash(self.get_name())
84 h = h * 37 + hash(self.p)
85 h = h * 37 + hash(self.q)
86 h = h * 37 + hash(self.g)
87 h = h * 37 + hash(self.y)
88
89 return hash(h)
90
93
96
98 return self.x is not None
99
101 digest = sha1(data).digest()
102 dss = DSA.construct((long(self.y), long(self.g), long(self.p), long(self.q), long(self.x)))
103
104 qsize = len(util.deflate_long(self.q, 0))
105 while True:
106 k = util.inflate_long(os.urandom(qsize), 1)
107 if (k > 2) and (k < self.q):
108 break
109 r, s = dss.sign(util.inflate_long(digest, 1), k)
110 m = Message()
111 m.add_string('ssh-dss')
112
113 rstr = util.deflate_long(r, 0)
114 sstr = util.deflate_long(s, 0)
115 if len(rstr) < 20:
116 rstr = zero_byte * (20 - len(rstr)) + rstr
117 if len(sstr) < 20:
118 sstr = zero_byte * (20 - len(sstr)) + sstr
119 m.add_string(rstr + sstr)
120 return m
121
139
141 if self.x is None:
142 raise SSHException('Not enough key information')
143 keylist = [0, self.p, self.q, self.g, self.y, self.x]
144 try:
145 b = BER()
146 b.encode(keylist)
147 except BERException:
148 raise SSHException('Unable to create ber encoding of key')
149 return b.asbytes()
150
152 self._write_private_key_file('DSA', filename, self._encode_key(), password)
153
155 self._write_private_key('DSA', file_obj, self._encode_key(), password)
156
157 - def generate(bits=1024, progress_func=None):
158 """
159 Generate a new private DSS key. This factory function can be used to
160 generate a new host key or authentication key.
161
162 :param int bits: number of bits the generated key should be.
163 :param function progress_func:
164 an optional function to call at key points in key generation (used
165 by ``pyCrypto.PublicKey``).
166 :return: new `.DSSKey` private key
167 """
168 dsa = DSA.generate(bits, os.urandom, progress_func)
169 key = DSSKey(vals=(dsa.p, dsa.q, dsa.g, dsa.y))
170 key.x = dsa.x
171 return key
172 generate = staticmethod(generate)
173
174
175
177 data = self._read_private_key_file('DSA', filename, password)
178 self._decode_key(data)
179
181 data = self._read_private_key('DSA', file_obj, password)
182 self._decode_key(data)
183
185
186
187 try:
188 keylist = BER(data).decode()
189 except BERException as e:
190 raise SSHException('Unable to parse key file: ' + str(e))
191 if (type(keylist) is not list) or (len(keylist) < 6) or (keylist[0] != 0):
192 raise SSHException('not a valid DSA private key file (bad ber encoding)')
193 self.p = keylist[1]
194 self.q = keylist[2]
195 self.g = keylist[3]
196 self.y = keylist[4]
197 self.x = keylist[5]
198 self.size = util.bit_length(self.p)
199