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
18package javax.crypto;
19
20import java.security.InvalidAlgorithmParameterException;
21import java.security.InvalidKeyException;
22import java.security.Key;
23import java.security.NoSuchAlgorithmException;
24import java.security.NoSuchProviderException;
25import java.security.Provider;
26import java.security.SecureRandom;
27import java.security.Security;
28import java.security.spec.AlgorithmParameterSpec;
29import org.apache.harmony.security.fortress.Engine;
30
31/**
32 * This class provides the functionality for a key exchange protocol. This
33 * enables two or more parties to agree on a secret key for symmetric
34 * cryptography.
35 */
36public class KeyAgreement {
37
38    // Used to access common engine functionality
39    private static final Engine ENGINE = new Engine("KeyAgreement");
40
41    // Store SecureRandom
42    private static final SecureRandom RANDOM = new SecureRandom();
43
44    // Store used provider
45    private final Provider provider;
46
47    // Store used spi implementation
48    private final KeyAgreementSpi spiImpl;
49
50    // Store used algorithm name
51    private final String algorithm;
52
53    /**
54     * Creates a new {@code KeyAgreement} instance.
55     *
56     * @param keyAgreeSpi
57     *            the <b>SPI</b> delegate.
58     * @param provider
59     *            the provider providing this KeyAgreement.
60     * @param algorithm
61     *            the name of the key agreement algorithm.
62     */
63    protected KeyAgreement(KeyAgreementSpi keyAgreeSpi, Provider provider,
64            String algorithm) {
65        this.provider = provider;
66        this.algorithm = algorithm;
67        this.spiImpl = keyAgreeSpi;
68    }
69
70    /**
71     * Returns the name of the key agreement algorithm.
72     *
73     * @return the name of the key agreement algorithm.
74     */
75    public final String getAlgorithm() {
76        return algorithm;
77    }
78
79    /**
80     * Returns the provider for this {@code KeyAgreement} instance.
81     *
82     * @return the provider for this {@code KeyAgreement} instance.
83     */
84    public final Provider getProvider() {
85        return provider;
86    }
87
88    /**
89     * Creates a new {@code KeyAgreement} for the specified algorithm.
90     *
91     * @param algorithm
92     *            the name of the key agreement algorithm to create.
93     * @return a key agreement for the specified algorithm.
94     * @throws NoSuchAlgorithmException
95     *             if no installed provider can provide the requested algorithm.
96     * @throws NullPointerException
97     *             if the specified algorithm is {@code null}.
98     */
99    public static final KeyAgreement getInstance(String algorithm)
100            throws NoSuchAlgorithmException {
101        if (algorithm == null) {
102            throw new NullPointerException("algorithm == null");
103        }
104        Engine.SpiAndProvider sap = ENGINE.getInstance(algorithm, null);
105        return new KeyAgreement((KeyAgreementSpi) sap.spi, sap.provider, algorithm);
106    }
107
108    /**
109     * Creates a new {@code KeyAgreement} for the specified algorithm from the
110     * specified provider.
111     *
112     * @param algorithm
113     *            the name of the key agreement algorithm to create.
114     * @param provider
115     *            the name of the provider that provides the requested
116     *            algorithm.
117     * @return a key agreement for the specified algorithm from the specified
118     *         provider.
119     * @throws NoSuchAlgorithmException
120     *             if the specified provider cannot provide the requested
121     *             algorithm.
122     * @throws NoSuchProviderException
123     *             if the specified provider does not exist.
124     * @throws IllegalArgumentException
125     *             if the specified provider name is {@code null} or empty.
126     */
127    public static final KeyAgreement getInstance(String algorithm,
128            String provider) throws NoSuchAlgorithmException,
129            NoSuchProviderException {
130        if (provider == null || provider.isEmpty()) {
131            throw new IllegalArgumentException("Provider is null or empty");
132        }
133        Provider impProvider = Security.getProvider(provider);
134        if (impProvider == null) {
135            throw new NoSuchProviderException(provider);
136        }
137        return getInstance(algorithm, impProvider);
138    }
139
140    /**
141     * Create a new {@code KeyAgreement} for the specified algorithm from the
142     * specified provider.
143     *
144     * @param algorithm
145     *            the name of the key agreement algorithm to create.
146     * @param provider
147     *            the provider that provides the requested algorithm.
148     * @return a key agreement for the specified algorithm from the specified
149     *         provider.
150     * @throws NoSuchAlgorithmException
151     *             if the specified provider cannot provide the requested
152     *             algorithm.
153     * @throws IllegalArgumentException
154     *             if the specified provider is {@code null}.
155     * @throws NullPointerException
156     *             if the specified algorithm name is {@code null}.
157     */
158    public static final KeyAgreement getInstance(String algorithm,
159            Provider provider) throws NoSuchAlgorithmException {
160        if (provider == null) {
161            throw new IllegalArgumentException("provider == null");
162        }
163        if (algorithm == null) {
164            throw new NullPointerException("algorithm == null");
165        }
166        Object spi = ENGINE.getInstance(algorithm, provider, null);
167        return new KeyAgreement((KeyAgreementSpi) spi, provider, algorithm);
168    }
169
170    /**
171     * Initializes this {@code KeyAgreement} with the specified key.
172     *
173     * @param key
174     *            the key to initialize this key agreement.
175     * @throws InvalidKeyException
176     *             if the specified key cannot be used to initialize this key
177     *             agreement.
178     */
179    public final void init(Key key) throws InvalidKeyException {
180        spiImpl.engineInit(key, RANDOM);//new SecureRandom());
181    }
182
183    /**
184     * Initializes this {@code KeyAgreement} with the specified key and the
185     * specified randomness source.
186     *
187     * @param key
188     *            the key to initialize this key agreement.
189     * @param random
190     *            the source for any randomness needed.
191     * @throws InvalidKeyException
192     *             if the specified key cannot be used to initialize this key
193     *             agreement.
194     */
195    public final void init(Key key, SecureRandom random)
196            throws InvalidKeyException {
197        spiImpl.engineInit(key, random);
198    }
199
200    /**
201     * Initializes this {@code KeyAgreement} with the specified key and the
202     * algorithm parameters.
203     *
204     * @param key
205     *            the key to initialize this key agreement.
206     * @param params
207     *            the parameters for this key agreement algorithm.
208     * @throws InvalidKeyException
209     *             if the specified key cannot be used to initialize this key
210     *             agreement.
211     * @throws InvalidAlgorithmParameterException
212     *             if the specified parameters are invalid for this key
213     *             agreement algorithm.
214     */
215    public final void init(Key key, AlgorithmParameterSpec params)
216            throws InvalidKeyException, InvalidAlgorithmParameterException {
217        spiImpl.engineInit(key, params, RANDOM);//new SecureRandom());
218    }
219
220    /**
221     * Initializes this {@code KeyAgreement} with the specified key, algorithm
222     * parameters and randomness source.
223     *
224     * @param key
225     *            the key to initialize this key agreement.
226     * @param params
227     *            the parameters for this key agreement algorithm.
228     * @param random
229     *            the source for any randomness needed.
230     * @throws InvalidKeyException
231     *             if the specified key cannot be used to initialize this key
232     *             agreement.
233     * @throws InvalidAlgorithmParameterException
234     *             if the specified parameters are invalid for this key
235     *             agreement algorithm.
236     */
237    public final void init(Key key, AlgorithmParameterSpec params,
238            SecureRandom random) throws InvalidKeyException,
239            InvalidAlgorithmParameterException {
240        spiImpl.engineInit(key, params, random);
241    }
242
243    /**
244     * Does the next (or the last) phase of the key agreement, using the
245     * specified key.
246     *
247     * @param key
248     *            the key received from the other party for this phase.
249     * @param lastPhase
250     *            set to {@code true} if this is the last phase of this key
251     *            agreement.
252     * @return the intermediate key from this phase or {@code null} if there is
253     *         no intermediate key for this phase.
254     * @throws InvalidKeyException
255     *             if the specified key cannot be used in this key agreement or
256     *             this phase,
257     * @throws IllegalStateException
258     *             if this instance has not been initialized.
259     */
260    public final Key doPhase(Key key, boolean lastPhase)
261            throws InvalidKeyException, IllegalStateException {
262        return spiImpl.engineDoPhase(key, lastPhase);
263    }
264
265    /**
266     * Generates the shared secret.
267     *
268     * @return the generated shared secret.
269     * @throws IllegalStateException
270     *             if this key agreement is not complete.
271     */
272    public final byte[] generateSecret() throws IllegalStateException {
273        return spiImpl.engineGenerateSecret();
274    }
275
276    /**
277     * Generates the shared secret and stores it into the buffer {@code
278     * sharedSecred} at {@code offset}.
279     *
280     * @param sharedSecret
281     *            the buffer to store the shared secret.
282     * @param offset
283     *            the offset in the buffer.
284     * @return the number of bytes stored in the buffer.
285     * @throws IllegalStateException
286     *             if this key agreement is not complete.
287     * @throws ShortBufferException
288     *             if the specified buffer is too small for the shared secret.
289     */
290    public final int generateSecret(byte[] sharedSecret, int offset)
291            throws IllegalStateException, ShortBufferException {
292        return spiImpl.engineGenerateSecret(sharedSecret, offset);
293    }
294
295    /**
296     * Generates the shared secret.
297     *
298     * @param algorithm
299     *            the algorithm to for the {@code SecretKey}
300     * @return the shared secret as a {@code SecretKey} of the specified
301     *         algorithm.
302     * @throws IllegalStateException
303     *             if this key agreement is not complete.
304     * @throws NoSuchAlgorithmException
305     *             if the specified algorithm for the secret key does not
306     *             exists.
307     * @throws InvalidKeyException
308     *             if a {@code SecretKey} with the specified algorithm cannot be
309     *             created using the generated shared secret.
310     */
311    public final SecretKey generateSecret(String algorithm)
312            throws IllegalStateException, NoSuchAlgorithmException,
313            InvalidKeyException {
314        return spiImpl.engineGenerateSecret(algorithm);
315    }
316
317}
318