1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 """
20 L{ECDSAKey}
21 """
22
23 import binascii
24 from hashlib import sha256
25
26 from ecdsa import SigningKey, VerifyingKey, der, curves
27 from ecdsa.test_pyecdsa import ECDSA
28
29 from paramiko.common import four_byte, one_byte
30 from paramiko.message import Message
31 from paramiko.pkey import PKey
32 from paramiko.py3compat import byte_chr, u
33 from paramiko.ssh_exception import SSHException
34
35
37 """
38 Representation of an ECDSA key which can be used to sign and verify SSH2
39 data.
40 """
41
42 - def __init__(self, msg=None, data=None, filename=None, password=None, vals=None, file_obj=None):
43 self.verifying_key = None
44 self.signing_key = None
45 if file_obj is not None:
46 self._from_private_key(file_obj, password)
47 return
48 if filename is not None:
49 self._from_private_key_file(filename, password)
50 return
51 if (msg is None) and (data is not None):
52 msg = Message(data)
53 if vals is not None:
54 self.verifying_key, self.signing_key = vals
55 else:
56 if msg is None:
57 raise SSHException('Key object may not be empty')
58 if msg.get_text() != 'ecdsa-sha2-nistp256':
59 raise SSHException('Invalid key')
60 curvename = msg.get_text()
61 if curvename != 'nistp256':
62 raise SSHException("Can't handle curve of type %s" % curvename)
63
64 pointinfo = msg.get_binary()
65 if pointinfo[0:1] != four_byte:
66 raise SSHException('Point compression is being used: %s' %
67 binascii.hexlify(pointinfo))
68 self.verifying_key = VerifyingKey.from_string(pointinfo[1:],
69 curve=curves.NIST256p)
70 self.size = 256
71
82
85
87 h = hash(self.get_name())
88 h = h * 37 + hash(self.verifying_key.pubkey.point.x())
89 h = h * 37 + hash(self.verifying_key.pubkey.point.y())
90 return hash(h)
91
93 return 'ecdsa-sha2-nistp256'
94
97
99 return self.signing_key is not None
100
102 sig = self.signing_key.sign_deterministic(
103 data, sigencode=self._sigencode, hashfunc=sha256)
104 m = Message()
105 m.add_string('ecdsa-sha2-nistp256')
106 m.add_string(sig)
107 return m
108
110 if msg.get_text() != 'ecdsa-sha2-nistp256':
111 return False
112 sig = msg.get_binary()
113
114
115
116 hash_obj = sha256(data).digest()
117 return self.verifying_key.verify_digest(sig, hash_obj,
118 sigdecode=self._sigdecode)
119
121 key = self.signing_key or self.verifying_key
122 self._write_private_key_file('EC', filename, key.to_der(), password)
123
125 key = self.signing_key or self.verifying_key
126 self._write_private_key('EC', file_obj, key.to_der(), password)
127
128 - def generate(bits, progress_func=None):
129 """
130 Generate a new private RSA key. This factory function can be used to
131 generate a new host key or authentication key.
132
133 @param bits: number of bits the generated key should be.
134 @type bits: int
135 @param progress_func: an optional function to call at key points in
136 key generation (used by C{pyCrypto.PublicKey}).
137 @type progress_func: function
138 @return: new private key
139 @rtype: L{RSAKey}
140 """
141 signing_key = ECDSA.generate()
142 key = ECDSAKey(vals=(signing_key, signing_key.get_verifying_key()))
143 return key
144 generate = staticmethod(generate)
145
146
147
149 data = self._read_private_key_file('EC', filename, password)
150 self._decode_key(data)
151
153 data = self._read_private_key('EC', file_obj, password)
154 self._decode_key(data)
155
156 ALLOWED_PADDINGS = [one_byte, byte_chr(2) * 2, byte_chr(3) * 3, byte_chr(4) * 4,
157 byte_chr(5) * 5, byte_chr(6) * 6, byte_chr(7) * 7]
158
160 s, padding = der.remove_sequence(data)
161 if padding:
162 if padding not in self.ALLOWED_PADDINGS:
163 raise ValueError("weird padding: %s" % u(binascii.hexlify(data)))
164 data = data[:-len(padding)]
165 key = SigningKey.from_der(data)
166 self.signing_key = key
167 self.verifying_key = key.get_verifying_key()
168 self.size = 256
169
175
181