Exemplo n.º 1
0
 def _parse_kexecdh_init(self, m):
     Q_C_bytes = m.get_string()
     self.Q_C = ec.EllipticCurvePublicNumbers.from_encoded_point(
         self.curve, Q_C_bytes
     )
     K_S = self.transport.get_server_key().asbytes()
     K = self.P.exchange(ec.ECDH(), self.Q_C.public_key(default_backend()))
     K = long(hexlify(K), 16)
     # compute exchange hash
     hm = Message()
     hm.add(self.transport.remote_version, self.transport.local_version,
            self.transport.remote_kex_init, self.transport.local_kex_init)
     hm.add_string(K_S)
     hm.add_string(Q_C_bytes)
     # SEC1: V2.0  2.3.3 Elliptic-Curve-Point-to-Octet-String Conversion
     hm.add_string(self.Q_S.public_numbers().encode_point())
     hm.add_mpint(long(K))
     H = self.hash_algo(hm.asbytes()).digest()
     self.transport._set_K_H(K, H)
     sig = self.transport.get_server_key().sign_ssh_data(H)
     # construct reply
     m = Message()
     m.add_byte(c_MSG_KEXECDH_REPLY)
     m.add_string(K_S)
     m.add_string(self.Q_S.public_numbers().encode_point())
     m.add_string(sig)
     self.transport._send_message(m)
     self.transport._activate_outbound()
Exemplo n.º 2
0
 def _parse_kexecdh_init(self, m):
     Q_C_bytes = m.get_string()
     self.Q_C = ec.EllipticCurvePublicNumbers.from_encoded_point(
         self.curve, Q_C_bytes)
     K_S = self.transport.get_server_key().asbytes()
     K = self.P.exchange(ec.ECDH(), self.Q_C.public_key(default_backend()))
     K = long(hexlify(K), 16)
     # compute exchange hash
     hm = Message()
     hm.add(self.transport.remote_version, self.transport.local_version,
            self.transport.remote_kex_init, self.transport.local_kex_init)
     hm.add_string(K_S)
     hm.add_string(Q_C_bytes)
     # SEC1: V2.0  2.3.3 Elliptic-Curve-Point-to-Octet-String Conversion
     hm.add_string(self.Q_S.public_numbers().encode_point())
     hm.add_mpint(long(K))
     H = self.hash_algo(hm.asbytes()).digest()
     self.transport._set_K_H(K, H)
     sig = self.transport.get_server_key().sign_ssh_data(H)
     # construct reply
     m = Message()
     m.add_byte(c_MSG_KEXECDH_REPLY)
     m.add_string(K_S)
     m.add_string(self.Q_S.public_numbers().encode_point())
     m.add_string(sig)
     self.transport._send_message(m)
     self.transport._activate_outbound()
Exemplo n.º 3
0
 def _pack(self, msg):
     self._flags = 0
     if self.st_size is not None:
         self._flags |= self.FLAG_SIZE
     if (self.st_uid is not None) and (self.st_gid is not None):
         self._flags |= self.FLAG_UIDGID
     if self.st_mode is not None:
         self._flags |= self.FLAG_PERMISSIONS
     if (self.st_atime is not None) and (self.st_mtime is not None):
         self._flags |= self.FLAG_AMTIME
     if len(self.attr) > 0:
         self._flags |= self.FLAG_EXTENDED
     msg.add_int(self._flags)
     if self._flags & self.FLAG_SIZE:
         msg.add_int64(self.st_size)
     if self._flags & self.FLAG_UIDGID:
         msg.add_int(self.st_uid)
         msg.add_int(self.st_gid)
     if self._flags & self.FLAG_PERMISSIONS:
         msg.add_int(self.st_mode)
     if self._flags & self.FLAG_AMTIME:
         # throw away any fractional seconds
         msg.add_int(long(self.st_atime))
         msg.add_int(long(self.st_mtime))
     if self._flags & self.FLAG_EXTENDED:
         msg.add_int(len(self.attr))
         for key, val in self.attr.items():
             msg.add_string(key)
             msg.add_string(val)
     return
Exemplo n.º 4
0
 def _pack(self, msg):
     self._flags = 0
     if self.st_size is not None:
         self._flags |= self.FLAG_SIZE
     if (self.st_uid is not None) and (self.st_gid is not None):
         self._flags |= self.FLAG_UIDGID
     if self.st_mode is not None:
         self._flags |= self.FLAG_PERMISSIONS
     if (self.st_atime is not None) and (self.st_mtime is not None):
         self._flags |= self.FLAG_AMTIME
     if len(self.attr) > 0:
         self._flags |= self.FLAG_EXTENDED
     msg.add_int(self._flags)
     if self._flags & self.FLAG_SIZE:
         msg.add_int64(self.st_size)
     if self._flags & self.FLAG_UIDGID:
         msg.add_int(self.st_uid)
         msg.add_int(self.st_gid)
     if self._flags & self.FLAG_PERMISSIONS:
         msg.add_int(self.st_mode)
     if self._flags & self.FLAG_AMTIME:
         # throw away any fractional seconds
         msg.add_int(long(self.st_atime))
         msg.add_int(long(self.st_mtime))
     if self._flags & self.FLAG_EXTENDED:
         msg.add_int(len(self.attr))
         for key, val in self.attr.items():
             msg.add_string(key)
             msg.add_string(val)
     return
