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