// 
// Decompiled by Procyon v0.6.0
// 

package org.bouncycastle.crypto.util;

import org.bouncycastle.crypto.params.X448PublicKeyParameters;
import org.bouncycastle.crypto.params.X25519PublicKeyParameters;
import org.bouncycastle.crypto.params.RSAKeyParameters;
import org.bouncycastle.asn1.pkcs.RSAPublicKey;
import org.bouncycastle.crypto.params.ECGOST3410Parameters;
import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves;
import org.bouncycastle.asn1.cryptopro.GOST3410PublicKeyAlgParameters;
import org.bouncycastle.crypto.params.ElGamalPublicKeyParameters;
import org.bouncycastle.crypto.params.ElGamalParameters;
import org.bouncycastle.internal.asn1.oiw.ElGamalParameter;
import org.bouncycastle.crypto.params.Ed448PublicKeyParameters;
import org.bouncycastle.crypto.params.Ed25519PublicKeyParameters;
import org.bouncycastle.asn1.x9.X9ECPoint;
import org.bouncycastle.asn1.x9.X9IntegerConverter;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.crypto.params.ECNamedDomainParameters;
import org.bouncycastle.asn1.x9.X962Parameters;
import org.bouncycastle.asn1.ua.DSTU4145BinaryField;
import org.bouncycastle.asn1.ua.DSTU4145ECBinary;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.asn1.ua.DSTU4145PointEncoder;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.asn1.ua.DSTU4145NamedCurves;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.ua.DSTU4145Params;
import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.crypto.params.DSAPublicKeyParameters;
import org.bouncycastle.crypto.params.DSAParameters;
import org.bouncycastle.asn1.x509.DSAParameter;
import org.bouncycastle.asn1.x9.ValidationParams;
import org.bouncycastle.crypto.params.DHValidationParameters;
import org.bouncycastle.asn1.x9.DomainParameters;
import org.bouncycastle.asn1.x9.DHPublicKey;
import org.bouncycastle.crypto.params.DHPublicKeyParameters;
import java.math.BigInteger;
import org.bouncycastle.crypto.params.DHParameters;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.pkcs.DHParameter;
import org.bouncycastle.internal.asn1.edec.EdECObjectIdentifiers;
import org.bouncycastle.asn1.ua.UAObjectIdentifiers;
import org.bouncycastle.internal.asn1.rosstandart.RosstandartObjectIdentifiers;
import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
import org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import java.util.HashMap;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.ASN1InputStream;
import java.io.InputStream;
import java.io.IOException;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import java.util.Map;

public class PublicKeyFactory
{
    private static Map converters;
    