Exemplo n.º 5
0
    def check(self, hash_algorithm, offset=0, length=0, block_size=0):
        """
        Ask the server for a hash of a section of this file.  This can be used
        to verify a successful upload or download, or for various rsync-like
        operations.

        The file is hashed from ``offset``, for ``length`` bytes.
        If ``length`` is 0, the remainder of the file is hashed.  Thus, if both
        ``offset`` and ``length`` are zero, the entire file is hashed.

        Normally, ``block_size`` will be 0 (the default), and this method will
        return a byte string representing the requested hash (for example, a
        string of length 16 for MD5, or 20 for SHA-1).  If a non-zero
        ``block_size`` is given, each chunk of the file (from ``offset`` to
        ``offset + length``) of ``block_size`` bytes is computed as a separate
        hash.  The hash results are all concatenated and returned as a single
        string.

        For example, ``check('sha1', 0, 1024, 512)`` will return a string of
        length 40.  The first 20 bytes will be the SHA-1 of the first 512 bytes
        of the file, and the last 20 bytes will be the SHA-1 of the next 512
        bytes.

        :param str hash_algorithm:
            the name of the hash algorithm to use (normally ``"sha1"`` or
            ``"md5"``)
        :param offset:
            offset into the file to begin hashing (0 means to start from the
            beginning)
        :param length:
            number of bytes to hash (0 means continue to the end of the file)
        :param int block_size:
            number of bytes to hash per result (must not be less than 256; 0
            means to compute only one hash of the entire segment)
        :return:
            `str` of bytes representing the hash of each block, concatenated
            together

        :raises:
            ``IOError`` -- if the server doesn't support the "check-file"
            extension, or possibly doesn't support the hash algorithm requested

        .. note:: Many (most?) servers don't support this extension yet.

        .. versionadded:: 1.4
        """
        t, msg = self.sftp._request(
            CMD_EXTENDED,
            "check-file",
            self.handle,
            hash_algorithm,
            long(offset),
            long(length),
            block_size,
        )
        msg.get_text()  # ext
        msg.get_text()  # alg
        data = msg.get_remainder()
        return data
Exemplo n.º 6
0
    def check(self, hash_algorithm, offset=0, length=0, block_size=0):
        """
        Ask the server for a hash of a section of this file.  This can be used
        to verify a successful upload or download, or for various rsync-like
        operations.

        The file is hashed from ``offset``, for ``length`` bytes.
        If ``length`` is 0, the remainder of the file is hashed.  Thus, if both
        ``offset`` and ``length`` are zero, the entire file is hashed.

        Normally, ``block_size`` will be 0 (the default), and this method will
        return a byte string representing the requested hash (for example, a
        string of length 16 for MD5, or 20 for SHA-1).  If a non-zero
        ``block_size`` is given, each chunk of the file (from ``offset`` to
        ``offset + length``) of ``block_size`` bytes is computed as a separate
        hash.  The hash results are all concatenated and returned as a single
        string.

        For example, ``check('sha1', 0, 1024, 512)`` will return a string of
        length 40.  The first 20 bytes will be the SHA-1 of the first 512 bytes
        of the file, and the last 20 bytes will be the SHA-1 of the next 512
        bytes.

        :param str hash_algorithm:
            the name of the hash algorithm to use (normally ``"sha1"`` or
            ``"md5"``)
        :param offset:
            offset into the file to begin hashing (0 means to start from the
            beginning)
        :param length:
            number of bytes to hash (0 means continue to the end of the file)
        :param int block_size:
            number of bytes to hash per result (must not be less than 256; 0
            means to compute only one hash of the entire segment)
        :return:
            `str` of bytes representing the hash of each block, concatenated
            together

        :raises:
            ``IOError`` -- if the server doesn't support the "check-file"
            extension, or possibly doesn't support the hash algorithm requested

        .. note:: Many (most?) servers don't support this extension yet.

        .. versionadded:: 1.4
        """
        t, msg = self.sftp._request(
            CMD_EXTENDED,
            "check-file",
            self.handle,
            hash_algorithm,
            long(offset),
            long(length),
            block_size,
        )
        msg.get_text()  # ext
        msg.get_text()  # alg
        data = msg.get_remainder()
        return data
Exemplo n.º 7
0
 def sign_ssh_data(self, data):
     digest = sha1(data).digest()
     rsa = RSA.construct((long(self.n), long(self.e), long(self.d)))
     sig = util.deflate_long(rsa.sign(self._pkcs1imify(digest), bytes())[0], 0)
     m = Message()
     m.add_string('ssh-rsa')
     m.add_string(sig)
     return m
Exemplo n.º 8
0
 def sign_ssh_data(self, data):
     digest = sha1(data).digest()
     rsa = RSA.construct((long(self.n), long(self.e), long(self.d)))
     sig = util.deflate_long(rsa.sign(self._pkcs1imify(digest), bytes())[0], 0)
     m = Message()
     m.add_string('ssh-rsa')
     m.add_string(sig)
     return m
Exemplo n.º 9
0
 def verify_ssh_sig(self, data, msg):
     if msg.get_text() != 'ssh-rsa':
         return False
     sig = util.inflate_long(msg.get_binary(), True)
     # verify the signature by SHA'ing the data and encrypting it using the
     # public key.  some wackiness ensues where we "pkcs1imify" the 20-byte
     # hash into a string as long as the RSA key.
     hash_obj = util.inflate_long(self._pkcs1imify(sha1(data).digest()), True)
     rsa = RSA.construct((long(self.n), long(self.e)))
     return rsa.verify(hash_obj, (sig,))
Exemplo n.º 10
0
 def verify_ssh_sig(self, data, msg):
     if msg.get_text() != 'ssh-rsa':
         return False
     sig = util.inflate_long(msg.get_binary(), True)
     # verify the signature by SHA'ing the data and encrypting it using the
     # public key.  some wackiness ensues where we "pkcs1imify" the 20-byte
     # hash into a string as long as the RSA key.
     hash_obj = util.inflate_long(self._pkcs1imify(sha1(data).digest()), True)
     rsa = RSA.construct((long(self.n), long(self.e)))
     return rsa.verify(hash_obj, (sig,))
