def handle_line()

in pipe-cli/src/utilities/putty/kh2reg.py [0:0]


def handle_line(line, output_formatter, try_hosts):
    try:
        # Remove leading/trailing whitespace (should zap CR and LF)
        line = line.strip()

        # Skip blanks and comments
        if line == '' or line[0] == '#':
            raise BlankInputLine

        # Split line on spaces.
        fields = line.split(' ')

        # Common fields
        hostpat = fields[0]
        keyparams = []      # placeholder
        keytype = ""        # placeholder

        # Grotty heuristic to distinguish known_hosts from known_hosts2:
        # is second field entirely decimal digits?
        if re.match (r"\d*$", fields[1]):

            # Treat as SSH-1-type host key.
            # Format: hostpat bits10 exp10 mod10 comment...
            # (PuTTY doesn't store the number of bits.)
            keyparams = list(map(int, fields[2:4]))
            keytype = "rsa"

        else:

            # Treat as SSH-2-type host key.
            # Format: hostpat keytype keyblob64 comment...
            sshkeytype, blob = fields[1], base64.decodebytes(
                fields[2].encode("ASCII"))

            # 'blob' consists of a number of
            #   uint32    N (big-endian)
            #   uint8[N]  field_data
            subfields = []
            while blob:
                sizefmt = ">L"
                (size,) = struct.unpack (sizefmt, blob[0:4])
                size = int(size)   # req'd for slicage
                (data,) = struct.unpack (">%lus" % size, blob[4:size+4])
                subfields.append(data)
                blob = blob [struct.calcsize(sizefmt) + size : ]

            # The first field is keytype again.
            if subfields[0].decode("ASCII") != sshkeytype:
                raise KeyFormatError("""
                    outer and embedded key types do not match: '%s', '%s'
                    """ % (sshkeytype, subfields[1]))

            # Translate key type string into something PuTTY can use, and
            # munge the rest of the data.
            if sshkeytype == "ssh-rsa":
                keytype = "rsa2"
                # The rest of the subfields we can treat as an opaque list
                # of bignums (same numbers and order as stored by PuTTY).
                keyparams = list(map(strtoint, subfields[1:]))

            elif sshkeytype == "ssh-dss":
                keytype = "dss"
                # Same again.
                keyparams = list(map(strtoint, subfields[1:]))

            elif sshkeytype in nist_curves:
                keytype = sshkeytype
                # Have to parse this a bit.
                if len(subfields) > 3:
                    raise KeyFormatError("too many subfields in blob")
                (curvename, Q) = subfields[1:]
                # First is yet another copy of the key name.
                if not re.match("ecdsa-sha2-" + re.escape(
                        curvename.decode("ASCII")), sshkeytype):
                    raise KeyFormatError("key type mismatch ('%s' vs '%s')"
                            % (sshkeytype, curvename))
                # Second contains key material X and Y (hopefully).
                # First a magic octet indicating point compression.
                point_type = struct.unpack_from("B", Q, 0)[0]
                Qrest = Q[1:]
                if point_type == 4:
                    # Then two equal-length bignums (X and Y).
                    bnlen = len(Qrest)
                    if (bnlen % 1) != 0:
                        raise KeyFormatError("odd-length X+Y")
                    bnlen = bnlen // 2
                    x = strtoint(Qrest[:bnlen])
                    y = strtoint(Qrest[bnlen:])
                elif 2 <= point_type <= 3:
                    # A compressed point just specifies X, and leaves
                    # Y implicit except for parity, so we have to
                    # recover it from the curve equation.
                    curve = nist_curves[sshkeytype]
                    x = strtoint(Qrest)
                    yy = (x*x*x + curve.a*x + curve.b) % curve.p
                    y = SqrtModP.root(yy, curve.p)
                    if y % 2 != point_type % 2:
                        y = curve.p - y

                keyparams = [curvename, x, y]

            elif sshkeytype in { "ssh-ed25519",  "ssh-ed448" }:
                keytype = sshkeytype

                if len(subfields) != 2:
                    raise KeyFormatError("wrong number of subfields in blob")
                # Key material y, with the top bit being repurposed as
                # the expected parity of the associated x (point
                # compression).
                y = strtoint_le(subfields[1])
                x_parity = y >> 255
                y &= ~(1 << 255)

                # Curve parameters.
                p, d, a = {
                    "ssh-ed25519": (2**255 - 19, 0x52036cee2b6ffe738cc740797779e89800700a4d4141d8ab75eb4dca135978a3, -1),
                    "ssh-ed448": (2**448-2**224-1, -39081, +1),
                }[sshkeytype]

                # Recover x^2 = (y^2 - 1) / (d y^2 - a).
                xx = (y*y - 1) * invert(d*y*y - a, p) % p

                # Take the square root.
                x = SqrtModP.root(xx, p)

                # Pick the square root of the correct parity.
                if (x % 2) != x_parity:
                    x = p - x

                keyparams = [x, y]
            else:
                raise UnknownKeyType(sshkeytype)

        # Now print out one line per host pattern, discarding wildcards.
        for host in hostpat.split(','):
            if re.search (r"[*?!]", host):
                warn("skipping wildcard host pattern '%s'" % host)
                continue

            if re.match (r"\|", host):
                for try_host in try_hosts:
                    if openssh_hashed_host_match(host.encode('ASCII'),
                                                 try_host.encode('UTF-8')):
                        host = try_host
                        break
                else:
                    warn("unable to match hashed hostname '%s'" % host)
                    continue

            m = re.match (r"\[([^]]*)\]:(\d*)$", host)
            if m:
                (host, port) = m.group(1,2)
                port = int(port)
            else:
                port = 22
            # Slightly bizarre output key format: 'type@port:hostname'
            # XXX: does PuTTY do anything useful with literal IP[v4]s?
            key = keytype + ("@%d:%s" % (port, host))
            # Most of these are numbers, but there's the occasional
            # string that needs passing through
            value = ",".join(map(
                lambda x: x if isinstance(x, str)
                else x.decode('ASCII') if isinstance(x, bytes)
                else inttohex(x), keyparams))
            output_formatter.key(key, value)

    except UnknownKeyType as k:
        warn("unknown SSH key type '%s', skipping" % k.keytype)
    except KeyFormatError as k:
        warn("trouble parsing key (%s), skipping" % k.msg)
    except BlankInputLine:
        pass