#!/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)

implement keyconvert in python. Problems with DSA keys, M2Crypto doesn't allow us to give set the pub key parameter.