Exemplo n.º 11
0
 def __init__(self, nbits, initial_value=long(1), overflow=long(0)):
     self.blocksize = nbits / 8
     self.overflow = overflow
     # start with value - 1 so we don't have to store intermediate values when counting
     # could the iv be 0?
     if initial_value == 0:
         self.value = array.array('c', max_byte * self.blocksize)
     else:
         x = deflate_long(initial_value - 1, add_sign_padding=False)
         self.value = array.array('c', zero_byte * (self.blocksize - len(x)) + x)
Exemplo n.º 12
0
 def _prefetch_thread(self, chunks):
     # do these read requests in a temporary thread because there may be
     # a lot of them, so it may block.
     for offset, length in chunks:
         with self._prefetch_lock:
             num = self.sftp._async_request(self, CMD_READ, self.handle, long(offset), int(length))
             self._prefetch_extents[num] = (offset, length)
Exemplo n.º 13
0
 def _parse_kexecdh_reply(self, m):
     K_S = m.get_string()
     Q_S_bytes = m.get_string()
     self.Q_S = ec.EllipticCurvePublicKey.from_encoded_point(
         self.curve, Q_S_bytes
     )
     sig = m.get_binary()
     K = self.P.exchange(ec.ECDH(), self.Q_S)
     K = long(hexlify(K), 16)
     # compute exchange hash and verify signature
     hm = Message()
     hm.add(
         self.transport.local_version,
         self.transport.remote_version,
         self.transport.local_kex_init,
         self.transport.remote_kex_init,
     )
     hm.add_string(K_S)
     # SEC1: V2.0  2.3.3 Elliptic-Curve-Point-to-Octet-String Conversion
     hm.add_string(
         self.Q_C.public_bytes(
             serialization.Encoding.X962,
             serialization.PublicFormat.UncompressedPoint,
         )
     )
     hm.add_string(Q_S_bytes)
     hm.add_mpint(K)
     self.transport._set_K_H(K, self.hash_algo(hm.asbytes()).digest())
     self.transport._verify_key(K_S, sig)
     self.transport._activate_outbound()
Exemplo n.º 14
0
    def _parse_modulus(self, line):
        timestamp, mod_type, tests, tries, size, generator, modulus = line.split()
        mod_type = int(mod_type)
        tests = int(tests)
        tries = int(tries)
        size = int(size)
        generator = int(generator)
        modulus = long(modulus, 16)

        # weed out primes that aren't at least:
        # type 2 (meets basic structural requirements)
        # test 4 (more than just a small-prime sieve)
        # tries < 100 if test & 4 (at least 100 tries of miller-rabin)
        if (mod_type < 2) or (tests < 4) or ((tests & 4) and (tests < 8) and (tries < 100)):
            self.discarded.append((modulus, 'does not meet basic requirements'))
            return
        if generator == 0:
            generator = 2

        # there's a bug in the ssh "moduli" file (yeah, i know: shock! dismay!
        # call cnn!) where it understates the bit lengths of these primes by 1.
        # this is okay.
        bl = util.bit_length(modulus)
        if (bl != size) and (bl != size + 1):
            self.discarded.append((modulus, 'incorrectly reported bit length %d' % size))
            return
        if bl not in self.pack:
            self.pack[bl] = []
        self.pack[bl].append((generator, modulus))
Exemplo n.º 15
0
 def _prefetch_thread(self, chunks):
     # do these read requests in a temporary thread because there may be
     # a lot of them, so it may block.
     for offset, length in chunks:
         with self._prefetch_lock:
             num = self.sftp._async_request(self, CMD_READ, self.handle, long(offset), int(length))
             self._prefetch_extents[num] = (offset, length)
Exemplo n.º 16
0
 def _parse_kexecdh_init(self, m):
     peer_key_bytes = m.get_string()
     peer_key = X25519PublicKey.from_public_bytes(peer_key_bytes)
     K = self._perform_exchange(peer_key)
     K = long(binascii.hexlify(K), 16)
     # compute exchange hash
     hm = Message()
     hm.add(
         self.transport.remote_version,
         self.transport.local_version,
         self.transport.remote_kex_init,
         self.transport.local_kex_init,
     )
     server_key_bytes = self.transport.get_server_key().asbytes()
     exchange_key_bytes = self.key.public_key().public_bytes(
         serialization.Encoding.Raw, serialization.PublicFormat.Raw)
     hm.add_string(server_key_bytes)
     hm.add_string(peer_key_bytes)
     hm.add_string(exchange_key_bytes)
     hm.add_mpint(K)
     H = self.hash_algo(hm.asbytes()).digest()
     self.transport._set_K_H(K, H)
     sig = self.transport.get_server_key().sign_ssh_data(H)
     # construct reply
     m = Message()
     m.add_byte(c_MSG_KEXECDH_REPLY)
     m.add_string(server_key_bytes)
     m.add_string(exchange_key_bytes)
     m.add_string(sig)
     self.transport._send_message(m)
     self.transport._activate_outbound()
Exemplo n.º 17
0
 def _parse_kexecdh_reply(self, m):
     K_S = m.get_string()
     Q_S_bytes = m.get_string()
     self.Q_S = ec.EllipticCurvePublicNumbers.from_encoded_point(
         self.curve, Q_S_bytes
     )
     sig = m.get_binary()
     K = self.P.exchange(ec.ECDH(), self.Q_S.public_key(default_backend()))
     K = long(hexlify(K), 16)
     # compute exchange hash and verify signature
     hm = Message()
     hm.add(
         self.transport.local_version,
         self.transport.remote_version,
         self.transport.local_kex_init,
         self.transport.remote_kex_init,
     )
     hm.add_string(K_S)
     # SEC1: V2.0  2.3.3 Elliptic-Curve-Point-to-Octet-String Conversion
     hm.add_string(self.Q_C.public_numbers().encode_point())
     hm.add_string(Q_S_bytes)
     hm.add_mpint(K)
     self.transport._set_K_H(K, self.hash_algo(hm.asbytes()).digest())
     self.transport._verify_key(K_S, sig)
     self.transport._activate_outbound()
