1/*
2 * Copyright (c) 1997, 2014, 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
26package com.sun.crypto.provider;
27
28import java.security.InvalidKeyException;
29import java.security.spec.KeySpec;
30import java.security.spec.InvalidKeySpecException;
31import javax.crypto.SecretKey;
32import javax.crypto.SecretKeyFactorySpi;
33import javax.crypto.spec.PBEKeySpec;
34import java.util.HashSet;
35import java.util.Locale;
36
37/**
38 * This class implements a key factory for PBE keys according to PKCS#5,
39 * meaning that the password must consist of printable ASCII characters
40 * (values 32 to 126 decimal inclusive) and only the low order 8 bits
41 * of each password character are used.
42 *
43 * @author Jan Luehe
44 *
45 */
46abstract class PBEKeyFactory extends SecretKeyFactorySpi {
47
48    private String type;
49    private static HashSet<String> validTypes;
50
51    /**
52     * Simple constructor
53     */
54    private PBEKeyFactory(String keytype) {
55        type = keytype;
56    }
57
58    static {
59        validTypes = new HashSet<>(17);
60        validTypes.add("PBEWithMD5AndDES".toUpperCase(Locale.ENGLISH));
61        validTypes.add("PBEWithSHA1AndDESede".toUpperCase(Locale.ENGLISH));
62        validTypes.add("PBEWithSHA1AndRC2_40".toUpperCase(Locale.ENGLISH));
63        validTypes.add("PBEWithSHA1AndRC2_128".toUpperCase(Locale.ENGLISH));
64        validTypes.add("PBEWithSHA1AndRC4_40".toUpperCase(Locale.ENGLISH));
65        validTypes.add("PBEWithSHA1AndRC4_128".toUpperCase(Locale.ENGLISH));
66        // Proprietary algorithm.
67        validTypes.add("PBEWithMD5AndTripleDES".toUpperCase(Locale.ENGLISH));
68        validTypes.add("PBEWithHmacSHA1AndAES_128".toUpperCase(Locale.ENGLISH));
69        validTypes.add("PBEWithHmacSHA224AndAES_128".toUpperCase(Locale.ENGLISH));
70        validTypes.add("PBEWithHmacSHA256AndAES_128".toUpperCase(Locale.ENGLISH));
71        validTypes.add("PBEWithHmacSHA384AndAES_128".toUpperCase(Locale.ENGLISH));
72        validTypes.add("PBEWithHmacSHA512AndAES_128".toUpperCase(Locale.ENGLISH));
73        validTypes.add("PBEWithHmacSHA1AndAES_256".toUpperCase(Locale.ENGLISH));
74        validTypes.add("PBEWithHmacSHA224AndAES_256".toUpperCase(Locale.ENGLISH));
75        validTypes.add("PBEWithHmacSHA256AndAES_256".toUpperCase(Locale.ENGLISH));
76        validTypes.add("PBEWithHmacSHA384AndAES_256".toUpperCase(Locale.ENGLISH));
77        validTypes.add("PBEWithHmacSHA512AndAES_256".toUpperCase(Locale.ENGLISH));
78    }
79
80    public static final class PBEWithMD5AndDES
81            extends PBEKeyFactory {
82        public PBEWithMD5AndDES()  {
83            super("PBEWithMD5AndDES");
84        }
85    }
86
87    public static final class PBEWithSHA1AndDESede
88            extends PBEKeyFactory {
89        public PBEWithSHA1AndDESede()  {
90            super("PBEWithSHA1AndDESede");
91        }
92    }
93
94    public static final class PBEWithSHA1AndRC2_40
95            extends PBEKeyFactory {
96        public PBEWithSHA1AndRC2_40()  {
97            super("PBEWithSHA1AndRC2_40");
98        }
99    }
100
101    public static final class PBEWithSHA1AndRC2_128
102            extends PBEKeyFactory {
103        public PBEWithSHA1AndRC2_128()  {
104            super("PBEWithSHA1AndRC2_128");
105        }
106    }
107
108    public static final class PBEWithSHA1AndRC4_40
109            extends PBEKeyFactory {
110        public PBEWithSHA1AndRC4_40()  {
111            super("PBEWithSHA1AndRC4_40");
112        }
113    }
114
115    public static final class PBEWithSHA1AndRC4_128
116            extends PBEKeyFactory {
117        public PBEWithSHA1AndRC4_128()  {
118            super("PBEWithSHA1AndRC4_128");
119        }
120    }
121
122    /*
123     * Private proprietary algorithm for supporting JCEKS.
124     */
125    public static final class PBEWithMD5AndTripleDES
126            extends PBEKeyFactory {
127        public PBEWithMD5AndTripleDES()  {
128            super("PBEWithMD5AndTripleDES");
129        }
130    }
131
132    public static final class PBEWithHmacSHA1AndAES_128
133            extends PBEKeyFactory {
134        public PBEWithHmacSHA1AndAES_128()  {
135            super("PBEWithHmacSHA1AndAES_128");
136        }
137    }
138
139    public static final class PBEWithHmacSHA224AndAES_128
140            extends PBEKeyFactory {
141        public PBEWithHmacSHA224AndAES_128()  {
142            super("PBEWithHmacSHA224AndAES_128");
143        }
144    }
145
146    public static final class PBEWithHmacSHA256AndAES_128
147            extends PBEKeyFactory {
148        public PBEWithHmacSHA256AndAES_128()  {
149            super("PBEWithHmacSHA256AndAES_128");
150        }
151    }
152
153    public static final class PBEWithHmacSHA384AndAES_128
154            extends PBEKeyFactory {
155        public PBEWithHmacSHA384AndAES_128()  {
156            super("PBEWithHmacSHA384AndAES_128");
157        }
158    }
159
160    public static final class PBEWithHmacSHA512AndAES_128
161            extends PBEKeyFactory {
162        public PBEWithHmacSHA512AndAES_128()  {
163            super("PBEWithHmacSHA512AndAES_128");
164        }
165    }
166
167    public static final class PBEWithHmacSHA1AndAES_256
168            extends PBEKeyFactory {
169        public PBEWithHmacSHA1AndAES_256()  {
170            super("PBEWithHmacSHA1AndAES_256");
171        }
172    }
173
174    public static final class PBEWithHmacSHA224AndAES_256
175            extends PBEKeyFactory {
176        public PBEWithHmacSHA224AndAES_256()  {
177            super("PBEWithHmacSHA224AndAES_256");
178        }
179    }
180
181    public static final class PBEWithHmacSHA256AndAES_256
182            extends PBEKeyFactory {
183        public PBEWithHmacSHA256AndAES_256()  {
184            super("PBEWithHmacSHA256AndAES_256");
185        }
186    }
187
188    public static final class PBEWithHmacSHA384AndAES_256
189            extends PBEKeyFactory {
190        public PBEWithHmacSHA384AndAES_256()  {
191            super("PBEWithHmacSHA384AndAES_256");
192        }
193    }
194
195    public static final class PBEWithHmacSHA512AndAES_256
196            extends PBEKeyFactory {
197        public PBEWithHmacSHA512AndAES_256()  {
198            super("PBEWithHmacSHA512AndAES_256");
199        }
200    }
201
202    /**
203     * Generates a <code>SecretKey</code> object from the provided key
204     * specification (key material).
205     *
206     * @param keySpec the specification (key material) of the secret key
207     *
208     * @return the secret key
209     *
210     * @exception InvalidKeySpecException if the given key specification
211     * is inappropriate for this key factory to produce a public key.
212     */
213    protected SecretKey engineGenerateSecret(KeySpec keySpec)
214        throws InvalidKeySpecException
215    {
216        if (!(keySpec instanceof PBEKeySpec)) {
217            throw new InvalidKeySpecException("Invalid key spec");
218        }
219        return new PBEKey((PBEKeySpec)keySpec, type);
220    }
221
222    /**
223     * Returns a specification (key material) of the given key
224     * in the requested format.
225     *
226     * @param key the key
227     *
228     * @param keySpec the requested format in which the key material shall be
229     * returned
230     *
231     * @return the underlying key specification (key material) in the
232     * requested format
233     *
234     * @exception InvalidKeySpecException if the requested key specification is
235     * inappropriate for the given key, or the given key cannot be processed
236     * (e.g., the given key has an unrecognized algorithm or format).
237     */
238    protected KeySpec engineGetKeySpec(SecretKey key, Class<?> keySpecCl)
239        throws InvalidKeySpecException {
240        if ((key instanceof SecretKey)
241            && (validTypes.contains(key.getAlgorithm().toUpperCase(Locale.ENGLISH)))
242            && (key.getFormat().equalsIgnoreCase("RAW"))) {
243
244            // Check if requested key spec is amongst the valid ones
245            if ((keySpecCl != null)
246                && PBEKeySpec.class.isAssignableFrom(keySpecCl)) {
247                byte[] passwdBytes = key.getEncoded();
248                char[] passwdChars = new char[passwdBytes.length];
249                for (int i=0; i<passwdChars.length; i++)
250                    passwdChars[i] = (char) (passwdBytes[i] & 0x7f);
251                PBEKeySpec ret = new PBEKeySpec(passwdChars);
252                // password char[] was cloned in PBEKeySpec constructor,
253                // so we can zero it out here
254                java.util.Arrays.fill(passwdChars, ' ');
255                java.util.Arrays.fill(passwdBytes, (byte)0x00);
256                return ret;
257            } else {
258                throw new InvalidKeySpecException("Invalid key spec");
259            }
260        } else {
261            throw new InvalidKeySpecException("Invalid key "
262                                              + "format/algorithm");
263        }
264    }
265
266    /**
267     * Translates a <code>SecretKey</code> object, whose provider may be
268     * unknown or potentially untrusted, into a corresponding
269     * <code>SecretKey</code> object of this key factory.
270     *
271     * @param key the key whose provider is unknown or untrusted
272     *
273     * @return the translated key
274     *
275     * @exception InvalidKeyException if the given key cannot be processed by
276     * this key factory.
277     */
278    protected SecretKey engineTranslateKey(SecretKey key)
279        throws InvalidKeyException
280    {
281        try {
282            if ((key != null) &&
283                (validTypes.contains(key.getAlgorithm().toUpperCase(Locale.ENGLISH))) &&
284                (key.getFormat().equalsIgnoreCase("RAW"))) {
285
286                // Check if key originates from this factory
287                if (key instanceof com.sun.crypto.provider.PBEKey) {
288                    return key;
289                }
290
291                // Convert key to spec
292                PBEKeySpec pbeKeySpec = (PBEKeySpec)engineGetKeySpec
293                    (key, PBEKeySpec.class);
294
295                // Create key from spec, and return it
296                return engineGenerateSecret(pbeKeySpec);
297            } else {
298                throw new InvalidKeyException("Invalid key format/algorithm");
299            }
300
301        } catch (InvalidKeySpecException ikse) {
302            throw new InvalidKeyException("Cannot translate key: "
303                                          + ikse.getMessage());
304        }
305    }
306}
307