implement keyconvert in python.
[sfa.git] / keyconvert / keyconvert.py
1 #!/usr/bin/env python
2
3 import sys
4 import base64
5 import struct
6 import binascii
7 from M2Crypto import RSA, DSA
8
9
10 def decode_key(fname):
11     """Convert base64 encoded openssh key to binary"""
12     contents = open(fname).read()
13     fields = contents.split()
14
15     in_key = False
16     for f in fields:
17         f = f.strip()
18         if f.startswith("ssh-"):
19             in_key = True
20             continue
21         elif in_key:
22             return base64.b64decode(f)
23         
24     return None
25
26
27 # openssh binary key format
28 #
29 # a section:
30 # length = 4 bytes (32-bit big-endian integer)
31 # data = length bytes of string 
32
33 # sections of the key ( for RSA )
34 # [key-type (in ASCII)] [public exponent (bignum)] [primes (bignum)]
35 #
36 # sections of the key ( for DSA )
37 # [key-type (in ASCII)] [p (bignum)] [q (bignum)] [g (bignum)] [y (bignum)]
38 #
39 # - baris
40 def read_key(key):
41     
42     def read_length(key):
43         length = key[0:4]
44         length = struct.unpack(">l", length)[0]
45         return length, key
46         
47     def read_values(key, count):
48         v = []
49         for i in range(count):
50             length, key = read_length(key)
51             size = 4 + length
52             v.append(key[:size])
53             key = key[size:]
54         return v
55
56     length, key = read_length(key)
57     key = key[4:]
58     key_type = key[:length]
59     key = key[length:]
60
61     if key_type == "ssh-rsa":
62         # prepare parameters for RSA.new_pub_key
63         v = read_values(key, 2)
64         e, n = v[0], v[1]
65         return key_type, e, n
66
67     elif key_type == "ssh-dss":
68         # prepare parameters for DSA.set_params
69         v = read_values(key, 4)
70         p, q, g, y = v[0], v[1], v[2], v[3]
71         return key_type, p, q, g, y
72
73
74 def convert(fin, fout):
75     key = decode_key(fin)
76     ret = read_key(key)
77     key_type = ret[0]
78
79     if key_type == "ssh-rsa":
80         e, n = ret[1:]
81         rsa = RSA.new_pub_key((e, n))
82         rsa.save_pem(fout)
83
84     elif key_type == "ssh-dss":
85         p, q, g, y = ret[1:]
86         dsa = DSA.set_params(p, q, g)
87         dsa.gen_key()
88         dsa.save_pub_key(fout)
89         # FIXME: This is wrong.
90         # M2Crypto doesn't allow us to set the public key parameter
91         raise(Exception, "DSA keys are not supported yet: M2Crypto doesn't allow us to set the public key parameter")
92
93
94 if __name__ == "__main__":
95     if len(sys.argv) != 3:
96         print "Usage: %s <input-file> <output-file>"
97         sys.exit(1)
98
99     fin = sys.argv[1]
100     fout = sys.argv[2]
101     convert(fin, fout)