Exemplo n.º 18
0
    def _parse_kexecdh_reply(self, m):
        peer_host_key_bytes = m.get_string()
        peer_key_bytes = m.get_string()
        sig = m.get_binary()

        peer_key = X25519PublicKey.from_public_bytes(peer_key_bytes)

        K = self._perform_exchange(peer_key)
        K = long(binascii.hexlify(K), 16)
        # compute exchange hash and verify signature
        hm = Message()
        hm.add(
            self.transport.local_version,
            self.transport.remote_version,
            self.transport.local_kex_init,
            self.transport.remote_kex_init,
        )
        hm.add_string(peer_host_key_bytes)
        hm.add_string(self.key.public_key().public_bytes(
            serialization.Encoding.Raw, serialization.PublicFormat.Raw))
        hm.add_string(peer_key_bytes)
        hm.add_mpint(K)
        self.transport._set_K_H(K, self.hash_algo(hm.asbytes()).digest())
        self.transport._verify_key(peer_host_key_bytes, sig)
        self.transport._activate_outbound()
Exemplo n.º 19
0
def deflate_long(n, add_sign_padding=True):
    """turns a long-int into a normalized byte string (adapted from Crypto.Util.number)"""
    # after much testing, this algorithm was deemed to be the fastest
    s = bytes()
    n = long(n)
    while (n != 0) and (n != -1):
        s = struct.pack('>I', n & xffffffff) + s
        n >>= 32
    # strip off leading zeros, FFs
    for i in enumerate(s):
        if (n == 0) and (i[1] != deflate_zero):
            break
        if (n == -1) and (i[1] != deflate_ff):
            break
    else:
        # degenerate case, n was either 0 or -1
        i = (0,)
        if n == 0:
            s = zero_byte
        else:
            s = max_byte
    s = s[i[0]:]
    if add_sign_padding:
        if (n == 0) and (byte_ord(s[0]) >= 0x80):
            s = zero_byte + s
        if (n == -1) and (byte_ord(s[0]) < 0x80):
            s = max_byte + s
    return s
Exemplo n.º 20
0
    def _parse_modulus(self, line):
        timestamp, mod_type, tests, tries, size, generator, modulus = line.split(
        )
        mod_type = int(mod_type)
        tests = int(tests)
        tries = int(tries)
        size = int(size)
        generator = int(generator)
        modulus = long(modulus, 16)

        # weed out primes that aren't at least:
        # type 2 (meets basic structural requirements)
        # test 4 (more than just a small-prime sieve)
        # tries < 100 if test & 4 (at least 100 tries of miller-rabin)
        if (mod_type < 2) or (tests < 4) or ((tests & 4) and (tests < 8) and
                                             (tries < 100)):
            self.discarded.append(
                (modulus, 'does not meet basic requirements'))
            return
        if generator == 0:
            generator = 2

        # there's a bug in the ssh "moduli" file (yeah, i know: shock! dismay!
        # call cnn!) where it understates the bit lengths of these primes by 1.
        # this is okay.
        bl = util.bit_length(modulus)
        if (bl != size) and (bl != size + 1):
            self.discarded.append(
                (modulus, 'incorrectly reported bit length %d' % size))
            return
        if bl not in self.pack:
            self.pack[bl] = []
        self.pack[bl].append((generator, modulus))
Exemplo n.º 21
0
    def verify_ssh_sig(self, data, msg):
        if len(msg.asbytes()) == 40:
            # spies.com bug: signature has no header
            sig = msg.asbytes()
        else:
            kind = msg.get_text()
            if kind != 'ssh-dss':
                return 0
            sig = msg.get_binary()

        # pull out (r, s) which are NOT encoded as mpints
        sigR = util.inflate_long(sig[:20], 1)
        sigS = util.inflate_long(sig[20:], 1)
        sigM = util.inflate_long(sha1(data).digest(), 1)

        dss = DSA.construct((long(self.y), long(self.g), long(self.p), long(self.q)))
        return dss.verify(sigM, (sigR, sigS))
Exemplo n.º 22
0
    def verify_ssh_sig(self, data, msg):
        if len(msg.asbytes()) == 40:
            # spies.com bug: signature has no header
            sig = msg.asbytes()
        else:
            kind = msg.get_text()
            if kind != 'ssh-dss':
                return 0
            sig = msg.get_binary()

        # pull out (r, s) which are NOT encoded as mpints
        sigR = util.inflate_long(sig[:20], 1)
        sigS = util.inflate_long(sig[20:], 1)
        sigM = util.inflate_long(sha1(data).digest(), 1)

        dss = DSA.construct((long(self.y), long(self.g), long(self.p), long(self.q)))
        return dss.verify(sigM, (sigR, sigS))
Exemplo n.º 23
0
    def __init__(self, transport):
        self.transport = transport

        self.P = long(0)
        # Client public key
        self.Q_C = None
        # Server public key
        self.Q_S = None
Exemplo n.º 24
0
def inflate_long(s, always_positive=False):
    """turns a normalized byte string into a long-int (adapted from Crypto.Util.number)"""
    out = long(0)
    negative = 0
    if not always_positive and (len(s) > 0) and (byte_ord(s[0]) >= 0x80):
        negative = 1
    if len(s) % 4:
        filler = zero_byte
        if negative:
            filler = max_byte
        # never convert this to ``s +=`` because this is a string, not a number
        # noinspection PyAugmentAssignment
        s = filler * (4 - len(s) % 4) + s
    for i in range(0, len(s), 4):
        out = (out << 32) + struct.unpack('>I', s[i:i+4])[0]
    if negative:
        out -= (long(1) << (8 * len(s)))
    return out
