001/* PBEKeySpec.java -- Wrapper for password-based keys.
002   Copyright (C) 2004, 2006  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.spec;
040
041import java.security.spec.KeySpec;
042
043/**
044 * A wrapper for a password-based key, used for password-based
045 * encryption (PBE).
046 *
047 * <p>Examples of password-based encryption algorithms include:
048 *
049 * <ul>
050 * <li><a href="http://www.rsasecurity.com/rsalabs/pkcs/pkcs-5/">PKCS #5
051 * - Password-Based Cryptography Standard</a></li>
052 * <li><a href="http://www.rsasecurity.com/rsalabs/pkcs/pkcs-12/">PKCS
053 * #12 - Personal Information Exchange Syntax Standard</a></li>
054 * </ul>
055 *
056 * @author Casey Marshall (csm@gnu.org)
057 * @since 1.4
058 * @see javax.crypto.SecretKeyFactory
059 * @see PBEParameterSpec
060 */
061public class PBEKeySpec implements KeySpec
062{
063
064  // Fields.
065  // ------------------------------------------------------------------------
066
067  /** The iteration count. */
068  private int iterationCount;
069
070  /** The generated key length. */
071  private int keyLength;
072
073  /** The password. */
074  private char[] password;
075
076  /** The salt. */
077  private byte[] salt;
078
079  /** The password state */
080  private boolean passwordValid = true;
081
082  // Constructors.
083  // ------------------------------------------------------------------------
084
085  /**
086   * Create a new PBE key spec with just a password.
087   * <p>
088   * A copy of the password argument is stored instead of the argument itself.
089   *
090   * @param password The password char array.
091   */
092  public PBEKeySpec(char[] password)
093  {
094    setPassword(password);
095
096    // load the default values for unspecified variables.
097    salt = null;
098    iterationCount = 0;
099    keyLength = 0;
100  }
101
102  /**
103   * Create a PBE key spec with a password, salt, and iteration count.
104   * <p>
105   * A copy of the password and salt arguments are stored instead of the
106   * arguments themselves.
107   *
108   * @param password The password char array.
109   * @param salt The salt bytes.
110   * @param iterationCount The iteration count.
111   * @throws NullPointerException If salt is null
112   * @throws IllegalArgumentException If salt is an empty array, or
113   *           iterationCount is negative
114   */
115  public PBEKeySpec(char[] password, byte[] salt, int iterationCount)
116  {
117    setPassword(password);
118    setSalt(salt);
119    setIterationCount(iterationCount);
120
121    // load default values into unspecified variables.
122    keyLength = 0;
123  }
124
125  /**
126   * Create a PBE key spec with a password, salt, iteration count, and key
127   * length.
128   * <p>
129   * A copy of the password and salt arguments are stored instead of the
130   * arguments themselves.
131   *
132   * @param password The password char array.
133   * @param salt The salt bytes.
134   * @param iterationCount The iteration count.
135   * @param keyLength The generated key length.
136   * @throws NullPointerException If salt is null
137   * @throws IllegalArgumentException If salt is an empty array, if
138   *           iterationCount or keyLength is negative
139   */
140  public PBEKeySpec(char[] password, byte[] salt, int iterationCount,
141                    int keyLength)
142  {
143    setPassword(password);
144    setSalt(salt);
145    setIterationCount(iterationCount);
146    setKeyLength(keyLength);
147  }
148
149  // Instance methods.
150  // ------------------------------------------------------------------------
151
152  /**
153   * Clear the password array by filling it with null characters.
154   * <p>
155   * This clears the stored copy of the password, not the original char array
156   * used to create the password.
157   */
158  public final void clearPassword()
159  {
160    if (password == null)
161      return;
162    for (int i = 0; i < password.length; i++)
163      password[i] = '\u0000';
164
165    // since the password is cleared, it is no longer valid
166    passwordValid = false;
167  }
168
169  /**
170   * Get the iteration count, or 0 if it has not been specified.
171   *
172   * @return The iteration count, or 0 if it has not been specified.
173   */
174  public final int getIterationCount()
175  {
176    return iterationCount;
177  }
178
179  /**
180   * Get the generated key length, or 0 if it has not been specified.
181   *
182   * @return The key length, or 0 if it has not been specified.
183   */
184  public final int getKeyLength()
185  {
186    return keyLength;
187  }
188
189  /**
190   * Get the password character array copy.
191   * <p>
192   * This returns a copy of the password, not the password itself.
193   *
194   * @return a clone of the password.
195   * @throws IllegalStateException If {@link #clearPassword()} has already been
196   *           called.
197   */
198  public final char[] getPassword()
199  {
200    if (! passwordValid)
201      throw new IllegalStateException("clearPassword() has been called, the "
202                                      + "password is no longer valid");
203    return (char[]) password.clone();
204  }
205
206  /**
207   * Get the salt bytes array copy.
208   * <p>
209   * This returns a copy of the salt, not the salt itself.
210   *
211   * @return The salt.
212   */
213  public final byte[] getSalt()
214  {
215    if (salt != null)
216      return (byte[]) salt.clone();
217    return null;
218  }
219
220  /**
221   * Set the password char array.
222   * <p>
223   * A copy of the password argument is stored instead of the argument itself.
224   *
225   * @param password The password to be set
226   */
227  private void setPassword(char[] password)
228  {
229    if (password != null)
230      this.password = (char[]) password.clone();
231    else
232      this.password = new char[0];
233
234    passwordValid = true;
235  }
236
237  /**
238   * Set the salt byte array.
239   * <p>
240   * A copy of the salt arguments is stored instead of the argument itself.
241   *
242   * @param salt The salt to be set.
243   * @throws NullPointerException If the salt is null.
244   * @throws IllegalArgumentException If the salt is an empty array.
245   */
246  private void setSalt(byte[] salt)
247  {
248    if (salt.length == 0)
249      throw new IllegalArgumentException("salt MUST NOT be an empty byte array");
250
251    this.salt = (byte[]) salt.clone();
252  }
253
254  /**
255   * Set the iterationCount.
256   *
257   * @param iterationCount The iteration count to be set.
258   * @throws IllegalArgumentException If the iterationCount is negative.
259   */
260  private void setIterationCount(int iterationCount)
261  {
262    if (iterationCount < 0)
263      throw new IllegalArgumentException("iterationCount MUST be positive");
264
265    this.iterationCount = iterationCount;
266  }
267
268  /**
269   * Set the keyLength.
270   *
271   * @param keyLength The keyLength to be set.
272   * @throws IllegalArgumentException if the keyLength is negative.
273   */
274  private void setKeyLength(int keyLength)
275  {
276    if (keyLength < 0)
277      throw new IllegalArgumentException("keyLength MUST be positive");
278
279    this.keyLength = keyLength;
280  }
281}