Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
kex_gex.py289 linesDownload Raw Back to paramiko
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 the6# terms of the GNU Lesser General Public License as published by the Free7# 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 ANY11# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR12# A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more13# details.14#15# You should have received a copy of the GNU Lesser General Public License16# along with Paramiko; if not, write to the Free Software Foundation, Inc.,17# 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.18 19"""20Variant on `KexGroup1 <paramiko.kex_group1.KexGroup1>` where the prime "p" and21generator "g" are provided by the server.  A bit more work is required on the22client side, and a **lot** more on the server side.23"""24 25import os26from hashlib import sha1, sha25627 28from paramiko import util29from paramiko.common import DEBUG, byte_chr, byte_ord, byte_mask30from paramiko.message import Message31from paramiko.ssh_exception import SSHException32 33 34(35    _MSG_KEXDH_GEX_REQUEST_OLD,36    _MSG_KEXDH_GEX_GROUP,37    _MSG_KEXDH_GEX_INIT,38    _MSG_KEXDH_GEX_REPLY,39    _MSG_KEXDH_GEX_REQUEST,40) = range(30, 35)41 42(43    c_MSG_KEXDH_GEX_REQUEST_OLD,44    c_MSG_KEXDH_GEX_GROUP,45    c_MSG_KEXDH_GEX_INIT,46    c_MSG_KEXDH_GEX_REPLY,47    c_MSG_KEXDH_GEX_REQUEST,48) = [byte_chr(c) for c in range(30, 35)]49 50 51class KexGex:52 53    name = "diffie-hellman-group-exchange-sha1"54    min_bits = 102455    max_bits = 819256    preferred_bits = 204857    hash_algo = sha158 59    def __init__(self, transport):60        self.transport = transport61        self.p = None62        self.q = None63        self.g = None64        self.x = None65        self.e = None66        self.f = None67        self.old_style = False68 69    def start_kex(self, _test_old_style=False):70        if self.transport.server_mode:71            self.transport._expect_packet(72                _MSG_KEXDH_GEX_REQUEST, _MSG_KEXDH_GEX_REQUEST_OLD73            )74            return75        # request a bit range: we accept (min_bits) to (max_bits), but prefer76        # (preferred_bits).  according to the spec, we shouldn't pull the77        # minimum up above 1024.78        m = Message()79        if _test_old_style:80            # only used for unit tests: we shouldn't ever send this81            m.add_byte(c_MSG_KEXDH_GEX_REQUEST_OLD)82            m.add_int(self.preferred_bits)83            self.old_style = True84        else:85            m.add_byte(c_MSG_KEXDH_GEX_REQUEST)86            m.add_int(self.min_bits)87            m.add_int(self.preferred_bits)88            m.add_int(self.max_bits)89        self.transport._send_message(m)90        self.transport._expect_packet(_MSG_KEXDH_GEX_GROUP)91 92    def parse_next(self, ptype, m):93        if ptype == _MSG_KEXDH_GEX_REQUEST:94            return self._parse_kexdh_gex_request(m)95        elif ptype == _MSG_KEXDH_GEX_GROUP:96            return self._parse_kexdh_gex_group(m)97        elif ptype == _MSG_KEXDH_GEX_INIT:98            return self._parse_kexdh_gex_init(m)99        elif ptype == _MSG_KEXDH_GEX_REPLY:100            return self._parse_kexdh_gex_reply(m)101        elif ptype == _MSG_KEXDH_GEX_REQUEST_OLD:102            return self._parse_kexdh_gex_request_old(m)103        msg = "KexGex {} asked to handle packet type {:d}"104        raise SSHException(msg.format(self.name, ptype))105 106    # ...internals...107 108    def _generate_x(self):109        # generate an "x" (1 < x < (p-1)/2).110        q = (self.p - 1) // 2111        qnorm = util.deflate_long(q, 0)112        qhbyte = byte_ord(qnorm[0])113        byte_count = len(qnorm)114        qmask = 0xFF115        while not (qhbyte & 0x80):116            qhbyte <<= 1117            qmask >>= 1118        while True:119            x_bytes = os.urandom(byte_count)120            x_bytes = byte_mask(x_bytes[0], qmask) + x_bytes[1:]121            x = util.inflate_long(x_bytes, 1)122            if (x > 1) and (x < q):123                break124        self.x = x125 126    def _parse_kexdh_gex_request(self, m):127        minbits = m.get_int()128        preferredbits = m.get_int()129        maxbits = m.get_int()130        # smoosh the user's preferred size into our own limits131        if preferredbits > self.max_bits:132            preferredbits = self.max_bits133        if preferredbits < self.min_bits:134            preferredbits = self.min_bits135        # fix min/max if they're inconsistent.  technically, we could just pout136        # and hang up, but there's no harm in giving them the benefit of the137        # doubt and just picking a bitsize for them.138        if minbits > preferredbits:139            minbits = preferredbits140        if maxbits < preferredbits:141            maxbits = preferredbits142        # now save a copy143        self.min_bits = minbits144        self.preferred_bits = preferredbits145        self.max_bits = maxbits146        # generate prime147        pack = self.transport._get_modulus_pack()148        if pack is None:149            raise SSHException("Can't do server-side gex with no modulus pack")150        self.transport._log(151            DEBUG,152            "Picking p ({} <= {} <= {} bits)".format(153                minbits, preferredbits, maxbits154            ),155        )156        self.g, self.p = pack.get_modulus(minbits, preferredbits, maxbits)157        m = Message()158        m.add_byte(c_MSG_KEXDH_GEX_GROUP)159        m.add_mpint(self.p)160        m.add_mpint(self.g)161        self.transport._send_message(m)162        self.transport._expect_packet(_MSG_KEXDH_GEX_INIT)163 164    def _parse_kexdh_gex_request_old(self, m):165        # same as above, but without min_bits or max_bits (used by older166        # clients like putty)167        self.preferred_bits = m.get_int()168        # smoosh the user's preferred size into our own limits169        if self.preferred_bits > self.max_bits:170            self.preferred_bits = self.max_bits171        if self.preferred_bits < self.min_bits:172            self.preferred_bits = self.min_bits173        # generate prime174        pack = self.transport._get_modulus_pack()175        if pack is None:176            raise SSHException("Can't do server-side gex with no modulus pack")177        self.transport._log(178            DEBUG, "Picking p (~ {} bits)".format(self.preferred_bits)179        )180        self.g, self.p = pack.get_modulus(181            self.min_bits, self.preferred_bits, self.max_bits182        )183        m = Message()184        m.add_byte(c_MSG_KEXDH_GEX_GROUP)185        m.add_mpint(self.p)186        m.add_mpint(self.g)187        self.transport._send_message(m)188        self.transport._expect_packet(_MSG_KEXDH_GEX_INIT)189        self.old_style = True190 191    def _parse_kexdh_gex_group(self, m):192        self.p = m.get_mpint()193        self.g = m.get_mpint()194        # reject if p's bit length < 1024 or > 8192195        bitlen = util.bit_length(self.p)196        if (bitlen < 1024) or (bitlen > 8192):197            raise SSHException(198                "Server-generated gex p (don't ask) is out of range "199                "({} bits)".format(bitlen)200            )201        self.transport._log(DEBUG, "Got server p ({} bits)".format(bitlen))202        self._generate_x()203        # now compute e = g^x mod p204        self.e = pow(self.g, self.x, self.p)205        m = Message()206        m.add_byte(c_MSG_KEXDH_GEX_INIT)207        m.add_mpint(self.e)208        self.transport._send_message(m)209        self.transport._expect_packet(_MSG_KEXDH_GEX_REPLY)210 211    def _parse_kexdh_gex_init(self, m):212        self.e = m.get_mpint()213        if (self.e < 1) or (self.e > self.p - 1):214            raise SSHException('Client kex "e" is out of range')215        self._generate_x()216        self.f = pow(self.g, self.x, self.p)217        K = pow(self.e, self.x, self.p)218        key = self.transport.get_server_key().asbytes()219        # okay, build up the hash H of220        # (V_C || V_S || I_C || I_S || K_S || min || n || max || p || g || e || f || K)  # noqa221        hm = Message()222        hm.add(223            self.transport.remote_version,224            self.transport.local_version,225            self.transport.remote_kex_init,226            self.transport.local_kex_init,227            key,228        )229        if not self.old_style:230            hm.add_int(self.min_bits)231        hm.add_int(self.preferred_bits)232        if not self.old_style:233            hm.add_int(self.max_bits)234        hm.add_mpint(self.p)235        hm.add_mpint(self.g)236        hm.add_mpint(self.e)237        hm.add_mpint(self.f)238        hm.add_mpint(K)239        H = self.hash_algo(hm.asbytes()).digest()240        self.transport._set_K_H(K, H)241        # sign it242        sig = self.transport.get_server_key().sign_ssh_data(243            H, self.transport.host_key_type244        )245        # send reply246        m = Message()247        m.add_byte(c_MSG_KEXDH_GEX_REPLY)248        m.add_string(key)249        m.add_mpint(self.f)250        m.add_string(sig)251        self.transport._send_message(m)252        self.transport._activate_outbound()253 254    def _parse_kexdh_gex_reply(self, m):255        host_key = m.get_string()256        self.f = m.get_mpint()257        sig = m.get_string()258        if (self.f < 1) or (self.f > self.p - 1):259            raise SSHException('Server kex "f" is out of range')260        K = pow(self.f, self.x, self.p)261        # okay, build up the hash H of262        # (V_C || V_S || I_C || I_S || K_S || min || n || max || p || g || e || f || K)  # noqa263        hm = Message()264        hm.add(265            self.transport.local_version,266            self.transport.remote_version,267            self.transport.local_kex_init,268            self.transport.remote_kex_init,269            host_key,270        )271        if not self.old_style:272            hm.add_int(self.min_bits)273        hm.add_int(self.preferred_bits)274        if not self.old_style:275            hm.add_int(self.max_bits)276        hm.add_mpint(self.p)277        hm.add_mpint(self.g)278        hm.add_mpint(self.e)279        hm.add_mpint(self.f)280        hm.add_mpint(K)281        self.transport._set_K_H(K, self.hash_algo(hm.asbytes()).digest())282        self.transport._verify_key(host_key, sig)283        self.transport._activate_outbound()284 285 286class KexGexSHA256(KexGex):287    name = "diffie-hellman-group-exchange-sha256"288    hash_algo = sha256289 
codekingpro/portable-devtools · Team Ai