001/* KeyGenerator.java -- Interface to a symmetric key generator.
002   Copyright (C) 2004  Free Software Foundation, Inc.
003
004This file is part of GNU Classpath.
005
006GNU Classpath is free software; you can redistribute it and/or modify
007it under the terms of the GNU General Public License as published by
008the Free Software Foundation; either version 2, or (at your option)
009any later version.
010
011GNU Classpath is distributed in the hope that it will be useful, but
012WITHOUT ANY WARRANTY; without even the implied warranty of
013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014General Public License for more details.
015
016You should have received a copy of the GNU General Public License
017along with GNU Classpath; see the file COPYING.  If not, write to the
018Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
01902110-1301 USA.
020
021Linking this library statically or dynamically with other modules is
022making a combined work based on this library.  Thus, the terms and
023conditions of the GNU General Public License cover the whole
024combination.
025
026As a special exception, the copyright holders of this library give you
027permission to link this library with independent modules to produce an
028executable, regardless of the license terms of these independent
029modules, and to copy and distribute the resulting executable under
030terms of your choice, provided that you also meet, for each linked
031independent module, the terms and conditions of the license of that
032module.  An independent module is a module which is not derived from
033or based on this library.  If you modify this library, you may extend
034this exception to your version of the library, but you are not
035obligated to do so.  If you do not wish to do so, delete this
036exception statement from your version. */
037
038
039package javax.crypto;
040
041import gnu.java.security.Engine;
042
043import java.lang.reflect.InvocationTargetException;
044import java.security.InvalidAlgorithmParameterException;
045import java.security.NoSuchAlgorithmException;
046import java.security.NoSuchProviderException;
047import java.security.Provider;
048import java.security.SecureRandom;
049import java.security.Security;
050import java.security.spec.AlgorithmParameterSpec;
051
052/**
053 * A generic producer of keys for symmetric cryptography. The keys
054 * returned may be simple wrappers around byte arrays, or, if the
055 * target cipher requires them, more complex objects.
056 *
057 * @author Casey Marshall (csm@gnu.org)
058 * @since 1.4
059 * @see Cipher
060 * @see Mac
061 */
062public class KeyGenerator
063{
064
065  // Constants and fields.
066  // ------------------------------------------------------------------------
067
068  private static final String SERVICE = "KeyGenerator";
069
070  /** The underlying generator implementation. */
071  private KeyGeneratorSpi kgSpi;
072
073  /** The provider of the implementation. */
074  private Provider provider;
075
076  /** The name of the algorithm. */
077  private String algorithm;
078
079  // Constructor.
080  // ------------------------------------------------------------------------
081
082  /**
083   * Create a new key generator.
084   *
085   * @param kgSpi     The underlying generator.
086   * @param provider  The provider of this implementation.
087   * @param algorithm The algorithm's name.
088   */
089  protected KeyGenerator(KeyGeneratorSpi kgSpi, Provider provider,
090                         String algorithm)
091  {
092    this.kgSpi = kgSpi;
093    this.provider = provider;
094    this.algorithm = algorithm;
095  }
096
097  /**
098   * Create a new key generator, returning the first available implementation.
099   *
100   * @param algorithm The generator algorithm name.
101   * @throws NoSuchAlgorithmException If the specified algorithm does not exist.
102   * @throws IllegalArgumentException if <code>algorithm</code> is
103   *           <code>null</code> or is an empty string.
104   */
105  public static final KeyGenerator getInstance(String algorithm)
106      throws NoSuchAlgorithmException
107  {
108    Provider[] p = Security.getProviders();
109    NoSuchAlgorithmException lastException = null;
110    for (int i = 0; i < p.length; i++)
111      try
112        {
113          return getInstance(algorithm, p[i]);
114        }
115      catch (NoSuchAlgorithmException x)
116        {
117          lastException = x;
118        }
119    if (lastException != null)
120      throw lastException;
121    throw new NoSuchAlgorithmException(algorithm);
122  }
123
124  /**
125   * Create a new key generator from the named provider.
126   *
127   * @param algorithm The generator algorithm name.
128   * @param provider The name of the provider to use.
129   * @return An appropriate key generator, if found.
130   * @throws NoSuchAlgorithmException If the specified algorithm is not
131   *           implemented by the named provider.
132   * @throws NoSuchProviderException If the named provider does not exist.
133   * @throws IllegalArgumentException if either <code>algorithm</code> or
134   *           <code>provider</code> is <code>null</code>, or if
135   *           <code>algorithm</code> is an empty string.
136   */
137  public static final KeyGenerator getInstance(String algorithm, String provider)
138      throws NoSuchAlgorithmException, NoSuchProviderException
139  {
140    if (provider == null)
141      throw new IllegalArgumentException("provider MUST NOT be null");
142    Provider p = Security.getProvider(provider);
143    if (p == null)
144      throw new NoSuchProviderException(provider);
145    return getInstance(algorithm, p);
146  }
147
148  /**
149   * Create a new key generator from the supplied provider.
150   *
151   * @param algorithm The generator algorithm name.
152   * @param provider The provider to use.
153   * @return An appropriate key generator, if found.
154   * @throws NoSuchAlgorithmException If the specified algorithm is not
155   *           implemented by the provider.
156   * @throws IllegalArgumentException if either <code>algorithm</code> or
157   *           <code>provider</code> is <code>null</code>, or if
158   *           <code>algorithm</code> is an empty string.
159   */
160  public static final KeyGenerator getInstance(String algorithm,
161                                               Provider provider)
162      throws NoSuchAlgorithmException
163  {
164    StringBuilder sb = new StringBuilder("KeyGenerator algorithm [")
165        .append(algorithm).append("] from provider[")
166        .append(provider).append("] could not be created");
167    Throwable cause;
168    try
169      {
170        Object spi = Engine.getInstance(SERVICE, algorithm, provider);
171        KeyGenerator instance = new KeyGenerator((KeyGeneratorSpi) spi,
172                                                 provider,
173                                                 algorithm);
174        instance.init(new SecureRandom());
175        return instance;
176      }
177    catch (InvocationTargetException x)
178      {
179        cause = x.getCause();
180        if (cause instanceof NoSuchAlgorithmException)
181          throw (NoSuchAlgorithmException) cause;
182        if (cause == null)
183          cause = x;
184      }
185    catch (ClassCastException x)
186      {
187        cause = x;
188      }
189    NoSuchAlgorithmException x = new NoSuchAlgorithmException(sb.toString());
190    x.initCause(cause);
191    throw x;
192  }
193
194  /**
195   * Generate a key.
196   *
197   * @return The new key.
198   */
199  public final SecretKey generateKey()
200  {
201    return kgSpi.engineGenerateKey();
202  }
203
204  /**
205   * Return the name of this key generator.
206   *
207   * @return The algorithm name.
208   */
209  public final String getAlgorithm()
210  {
211    return algorithm;
212  }
213
214  /**
215   * Return the provider of the underlying implementation.
216   *
217   * @return The provider.
218   */
219  public final Provider getProvider()
220  {
221    return provider;
222  }
223
224  /**
225   * Initialize this key generator with a set of parameters; the
226   * highest-priority {@link java.security.SecureRandom} implementation
227   * will be used.
228   *
229   * @param params The algorithm parameters.
230   * @throws java.security.InvalidAlgorithmParameterException If the
231   *         supplied parameters are inapproprate.
232   */
233  public final void init(AlgorithmParameterSpec params)
234    throws InvalidAlgorithmParameterException
235  {
236    init(params, new SecureRandom());
237  }
238
239  /**
240   * Initialize this key generator with a set of parameters and a source
241   * of randomness.
242   *
243   * @param params The algorithm parameters.
244   * @param random The source of randomness.
245   * @throws java.security.InvalidAlgorithmParameterException If the
246   *         supplied parameters are inapproprate.
247   */
248  public final void init(AlgorithmParameterSpec params, SecureRandom random)
249    throws InvalidAlgorithmParameterException
250  {
251    kgSpi.engineInit(params, random);
252  }
253
254  /**
255   * Initialize this key generator with a key size (in bits); the
256   * highest-priority {@link java.security.SecureRandom} implementation
257   * will be used.
258   *
259   * @param keySize The target key size, in bits.
260   * @throws java.security.InvalidParameterException If the
261   *         key size is unsupported.
262   */
263  public final void init(int keySize)
264  {
265    init(keySize, new SecureRandom());
266  }
267
268  /**
269   * Initialize this key generator with a key size (in bits) and a
270   * source of randomness.
271   *
272   * @param keySize The target key size, in bits.
273   * @param random  The source of randomness.
274   * @throws java.security.InvalidAlgorithmParameterException If the
275   *         key size is unsupported.
276   */
277  public final void init(int keySize, SecureRandom random)
278  {
279    kgSpi.engineInit(keySize, random);
280  }
281
282  /**
283   * Initialize this key generator with a source of randomness. The
284   * implementation-specific default parameters (such as key size) will
285   * be used.
286   *
287   * @param random The source of randomness.
288   */
289  public final void init(SecureRandom random)
290  {
291    kgSpi.engineInit(random);
292  }
293}