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