Exemplo n.º 25
0
 def _read(self, size):
     size = min(size, self.MAX_REQUEST_SIZE)
     if self._prefetching:
         data = self._read_prefetch(size)
         if data is not None:
             return data
     t, msg = self.sftp._request(CMD_READ, self.handle, long(self._realpos), int(size))
     if t != CMD_DATA:
         raise SFTPError('Expected data')
     return msg.get_string()
Exemplo n.º 26
0
 def _read(self, size):
     size = min(size, self.MAX_REQUEST_SIZE)
     if self._prefetching:
         data = self._read_prefetch(size)
         if data is not None:
             return data
     t, msg = self.sftp._request(CMD_READ, self.handle, long(self._realpos), int(size))
     if t != CMD_DATA:
         raise SFTPError('Expected data')
     return msg.get_string()
Exemplo n.º 27
0
 def sign_ssh_data(self, data):
     digest = sha1(data).digest()
     dss = DSA.construct((long(self.y), long(self.g), long(self.p), long(self.q), long(self.x)))
     # generate a suitable k
     qsize = len(util.deflate_long(self.q, 0))
     while True:
         k = util.inflate_long(os.urandom(qsize), 1)
         if (k > 2) and (k < self.q):
             break
     r, s = dss.sign(util.inflate_long(digest, 1), k)
     m = Message()
     m.add_string('ssh-dss')
     # apparently, in rare cases, r or s may be shorter than 20 bytes!
     rstr = util.deflate_long(r, 0)
     sstr = util.deflate_long(s, 0)
     if len(rstr) < 20:
         rstr = zero_byte * (20 - len(rstr)) + rstr
     if len(sstr) < 20:
         sstr = zero_byte * (20 - len(sstr)) + sstr
     m.add_string(rstr + sstr)
     return m
Exemplo n.º 28
0
 def sign_ssh_data(self, data):
     digest = sha1(data).digest()
     dss = DSA.construct((long(self.y), long(self.g), long(self.p), long(self.q), long(self.x)))
     # generate a suitable k
     qsize = len(util.deflate_long(self.q, 0))
     while True:
         k = util.inflate_long(os.urandom(qsize), 1)
         if (k > 2) and (k < self.q):
             break
     r, s = dss.sign(util.inflate_long(digest, 1), k)
     m = Message()
     m.add_string('ssh-dss')
     # apparently, in rare cases, r or s may be shorter than 20 bytes!
     rstr = util.deflate_long(r, 0)
     sstr = util.deflate_long(s, 0)
     if len(rstr) < 20:
         rstr = zero_byte * (20 - len(rstr)) + rstr
     if len(sstr) < 20:
         sstr = zero_byte * (20 - len(sstr)) + sstr
     m.add_string(rstr + sstr)
     return m
Exemplo n.º 29
0
 def _parse_kexecdh_init(self, m):
     Q_C_bytes = m.get_string()
     self.Q_C = ec.EllipticCurvePublicKey.from_encoded_point(
         self.curve, Q_C_bytes)
     K_S = self.transport.get_server_key().asbytes()
     K = self.P.exchange(ec.ECDH(), self.Q_C)
     K = long(hexlify(K), 16)
     # compute exchange hash
     hm = Message()
     hm.add(
         self.transport.remote_version,
         self.transport.local_version,
         self.transport.remote_kex_init,
         self.transport.local_kex_init,
     )
     hm.add_string(K_S)
     hm.add_string(Q_C_bytes)
     # SEC1: V2.0  2.3.3 Elliptic-Curve-Point-to-Octet-String Conversion
     hm.add_string(
         self.Q_S.public_bytes(
             serialization.Encoding.X962,
             serialization.PublicFormat.UncompressedPoint,
         ))
     hm.add_mpint(long(K))
     H = self.hash_algo(hm.asbytes()).digest()
     self.transport._set_K_H(K, H)
     sig = self.transport.get_server_key().sign_ssh_data(
         H, self.transport.host_key_type)
     # construct reply
     m = Message()
     m.add_byte(c_MSG_KEXECDH_REPLY)
     m.add_string(K_S)
     m.add_string(
         self.Q_S.public_bytes(
             serialization.Encoding.X962,
             serialization.PublicFormat.UncompressedPoint,
         ))
     m.add_string(sig)
     self.transport._send_message(m)
     self.transport._activate_outbound()
Exemplo n.º 30
0
 def _write(self, data):
     # may write less than requested if it would exceed max packet size
     chunk = min(len(data), self.MAX_REQUEST_SIZE)
     self._reqs.append(
         self.sftp._async_request(type(None), CMD_WRITE, self.handle, long(self._realpos), data[:chunk])
     )
     if not self.pipelined or (len(self._reqs) > 100 and self.sftp.sock.recv_ready()):
         while len(self._reqs):
             req = self._reqs.popleft()
             t, msg = self.sftp._read_response(req)
             if t != CMD_STATUS:
                 raise SFTPError("Expected status")
             # convert_status already called
     return chunk
Exemplo n.º 31
0
 def _write(self, data):
     # may write less than requested if it would exceed max packet size
     chunk = min(len(data), self.MAX_REQUEST_SIZE)
     self._reqs.append(
         self.sftp._async_request(type(None), CMD_WRITE, self.handle,
                                  long(self._realpos), data[:chunk]))
     if not self.pipelined or (len(self._reqs) > 100
                               and self.sftp.sock.recv_ready()):
         while len(self._reqs):
             req = self._reqs.popleft()
             t, msg = self.sftp._read_response(req)
             if t != CMD_STATUS:
                 raise SFTPError('Expected status')
             # convert_status already called
     return chunk
