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