Package paramiko :: Module dsskey
[frames] | no frames]

Source Code for Module paramiko.dsskey

  1  # Copyright (C) 2003-2007  Robey Pointer <robeypointer@gmail.com> 
  2  # 
  3  # This file is part of paramiko. 
  4  # 
  5  # Paramiko is free software; you can redistribute it and/or modify it under the 
  6  # terms of the GNU Lesser General Public License as published by the Free 
  7  # Software Foundation; either version 2.1 of the License, or (at your option) 
  8  # any later version. 
  9  # 
 10  # Paramiko is distrubuted in the hope that it will be useful, but WITHOUT ANY 
 11  # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 
 12  # A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more 
 13  # details. 
 14  # 
 15  # You should have received a copy of the GNU Lesser General Public License 
 16  # along with Paramiko; if not, write to the Free Software Foundation, Inc., 
 17  # 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA. 
 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   
34 -class DSSKey (PKey):
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
67 - def __str__(self):
68 m = Message() 69 m.add_string('ssh-dss') 70 m.add_mpint(self.p) 71 m.add_mpint(self.q) 72 m.add_mpint(self.g) 73 m.add_mpint(self.y) 74 return str(m)
75
76 - def __hash__(self):
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 # h might be a long by now... 83 return hash(h)
84
85 - def get_name(self):
86 return 'ssh-dss'
87
88 - def get_bits(self):
89 return self.size
90
91 - def can_sign(self):
92 return self.x is not None
93
94 - def sign_ssh_data(self, rng, data):
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 # generate a suitable k 98 qsize = len(util.deflate_long(self.q, 0)) 99 while True: 100 k = util.inflate_long(rng.read(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 # apparently, in rare cases, r or s may be shorter than 20 bytes! 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
116 - def verify_ssh_sig(self, data, msg):
117 if len(str(msg)) == 40: 118 # spies.com bug: signature has no header 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 # pull out (r, s) which are NOT encoded as mpints 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
134 - def _encode_key(self):
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
145 - def write_private_key_file(self, filename, password=None):
146 self._write_private_key_file('DSA', filename, self._encode_key(), password)
147
148 - def write_private_key(self, file_obj, password=None):
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 dsa = DSA.generate(bits, rng.read, progress_func) 165 key = DSSKey(vals=(dsa.p, dsa.q, dsa.g, dsa.y)) 166 key.x = dsa.x 167 return key
168 generate = staticmethod(generate) 169 170 171 ### internals... 172 173
174 - def _from_private_key_file(self, filename, password):
175 data = self._read_private_key_file('DSA', filename, password) 176 self._decode_key(data)
177
178 - def _from_private_key(self, file_obj, password):
179 data = self._read_private_key('DSA', file_obj, password) 180 self._decode_key(data)
181
182 - def _decode_key(self, data):
183 # private key file contains: 184 # DSAPrivateKey = { version = 0, p, q, g, y, x } 185 try: 186 keylist = BER(data).decode() 187 except BERException, x: 188 raise SSHException('Unable to parse key file: ' + str(x)) 189 if (type(keylist) is not list) or (len(keylist) < 6) or (keylist[0] != 0): 190 raise SSHException('not a valid DSA private key file (bad ber encoding)') 191 self.p = keylist[1] 192 self.q = keylist[2] 193 self.g = keylist[3] 194 self.y = keylist[4] 195 self.x = keylist[5] 196 self.size = util.bit_length(self.p)
197