Exemplo n.º 32
0
    def _parse_kexc25519_init(self, m):
        # server mode

        # Only one field in the client's message, which is their public key
        Q_C_bytes = m.get_string()
        self.Q_C = x25519.X25519PublicKey.from_public_bytes(Q_C_bytes)

        # Compute shared secret
        K = self.P.exchange(self.Q_C)
        K = long(hexlify(K), 16)

        # Prepare hostkey
        K_S = self.transport.get_server_key().asbytes()

        # Compute initial transport key
        hm = Message()
        hm.add(
            self.transport.remote_version,
            self.transport.local_version,
            self.transport.remote_kex_init,
            self.transport.local_kex_init,
        )

        hm.add_string(K_S)
        hm.add_string(Q_C_bytes)
        hm.add_string(
            self.Q_S.public_bytes(encoding=Encoding.Raw,
                                  format=PublicFormat.Raw))
        hm.add_mpint(K)
        H = self.hash_algo(hm.asbytes()).digest()
        self.transport._set_K_H(K, H)

        # Compute signature
        sig = self.transport.get_server_key().sign_ssh_data(H)
        # construct reply
        m = Message()
        m.add_byte(c_MSG_KEXC25519_REPLY)
        m.add_string(K_S)
        m.add_string(
            self.Q_S.public_bytes(encoding=Encoding.Raw,
                                  format=PublicFormat.Raw))
        m.add_string(sig)
        self.transport._send_message(m)
        self.transport._activate_outbound()
Exemplo n.º 33
0
    def _parse_kexc25519_reply(self, m):
        # client mode

        # 3 fields in response:
        #   - KEX host key
        #   - Ephemeral (Curve25519) key
        #   - Signature
        K_S = m.get_string()
        self.Q_S = x25519.X25519PublicKey.from_public_bytes(m.get_string())
        sig = m.get_binary()

        # Compute shared secret
        K = self.P.exchange(self.Q_S)
        K = long(hexlify(K), 16)

        hm = Message()
        hm.add(
            self.transport.local_version,
            self.transport.remote_version,
            self.transport.local_kex_init,
            self.transport.remote_kex_init,
        )

        # "hm" is used as the initial transport key
        hm.add_string(K_S)
        hm.add_string(
            self.Q_C.public_bytes(encoding=Encoding.Raw,
                                  format=PublicFormat.Raw))
        hm.add_string(
            self.Q_S.public_bytes(encoding=Encoding.Raw,
                                  format=PublicFormat.Raw))
        hm.add_mpint(K)
        self.transport._set_K_H(K, self.hash_algo(hm.asbytes()).digest())
        # Verify that server signed kex message with its own pubkey
        self.transport._verify_key(K_S, sig)
        self.transport._activate_outbound()
Exemplo n.º 34
0
    cr_byte_value = 13
    linefeed_byte_value = 10


def asbytes(s):
    if not isinstance(s, bytes_types):
        if isinstance(s, string_types):
            s = b(s)
        else:
            try:
                s = s.asbytes()
            except Exception:
                raise Exception('Unknown type')
    return s

xffffffff = long(0xffffffff)
x80000000 = long(0x80000000)
o666 = 438
o660 = 432
o644 = 420
o600 = 384
o777 = 511
o700 = 448
o70 = 56

DEBUG = logging.DEBUG
INFO = logging.INFO
WARNING = logging.WARNING
ERROR = logging.ERROR
CRITICAL = logging.CRITICAL
Exemplo n.º 35
0
 def __init__(self, transport):
     self.transport = transport
     self.x = long(0)
     self.e = long(0)
     self.f = long(0)
