Coverage for /pythoncovmergedfiles/medio/medio/src/paramiko/paramiko/kex_ecdh_nist.py: 33%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1"""
2Ephemeral Elliptic Curve Diffie-Hellman (ECDH) key exchange
3RFC 5656, Section 4
4"""
6from hashlib import sha256, sha384, sha512
7from paramiko.common import byte_chr
8from paramiko.message import Message
9from paramiko.ssh_exception import SSHException
10from cryptography.hazmat.backends import default_backend
11from cryptography.hazmat.primitives.asymmetric import ec
12from cryptography.hazmat.primitives import serialization
13from binascii import hexlify
15_MSG_KEXECDH_INIT, _MSG_KEXECDH_REPLY = range(30, 32)
16c_MSG_KEXECDH_INIT, c_MSG_KEXECDH_REPLY = [byte_chr(c) for c in range(30, 32)]
19class KexNistp256:
21 name = "ecdh-sha2-nistp256"
22 hash_algo = sha256
23 curve = ec.SECP256R1()
25 def __init__(self, transport):
26 self.transport = transport
27 # private key, client public and server public keys
28 self.P = 0
29 self.Q_C = None
30 self.Q_S = None
32 def start_kex(self):
33 self._generate_key_pair()
34 if self.transport.server_mode:
35 self.transport._expect_packet(_MSG_KEXECDH_INIT)
36 return
37 m = Message()
38 m.add_byte(c_MSG_KEXECDH_INIT)
39 # SEC1: V2.0 2.3.3 Elliptic-Curve-Point-to-Octet-String Conversion
40 m.add_string(
41 self.Q_C.public_bytes(
42 serialization.Encoding.X962,
43 serialization.PublicFormat.UncompressedPoint,
44 )
45 )
46 self.transport._send_message(m)
47 self.transport._expect_packet(_MSG_KEXECDH_REPLY)
49 def parse_next(self, ptype, m):
50 if self.transport.server_mode and (ptype == _MSG_KEXECDH_INIT):
51 return self._parse_kexecdh_init(m)
52 elif not self.transport.server_mode and (ptype == _MSG_KEXECDH_REPLY):
53 return self._parse_kexecdh_reply(m)
54 raise SSHException(
55 "KexECDH asked to handle packet type {:d}".format(ptype)
56 )
58 def _generate_key_pair(self):
59 self.P = ec.generate_private_key(self.curve, default_backend())
60 if self.transport.server_mode:
61 self.Q_S = self.P.public_key()
62 return
63 self.Q_C = self.P.public_key()
65 def _parse_kexecdh_init(self, m):
66 Q_C_bytes = m.get_string()
67 self.Q_C = ec.EllipticCurvePublicKey.from_encoded_point(
68 self.curve, Q_C_bytes
69 )
70 K_S = self.transport.get_server_key().asbytes()
71 K = self.P.exchange(ec.ECDH(), self.Q_C)
72 K = int(hexlify(K), 16)
73 # compute exchange hash
74 hm = Message()
75 hm.add(
76 self.transport.remote_version,
77 self.transport.local_version,
78 self.transport.remote_kex_init,
79 self.transport.local_kex_init,
80 )
81 hm.add_string(K_S)
82 hm.add_string(Q_C_bytes)
83 # SEC1: V2.0 2.3.3 Elliptic-Curve-Point-to-Octet-String Conversion
84 hm.add_string(
85 self.Q_S.public_bytes(
86 serialization.Encoding.X962,
87 serialization.PublicFormat.UncompressedPoint,
88 )
89 )
90 hm.add_mpint(int(K))
91 H = self.hash_algo(hm.asbytes()).digest()
92 self.transport._set_K_H(K, H)
93 sig = self.transport.get_server_key().sign_ssh_data(
94 H, self.transport.host_key_type
95 )
96 # construct reply
97 m = Message()
98 m.add_byte(c_MSG_KEXECDH_REPLY)
99 m.add_string(K_S)
100 m.add_string(
101 self.Q_S.public_bytes(
102 serialization.Encoding.X962,
103 serialization.PublicFormat.UncompressedPoint,
104 )
105 )
106 m.add_string(sig)
107 self.transport._send_message(m)
108 self.transport._activate_outbound()
110 def _parse_kexecdh_reply(self, m):
111 K_S = m.get_string()
112 Q_S_bytes = m.get_string()
113 self.Q_S = ec.EllipticCurvePublicKey.from_encoded_point(
114 self.curve, Q_S_bytes
115 )
116 sig = m.get_binary()
117 K = self.P.exchange(ec.ECDH(), self.Q_S)
118 K = int(hexlify(K), 16)
119 # compute exchange hash and verify signature
120 hm = Message()
121 hm.add(
122 self.transport.local_version,
123 self.transport.remote_version,
124 self.transport.local_kex_init,
125 self.transport.remote_kex_init,
126 )
127 hm.add_string(K_S)
128 # SEC1: V2.0 2.3.3 Elliptic-Curve-Point-to-Octet-String Conversion
129 hm.add_string(
130 self.Q_C.public_bytes(
131 serialization.Encoding.X962,
132 serialization.PublicFormat.UncompressedPoint,
133 )
134 )
135 hm.add_string(Q_S_bytes)
136 hm.add_mpint(K)
137 self.transport._set_K_H(K, self.hash_algo(hm.asbytes()).digest())
138 self.transport._verify_key(K_S, sig)
139 self.transport._activate_outbound()
142class KexNistp384(KexNistp256):
143 name = "ecdh-sha2-nistp384"
144 hash_algo = sha384
145 curve = ec.SECP384R1()
148class KexNistp521(KexNistp256):
149 name = "ecdh-sha2-nistp521"
150 hash_algo = sha512
151 curve = ec.SECP521R1()