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