Exemplo n.º 36
0
def transport_run(self):
    # (use the exposed "run" method, because if we specify a thread target
    # of a private method, threading.Thread will keep a reference to it
    # indefinitely, creating a GC cycle and not letting Transport ever be
    # GC'd. it's a bug in Thread.)

    # Hold reference to 'sys' so we can test sys.modules to detect
    # interpreter shutdown.
    self.sys = sys

    # active=True occurs before the thread is launched, to avoid a race
    _active_threads.append(self)
    tid = hex(long(id(self)) & xffffffff)
    if self.server_mode:
        self._log(DEBUG, "starting thread (server mode): {}".format(tid))
    else:
        self._log(DEBUG, "starting thread (client mode): {}".format(tid))
    try:
        try:
            self.packetizer.write_all(b(self.local_version + "\r\n"))
            self._log(
                DEBUG,
                "Local version/idstring: {}".format(self.local_version),
            )  # noqa
            self._check_banner()
            # The above is actually very much part of the handshake, but
            # sometimes the banner can be read but the machine is not
            # responding, for example when the remote ssh daemon is loaded
            # in to memory but we can not read from the disk/spawn a new
            # shell.
            # Make sure we can specify a timeout for the initial handshake.
            # Re-use the banner timeout for now.
            self.packetizer.start_handshake(self.handshake_timeout)
            self._send_kex_init()
            self._expect_packet(MSG_KEXINIT)

            while self.active:
                if self.packetizer.need_rekey() and not self.in_kex:
                    self._send_kex_init()
                try:
                    ptype, m = self.packetizer.read_message()
                except NeedRekeyException:
                    continue
                if ptype == MSG_IGNORE:
                    continue
                elif ptype == MSG_DISCONNECT:
                    self._parse_disconnect(m)
                    break
                elif ptype == MSG_DEBUG:
                    self._parse_debug(m)
                    continue
                if len(self._expected_packet) > 0:
                    if ptype not in self._expected_packet:
                        if ptype == 30:
                            continue
                        raise SSHException(
                            "Expecting packet from {!r}, got {:d}".format(
                                self._expected_packet, ptype
                            )
                        )  # noqa
                    self._expected_packet = tuple()
                    if (ptype >= 30) and (ptype <= 41):
                        self.kex_engine.parse_next(ptype, m)
                        continue

                if ptype in self._handler_table:
                    error_msg = self._ensure_authed(ptype, m)
                    if error_msg:
                        self._send_message(error_msg)
                    else:
                        self._handler_table[ptype](self, m)
                elif ptype in self._channel_handler_table:
                    chanid = m.get_int()
                    chan = self._channels.get(chanid)
                    if chan is not None:
                        self._channel_handler_table[ptype](chan, m)
                    elif chanid in self.channels_seen:
                        self._log(
                            DEBUG,
                            "Ignoring message for dead channel {:d}".format(  # noqa
                                chanid
                            ),
                        )
                    else:
                        self._log(
                            ERROR,
                            "Channel request for unknown channel {:d}".format(  # noqa
                                chanid
                            ),
                        )
                        break
                elif (
                    self.auth_handler is not None
                    and ptype in self.auth_handler._handler_table
                ):
                    handler = self.auth_handler._handler_table[ptype]
                    handler(self.auth_handler, m)
                    if len(self._expected_packet) > 0:
                        continue
                else:
                    # Respond with "I don't implement this particular
                    # message type" message (unless the message type was
                    # itself literally MSG_UNIMPLEMENTED, in which case, we
                    # just shut up to avoid causing a useless loop).
                    name = MSG_NAMES[ptype]
                    warning = "Oops, unhandled type {} ({!r})".format(
                        ptype, name
                    )
                    self._log(WARNING, warning)
                    if ptype != MSG_UNIMPLEMENTED:
                        msg = Message()
                        msg.add_byte(cMSG_UNIMPLEMENTED)
                        msg.add_int(m.seqno)
                        self._send_message(msg)
                self.packetizer.complete_handshake()
        except SSHException as e:
            self._log(ERROR, "Exception: " + str(e))
            self._log(ERROR, util.tb_strings())
            self.saved_exception = e
        except EOFError as e:
            self._log(DEBUG, "EOF in transport thread")
            self.saved_exception = e
        except socket.error as e:
            if type(e.args) is tuple:
                if e.args:
                    emsg = "{} ({:d})".format(e.args[1], e.args[0])
                else:  # empty tuple, e.g. socket.timeout
                    emsg = str(e) or repr(e)
            else:
                emsg = e.args
            self._log(ERROR, "Socket exception: " + emsg)
            self.saved_exception = e
        except Exception as e:
            self._log(ERROR, "Unknown exception: " + str(e))
            self._log(ERROR, util.tb_strings())
            self.saved_exception = e
        _active_threads.remove(self)
        for chan in list(self._channels.values()):
            chan._unlink()
        if self.active:
            self.active = False
            self.packetizer.close()
            if self.completion_event is not None:
                self.completion_event.set()
            if self.auth_handler is not None:
                self.auth_handler.abort()
            for event in self.channel_events.values():
                event.set()
            try:
                self.lock.acquire()
                self.server_accept_cv.notify()
            finally:
                self.lock.release()
        self.sock.close()
    except Exception:
        # Don't raise spurious 'NoneType has no attribute X' errors when we
        # wake up during interpreter shutdown. Or rather -- raise
        # everything *if* sys.modules (used as a convenient sentinel)
        # appears to still exist.
        if self.sys.modules is not None:
            raise
Exemplo n.º 37
0
 def __init__(self, transport):
     self.transport = transport
     # private key, client public and server public keys
     self.P = long(0)
     self.Q_C = None
     self.Q_S = None
Exemplo n.º 38
0
 def new(cls, nbits, initial_value=long(1), overflow=long(0)):
     return cls(nbits, initial_value=initial_value, overflow=overflow)
