1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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
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
76
79
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
88
91
93 return self.d is not None
94
103
114
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
129 self._write_private_key_file('RSA', filename, self._encode_key(), password)
130
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
154
163
165 data = self._read_private_key_file('RSA', filename, password)
166 self._decode_key(data)
167
169 data = self._read_private_key('RSA', file_obj, password)
170 self._decode_key(data)
171
173
174
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
185 self.p = keylist[4]
186 self.q = keylist[5]
187 self.size = util.bit_length(self.n)
188