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