implement keyconvert in python.
authorBarış Metin <Talip-Baris.Metin@sophia.inria.fr>
Tue, 29 Jun 2010 12:53:13 +0000 (12:53 +0000)
committerBarış Metin <Talip-Baris.Metin@sophia.inria.fr>
Tue, 29 Jun 2010 12:53:13 +0000 (12:53 +0000)
Problems with DSA keys, M2Crypto doesn't allow us to give set the pub key parameter.

keyconvert/keyconvert.py [new file with mode: 0755]

diff --git a/keyconvert/keyconvert.py b/keyconvert/keyconvert.py
new file mode 100755 (executable)
index 0000000..af12b1f
--- /dev/null
@@ -0,0 +1,101 @@
+#!/usr/bin/env python
+
+import sys
+import base64
+import struct
+import binascii
+from M2Crypto import RSA, DSA
+
+
+def decode_key(fname):
+    """Convert base64 encoded openssh key to binary"""
+    contents = open(fname).read()
+    fields = contents.split()
+
+    in_key = False
+    for f in fields:
+        f = f.strip()
+        if f.startswith("ssh-"):
+            in_key = True
+            continue
+        elif in_key:
+            return base64.b64decode(f)
+        
+    return None
+
+
+# openssh binary key format
+#
+# a section:
+# length = 4 bytes (32-bit big-endian integer)
+# data = length bytes of string 
+# 
+# sections of the key ( for RSA )
+# [key-type (in ASCII)] [public exponent (bignum)] [primes (bignum)]
+#
+# sections of the key ( for DSA )
+# [key-type (in ASCII)] [p (bignum)] [q (bignum)] [g (bignum)] [y (bignum)]
+#
+# - baris
+def read_key(key):
+    
+    def read_length(key):
+        length = key[0:4]
+        length = struct.unpack(">l", length)[0]
+        return length, key
+        
+    def read_values(key, count):
+        v = []
+        for i in range(count):
+            length, key = read_length(key)
+            size = 4 + length
+            v.append(key[:size])
+            key = key[size:]
+        return v
+
+    length, key = read_length(key)
+    key = key[4:]
+    key_type = key[:length]
+    key = key[length:]
+
+    if key_type == "ssh-rsa":
+        # prepare parameters for RSA.new_pub_key
+        v = read_values(key, 2)
+        e, n = v[0], v[1]
+        return key_type, e, n
+
+    elif key_type == "ssh-dss":
+        # prepare parameters for DSA.set_params
+        v = read_values(key, 4)
+        p, q, g, y = v[0], v[1], v[2], v[3]
+        return key_type, p, q, g, y
+
+
+def convert(fin, fout):
+    key = decode_key(fin)
+    ret = read_key(key)
+    key_type = ret[0]
+
+    if key_type == "ssh-rsa":
+        e, n = ret[1:]
+        rsa = RSA.new_pub_key((e, n))
+        rsa.save_pem(fout)
+
+    elif key_type == "ssh-dss":
+        p, q, g, y = ret[1:]
+        dsa = DSA.set_params(p, q, g)
+        dsa.gen_key()
+        dsa.save_pub_key(fout)
+        # FIXME: This is wrong.
+        # M2Crypto doesn't allow us to set the public key parameter
+        raise(Exception, "DSA keys are not supported yet: M2Crypto doesn't allow us to set the public key parameter")
+
+
+if __name__ == "__main__":
+    if len(sys.argv) != 3:
+        print "Usage: %s <input-file> <output-file>"
+        sys.exit(1)
+
+    fin = sys.argv[1]
+    fout = sys.argv[2]
+    convert(fin, fout)