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 
26 package com.sun.crypto.provider;
27 
28 import java.security.*;
29 import java.security.spec.*;
30 import javax.crypto.*;
31 import javax.crypto.spec.*;
32 import 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 
49 public 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      */
DESCipher()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      */
engineSetMode(String mode)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      */
engineSetPadding(String paddingScheme)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      */
engineGetBlockSize()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      */
engineGetOutputSize(int inputLen)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      */
engineGetIV()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      */
engineGetParameters()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      */
engineInit(int opmode, Key key, SecureRandom random)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      */
engineInit(int opmode, Key key, AlgorithmParameterSpec params, SecureRandom random)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 
engineInit(int opmode, Key key, AlgorithmParameters params, SecureRandom random)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      */
engineUpdate(byte[] input, int inputOffset, int inputLen)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      */
engineUpdate(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset)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      */
engineDoFinal(byte[] input, int inputOffset, int inputLen)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      */
engineDoFinal(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset)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      */
engineGetKeySize(Key key)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      */
engineWrap(Key key)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      */
engineUnwrap(byte[] wrappedKey, String wrappedKeyAlgorithm, int wrappedKeyType)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