1   
  2   
  3   
  4   
  5   
  6   
  7   
  8   
  9   
 10   
 11   
 12   
 13   
 14   
 15   
 16   
 17   
 18   
 19  """ 
 20  L{RSAKey} 
 21  """ 
 22   
 23  from Crypto.PublicKey import RSA 
 24  from Crypto.Hash import SHA, MD5 
 25  from Crypto.Cipher import DES3 
 26   
 27  from paramiko.common import * 
 28  from paramiko import util 
 29  from paramiko.message import Message 
 30  from paramiko.ber import BER, BERException 
 31  from paramiko.pkey import PKey 
 32  from paramiko.ssh_exception import SSHException 
 33   
 34   
 36      """ 
 37      Representation of an RSA key which can be used to sign and verify SSH2 
 38      data. 
 39      """ 
 40   
 41 -    def __init__(self, msg=None, data=None, filename=None, password=None, vals=None, file_obj=None): 
  42          self.n = None 
 43          self.e = None 
 44          self.d = None 
 45          self.p = None 
 46          self.q = None 
 47          if file_obj is not None: 
 48              self._from_private_key(file_obj, password) 
 49              return 
 50          if filename is not None: 
 51              self._from_private_key_file(filename, password) 
 52              return 
 53          if (msg is None) and (data is not None): 
 54              msg = Message(data) 
 55          if vals is not None: 
 56              self.e, self.n = vals 
 57          else: 
 58              if msg is None: 
 59                  raise SSHException('Key object may not be empty') 
 60              if msg.get_string() != 'ssh-rsa': 
 61                  raise SSHException('Invalid key') 
 62              self.e = msg.get_mpint() 
 63              self.n = msg.get_mpint() 
 64          self.size = util.bit_length(self.n) 
  65   
 72   
 74          h = hash(self.get_name()) 
 75          h = h * 37 + hash(self.e) 
 76          h = h * 37 + hash(self.n) 
 77          return hash(h) 
  78   
 81   
 84   
 86          return self.d is not None 
  87   
 89          digest = SHA.new(data).digest() 
 90          rsa = RSA.construct((long(self.n), long(self.e), long(self.d))) 
 91          sig = util.deflate_long(rsa.sign(self._pkcs1imify(digest), '')[0], 0) 
 92          m = Message() 
 93          m.add_string('ssh-rsa') 
 94          m.add_string(sig) 
 95          return m 
  96   
 98          if msg.get_string() != 'ssh-rsa': 
 99              return False 
100          sig = util.inflate_long(msg.get_string(), True) 
101           
102           
103           
104          hash_obj = util.inflate_long(self._pkcs1imify(SHA.new(data).digest()), True) 
105          rsa = RSA.construct((long(self.n), long(self.e))) 
106          return rsa.verify(hash_obj, (sig,)) 
 107   
109          if (self.p is None) or (self.q is None): 
110              raise SSHException('Not enough key info to write private key file') 
111          keylist = [ 0, self.n, self.e, self.d, self.p, self.q, 
112                      self.d % (self.p - 1), self.d % (self.q - 1), 
113                      util.mod_inverse(self.q, self.p) ] 
114          try: 
115              b = BER() 
116              b.encode(keylist) 
117          except BERException: 
118              raise SSHException('Unable to create ber encoding of key') 
119          return str(b) 
 120   
122          self._write_private_key_file('RSA', filename, self._encode_key(), password) 
 123           
125          self._write_private_key('RSA', file_obj, self._encode_key(), password) 
 126   
127 -    def generate(bits, progress_func=None): 
 128          """ 
129          Generate a new private RSA key.  This factory function can be used to 
130          generate a new host key or authentication key. 
131   
132          @param bits: number of bits the generated key should be. 
133          @type bits: int 
134          @param progress_func: an optional function to call at key points in 
135              key generation (used by C{pyCrypto.PublicKey}). 
136          @type progress_func: function 
137          @return: new private key 
138          @rtype: L{RSAKey} 
139          """ 
140          randpool.stir() 
141          rsa = RSA.generate(bits, randpool.get_bytes, progress_func) 
142          key = RSAKey(vals=(rsa.e, rsa.n)) 
143          key.d = rsa.d 
144          key.p = rsa.p 
145          key.q = rsa.q 
146          return key 
 147      generate = staticmethod(generate) 
148   
149   
150       
151   
152   
154          """ 
155          turn a 20-byte SHA1 hash into a blob of data as large as the key's N, 
156          using PKCS1's \"emsa-pkcs1-v1_5\" encoding.  totally bizarre. 
157          """ 
158          SHA1_DIGESTINFO = '\x30\x21\x30\x09\x06\x05\x2b\x0e\x03\x02\x1a\x05\x00\x04\x14' 
159          size = len(util.deflate_long(self.n, 0)) 
160          filler = '\xff' * (size - len(SHA1_DIGESTINFO) - len(data) - 3) 
161          return '\x00\x01' + filler + '\x00' + SHA1_DIGESTINFO + data 
 162   
164          data = self._read_private_key_file('RSA', filename, password) 
165          self._decode_key(data) 
 166       
168          data = self._read_private_key('RSA', file_obj, password) 
169          self._decode_key(data) 
 170       
172           
173           
174          try: 
175              keylist = BER(data).decode() 
176          except BERException: 
177              raise SSHException('Unable to parse key file') 
178          if (type(keylist) is not list) or (len(keylist) < 4) or (keylist[0] != 0): 
179              raise SSHException('Not a valid RSA private key file (bad ber encoding)') 
180          self.n = keylist[1] 
181          self.e = keylist[2] 
182          self.d = keylist[3] 
183           
184          self.p = keylist[4] 
185          self.q = keylist[5] 
186          self.size = util.bit_length(self.n) 
  187