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

Source Code for Module paramiko.rsakey

  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 distributed 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  RSA keys. 
 21  """ 
 22   
 23  import os 
 24  from hashlib import sha1 
 25   
 26  from Crypto.PublicKey import RSA 
 27   
 28  from paramiko import util 
 29  from paramiko.common import max_byte, zero_byte, one_byte 
 30  from paramiko.message import Message 
 31  from paramiko.ber import BER, BERException 
 32  from paramiko.pkey import PKey 
 33  from paramiko.py3compat import long 
 34  from paramiko.ssh_exception import SSHException 
 35   
 36  SHA1_DIGESTINFO = b'\x30\x21\x30\x09\x06\x05\x2b\x0e\x03\x02\x1a\x05\x00\x04\x14' 
 37   
 38   
39 -class RSAKey (PKey):
40 """ 41 Representation of an RSA key which can be used to sign and verify SSH2 42 data. 43 """ 44
45 - def __init__(self, msg=None, data=None, filename=None, password=None, vals=None, file_obj=None):
46 self.n = None 47 self.e = None 48 self.d = None 49 self.p = None 50 self.q = None 51 if file_obj is not None: 52 self._from_private_key(file_obj, password) 53 return 54 if filename is not None: 55 self._from_private_key_file(filename, password) 56 return 57 if (msg is None) and (data is not None): 58 msg = Message(data) 59 if vals is not None: 60 self.e, self.n = vals 61 else: 62 if msg is None: 63 raise SSHException('Key object may not be empty') 64 if msg.get_text() != 'ssh-rsa': 65 raise SSHException('Invalid key') 66 self.e = msg.get_mpint() 67 self.n = msg.get_mpint() 68 self.size = util.bit_length(self.n)
69
70 - def asbytes(self):
71 m = Message() 72 m.add_string('ssh-rsa') 73 m.add_mpint(self.e) 74 m.add_mpint(self.n) 75 return m.asbytes()
76
77 - def __str__(self):
78 return self.asbytes()
79
80 - def __hash__(self):
81 h = hash(self.get_name()) 82 h = h * 37 + hash(self.e) 83 h = h * 37 + hash(self.n) 84 return hash(h)
85
86 - def get_name(self):
87 return 'ssh-rsa'
88
89 - def get_bits(self):
90 return self.size
91
92 - def can_sign(self):
93 return self.d is not None
94
95 - def sign_ssh_data(self, data):
96 digest = sha1(data).digest() 97 rsa = RSA.construct((long(self.n), long(self.e), long(self.d))) 98 sig = util.deflate_long(rsa.sign(self._pkcs1imify(digest), bytes())[0], 0) 99 m = Message() 100 m.add_string('ssh-rsa') 101 m.add_string(sig) 102 return m
103
104 - def verify_ssh_sig(self, data, msg):
105 if msg.get_text() != 'ssh-rsa': 106 return False 107 sig = util.inflate_long(msg.get_binary(), True) 108 # verify the signature by SHA'ing the data and encrypting it using the 109 # public key. some wackiness ensues where we "pkcs1imify" the 20-byte 110 # hash into a string as long as the RSA key. 111 hash_obj = util.inflate_long(self._pkcs1imify(sha1(data).digest()), True) 112 rsa = RSA.construct((long(self.n), long(self.e))) 113 return rsa.verify(hash_obj, (sig,))
114
115 - def _encode_key(self):
116 if (self.p is None) or (self.q is None): 117 raise SSHException('Not enough key info to write private key file') 118 keylist = [0, self.n, self.e, self.d, self.p, self.q, 119 self.d % (self.p - 1), self.d % (self.q - 1), 120 util.mod_inverse(self.q, self.p)] 121 try: 122 b = BER() 123 b.encode(keylist) 124 except BERException: 125 raise SSHException('Unable to create ber encoding of key') 126 return b.asbytes()
127
128 - def write_private_key_file(self, filename, password=None):
129 self._write_private_key_file('RSA', filename, self._encode_key(), password)
130
131 - def write_private_key(self, file_obj, password=None):
132 self._write_private_key('RSA', file_obj, self._encode_key(), password)
133
134 - def generate(bits, progress_func=None):
135 """ 136 Generate a new private RSA key. This factory function can be used to 137 generate a new host key or authentication key. 138 139 :param int bits: number of bits the generated key should be. 140 :param function progress_func: 141 an optional function to call at key points in key generation (used 142 by ``pyCrypto.PublicKey``). 143 :return: new `.RSAKey` private key 144 """ 145 rsa = RSA.generate(bits, os.urandom, progress_func) 146 key = RSAKey(vals=(rsa.e, rsa.n)) 147 key.d = rsa.d 148 key.p = rsa.p 149 key.q = rsa.q 150 return key
151 generate = staticmethod(generate) 152 153 ### internals... 154
155 - def _pkcs1imify(self, data):
156 """ 157 turn a 20-byte SHA1 hash into a blob of data as large as the key's N, 158 using PKCS1's \"emsa-pkcs1-v1_5\" encoding. totally bizarre. 159 """ 160 size = len(util.deflate_long(self.n, 0)) 161 filler = max_byte * (size - len(SHA1_DIGESTINFO) - len(data) - 3) 162 return zero_byte + one_byte + filler + zero_byte + SHA1_DIGESTINFO + data
163
164 - def _from_private_key_file(self, filename, password):
165 data = self._read_private_key_file('RSA', filename, password) 166 self._decode_key(data)
167
168 - def _from_private_key(self, file_obj, password):
169 data = self._read_private_key('RSA', file_obj, password) 170 self._decode_key(data)
171
172 - def _decode_key(self, data):
173 # private key file contains: 174 # RSAPrivateKey = { version = 0, n, e, d, p, q, d mod p-1, d mod q-1, q**-1 mod p } 175 try: 176 keylist = BER(data).decode() 177 except BERException: 178 raise SSHException('Unable to parse key file') 179 if (type(keylist) is not list) or (len(keylist) < 4) or (keylist[0] != 0): 180 raise SSHException('Not a valid RSA private key file (bad ber encoding)') 181 self.n = keylist[1] 182 self.e = keylist[2] 183 self.d = keylist[3] 184 # not really needed 185 self.p = keylist[4] 186 self.q = keylist[5] 187 self.size = util.bit_length(self.n)
188