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.InvalidKeyException;
21import java.security.NoSuchAlgorithmException;
22import java.security.NoSuchProviderException;
23import java.security.Provider;
24import java.security.Security;
25import java.security.spec.InvalidKeySpecException;
26import java.security.spec.KeySpec;
27import org.apache.harmony.security.fortress.Engine;
28
29
30/**
31 * The public API for {@code SecretKeyFactory} implementations.
32 * <p>
33 * Secret key factories provide the following functionality:
34 * <ul>
35 * <li>convert {@link SecretKey} objects to and from {@link KeySpec} objects</li>
36 * <li>translate {@link SecretKey} objects from one provider implementation to
37 * another</li>
38 * </ul>
39 * Which key specifications are supported by the {@link #generateSecret} and
40 * {@link #getKeySpec} is provider dependent.
41 */
42public class SecretKeyFactory {
43
44    // Used to access common engine functionality
45    private static final Engine ENGINE = new Engine("SecretKeyFactory");
46
47    // Store used provider
48    private final Provider provider;
49
50    // Store used spi implementation
51    private final SecretKeyFactorySpi spiImpl;
52
53    // Store used algorithm name
54    private final String algorithm;
55
56    /**
57     * Creates a new {@code SecretKeyFactory}
58     *
59     * @param keyFacSpi
60     *            the SPI delegate.
61     * @param provider
62     *            the provider providing this key factory.
63     * @param algorithm
64     *            the algorithm name for the secret key.
65     */
66    protected SecretKeyFactory(SecretKeyFactorySpi keyFacSpi,
67            Provider provider, String algorithm) {
68        this.provider = provider;
69        this.algorithm = algorithm;
70        this.spiImpl = keyFacSpi;
71    }
72
73    /**
74     * Returns the name of the secret key algorithm.
75     *
76     * @return the name of the secret key algorithm.
77     */
78    public final String getAlgorithm() {
79        return algorithm;
80    }
81
82    /**
83     * Returns the provider for this {@code SecretKeyFactory} instance.
84     *
85     * @return the provider for this {@code SecretKeyFactory} instance.
86     */
87    public final Provider getProvider() {
88        return provider;
89    }
90
91    /**
92     * Creates a new {@code SecretKeyFactory} instance for the specified key
93     * algorithm.
94     *
95     * @param algorithm
96     *            the name of the key algorithm.
97     * @return a secret key factory for the specified key algorithm.
98     * @throws NoSuchAlgorithmException
99     *             if no installed provider can provide the requested algorithm.
100     * @throws NullPointerException
101     *             if the specified algorithm is {@code null}.
102     */
103    public static final SecretKeyFactory getInstance(String algorithm)
104            throws NoSuchAlgorithmException {
105        if (algorithm == null) {
106            throw new NullPointerException("algorithm == null");
107        }
108        Engine.SpiAndProvider sap = ENGINE.getInstance(algorithm, null);
109        return new SecretKeyFactory((SecretKeyFactorySpi) sap.spi, sap.provider, algorithm);
110    }
111
112    /**
113     * Creates a new {@code SecretKeyFactory} instance for the specified key
114     * algorithm from the specified {@code provider}.
115     *
116     * @param algorithm
117     *            the name of the key algorithm.
118     * @param provider
119     *            the name of the provider that provides the requested
120     *            algorithm.
121     * @return a secret key factory for the specified key algorithm from the
122     *         specified provider.
123     * @throws NoSuchAlgorithmException
124     *             if the specified provider cannot provide the requested
125     *             algorithm.
126     * @throws NoSuchProviderException
127     *             if the specified provider does not exist.
128     * @throws IllegalArgumentException
129     *             if the specified provider name is {@code null} or empty.
130     */
131    public static final SecretKeyFactory getInstance(String algorithm,
132            String provider) throws NoSuchAlgorithmException,
133            NoSuchProviderException {
134        if (provider == null || provider.isEmpty()) {
135            throw new IllegalArgumentException("Provider is null or empty");
136        }
137        Provider impProvider = Security.getProvider(provider);
138        if (impProvider == null) {
139            throw new NoSuchProviderException(provider);
140        }
141        return getInstance(algorithm, impProvider);
142    }
143
144    /**
145     * Creates a new {@code SecretKeyFactory} instance for the specified key
146     * algorithm from the specified provider.
147     *
148     * @param algorithm
149     *            the name of the key algorithm.
150     * @param provider
151     *            the provider that provides the requested algorithm.
152     * @return a secret key factory for the specified key algorithm from the
153     *         specified provider.
154     * @throws NoSuchAlgorithmException
155     *             if the specified provider cannot provider the requested
156     *             algorithm.
157     * @throws IllegalArgumentException
158     *             if the specified provider is {@code null}.
159     * @throws NullPointerException
160     *             is the specified algorithm name is {@code null}.
161     */
162    public static final SecretKeyFactory getInstance(String algorithm,
163            Provider provider) throws NoSuchAlgorithmException {
164        if (provider == null) {
165            throw new IllegalArgumentException("provider == null");
166        }
167        if (algorithm == null) {
168            throw new NullPointerException("algorithm == null");
169        }
170        Object spi = ENGINE.getInstance(algorithm, provider, null);
171        return new SecretKeyFactory((SecretKeyFactorySpi) spi, provider, algorithm);
172    }
173
174    /**
175     * Generate a secret key from the specified key specification.
176     *
177     * @param keySpec
178     *            the key specification.
179     * @return a secret key.
180     * @throws InvalidKeySpecException
181     *             if the specified key specification cannot be used to generate
182     *             a secret key.
183     */
184    public final SecretKey generateSecret(KeySpec keySpec)
185            throws InvalidKeySpecException {
186        return spiImpl.engineGenerateSecret(keySpec);
187    }
188
189    /**
190     * Returns the key specification of the specified secret key.
191     *
192     * @param key
193     *            the secret key to get the specification from.
194     * @param keySpec
195     *            the target key specification class.
196     * @return an instance of the specified key specification class.
197     * @throws InvalidKeySpecException
198     *             if the specified secret key cannot be transformed into the
199     *             requested key specification.
200     */
201    @SuppressWarnings("unchecked")
202    public final KeySpec getKeySpec(SecretKey key, Class keySpec)
203            throws InvalidKeySpecException {
204        return spiImpl.engineGetKeySpec(key, keySpec);
205    }
206
207    /**
208     * Translates the specified secret key into an instance of the corresponding
209     * key from the provider of this key factory.
210     *
211     * @param key
212     *            the secret key to translate.
213     * @return the corresponding translated key.
214     * @throws InvalidKeyException
215     *             if the specified key cannot be translated using this key
216     *             factory.
217     */
218    public final SecretKey translateKey(SecretKey key)
219            throws InvalidKeyException {
220        return spiImpl.engineTranslateKey(key);
221
222    }
223}
224