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