1 /*
2  * Copyright (c) 1997, 2013, 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.io.UnsupportedEncodingException;
29 import java.security.*;
30 import java.security.spec.*;
31 import javax.crypto.*;
32 import javax.crypto.spec.*;
33 
34 /**
35  * This class represents password-based encryption as defined by the PKCS #5
36  * standard.
37  * The particular algorithm implemented is pbeWithMD5AndDES-CBC.
38  * Padding is done as described in PKCS #5.
39  *
40  * @author Jan Luehe
41  *
42  *
43  * @see javax.crypto.Cipher
44  */
45 public final class PBEWithMD5AndDESCipher extends CipherSpi {
46 
47     // the encapsulated DES cipher
48     private PBES1Core core;
49 
50     /**
51      * Creates an instance of this cipher, and initializes its mode (CBC) and
52      * padding (PKCS5).
53      *
54      * @exception NoSuchAlgorithmException if the required cipher mode (CBC) is
55      * unavailable
56      * @exception NoSuchPaddingException if the required padding mechanism
57      * (PKCS5Padding) is unavailable
58      */
PBEWithMD5AndDESCipher()59     public PBEWithMD5AndDESCipher()
60         throws NoSuchAlgorithmException, NoSuchPaddingException {
61         core = new PBES1Core("DES");
62     }
63 
64     /**
65      * Sets the mode of this cipher. This algorithm can only be run in CBC
66      * mode.
67      *
68      * @param mode the cipher mode
69      *
70      * @exception NoSuchAlgorithmException if the requested cipher mode is
71      * invalid
72      */
engineSetMode(String mode)73     protected void engineSetMode(String mode) throws NoSuchAlgorithmException {
74         if ((mode != null) && (!mode.equalsIgnoreCase("CBC"))) {
75             throw new NoSuchAlgorithmException("Invalid cipher mode: " + mode);
76         }
77     }
78 
79      /**
80      * Sets the padding mechanism of this cipher. This algorithm only uses
81      * PKCS #5 padding.
82      *
83      * @param paddingScheme the padding mechanism
84      *
85      * @exception NoSuchPaddingException if the requested padding mechanism
86      * is invalid
87      */
engineSetPadding(String paddingScheme)88     protected void engineSetPadding(String paddingScheme)
89         throws NoSuchPaddingException
90     {
91         if ((paddingScheme != null) &&
92             (!paddingScheme.equalsIgnoreCase("PKCS5Padding"))) {
93             throw new NoSuchPaddingException("Invalid padding scheme: " +
94                                              paddingScheme);
95         }
96     }
97 
98     /**
99      * Returns the block size (in bytes).
100      *
101      * @return the block size (in bytes)
102      */
engineGetBlockSize()103     protected int engineGetBlockSize() {
104         return core.getBlockSize();
105     }
106 
107     /**
108      * Returns the length in bytes that an output buffer would need to be in
109      * order to hold the result of the next <code>update</code> or
110      * <code>doFinal</code> operation, given the input length
111      * <code>inputLen</code> (in bytes).
112      *
113      * <p>This call takes into account any unprocessed (buffered) data from a
114      * previous <code>update</code> call, and padding.
115      *
116      * <p>The actual output length of the next <code>update</code> or
117      * <code>doFinal</code> call may be smaller than the length returned by
118      * this method.
119      *
120      * @param inputLen the input length (in bytes)
121      *
122      * @return the required output buffer size (in bytes)
123      *
124      */
engineGetOutputSize(int inputLen)125     protected int engineGetOutputSize(int inputLen) {
126         return core.getOutputSize(inputLen);
127     }
128 
129     /**
130      * Returns the initialization vector (IV) in a new buffer.
131      *
132      * <p> This is useful in the case where a random IV has been created
133      * (see <a href = "#init">init</a>),
134      * or in the context of password-based encryption or
135      * decryption, where the IV is derived from a user-supplied password.
136      *
137      * @return the initialization vector in a new buffer, or null if the
138      * underlying algorithm does not use an IV, or if the IV has not yet
139      * been set.
140      */
engineGetIV()141     protected byte[] engineGetIV() {
142         return core.getIV();
143     }
144 
145     /**
146      * Returns the parameters used with this cipher.
147      *
148      * <p>The returned parameters may be the same that were used to initialize
149      * this cipher, or may contain the default set of parameters or a set of
150      * randomly generated parameters used by the underlying cipher
151      * implementation (provided that the underlying cipher implementation
152      * uses a default set of parameters or creates new parameters if it needs
153      * parameters but was not initialized with any).
154      *
155      * @return the parameters used with this cipher, or null if this cipher
156      * does not use any parameters.
157      */
engineGetParameters()158     protected AlgorithmParameters engineGetParameters() {
159         return core.getParameters();
160     }
161 
162     /**
163      * Initializes this cipher with a key and a source
164      * of randomness.
165      * The cipher is initialized for one of the following four operations:
166      * encryption, decryption, key wrapping or key unwrapping, depending on
167      * the value of <code>opmode</code>.
168      *
169      * <p>If this cipher (including its underlying feedback or padding scheme)
170      * requires any random bytes, it will get them from <code>random</code>.
171      *
172      * @param opmode the operation mode of this cipher (this is one of
173      * the following:
174      * <code>ENCRYPT_MODE</code>, <code>DECRYPT_MODE</code>),
175      * <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>)
176      * @param key the encryption key
177      * @param random the source of randomness
178      *
179      * @exception InvalidKeyException if the given key is inappropriate for
180      * initializing this cipher
181      */
engineInit(int opmode, Key key, SecureRandom random)182     protected void engineInit(int opmode, Key key, SecureRandom random)
183         throws InvalidKeyException {
184         try {
185             engineInit(opmode, key, (AlgorithmParameterSpec) null, random);
186         } catch (InvalidAlgorithmParameterException ie) {
187             InvalidKeyException ike =
188                 new InvalidKeyException("requires PBE parameters");
189             ike.initCause(ie);
190             throw ike;
191         }
192     }
193 
194     /**
195      * Initializes this cipher with a key, a set of
196      * algorithm parameters, and a source of randomness.
197      * The cipher is initialized for one of the following four operations:
198      * encryption, decryption, key wrapping or key unwrapping, depending on
199      * the value of <code>opmode</code>.
200      *
201      * <p>If this cipher (including its underlying feedback or padding scheme)
202      * requires any random bytes, it will get them from <code>random</code>.
203      *
204      * @param opmode the operation mode of this cipher (this is one of
205      * the following:
206      * <code>ENCRYPT_MODE</code>, <code>DECRYPT_MODE</code>),
207      * <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>)
208      * @param key the encryption key
209      * @param params the algorithm parameters
210      * @param random the source of randomness
211      *
212      * @exception InvalidKeyException if the given key is inappropriate for
213      * initializing this cipher
214      * @exception InvalidAlgorithmParameterException if the given algorithm
215      * parameters are inappropriate for this cipher
216      */
engineInit(int opmode, Key key, AlgorithmParameterSpec params, SecureRandom random)217     protected void engineInit(int opmode, Key key,
218                               AlgorithmParameterSpec params,
219                               SecureRandom random)
220         throws InvalidKeyException, InvalidAlgorithmParameterException {
221         core.init(opmode, key, params, random);
222     }
223 
engineInit(int opmode, Key key, AlgorithmParameters params, SecureRandom random)224     protected void engineInit(int opmode, Key key,
225                               AlgorithmParameters params,
226                               SecureRandom random)
227         throws InvalidKeyException, InvalidAlgorithmParameterException {
228         core.init(opmode, key, params, random);
229     }
230 
231     /**
232      * Continues a multiple-part encryption or decryption operation
233      * (depending on how this cipher was initialized), processing another data
234      * part.
235      *
236      * <p>The first <code>inputLen</code> bytes in the <code>input</code>
237      * buffer, starting at <code>inputOffset</code>, are processed, and the
238      * result is stored in a new buffer.
239      *
240      * @param input the input buffer
241      * @param inputOffset the offset in <code>input</code> where the input
242      * starts
243      * @param inputLen the input length
244      *
245      * @return the new buffer with the result
246      *
247      */
engineUpdate(byte[] input, int inputOffset, int inputLen)248     protected byte[] engineUpdate(byte[] input, int inputOffset, int inputLen)
249     {
250         return core.update(input, inputOffset, inputLen);
251     }
252 
253     /**
254      * Continues a multiple-part encryption or decryption operation
255      * (depending on how this cipher was initialized), processing another data
256      * part.
257      *
258      * <p>The first <code>inputLen</code> bytes in the <code>input</code>
259      * buffer, starting at <code>inputOffset</code>, are processed, and the
260      * result is stored in the <code>output</code> buffer, starting at
261      * <code>outputOffset</code>.
262      *
263      * @param input the input buffer
264      * @param inputOffset the offset in <code>input</code> where the input
265      * starts
266      * @param inputLen the input length
267      * @param output the buffer for the result
268      * @param outputOffset the offset in <code>output</code> where the result
269      * is stored
270      *
271      * @return the number of bytes stored in <code>output</code>
272      *
273      * @exception ShortBufferException if the given output buffer is too small
274      * to hold the result
275      */
engineUpdate(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset)276     protected int engineUpdate(byte[] input, int inputOffset, int inputLen,
277                                byte[] output, int outputOffset)
278         throws ShortBufferException
279     {
280         return core.update(input, inputOffset, inputLen,
281                            output, outputOffset);
282     }
283 
284     /**
285      * Encrypts or decrypts data in a single-part operation,
286      * or finishes a multiple-part operation.
287      * The data is encrypted or decrypted, depending on how this cipher was
288      * initialized.
289      *
290      * <p>The first <code>inputLen</code> bytes in the <code>input</code>
291      * buffer, starting at <code>inputOffset</code>, and any input bytes that
292      * may have been buffered during a previous <code>update</code> operation,
293      * are processed, with padding (if requested) being applied.
294      * The result is stored in a new buffer.
295      *
296      * <p>The cipher is reset to its initial state (uninitialized) after this
297      * call.
298      *
299      * @param input the input buffer
300      * @param inputOffset the offset in <code>input</code> where the input
301      * starts
302      * @param inputLen the input length
303      *
304      * @return the new buffer with the result
305      *
306      * @exception IllegalBlockSizeException if this cipher is a block cipher,
307      * no padding has been requested (only in encryption mode), and the total
308      * input length of the data processed by this cipher is not a multiple of
309      * block size
310      * @exception BadPaddingException if decrypting and padding is chosen,
311      * but the last input data does not have proper padding bytes.
312      */
engineDoFinal(byte[] input, int inputOffset, int inputLen)313     protected byte[] engineDoFinal(byte[] input, int inputOffset, int inputLen)
314         throws IllegalBlockSizeException, BadPaddingException
315     {
316         return core.doFinal(input, inputOffset, inputLen);
317     }
318 
319     /**
320      * Encrypts or decrypts data in a single-part operation,
321      * or finishes a multiple-part operation.
322      * The data is encrypted or decrypted, depending on how this cipher was
323      * initialized.
324      *
325      * <p>The first <code>inputLen</code> bytes in the <code>input</code>
326      * buffer, starting at <code>inputOffset</code>, and any input bytes that
327      * may have been buffered during a previous <code>update</code> operation,
328      * are processed, with padding (if requested) being applied.
329      * The result is stored in the <code>output</code> buffer, starting at
330      * <code>outputOffset</code>.
331      *
332      * <p>The cipher is reset to its initial state (uninitialized) after this
333      * call.
334      *
335      * @param input the input buffer
336      * @param inputOffset the offset in <code>input</code> where the input
337      * starts
338      * @param inputLen the input length
339      * @param output the buffer for the result
340      * @param outputOffset the offset in <code>output</code> where the result
341      * is stored
342      *
343      * @return the number of bytes stored in <code>output</code>
344      *
345      * @exception IllegalBlockSizeException if this cipher is a block cipher,
346      * no padding has been requested (only in encryption mode), and the total
347      * input length of the data processed by this cipher is not a multiple of
348      * block size
349      * @exception ShortBufferException if the given output buffer is too small
350      * to hold the result
351      * @exception BadPaddingException if decrypting and padding is chosen,
352      * but the last input data does not have proper padding bytes.
353      */
engineDoFinal(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset)354     protected int engineDoFinal(byte[] input, int inputOffset, int inputLen,
355                                 byte[] output, int outputOffset)
356         throws ShortBufferException, IllegalBlockSizeException,
357                BadPaddingException
358     {
359         return core.doFinal(input, inputOffset, inputLen,
360                             output, outputOffset);
361     }
362 
363     /**
364      *  Returns the key size of the given key object.
365      *
366      * @param key the key object.
367      *
368      * @return the key size of the given key object.
369      *
370      * @exception InvalidKeyException if <code>key</code> is invalid.
371      */
engineGetKeySize(Key key)372     protected int engineGetKeySize(Key key) throws InvalidKeyException {
373         // Always returns 56 since the encryption key
374         // is a DES key.
375         return 56;
376     }
377 
378     /**
379      * Wrap a key.
380      *
381      * @param key the key to be wrapped.
382      *
383      * @return the wrapped key.
384      *
385      * @exception IllegalBlockSizeException if this cipher is a block
386      * cipher, no padding has been requested, and the length of the
387      * encoding of the key to be wrapped is not a
388      * multiple of the block size.
389      *
390      * @exception InvalidKeyException if it is impossible or unsafe to
391      * wrap the key with this cipher (e.g., a hardware protected key is
392      * being passed to a software only cipher).
393      */
engineWrap(Key key)394     protected byte[] engineWrap(Key key)
395         throws IllegalBlockSizeException, InvalidKeyException {
396         return core.wrap(key);
397     }
398 
399     /**
400      * Unwrap a previously wrapped key.
401      *
402      * @param wrappedKey the key to be unwrapped.
403      *
404      * @param wrappedKeyAlgorithm the algorithm the wrapped key is for.
405      *
406      * @param wrappedKeyType the type of the wrapped key.
407      * This is one of <code>Cipher.SECRET_KEY</code>,
408      * <code>Cipher.PRIVATE_KEY</code>, or <code>Cipher.PUBLIC_KEY</code>.
409      *
410      * @return the unwrapped key.
411      *
412      * @exception NoSuchAlgorithmException if no installed providers
413      * can create keys of type <code>wrappedKeyType</code> for the
414      * <code>wrappedKeyAlgorithm</code>.
415      *
416      * @exception InvalidKeyException if <code>wrappedKey</code> does not
417      * represent a wrapped key of type <code>wrappedKeyType</code> for
418      * the <code>wrappedKeyAlgorithm</code>.
419      */
engineUnwrap(byte[] wrappedKey, String wrappedKeyAlgorithm, int wrappedKeyType)420     protected Key engineUnwrap(byte[] wrappedKey,
421                                String wrappedKeyAlgorithm,
422                                int wrappedKeyType)
423         throws InvalidKeyException, NoSuchAlgorithmException {
424         byte[] encodedKey;
425 
426         return core.unwrap(wrappedKey, wrappedKeyAlgorithm,
427                            wrappedKeyType);
428     }
429 }
430