package com.jscape.inet.ssh.protocol.v2.marshaling.keys;

import com.jscape.inet.ssh.protocol.v2.marshaling.primitive.MpintCodec;
import com.jscape.util.io.DataCodec;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.Provider;
import java.security.PublicKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.RSAPublicKeySpec;

/**
 * @author Alex Usun
 */
public class RsaPublicKeyCodec
        implements DataCodec<PublicKey> {

    private final Object provider;

    public static RsaPublicKeyCodec codecFor(String provider) {
        return new RsaPublicKeyCodec(provider);
    }

    public static RsaPublicKeyCodec codecFor(Provider provider) {
        return new RsaPublicKeyCodec(provider);
    }

    private RsaPublicKeyCodec(Object provider) {
        this.provider = provider;
    }

    @Override
    public PublicKey read(InputStream in)
            throws IOException {
        BigInteger e = MpintCodec.readValue(in);
        BigInteger n = MpintCodec.readValue(in);

        try {
            RSAPublicKeySpec keySpec = new RSAPublicKeySpec(n, e);
            KeyFactory keyFactory = this.provider instanceof String ? KeyFactory.getInstance("RSA", (String) this.provider) : this.provider instanceof Provider ? KeyFactory.getInstance("RSA", (Provider) this.provider) : KeyFactory.getInstance("RSA");

            return keyFactory.generatePublic(keySpec);
        } catch (Exception ex) {
            throw new IOException(ex);
        }
    }

    @Override
    public void write(PublicKey value, OutputStream out)
            throws IOException {
        RSAPublicKey publicKey = (RSAPublicKey) value;
        MpintCodec.writeValue(publicKey.getPublicExponent(), out);
        MpintCodec.writeValue(publicKey.getModulus(), out);
    }
}
