1/*
2 *  Licensed to the Apache Software Foundation (ASF) under one or more
3 *  contributor license agreements.  See the NOTICE file distributed with
4 *  this work for additional information regarding copyright ownership.
5 *  The ASF licenses this file to You under the Apache License, Version 2.0
6 *  (the "License"); you may not use this file except in compliance with
7 *  the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 */
17
18 /*
19  * TODO
20  * 1. The class extends the PublicKeyImpl class in "org.apache.harmony.security" package.
21  *
22  * 2. The class uses methods in the auxiliary non-public "ThreeIntegerSequence" class
23  *    defined along with the "DSAPrivateKeyImpl" class.
24  *
25  * 3. See a compatibility with RI comments
26  *    in the below "DSAPublicKeyImpl(X509EncodedKeySpec keySpec)" constructor.
27  */
28
29package org.apache.harmony.security.provider.crypto;
30
31import java.io.IOException;
32import java.io.NotActiveException;
33import java.math.BigInteger;
34import java.security.interfaces.DSAParams;
35import java.security.interfaces.DSAPublicKey;
36import java.security.spec.DSAParameterSpec;
37import java.security.spec.DSAPublicKeySpec;
38import java.security.spec.InvalidKeySpecException;
39import java.security.spec.X509EncodedKeySpec;
40import org.apache.harmony.security.PublicKeyImpl;
41import org.apache.harmony.security.asn1.ASN1Integer;
42import org.apache.harmony.security.utils.AlgNameMapper;
43import org.apache.harmony.security.x509.AlgorithmIdentifier;
44import org.apache.harmony.security.x509.SubjectPublicKeyInfo;
45
46/**
47 * The class provides DSAPublicKey functionality by extending a class implementing PublicKey
48 * and implementing methods defined in both interfaces, DSAKey and DSAPublicKey
49 */
50public class DSAPublicKeyImpl extends PublicKeyImpl implements DSAPublicKey {
51
52    /**
53     * @serial
54     */
55    private static final long serialVersionUID = -2279672131310978336L;
56
57    private BigInteger y, g, p, q;
58
59    private transient DSAParams params;
60
61    /**
62     * Creates object from DSAPublicKeySpec.
63     *
64     * @param keySpec - a DSAPublicKeySpec object
65     */
66    public DSAPublicKeyImpl(DSAPublicKeySpec keySpec) {
67
68        super("DSA");
69
70        SubjectPublicKeyInfo spki;
71
72        p = keySpec.getP();
73        q = keySpec.getQ();
74        g = keySpec.getG();
75
76        ThreeIntegerSequence threeInts = new ThreeIntegerSequence(p
77                .toByteArray(), q.toByteArray(), g.toByteArray());
78
79        AlgorithmIdentifier ai = new AlgorithmIdentifier(AlgNameMapper
80                .map2OID("DSA"),
81                threeInts.getEncoded());
82
83        y = keySpec.getY();
84
85        spki = new SubjectPublicKeyInfo(ai, ASN1Integer.getInstance().encode(
86                y.toByteArray()));
87        setEncoding(spki.getEncoded());
88
89        params = (DSAParams) (new DSAParameterSpec(p, q, g));
90    }
91
92    /**
93     * Creates object from X509EncodedKeySpec.
94     *
95     * @param keySpec - a X509EncodedKeySpec object
96     *
97     * @throws InvalidKeySpecException - if key data cannot be obtain from encoded format
98     */
99    public DSAPublicKeyImpl(X509EncodedKeySpec keySpec)
100            throws InvalidKeySpecException {
101
102        super("DSA");
103
104        AlgorithmIdentifier ai;
105        ThreeIntegerSequence threeInts = null;
106
107        SubjectPublicKeyInfo subjectPublicKeyInfo = null;
108
109        byte[] encoding = keySpec.getEncoded();
110
111        String alg, algName;
112
113        try {
114            subjectPublicKeyInfo = (SubjectPublicKeyInfo) SubjectPublicKeyInfo.ASN1
115                    .decode(encoding);
116        } catch (IOException e) {
117            throw new InvalidKeySpecException("Failed to decode keySpec encoding: " + e);
118        }
119
120        try {
121            y = new BigInteger((byte[]) ASN1Integer.getInstance().decode(
122                    subjectPublicKeyInfo.getSubjectPublicKey()));
123        } catch (IOException e) {
124            throw new InvalidKeySpecException("Failed to decode parameters: " + e);
125        }
126
127        ai = subjectPublicKeyInfo.getAlgorithmIdentifier();
128
129        try {
130            threeInts = (ThreeIntegerSequence) ThreeIntegerSequence.ASN1
131                    .decode(ai.getParameters());
132        } catch (IOException e) {
133            throw new InvalidKeySpecException("Failed to decode parameters: " + e);
134        }
135        p = new BigInteger(threeInts.p);
136        q = new BigInteger(threeInts.q);
137        g = new BigInteger(threeInts.g);
138        params = (DSAParams) (new DSAParameterSpec(p, q, g));
139
140        setEncoding(encoding);
141
142        /*
143         * the following code implements RI behavior
144         */
145        alg = ai.getAlgorithm();
146        algName = AlgNameMapper.map2AlgName(alg);
147        setAlgorithm(algName == null ? alg : algName);
148    }
149
150    /**
151     * @return
152     *      a value of a public key (y).
153     */
154    public BigInteger getY() {
155        return y;
156    }
157
158    /**
159     * @return
160     *     DSA key parameters (p, q, g).
161     */
162    public DSAParams getParams() {
163        return params;
164    }
165
166    private void readObject(java.io.ObjectInputStream in) throws NotActiveException, IOException, ClassNotFoundException {
167        in.defaultReadObject();
168        params = new DSAParameterSpec(p, q, g);
169    }
170
171}
172