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