View Javadoc
1   /*
2    * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.  Oracle designates this
8    * particular file as subject to the "Classpath" exception as provided
9    * by Oracle in the LICENSE file that accompanied this code.
10   *
11   * This code is distributed in the hope that it will be useful, but WITHOUT
12   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14   * version 2 for more details (a copy is included in the LICENSE file that
15   * accompanied this code).
16   *
17   * You should have received a copy of the GNU General Public License version
18   * 2 along with this work; if not, write to the Free Software Foundation,
19   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20   *
21   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22   * or visit www.oracle.com if you need additional information or have any
23   * questions.
24   */
25  
26  package com.sun.crypto.provider;
27  
28  import java.security.InvalidKeyException;
29  import java.security.spec.KeySpec;
30  import java.security.spec.InvalidKeySpecException;
31  import javax.crypto.SecretKey;
32  import javax.crypto.SecretKeyFactorySpi;
33  import javax.crypto.spec.PBEKeySpec;
34  
35  /**
36   * This class implements a key factory for PBE keys derived using
37   * PBKDF2 with HmacSHA1/HmacSHA224/HmacSHA256/HmacSHA384/HmacSHA512
38   * pseudo random function (PRF) as defined in PKCS#5 v2.1.
39   *
40   * @author Valerie Peng
41   *
42   */
43  abstract class PBKDF2Core extends SecretKeyFactorySpi {
44  
45      private final String prfAlgo;
46  
47      PBKDF2Core(String prfAlgo) {
48          this.prfAlgo = prfAlgo;
49      }
50  
51      /**
52       * Generates a <code>SecretKey</code> object from the provided key
53       * specification (key material).
54       *
55       * @param keySpec the specification (key material) of the secret key
56       *
57       * @return the secret key
58       *
59       * @exception InvalidKeySpecException if the given key specification
60       * is inappropriate for this key factory to produce a public key.
61       */
62      protected SecretKey engineGenerateSecret(KeySpec keySpec)
63          throws InvalidKeySpecException
64      {
65          if (!(keySpec instanceof PBEKeySpec)) {
66              throw new InvalidKeySpecException("Invalid key spec");
67          }
68          PBEKeySpec ks = (PBEKeySpec) keySpec;
69          return new PBKDF2KeyImpl(ks, prfAlgo);
70      }
71  
72      /**
73       * Returns a specification (key material) of the given key
74       * in the requested format.
75       *
76       * @param key the key
77       *
78       * @param keySpec the requested format in which the key material shall be
79       * returned
80       *
81       * @return the underlying key specification (key material) in the
82       * requested format
83       *
84       * @exception InvalidKeySpecException if the requested key
85       * specification is inappropriate for the given key, or the
86       * given key cannot be processed (e.g., the given key has an
87       * unrecognized algorithm or format).
88       */
89      protected KeySpec engineGetKeySpec(SecretKey key, Class<?> keySpecCl)
90          throws InvalidKeySpecException {
91          if (key instanceof javax.crypto.interfaces.PBEKey) {
92              // Check if requested key spec is amongst the valid ones
93              if ((keySpecCl != null)
94                  && PBEKeySpec.class.isAssignableFrom(keySpecCl)) {
95                  javax.crypto.interfaces.PBEKey pKey =
96                      (javax.crypto.interfaces.PBEKey) key;
97                  return new PBEKeySpec
98                      (pKey.getPassword(), pKey.getSalt(),
99                       pKey.getIterationCount(), pKey.getEncoded().length*8);
100             } else {
101                 throw new InvalidKeySpecException("Invalid key spec");
102             }
103         } else {
104             throw new InvalidKeySpecException("Invalid key " +
105                                                "format/algorithm");
106         }
107     }
108 
109     /**
110      * Translates a <code>SecretKey</code> object, whose provider may be
111      * unknown or potentially untrusted, into a corresponding
112      * <code>SecretKey</code> object of this key factory.
113      *
114      * @param key the key whose provider is unknown or untrusted
115      *
116      * @return the translated key
117      *
118      * @exception InvalidKeyException if the given key cannot be processed by
119      * this key factory.
120      */
121     protected SecretKey engineTranslateKey(SecretKey key)
122         throws InvalidKeyException {
123         if ((key != null) &&
124             (key.getAlgorithm().equalsIgnoreCase("PBKDF2With" + prfAlgo)) &&
125             (key.getFormat().equalsIgnoreCase("RAW"))) {
126 
127             // Check if key originates from this factory
128             if (key instanceof com.sun.crypto.provider.PBKDF2KeyImpl) {
129                 return key;
130             }
131             // Check if key implements the PBEKey
132             if (key instanceof javax.crypto.interfaces.PBEKey) {
133                 javax.crypto.interfaces.PBEKey pKey =
134                     (javax.crypto.interfaces.PBEKey) key;
135                 try {
136                     PBEKeySpec spec =
137                         new PBEKeySpec(pKey.getPassword(),
138                                        pKey.getSalt(),
139                                        pKey.getIterationCount(),
140                                        pKey.getEncoded().length*8);
141                     return new PBKDF2KeyImpl(spec, prfAlgo);
142                 } catch (InvalidKeySpecException re) {
143                     InvalidKeyException ike = new InvalidKeyException
144                         ("Invalid key component(s)");
145                     ike.initCause(re);
146                     throw ike;
147                 }
148             }
149         }
150         throw new InvalidKeyException("Invalid key format/algorithm");
151     }
152 
153     public static final class HmacSHA1 extends PBKDF2Core {
154         public HmacSHA1() {
155             super("HmacSHA1");
156         }
157     }
158 
159     public static final class HmacSHA224 extends PBKDF2Core {
160         public HmacSHA224() {
161             super("HmacSHA224");
162         }
163     }
164 
165     public static final class HmacSHA256 extends PBKDF2Core {
166         public HmacSHA256() {
167             super("HmacSHA256");
168         }
169     }
170 
171     public static final class HmacSHA384 extends PBKDF2Core {
172         public HmacSHA384() {
173             super("HmacSHA384");
174         }
175     }
176 
177     public static final class HmacSHA512 extends PBKDF2Core {
178         public HmacSHA512() {
179             super("HmacSHA512");
180         }
181     }
182 }