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 rsa = RSA.generate(bits, rng.read, progress_func)
141 key = RSAKey(vals=(rsa.e, rsa.n))
142 key.d = rsa.d
143 key.p = rsa.p
144 key.q = rsa.q
145 return key
146 generate = staticmethod(generate)
147
148
149
150
151
153 """
154 turn a 20-byte SHA1 hash into a blob of data as large as the key's N,
155 using PKCS1's \"emsa-pkcs1-v1_5\" encoding. totally bizarre.
156 """
157 SHA1_DIGESTINFO = '\x30\x21\x30\x09\x06\x05\x2b\x0e\x03\x02\x1a\x05\x00\x04\x14'
158 size = len(util.deflate_long(self.n, 0))
159 filler = '\xff' * (size - len(SHA1_DIGESTINFO) - len(data) - 3)
160 return '\x00\x01' + filler + '\x00' + SHA1_DIGESTINFO + data
161
163 data = self._read_private_key_file('RSA', filename, password)
164 self._decode_key(data)
165
167 data = self._read_private_key('RSA', file_obj, password)
168 self._decode_key(data)
169
171
172
173 try:
174 keylist = BER(data).decode()
175 except BERException:
176 raise SSHException('Unable to parse key file')
177 if (type(keylist) is not list) or (len(keylist) < 4) or (keylist[0] != 0):
178 raise SSHException('Not a valid RSA private key file (bad ber encoding)')
179 self.n = keylist[1]
180 self.e = keylist[2]
181 self.d = keylist[3]
182
183 self.p = keylist[4]
184 self.q = keylist[5]
185 self.size = util.bit_length(self.n)
186