Exemplo n.º 39
0
class Message (object):
    """
    An SSH2 message is a stream of bytes that encodes some combination of
    strings, integers, bools, and infinite-precision integers (known in Python
    as longs).  This class builds or breaks down such a byte stream.
    
    Normally you don't need to deal with anything this low-level, but it's
    exposed for people implementing custom extensions, or features that
    paramiko doesn't support yet.
    """

    big_int = long(0xff000000)

    def __init__(self, content=None):
        """
        Create a new SSH2 message.

        :param str content:
            the byte stream to use as the message content (passed in only when
            decomposing a message).
        """
        if content is not None:
            self.packet = BytesIO(content)
        else:
            self.packet = BytesIO()

    def __str__(self):
        """
        Return the byte stream content of this message, as a string/bytes obj.
        """
        return self.asbytes()

    def __repr__(self):
        """
        Returns a string representation of this object, for debugging.
        """
        return 'paramiko.Message(' + repr(self.packet.getvalue()) + ')'

    def asbytes(self):
        """
        Return the byte stream content of this Message, as bytes.
        """
        return self.packet.getvalue()

    def rewind(self):
        """
        Rewind the message to the beginning as if no items had been parsed
        out of it yet.
        """
        self.packet.seek(0)

    def get_remainder(self):
        """
        Return the bytes (as a `str`) of this message that haven't already been
        parsed and returned.
        """
        position = self.packet.tell()
        remainder = self.packet.read()
        self.packet.seek(position)
        return remainder

    def get_so_far(self):
        """
        Returns the `str` bytes of this message that have been parsed and
        returned. The string passed into a message's constructor can be
        regenerated by concatenating ``get_so_far`` and `get_remainder`.
        """
        position = self.packet.tell()
        self.rewind()
        return self.packet.read(position)

    def get_bytes(self, n):
        """
        Return the next ``n`` bytes of the message (as a `str`), without
        decomposing into an int, decoded string, etc.  Just the raw bytes are
        returned. Returns a string of ``n`` zero bytes if there weren't ``n``
        bytes remaining in the message.
        """
        b = self.packet.read(n)
        max_pad_size = 1 << 20  # Limit padding to 1 MB
        if len(b) < n < max_pad_size:
            return b + zero_byte * (n - len(b))
        return b

    def get_byte(self):
        """
        Return the next byte of the message, without decomposing it.  This
        is equivalent to `get_bytes(1) <get_bytes>`.

        :return:
            the next (`str`) byte of the message, or ``'\000'`` if there aren't
            any bytes remaining.
        """
        return self.get_bytes(1)

    def get_boolean(self):
        """
        Fetch a boolean from the stream.
        """
        b = self.get_bytes(1)
        return b != zero_byte

    def get_int(self):
        """
        Fetch an int from the stream.

        :return: a 32-bit unsigned `int`.
        """
        byte = self.get_bytes(1)
        if byte == max_byte:
            return util.inflate_long(self.get_binary())
        byte += self.get_bytes(3)
        return struct.unpack('>I', byte)[0]

    def get_size(self):
        """
        Fetch an int from the stream.

        @return: a 32-bit unsigned integer.
        @rtype: int
        """
        return struct.unpack('>I', self.get_bytes(4))[0]

    def get_int64(self):
        """
        Fetch a 64-bit int from the stream.

        :return: a 64-bit unsigned integer (`long`).
        """
        return struct.unpack('>Q', self.get_bytes(8))[0]

    def get_mpint(self):
        """
        Fetch a long int (mpint) from the stream.

        :return: an arbitrary-length integer (`long`).
        """
        return util.inflate_long(self.get_binary())

    def get_string(self):
        """
        Fetch a `str` from the stream.  This could be a byte string and may
        contain unprintable characters.  (It's not unheard of for a string to
        contain another byte-stream message.)
        """
        return self.get_bytes(self.get_size())

    def get_text(self):
        """
        Fetch a string from the stream.  This could be a byte string and may
        contain unprintable characters.  (It's not unheard of for a string to
        contain another byte-stream Message.)

        @return: a string.
        @rtype: string
        """
        return u(self.get_bytes(self.get_size()))
        #return self.get_bytes(self.get_size())

    def get_binary(self):
        """
        Fetch a string from the stream.  This could be a byte string and may
        contain unprintable characters.  (It's not unheard of for a string to
        contain another byte-stream Message.)

        @return: a string.
        @rtype: string
        """
        return self.get_bytes(self.get_size())

    def get_list(self):
        """
        Fetch a `list` of `strings <str>` from the stream.
        
        These are trivially encoded as comma-separated values in a string.
        """
        return self.get_text().split(',')

    def add_bytes(self, b):
        """
        Write bytes to the stream, without any formatting.
        
        :param str b: bytes to add
        """
        self.packet.write(b)
        return self

    def add_byte(self, b):
        """
        Write a single byte to the stream, without any formatting.
        
        :param str b: byte to add
        """
        self.packet.write(b)
        return self

    def add_boolean(self, b):
        """
        Add a boolean value to the stream.
        
        :param bool b: boolean value to add
        """
        if b:
            self.packet.write(one_byte)
        else:
            self.packet.write(zero_byte)
        return self
            
    def add_size(self, n):
        """
        Add an integer to the stream.
        
        :param int n: integer to add
        """
        self.packet.write(struct.pack('>I', n))
        return self
            
    def add_int(self, n):
        """
        Add an integer to the stream.
        
        :param int n: integer to add
        """
        if n >= Message.big_int:
            self.packet.write(max_byte)
            self.add_string(util.deflate_long(n))
        else:
            self.packet.write(struct.pack('>I', n))
        return self

    def add_int64(self, n):
        """
        Add a 64-bit int to the stream.

        :param long n: long int to add
        """
        self.packet.write(struct.pack('>Q', n))
        return self

    def add_mpint(self, z):
        """
        Add a long int to the stream, encoded as an infinite-precision
        integer.  This method only works on positive numbers.
        
        :param long z: long int to add
        """
        self.add_string(util.deflate_long(z))
        return self

    def add_string(self, s):
        """
        Add a string to the stream.
        
        :param str s: string to add
        """
        s = asbytes(s)
        self.add_size(len(s))
        self.packet.write(s)
        return self

    def add_list(self, l):
        """
        Add a list of strings to the stream.  They are encoded identically to
        a single string of values separated by commas.  (Yes, really, that's
        how SSH2 does it.)
        
        :param list l: list of strings to add
        """
        self.add_string(','.join(l))
        return self
        
    def _add(self, i):
        if type(i) is bool:
            return self.add_boolean(i)
        elif isinstance(i, integer_types):
            return self.add_int(i)
        elif type(i) is list:
            return self.add_list(i)
        else:
            return self.add_string(i)

    def add(self, *seq):
        """
        Add a sequence of items to the stream.  The values are encoded based
        on their type: str, int, bool, list, or long.

        .. warning::
            Longs are encoded non-deterministically.  Don't use this method.
        
        :param seq: the sequence of items
        """
        for item in seq:
            self._add(item)
Exemplo n.º 40
0
 def __init__(self, transport):
     self.transport = transport
     # private key, client public and server public keys
     self.P = long(0)
     self.Q_C = None
     self.Q_S = None
Exemplo n.º 41
0
def asbytes(s):
    """Coerce to bytes if possible or return unchanged."""
    if isinstance(s, bytes):
        return s
    if isinstance(s, text_type):
        # Accept text and encode as utf-8 for compatibility only.
        return s.encode("utf-8")
    asbytes = getattr(s, "asbytes", None)
    if asbytes is not None:
        return asbytes()
    # May be an object that implements the buffer api, let callers handle.
    return s


xffffffff = long(0xffffffff)
x80000000 = long(0x80000000)
o666 = 438
o660 = 432
o644 = 420
o600 = 384
o777 = 511
o700 = 448
o70 = 56

DEBUG = logging.DEBUG
INFO = logging.INFO
WARNING = logging.WARNING
ERROR = logging.ERROR
CRITICAL = logging.CRITICAL
Exemplo n.º 42
0
 def __init__(self, transport):
     self.transport = transport
     self.x = long(0)
     self.e = long(0)
     self.f = long(0)