OSDN Git Service

Add PuTTY 0.61 to contrib directory.
[ffftp/ffftp.git] / contrib / putty / CONTRIB / KH2REG.PY
diff --git a/contrib/putty/CONTRIB/KH2REG.PY b/contrib/putty/CONTRIB/KH2REG.PY
new file mode 100644 (file)
index 0000000..fe78267
--- /dev/null
@@ -0,0 +1,157 @@
+#! /usr/bin/env python\r
+\r
+# $Id: kh2reg.py 8519 2009-04-26 23:44:28Z jacob $\r
+# Convert OpenSSH known_hosts and known_hosts2 files to "new format" PuTTY\r
+# host keys.\r
+#   usage:\r
+#     kh2reg.py [ --win ] known_hosts1 2 3 4 ... > hosts.reg\r
+#       Creates a Windows .REG file (double-click to install).\r
+#     kh2reg.py --unix    known_hosts1 2 3 4 ... > sshhostkeys\r
+#       Creates data suitable for storing in ~/.putty/sshhostkeys (Unix).\r
+# Line endings are someone else's problem as is traditional.\r
+# Developed for Python 1.5.2.\r
+\r
+import fileinput\r
+import base64\r
+import struct\r
+import string\r
+import re\r
+import sys\r
+import getopt\r
+\r
+def winmungestr(s):\r
+    "Duplicate of PuTTY's mungestr() in winstore.c:1.10 for Registry keys"\r
+    candot = 0\r
+    r = ""\r
+    for c in s:\r
+        if c in ' \*?%~' or ord(c)<ord(' ') or (c == '.' and not candot):\r
+            r = r + ("%%%02X" % ord(c))\r
+        else:\r
+            r = r + c\r
+        candot = 1\r
+    return r\r
+\r
+def strtolong(s):\r
+    "Convert arbitrary-length big-endian binary data to a Python long"\r
+    bytes = struct.unpack(">%luB" % len(s), s)\r
+    return reduce ((lambda a, b: (long(a) << 8) + long(b)), bytes)\r
+\r
+def longtohex(n):\r
+    """Convert long int to lower-case hex.\r
+\r
+    Ick, Python (at least in 1.5.2) doesn't appear to have a way to\r
+    turn a long int into an unadorned hex string -- % gets upset if the\r
+    number is too big, and raw hex() uses uppercase (sometimes), and\r
+    adds unwanted "0x...L" around it."""\r
+\r
+    plain=string.lower(re.match(r"0x([0-9A-Fa-f]*)l?$", hex(n), re.I).group(1))\r
+    return "0x" + plain\r
+\r
+output_type = 'windows'\r
+\r
+try:\r
+    optlist, args = getopt.getopt(sys.argv[1:], '', [ 'win', 'unix' ])\r
+    if filter(lambda x: x[0] == '--unix', optlist):\r
+        output_type = 'unix'\r
+except getopt.error, e:\r
+    sys.stderr.write(str(e) + "\n")\r
+    sys.exit(1)\r
+\r
+if output_type == 'windows':\r
+    # Output REG file header.\r
+    sys.stdout.write("""REGEDIT4\r
+\r
+[HKEY_CURRENT_USER\Software\SimonTatham\PuTTY\SshHostKeys]\r
+""")\r
+\r
+# Now process all known_hosts input.\r
+for line in fileinput.input(args):\r
+\r
+    try:\r
+        # Remove leading/trailing whitespace (should zap CR and LF)\r
+        line = string.strip (line)\r
+\r
+        # Skip blanks and comments\r
+        if line == '' or line[0] == '#':\r
+            raise "Skipping input line"\r
+\r
+        # Split line on spaces.\r
+        fields = string.split (line, ' ')\r
+\r
+        # Common fields\r
+        hostpat = fields[0]\r
+        magicnumbers = []   # placeholder\r
+        keytype = ""        # placeholder\r
+\r
+        # Grotty heuristic to distinguish known_hosts from known_hosts2:\r
+        # is second field entirely decimal digits?\r
+        if re.match (r"\d*$", fields[1]):\r
+\r
+            # Treat as SSH-1-type host key.\r
+            # Format: hostpat bits10 exp10 mod10 comment...\r
+            # (PuTTY doesn't store the number of bits.)\r
+            magicnumbers = map (long, fields[2:4])\r
+            keytype = "rsa"\r
+\r
+        else:\r
+\r
+            # Treat as SSH-2-type host key.\r
+            # Format: hostpat keytype keyblob64 comment...\r
+            sshkeytype, blob = fields[1], base64.decodestring (fields[2])\r
+\r
+            # 'blob' consists of a number of\r
+            #   uint32    N (big-endian)\r
+            #   uint8[N]  field_data\r
+            subfields = []\r
+            while blob:\r
+                sizefmt = ">L"\r
+                (size,) = struct.unpack (sizefmt, blob[0:4])\r
+                size = int(size)   # req'd for slicage\r
+                (data,) = struct.unpack (">%lus" % size, blob[4:size+4])\r
+                subfields.append(data)\r
+                blob = blob [struct.calcsize(sizefmt) + size : ]\r
+\r
+            # The first field is keytype again, and the rest we can treat as\r
+            # an opaque list of bignums (same numbers and order as stored\r
+            # by PuTTY). (currently embedded keytype is ignored entirely)\r
+            magicnumbers = map (strtolong, subfields[1:])\r
+\r
+            # Translate key type into something PuTTY can use.\r
+            if   sshkeytype == "ssh-rsa":   keytype = "rsa2"\r
+            elif sshkeytype == "ssh-dss":   keytype = "dss"\r
+            else:\r
+                raise "Unknown SSH key type", sshkeytype\r
+\r
+        # Now print out one line per host pattern, discarding wildcards.\r
+        for host in string.split (hostpat, ','):\r
+            if re.search (r"[*?!]", host):\r
+                sys.stderr.write("Skipping wildcard host pattern '%s'\n"\r
+                                 % host)\r
+                continue\r
+            elif re.match (r"\|", host):\r
+                sys.stderr.write("Skipping hashed hostname '%s'\n" % host)\r
+                continue\r
+            else:\r
+                m = re.match (r"\[([^]]*)\]:(\d*)$", host)\r
+                if m:\r
+                    (host, port) = m.group(1,2)\r
+                    port = int(port)\r
+                else:\r
+                    port = 22\r
+                # Slightly bizarre output key format: 'type@port:hostname'\r
+                # XXX: does PuTTY do anything useful with literal IP[v4]s?\r
+                key = keytype + ("@%d:%s" % (port, host))\r
+                value = string.join (map (longtohex, magicnumbers), ',')\r
+                if output_type == 'unix':\r
+                    # Unix format.\r
+                    sys.stdout.write('%s %s\n' % (key, value))\r
+                else:\r
+                    # Windows format.\r
+                    # XXX: worry about double quotes?\r
+                    sys.stdout.write("\"%s\"=\"%s\"\n"\r
+                                     % (winmungestr(key), value))\r
+\r
+    except "Unknown SSH key type", k:\r
+        sys.stderr.write("Unknown SSH key type '%s', skipping\n" % k)\r
+    except "Skipping input line":\r
+        pass\r