blob: abcfd0e43c2278fba5a7471a4fe6b347ed57ea19 [file] [log] [blame]
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001/*
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;
Kenny Root14a26bd2014-02-06 13:35:14 -080026import java.security.ProviderException;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080027import java.security.SecureRandom;
28import java.security.Security;
29import java.security.spec.AlgorithmParameterSpec;
Kenny Root14a26bd2014-02-06 13:35:14 -080030import java.util.ArrayList;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080031import org.apache.harmony.security.fortress.Engine;
32
33/**
34 * This class provides the functionality for a key exchange protocol. This
35 * enables two or more parties to agree on a secret key for symmetric
36 * cryptography.
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080037 */
38public class KeyAgreement {
39
Kenny Root14a26bd2014-02-06 13:35:14 -080040 // The service name.
41 private static final String SERVICE = "KeyAgreement";
42
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080043 // Used to access common engine functionality
Kenny Root14a26bd2014-02-06 13:35:14 -080044 private static final Engine ENGINE = new Engine(SERVICE);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080045
46 // Store SecureRandom
Brian Carlstrom0a480842010-10-18 23:00:51 -070047 private static final SecureRandom RANDOM = new SecureRandom();
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080048
49 // Store used provider
Kenny Root14a26bd2014-02-06 13:35:14 -080050 private Provider provider;
51
52 // Provider that was requested during creation.
53 private final Provider specifiedProvider;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080054
55 // Store used spi implementation
Kenny Root14a26bd2014-02-06 13:35:14 -080056 private KeyAgreementSpi spiImpl;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080057
58 // Store used algorithm name
59 private final String algorithm;
60
61 /**
Kenny Root14a26bd2014-02-06 13:35:14 -080062 * Lock held while the SPI is initializing.
63 */
64 private final Object initLock = new Object();
65
66 /**
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080067 * Creates a new {@code KeyAgreement} instance.
Jesse Wilsonce9ec012009-08-31 15:37:14 -070068 *
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080069 * @param keyAgreeSpi
70 * the <b>SPI</b> delegate.
71 * @param provider
72 * the provider providing this KeyAgreement.
73 * @param algorithm
74 * the name of the key agreement algorithm.
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080075 */
76 protected KeyAgreement(KeyAgreementSpi keyAgreeSpi, Provider provider,
77 String algorithm) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080078 this.spiImpl = keyAgreeSpi;
Kenny Root14a26bd2014-02-06 13:35:14 -080079 this.specifiedProvider = provider;
80 this.algorithm = algorithm;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080081 }
82
83 /**
84 * Returns the name of the key agreement algorithm.
Jesse Wilsonce9ec012009-08-31 15:37:14 -070085 *
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080086 * @return the name of the key agreement algorithm.
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080087 */
88 public final String getAlgorithm() {
89 return algorithm;
90 }
91
92 /**
93 * Returns the provider for this {@code KeyAgreement} instance.
Jesse Wilsonce9ec012009-08-31 15:37:14 -070094 *
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080095 * @return the provider for this {@code KeyAgreement} instance.
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080096 */
97 public final Provider getProvider() {
Kenny Root14a26bd2014-02-06 13:35:14 -080098 getSpi();
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080099 return provider;
100 }
101
102 /**
103 * Creates a new {@code KeyAgreement} for the specified algorithm.
Jesse Wilsonce9ec012009-08-31 15:37:14 -0700104 *
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800105 * @param algorithm
106 * the name of the key agreement algorithm to create.
107 * @return a key agreement for the specified algorithm.
108 * @throws NoSuchAlgorithmException
109 * if no installed provider can provide the requested algorithm.
110 * @throws NullPointerException
111 * if the specified algorithm is {@code null}.
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800112 */
Kenny Root14a26bd2014-02-06 13:35:14 -0800113 public static final KeyAgreement getInstance(String algorithm) throws NoSuchAlgorithmException {
114 return getKeyAgreement(algorithm, null);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800115 }
116
117 /**
118 * Creates a new {@code KeyAgreement} for the specified algorithm from the
119 * specified provider.
Jesse Wilsonce9ec012009-08-31 15:37:14 -0700120 *
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800121 * @param algorithm
122 * the name of the key agreement algorithm to create.
123 * @param provider
124 * the name of the provider that provides the requested
125 * algorithm.
126 * @return a key agreement for the specified algorithm from the specified
127 * provider.
128 * @throws NoSuchAlgorithmException
129 * if the specified provider cannot provide the requested
130 * algorithm.
131 * @throws NoSuchProviderException
132 * if the specified provider does not exist.
133 * @throws IllegalArgumentException
134 * if the specified provider name is {@code null} or empty.
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800135 */
Kenny Root14a26bd2014-02-06 13:35:14 -0800136 public static final KeyAgreement getInstance(String algorithm, String provider)
137 throws NoSuchAlgorithmException, NoSuchProviderException {
Elliott Hughes80a7fba2010-05-21 16:58:35 -0700138 if (provider == null || provider.isEmpty()) {
139 throw new IllegalArgumentException("Provider is null or empty");
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800140 }
141 Provider impProvider = Security.getProvider(provider);
142 if (impProvider == null) {
143 throw new NoSuchProviderException(provider);
144 }
Kenny Root14a26bd2014-02-06 13:35:14 -0800145 return getKeyAgreement(algorithm, impProvider);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800146 }
147
148 /**
149 * Create a new {@code KeyAgreement} for the specified algorithm from the
Kenny Root0a648872014-02-05 10:09:13 -0800150 * specified provider. The {@code provider} supplied does not have to be
151 * registered.
Jesse Wilsonce9ec012009-08-31 15:37:14 -0700152 *
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800153 * @param algorithm
154 * the name of the key agreement algorithm to create.
155 * @param provider
156 * the provider that provides the requested algorithm.
157 * @return a key agreement for the specified algorithm from the specified
158 * provider.
159 * @throws NoSuchAlgorithmException
160 * if the specified provider cannot provide the requested
161 * algorithm.
162 * @throws IllegalArgumentException
163 * if the specified provider is {@code null}.
164 * @throws NullPointerException
165 * if the specified algorithm name is {@code null}.
166 */
Kenny Root14a26bd2014-02-06 13:35:14 -0800167 public static final KeyAgreement getInstance(String algorithm, Provider provider)
168 throws NoSuchAlgorithmException {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800169 if (provider == null) {
Elliott Hughes80a7fba2010-05-21 16:58:35 -0700170 throw new IllegalArgumentException("provider == null");
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800171 }
Kenny Root14a26bd2014-02-06 13:35:14 -0800172 return getKeyAgreement(algorithm, provider);
173 }
174
175 private static KeyAgreement getKeyAgreement(String algorithm, Provider provider)
176 throws NoSuchAlgorithmException {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800177 if (algorithm == null) {
Kenny Root86acc042012-09-12 10:32:58 -0700178 throw new NullPointerException("algorithm == null");
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800179 }
Kenny Root14a26bd2014-02-06 13:35:14 -0800180
181 if (tryAlgorithm(null, provider, algorithm) == null) {
182 if (provider == null) {
183 throw new NoSuchAlgorithmException("No provider found for " + algorithm);
184 } else {
185 throw new NoSuchAlgorithmException("Provider " + provider.getName()
186 + " does not provide " + algorithm);
187 }
188 }
189 return new KeyAgreement(null, provider, algorithm);
190 }
191
192 private static Engine.SpiAndProvider tryAlgorithm(Key key, Provider provider, String algorithm) {
193 if (provider != null) {
194 Provider.Service service = provider.getService(SERVICE, algorithm);
195 if (service == null) {
196 return null;
197 }
198 return tryAlgorithmWithProvider(key, service);
199 }
200 ArrayList<Provider.Service> services = ENGINE.getServices(algorithm);
201 if (services == null) {
202 return null;
203 }
204 for (Provider.Service service : services) {
205 Engine.SpiAndProvider sap = tryAlgorithmWithProvider(key, service);
206 if (sap != null) {
207 return sap;
208 }
209 }
210 return null;
211 }
212
213 private static Engine.SpiAndProvider tryAlgorithmWithProvider(Key key, Provider.Service service) {
214 try {
215 if (key != null && !service.supportsParameter(key)) {
216 return null;
217 }
218
219 Engine.SpiAndProvider sap = ENGINE.getInstance(service, null);
220 if (sap.spi == null || sap.provider == null) {
221 return null;
222 }
223 if (!(sap.spi instanceof KeyAgreementSpi)) {
224 return null;
225 }
226 return sap;
227 } catch (NoSuchAlgorithmException ignored) {
228 }
229 return null;
230 }
231
232 /**
233 * Makes sure a KeyAgreementSpi that matches this type is selected.
234 */
235 private KeyAgreementSpi getSpi(Key key) {
236 synchronized (initLock) {
237 if (spiImpl != null && key == null) {
238 return spiImpl;
239 }
240
241 final Engine.SpiAndProvider sap = tryAlgorithm(key, specifiedProvider, algorithm);
242 if (sap == null) {
243 throw new ProviderException("No provider for " + getAlgorithm());
244 }
245
246 spiImpl = (KeyAgreementSpi) sap.spi;
247 provider = sap.provider;
248
249 return spiImpl;
250 }
251 }
252
253 /**
254 * Convenience call when the Key is not available.
255 */
256 private KeyAgreementSpi getSpi() {
257 return getSpi(null);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800258 }
259
260 /**
261 * Initializes this {@code KeyAgreement} with the specified key.
Jesse Wilsonce9ec012009-08-31 15:37:14 -0700262 *
Kenny Root14a26bd2014-02-06 13:35:14 -0800263 * @param key the key to initialize this key agreement.
264 * @throws InvalidKeyException if the specified key cannot be used to
265 * initialize this key agreement.
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800266 */
267 public final void init(Key key) throws InvalidKeyException {
Kenny Root14a26bd2014-02-06 13:35:14 -0800268 getSpi(key).engineInit(key, RANDOM);//new SecureRandom());
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800269 }
270
271 /**
272 * Initializes this {@code KeyAgreement} with the specified key and the
273 * specified randomness source.
Jesse Wilsonce9ec012009-08-31 15:37:14 -0700274 *
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800275 * @param key
276 * the key to initialize this key agreement.
277 * @param random
278 * the source for any randomness needed.
279 * @throws InvalidKeyException
280 * if the specified key cannot be used to initialize this key
281 * agreement.
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800282 */
283 public final void init(Key key, SecureRandom random)
284 throws InvalidKeyException {
Kenny Root14a26bd2014-02-06 13:35:14 -0800285 getSpi(key).engineInit(key, random);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800286 }
287
288 /**
289 * Initializes this {@code KeyAgreement} with the specified key and the
290 * algorithm parameters.
Jesse Wilsonce9ec012009-08-31 15:37:14 -0700291 *
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800292 * @param key
293 * the key to initialize this key agreement.
294 * @param params
295 * the parameters for this key agreement algorithm.
296 * @throws InvalidKeyException
297 * if the specified key cannot be used to initialize this key
298 * agreement.
299 * @throws InvalidAlgorithmParameterException
300 * if the specified parameters are invalid for this key
301 * agreement algorithm.
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800302 */
303 public final void init(Key key, AlgorithmParameterSpec params)
304 throws InvalidKeyException, InvalidAlgorithmParameterException {
Kenny Root14a26bd2014-02-06 13:35:14 -0800305 getSpi(key).engineInit(key, params, RANDOM);//new SecureRandom());
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800306 }
307
308 /**
309 * Initializes this {@code KeyAgreement} with the specified key, algorithm
310 * parameters and randomness source.
Jesse Wilsonce9ec012009-08-31 15:37:14 -0700311 *
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800312 * @param key
313 * the key to initialize this key agreement.
314 * @param params
315 * the parameters for this key agreement algorithm.
316 * @param random
317 * the source for any randomness needed.
318 * @throws InvalidKeyException
319 * if the specified key cannot be used to initialize this key
320 * agreement.
321 * @throws InvalidAlgorithmParameterException
322 * if the specified parameters are invalid for this key
323 * agreement algorithm.
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800324 */
325 public final void init(Key key, AlgorithmParameterSpec params,
326 SecureRandom random) throws InvalidKeyException,
327 InvalidAlgorithmParameterException {
Kenny Root14a26bd2014-02-06 13:35:14 -0800328 getSpi(key).engineInit(key, params, random);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800329 }
330
331 /**
332 * Does the next (or the last) phase of the key agreement, using the
333 * specified key.
Jesse Wilsonce9ec012009-08-31 15:37:14 -0700334 *
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800335 * @param key
336 * the key received from the other party for this phase.
337 * @param lastPhase
338 * set to {@code true} if this is the last phase of this key
339 * agreement.
340 * @return the intermediate key from this phase or {@code null} if there is
341 * no intermediate key for this phase.
342 * @throws InvalidKeyException
343 * if the specified key cannot be used in this key agreement or
344 * this phase,
345 * @throws IllegalStateException
346 * if this instance has not been initialized.
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800347 */
348 public final Key doPhase(Key key, boolean lastPhase)
349 throws InvalidKeyException, IllegalStateException {
Kenny Root14a26bd2014-02-06 13:35:14 -0800350 return getSpi().engineDoPhase(key, lastPhase);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800351 }
352
353 /**
354 * Generates the shared secret.
Jesse Wilsonce9ec012009-08-31 15:37:14 -0700355 *
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800356 * @return the generated shared secret.
357 * @throws IllegalStateException
358 * if this key agreement is not complete.
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800359 */
360 public final byte[] generateSecret() throws IllegalStateException {
Kenny Root14a26bd2014-02-06 13:35:14 -0800361 return getSpi().engineGenerateSecret();
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800362 }
363
364 /**
365 * Generates the shared secret and stores it into the buffer {@code
366 * sharedSecred} at {@code offset}.
Jesse Wilsonce9ec012009-08-31 15:37:14 -0700367 *
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800368 * @param sharedSecret
369 * the buffer to store the shared secret.
370 * @param offset
371 * the offset in the buffer.
372 * @return the number of bytes stored in the buffer.
373 * @throws IllegalStateException
374 * if this key agreement is not complete.
375 * @throws ShortBufferException
376 * if the specified buffer is too small for the shared secret.
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800377 */
378 public final int generateSecret(byte[] sharedSecret, int offset)
379 throws IllegalStateException, ShortBufferException {
Kenny Root14a26bd2014-02-06 13:35:14 -0800380 return getSpi().engineGenerateSecret(sharedSecret, offset);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800381 }
382
383 /**
384 * Generates the shared secret.
Jesse Wilsonce9ec012009-08-31 15:37:14 -0700385 *
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800386 * @param algorithm
387 * the algorithm to for the {@code SecretKey}
388 * @return the shared secret as a {@code SecretKey} of the specified
389 * algorithm.
390 * @throws IllegalStateException
391 * if this key agreement is not complete.
392 * @throws NoSuchAlgorithmException
393 * if the specified algorithm for the secret key does not
394 * exists.
395 * @throws InvalidKeyException
396 * if a {@code SecretKey} with the specified algorithm cannot be
397 * created using the generated shared secret.
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800398 */
399 public final SecretKey generateSecret(String algorithm)
400 throws IllegalStateException, NoSuchAlgorithmException,
401 InvalidKeyException {
Kenny Root14a26bd2014-02-06 13:35:14 -0800402 return getSpi().engineGenerateSecret(algorithm);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800403 }
404
Elliott Hughes80a7fba2010-05-21 16:58:35 -0700405}