    public static AsymmetricKeyParameter createKey(final byte[] array) throws IOException {
        if (array == null) {
            throw new IllegalArgumentException("keyInfoData array null");
        }
        if (array.length == 0) {
            throw new IllegalArgumentException("keyInfoData array empty");
        }
        return createKey(SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(array)));
    }
    
    public static AsymmetricKeyParameter createKey(final InputStream inputStream) throws IOException {
        return createKey(SubjectPublicKeyInfo.getInstance(new ASN1InputStream(inputStream).readObject()));
    }
    
    public static AsymmetricKeyParameter createKey(final SubjectPublicKeyInfo subjectPublicKeyInfo) throws IOException {
        if (subjectPublicKeyInfo == null) {
            throw new IllegalArgumentException("keyInfo argument null");
        }
        return createKey(subjectPublicKeyInfo, null);
    }
    
    public static AsymmetricKeyParameter createKey(final SubjectPublicKeyInfo subjectPublicKeyInfo, final Object o) throws IOException {
        if (subjectPublicKeyInfo == null) {
            throw new IllegalArgumentException("keyInfo argument null");
        }
        final AlgorithmIdentifier algorithm = subjectPublicKeyInfo.getAlgorithm();
        final SubjectPublicKeyInfoConverter subjectPublicKeyInfoConverter = PublicKeyFactory.converters.get(algorithm.getAlgorithm());
        if (null == subjectPublicKeyInfoConverter) {
            throw new IOException("algorithm identifier in public key not recognised: " + algorithm.getAlgorithm());
        }
        return subjectPublicKeyInfoConverter.getPublicKeyParameters(subjectPublicKeyInfo, o);
    }
    
    private static byte[] getRawKey(final SubjectPublicKeyInfo subjectPublicKeyInfo, final Object o) {
        return subjectPublicKeyInfo.getPublicKeyData().getOctets();
    }
    
    static {
        (PublicKeyFactory.converters = new HashMap()).put(PKCSObjectIdentifiers.rsaEncryption, new RSAConverter());
        PublicKeyFactory.converters.put(PKCSObjectIdentifiers.id_RSASSA_PSS, new RSAConverter());
        PublicKeyFactory.converters.put(X509ObjectIdentifiers.id_ea_rsa, new RSAConverter());
        PublicKeyFactory.converters.put(X9ObjectIdentifiers.dhpublicnumber, new DHPublicNumberConverter());
        PublicKeyFactory.converters.put(PKCSObjectIdentifiers.dhKeyAgreement, new DHAgreementConverter());
        PublicKeyFactory.converters.put(X9ObjectIdentifiers.id_dsa, new DSAConverter());
        PublicKeyFactory.converters.put(OIWObjectIdentifiers.dsaWithSHA1, new DSAConverter());
        PublicKeyFactory.converters.put(OIWObjectIdentifiers.elGamalAlgorithm, new ElGamalConverter());
        PublicKeyFactory.converters.put(X9ObjectIdentifiers.id_ecPublicKey, new ECConverter());
        PublicKeyFactory.converters.put(CryptoProObjectIdentifiers.gostR3410_2001, new GOST3410_2001Converter());
        PublicKeyFactory.converters.put(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_256, new GOST3410_2012Converter());
        PublicKeyFactory.converters.put(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_512, new GOST3410_2012Converter());
        PublicKeyFactory.converters.put(UAObjectIdentifiers.dstu4145be, new DSTUConverter());
        PublicKeyFactory.converters.put(UAObjectIdentifiers.dstu4145le, new DSTUConverter());
        PublicKeyFactory.converters.put(EdECObjectIdentifiers.id_X25519, new X25519Converter());
        PublicKeyFactory.converters.put(EdECObjectIdentifiers.id_X448, new X448Converter());
        PublicKeyFactory.converters.put(EdECObjectIdentifiers.id_Ed25519, new Ed25519Converter());
        PublicKeyFactory.converters.put(EdECObjectIdentifiers.id_Ed448, new Ed448Converter());
    }
    
    private static class DHAgreementConverter extends SubjectPublicKeyInfoConverter
    {
        @Override
        AsymmetricKeyParameter getPublicKeyParameters(final SubjectPublicKeyInfo subjectPublicKeyInfo, final Object o) throws IOException {
            final DHParameter instance = DHParameter.getInstance(subjectPublicKeyInfo.getAlgorithm().getParameters());
            final ASN1Integer asn1Integer = (ASN1Integer)subjectPublicKeyInfo.parsePublicKey();
            final BigInteger l = instance.getL();
            return new DHPublicKeyParameters(asn1Integer.getValue(), new DHParameters(instance.getP(), instance.getG(), null, (l == null) ? 0 : l.intValue()));
        }
    }
    
    private abstract static class SubjectPublicKeyInfoConverter
    {
        abstract AsymmetricKeyParameter getPublicKeyParameters(final SubjectPublicKeyInfo p0, final Object p1) throws IOException;
    }
    
    private static class DHPublicNumberConverter extends SubjectPublicKeyInfoConverter
    {
        @Override
        AsymmetricKeyParameter getPublicKeyParameters(final SubjectPublicKeyInfo subjectPublicKeyInfo, final Object o) throws IOException {
            final BigInteger y = DHPublicKey.getInstance(subjectPublicKeyInfo.parsePublicKey()).getY();
            final DomainParameters instance = DomainParameters.getInstance(subjectPublicKeyInfo.getAlgorithm().getParameters());
            final BigInteger p2 = instance.getP();
            final BigInteger g = instance.getG();
            final BigInteger q = instance.getQ();
            BigInteger j = null;
            if (instance.getJ() != null) {
                j = instance.getJ();
            }
            DHValidationParameters dhValidationParameters = null;
            final ValidationParams validationParams = instance.getValidationParams();
            if (validationParams != null) {
                dhValidationParameters = new DHValidationParameters(validationParams.getSeed(), validationParams.getPgenCounter().intValue());
            }
            return new DHPublicKeyParameters(y, new DHParameters(p2, g, q, j, dhValidationParameters));
        }
    }
    
    private static class DSAConverter extends SubjectPublicKeyInfoConverter
    {
        @Override
        AsymmetricKeyParameter getPublicKeyParameters(final SubjectPublicKeyInfo subjectPublicKeyInfo, final Object o) throws IOException {
            final ASN1Integer asn1Integer = (ASN1Integer)subjectPublicKeyInfo.parsePublicKey();
            final ASN1Encodable parameters = subjectPublicKeyInfo.getAlgorithm().getParameters();
            DSAParameters dsaParameters = null;
            if (parameters != null) {
                final DSAParameter instance = DSAParameter.getInstance(parameters.toASN1Primitive());
                dsaParameters = new DSAParameters(instance.getP(), instance.getQ(), instance.getG());
            }
            return new DSAPublicKeyParameters(asn1Integer.getValue(), dsaParameters);
        }
    }
    
    private static class DSTUConverter extends SubjectPublicKeyInfoConverter
    {
        @Override
        AsymmetricKeyParameter getPublicKeyParameters(final SubjectPublicKeyInfo subjectPublicKeyInfo, final Object o) throws IOException {
            final AlgorithmIdentifier algorithm = subjectPublicKeyInfo.getAlgorithm();
            final ASN1ObjectIdentifier algorithm2 = algorithm.getAlgorithm();
            final DSTU4145Params instance = DSTU4145Params.getInstance(algorithm.getParameters());
            ASN1OctetString asn1OctetString;
            try {
                asn1OctetString = (ASN1OctetString)subjectPublicKeyInfo.parsePublicKey();
            }
            catch (final IOException ex) {
                throw new IllegalArgumentException("error recovering DSTU public key");
            }
            final byte[] clone = Arrays.clone(asn1OctetString.getOctets());
            if (algorithm2.equals(UAObjectIdentifiers.dstu4145le)) {
                this.reverseBytes(clone);
            }
            ECDomainParameters byOID;
            if (instance.isNamedCurve()) {
                byOID = DSTU4145NamedCurves.getByOID(instance.getNamedCurve());
            }
            else {
                final DSTU4145ECBinary ecBinary = instance.getECBinary();
                final byte[] b = ecBinary.getB();
                if (algorithm2.equals(UAObjectIdentifiers.dstu4145le)) {
                    this.reverseBytes(b);
                }
                final BigInteger bigInteger = new BigInteger(1, b);
                final DSTU4145BinaryField field = ecBinary.getField();
                final ECCurve.F2m f2m = new ECCurve.F2m(field.getM(), field.getK1(), field.getK2(), field.getK3(), ecBinary.getA(), bigInteger, null, null);
                final byte[] g = ecBinary.getG();
                if (algorithm2.equals(UAObjectIdentifiers.dstu4145le)) {
                    this.reverseBytes(g);
                }
                byOID = new ECDomainParameters(f2m, DSTU4145PointEncoder.decodePoint(f2m, g), ecBinary.getN());
            }
            return new ECPublicKeyParameters(DSTU4145PointEncoder.decodePoint(byOID.getCurve(), clone), byOID);
        }
        
        private void reverseBytes(final byte[] array) {
            for (int i = 0; i < array.length / 2; ++i) {
                final byte b = array[i];
                array[i] = array[array.length - 1 - i];
                array[array.length - 1 - i] = b;
            }
        }
    }
    
    private static class ECConverter extends SubjectPublicKeyInfoConverter
    {
        @Override
        AsymmetricKeyParameter getPublicKeyParameters(final SubjectPublicKeyInfo subjectPublicKeyInfo, final Object o) {
            final X962Parameters instance = X962Parameters.getInstance(subjectPublicKeyInfo.getAlgorithm().getParameters());
            ECDomainParameters lookup;
            if (instance.isNamedCurve()) {
                lookup = ECNamedDomainParameters.lookup((ASN1ObjectIdentifier)instance.getParameters());
            }
            else if (instance.isImplicitlyCA()) {
                lookup = (ECDomainParameters)o;
            }
            else {
                lookup = new ECDomainParameters(X9ECParameters.getInstance(instance.getParameters()));
            }
            final byte[] bytes = subjectPublicKeyInfo.getPublicKeyData().getBytes();
            ASN1Primitive asn1Primitive = new DEROctetString(bytes);
            if (bytes[0] == 4 && bytes[1] == bytes.length - 2 && (bytes[2] == 2 || bytes[2] == 3) && new X9IntegerConverter().getByteLength(lookup.getCurve()) >= bytes.length - 3) {
                try {
                    asn1Primitive = ASN1Primitive.fromByteArray(bytes);
                }
                catch (final IOException ex) {
                    throw new IllegalArgumentException("error recovering public key");
                }
            }
            return new ECPublicKeyParameters(new X9ECPoint(lookup.getCurve(), (ASN1OctetString)asn1Primitive).getPoint(), lookup);
        }
    }
    
    private static class Ed25519Converter extends SubjectPublicKeyInfoConverter
    {
        @Override
        AsymmetricKeyParameter getPublicKeyParameters(final SubjectPublicKeyInfo subjectPublicKeyInfo, final Object o) {
            return new Ed25519PublicKeyParameters(getRawKey(subjectPublicKeyInfo, o));
        }
    }
    
    private static class Ed448Converter extends SubjectPublicKeyInfoConverter
    {
        @Override
        AsymmetricKeyParameter getPublicKeyParameters(final SubjectPublicKeyInfo subjectPublicKeyInfo, final Object o) {
            return new Ed448PublicKeyParameters(getRawKey(subjectPublicKeyInfo, o));
        }
    }
    
    private static class ElGamalConverter extends SubjectPublicKeyInfoConverter
    {
        @Override
        AsymmetricKeyParameter getPublicKeyParameters(final SubjectPublicKeyInfo subjectPublicKeyInfo, final Object o) throws IOException {
            final ElGamalParameter instance = ElGamalParameter.getInstance(subjectPublicKeyInfo.getAlgorithm().getParameters());
            return new ElGamalPublicKeyParameters(((ASN1Integer)subjectPublicKeyInfo.parsePublicKey()).getValue(), new ElGamalParameters(instance.getP(), instance.getG()));
        }
    }
    
    private static class GOST3410_2001Converter extends SubjectPublicKeyInfoConverter
    {
        @Override
        AsymmetricKeyParameter getPublicKeyParameters(final SubjectPublicKeyInfo subjectPublicKeyInfo, final Object o) {
            final GOST3410PublicKeyAlgParameters instance = GOST3410PublicKeyAlgParameters.getInstance(subjectPublicKeyInfo.getAlgorithm().getParameters());
            final ASN1ObjectIdentifier publicKeyParamSet = instance.getPublicKeyParamSet();
            final ECGOST3410Parameters ecgost3410Parameters = new ECGOST3410Parameters(new ECNamedDomainParameters(publicKeyParamSet, ECGOST3410NamedCurves.getByOIDX9(publicKeyParamSet)), publicKeyParamSet, instance.getDigestParamSet(), instance.getEncryptionParamSet());
            ASN1OctetString asn1OctetString;
            try {
                asn1OctetString = (ASN1OctetString)subjectPublicKeyInfo.parsePublicKey();
            }
            catch (final IOException ex) {
                throw new IllegalArgumentException("error recovering GOST3410_2001 public key");
            }
            final int n = 32;
            final int n2 = 2 * n;
            final byte[] octets = asn1OctetString.getOctets();
            if (octets.length != n2) {
                throw new IllegalArgumentException("invalid length for GOST3410_2001 public key");
            }
            final byte[] array = new byte[1 + n2];
            array[0] = 4;
            for (int i = 1; i <= n; ++i) {
                array[i] = octets[n - i];
                array[i + n] = octets[n2 - i];
            }
            return new ECPublicKeyParameters(ecgost3410Parameters.getCurve().decodePoint(array), ecgost3410Parameters);
        }
    }
    
    private static class GOST3410_2012Converter extends SubjectPublicKeyInfoConverter
    {
        @Override
        AsymmetricKeyParameter getPublicKeyParameters(final SubjectPublicKeyInfo subjectPublicKeyInfo, final Object o) {
            final AlgorithmIdentifier algorithm = subjectPublicKeyInfo.getAlgorithm();
            final ASN1ObjectIdentifier algorithm2 = algorithm.getAlgorithm();
            final GOST3410PublicKeyAlgParameters instance = GOST3410PublicKeyAlgParameters.getInstance(algorithm.getParameters());
            final ASN1ObjectIdentifier publicKeyParamSet = instance.getPublicKeyParamSet();
            final ECGOST3410Parameters ecgost3410Parameters = new ECGOST3410Parameters(new ECNamedDomainParameters(publicKeyParamSet, ECGOST3410NamedCurves.getByOIDX9(publicKeyParamSet)), publicKeyParamSet, instance.getDigestParamSet(), instance.getEncryptionParamSet());
            ASN1OctetString asn1OctetString;
            try {
                asn1OctetString = (ASN1OctetString)subjectPublicKeyInfo.parsePublicKey();
            }
            catch (final IOException ex) {
                throw new IllegalArgumentException("error recovering GOST3410_2012 public key");
            }
            int n = 32;
            if (algorithm2.equals(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_512)) {
                n = 64;
            }
            final int n2 = 2 * n;
            final byte[] octets = asn1OctetString.getOctets();
            if (octets.length != n2) {
                throw new IllegalArgumentException("invalid length for GOST3410_2012 public key");
            }
            final byte[] array = new byte[1 + n2];
            array[0] = 4;
            for (int i = 1; i <= n; ++i) {
                array[i] = octets[n - i];
                array[i + n] = octets[n2 - i];
            }
            return new ECPublicKeyParameters(ecgost3410Parameters.getCurve().decodePoint(array), ecgost3410Parameters);
        }
    }
    
    private static class RSAConverter extends SubjectPublicKeyInfoConverter
    {
        @Override
        AsymmetricKeyParameter getPublicKeyParameters(final SubjectPublicKeyInfo subjectPublicKeyInfo, final Object o) throws IOException {
            final RSAPublicKey instance = RSAPublicKey.getInstance(subjectPublicKeyInfo.parsePublicKey());
            return new RSAKeyParameters(false, instance.getModulus(), instance.getPublicExponent());
        }
    }
    
    private static class X25519Converter extends SubjectPublicKeyInfoConverter
    {
        @Override
        AsymmetricKeyParameter getPublicKeyParameters(final SubjectPublicKeyInfo subjectPublicKeyInfo, final Object o) {
            return new X25519PublicKeyParameters(getRawKey(subjectPublicKeyInfo, o));
        }
    }
    
    private static class X448Converter extends SubjectPublicKeyInfoConverter
    {
        @Override
        AsymmetricKeyParameter getPublicKeyParameters(final SubjectPublicKeyInfo subjectPublicKeyInfo, final Object o) {
            return new X448PublicKeyParameters(getRawKey(subjectPublicKeyInfo, o));
        }
    }
}
