1package org.bouncycastle.crypto.util;
2
3import java.io.IOException;
4import java.io.InputStream;
5import java.math.BigInteger;
6
7import org.bouncycastle.asn1.ASN1Encodable;
8import org.bouncycastle.asn1.ASN1InputStream;
9import org.bouncycastle.asn1.ASN1Integer;
10import org.bouncycastle.asn1.ASN1ObjectIdentifier;
11import org.bouncycastle.asn1.ASN1OctetString;
12import org.bouncycastle.asn1.ASN1Primitive;
13import org.bouncycastle.asn1.DEROctetString;
14// BEGIN android-removed
15// import org.bouncycastle.asn1.oiw.ElGamalParameter;
16// END android-removed
17import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
18import org.bouncycastle.asn1.pkcs.DHParameter;
19import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
20import org.bouncycastle.asn1.pkcs.RSAPublicKey;
21import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
22import org.bouncycastle.asn1.x509.DSAParameter;
23import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
24import org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
25import org.bouncycastle.asn1.x9.DHPublicKey;
26import org.bouncycastle.asn1.x9.DomainParameters;
27import org.bouncycastle.asn1.x9.ECNamedCurveTable;
28import org.bouncycastle.asn1.x9.ValidationParams;
29import org.bouncycastle.asn1.x9.X962Parameters;
30import org.bouncycastle.asn1.x9.X9ECParameters;
31import org.bouncycastle.asn1.x9.X9ECPoint;
32import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
33import org.bouncycastle.crypto.ec.CustomNamedCurves;
34import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
35import org.bouncycastle.crypto.params.DHParameters;
36import org.bouncycastle.crypto.params.DHPublicKeyParameters;
37import org.bouncycastle.crypto.params.DHValidationParameters;
38import org.bouncycastle.crypto.params.DSAParameters;
39import org.bouncycastle.crypto.params.DSAPublicKeyParameters;
40import org.bouncycastle.crypto.params.ECDomainParameters;
41import org.bouncycastle.crypto.params.ECNamedDomainParameters;
42import org.bouncycastle.crypto.params.ECPublicKeyParameters;
43// BEGIN android-removed
44// import org.bouncycastle.crypto.params.ElGamalParameters;
45// import org.bouncycastle.crypto.params.ElGamalPublicKeyParameters;
46// END android-removed
47import org.bouncycastle.crypto.params.RSAKeyParameters;
48
49/**
50 * Factory to create asymmetric public key parameters for asymmetric ciphers from range of
51 * ASN.1 encoded SubjectPublicKeyInfo objects.
52 */
53public class PublicKeyFactory
54{
55    /**
56     * Create a public key from a SubjectPublicKeyInfo encoding
57     *
58     * @param keyInfoData the SubjectPublicKeyInfo encoding
59     * @return the appropriate key parameter
60     * @throws IOException on an error decoding the key
61     */
62    public static AsymmetricKeyParameter createKey(byte[] keyInfoData) throws IOException
63    {
64        return createKey(SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(keyInfoData)));
65    }
66
67    /**
68     * Create a public key from a SubjectPublicKeyInfo encoding read from a stream
69     *
70     * @param inStr the stream to read the SubjectPublicKeyInfo encoding from
71     * @return the appropriate key parameter
72     * @throws IOException on an error decoding the key
73     */
74    public static AsymmetricKeyParameter createKey(InputStream inStr) throws IOException
75    {
76        return createKey(SubjectPublicKeyInfo.getInstance(new ASN1InputStream(inStr).readObject()));
77    }
78
79    /**
80     * Create a public key from the passed in SubjectPublicKeyInfo
81     *
82     * @param keyInfo the SubjectPublicKeyInfo containing the key data
83     * @return the appropriate key parameter
84     * @throws IOException on an error decoding the key
85     */
86    public static AsymmetricKeyParameter createKey(SubjectPublicKeyInfo keyInfo) throws IOException
87    {
88        AlgorithmIdentifier algId = keyInfo.getAlgorithm();
89
90        if (algId.getAlgorithm().equals(PKCSObjectIdentifiers.rsaEncryption)
91            || algId.getAlgorithm().equals(X509ObjectIdentifiers.id_ea_rsa))
92        {
93            RSAPublicKey pubKey = RSAPublicKey.getInstance(keyInfo.parsePublicKey());
94
95            return new RSAKeyParameters(false, pubKey.getModulus(), pubKey.getPublicExponent());
96        }
97        else if (algId.getAlgorithm().equals(X9ObjectIdentifiers.dhpublicnumber))
98        {
99            DHPublicKey dhPublicKey = DHPublicKey.getInstance(keyInfo.parsePublicKey());
100
101            BigInteger y = dhPublicKey.getY();
102
103            DomainParameters dhParams = DomainParameters.getInstance(algId.getParameters());
104
105            BigInteger p = dhParams.getP();
106            BigInteger g = dhParams.getG();
107            BigInteger q = dhParams.getQ();
108
109            BigInteger j = null;
110            if (dhParams.getJ() != null)
111            {
112                j = dhParams.getJ();
113            }
114
115            DHValidationParameters validation = null;
116            ValidationParams dhValidationParms = dhParams.getValidationParams();
117            if (dhValidationParms != null)
118            {
119                byte[] seed = dhValidationParms.getSeed();
120                BigInteger pgenCounter = dhValidationParms.getPgenCounter();
121
122                // TODO Check pgenCounter size?
123
124                validation = new DHValidationParameters(seed, pgenCounter.intValue());
125            }
126
127            return new DHPublicKeyParameters(y, new DHParameters(p, g, q, j, validation));
128        }
129        else if (algId.getAlgorithm().equals(PKCSObjectIdentifiers.dhKeyAgreement))
130        {
131            DHParameter params = DHParameter.getInstance(algId.getParameters());
132            ASN1Integer derY = (ASN1Integer)keyInfo.parsePublicKey();
133
134            BigInteger lVal = params.getL();
135            int l = lVal == null ? 0 : lVal.intValue();
136            DHParameters dhParams = new DHParameters(params.getP(), params.getG(), null, l);
137
138            return new DHPublicKeyParameters(derY.getValue(), dhParams);
139        }
140        // BEGIN android-removed
141        // else if (algId.getAlgorithm().equals(OIWObjectIdentifiers.elGamalAlgorithm))
142        // {
143        //     ElGamalParameter params = ElGamalParameter.getInstance(algId.getParameters());
144        //     ASN1Integer derY = (ASN1Integer)keyInfo.parsePublicKey();
145        //
146        //     return new ElGamalPublicKeyParameters(derY.getValue(), new ElGamalParameters(
147        //         params.getP(), params.getG()));
148        // }
149        // END android-removed
150        else if (algId.getAlgorithm().equals(X9ObjectIdentifiers.id_dsa)
151            || algId.getAlgorithm().equals(OIWObjectIdentifiers.dsaWithSHA1))
152        {
153            ASN1Integer derY = (ASN1Integer)keyInfo.parsePublicKey();
154            ASN1Encodable de = algId.getParameters();
155
156            DSAParameters parameters = null;
157            if (de != null)
158            {
159                DSAParameter params = DSAParameter.getInstance(de.toASN1Primitive());
160                parameters = new DSAParameters(params.getP(), params.getQ(), params.getG());
161            }
162
163            return new DSAPublicKeyParameters(derY.getValue(), parameters);
164        }
165        else if (algId.getAlgorithm().equals(X9ObjectIdentifiers.id_ecPublicKey))
166        {
167            X962Parameters params = X962Parameters.getInstance(algId.getParameters());
168
169            X9ECParameters x9;
170            ECDomainParameters dParams;
171
172            if (params.isNamedCurve())
173            {
174                ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)params.getParameters();
175
176                x9 = CustomNamedCurves.getByOID(oid);
177                if (x9 == null)
178                {
179                    x9 = ECNamedCurveTable.getByOID(oid);
180                }
181                dParams = new ECNamedDomainParameters(
182                         oid, x9.getCurve(), x9.getG(), x9.getN(), x9.getH(), x9.getSeed());
183            }
184            else
185            {
186                x9 = X9ECParameters.getInstance(params.getParameters());
187                dParams = new ECDomainParameters(
188                         x9.getCurve(), x9.getG(), x9.getN(), x9.getH(), x9.getSeed());
189            }
190
191            ASN1OctetString key = new DEROctetString(keyInfo.getPublicKeyData().getBytes());
192            X9ECPoint derQ = new X9ECPoint(x9.getCurve(), key);
193
194            return new ECPublicKeyParameters(derQ.getPoint(), dParams);
195        }
196        else
197        {
198            throw new RuntimeException("algorithm identifier in key not recognised");
199        }
200    }
201}
202