1 /* 2 * Copyright (c) 2002, 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 java.util.Arrays; 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 * 38 * @author Jan Luehe 39 * 40 * 41 * @see javax.crypto.Cipher 42 */ 43 final class PBES1Core { 44 45 // the encapsulated DES cipher 46 private CipherCore cipher; 47 private MessageDigest md; 48 private int blkSize; 49 private String algo = null; 50 private byte[] salt = null; 51 private int iCount = 10; 52 53 /** 54 * Creates an instance of PBE Cipher using the specified CipherSpi 55 * instance. 56 * 57 */ PBES1Core(String cipherAlg)58 PBES1Core(String cipherAlg) throws NoSuchAlgorithmException, 59 NoSuchPaddingException { 60 algo = cipherAlg; 61 if (algo.equals("DES")) { 62 cipher = new CipherCore(new DESCrypt(), 63 DESConstants.DES_BLOCK_SIZE); 64 } else if (algo.equals("DESede")) { 65 66 cipher = new CipherCore(new DESedeCrypt(), 67 DESConstants.DES_BLOCK_SIZE); 68 } else { 69 throw new NoSuchAlgorithmException("No Cipher implementation " + 70 "for PBEWithMD5And" + algo); 71 } 72 cipher.setMode("CBC"); 73 cipher.setPadding("PKCS5Padding"); 74 // get instance of MD5 75 md = MessageDigest.getInstance("MD5"); 76 } 77 78 /** 79 * Sets the mode of this cipher. This algorithm can only be run in CBC 80 * mode. 81 * 82 * @param mode the cipher mode 83 * 84 * @exception NoSuchAlgorithmException if the requested cipher mode is 85 * invalid 86 */ setMode(String mode)87 void setMode(String mode) throws NoSuchAlgorithmException { 88 cipher.setMode(mode); 89 } 90 91 /** 92 * Sets the padding mechanism of this cipher. This algorithm only uses 93 * PKCS #5 padding. 94 * 95 * @param padding the padding mechanism 96 * 97 * @exception NoSuchPaddingException if the requested padding mechanism 98 * is invalid 99 */ setPadding(String paddingScheme)100 void setPadding(String paddingScheme) throws NoSuchPaddingException { 101 cipher.setPadding(paddingScheme); 102 } 103 104 /** 105 * Returns the block size (in bytes). 106 * 107 * @return the block size (in bytes) 108 */ getBlockSize()109 int getBlockSize() { 110 return DESConstants.DES_BLOCK_SIZE; 111 } 112 113 /** 114 * Returns the length in bytes that an output buffer would need to be in 115 * order to hold the result of the next <code>update</code> or 116 * <code>doFinal</code> operation, given the input length 117 * <code>inputLen</code> (in bytes). 118 * 119 * <p>This call takes into account any unprocessed (buffered) data from a 120 * previous <code>update</code> call, and padding. 121 * 122 * <p>The actual output length of the next <code>update</code> or 123 * <code>doFinal</code> call may be smaller than the length returned by 124 * this method. 125 * 126 * @param inputLen the input length (in bytes) 127 * 128 * @return the required output buffer size (in bytes) 129 * 130 */ getOutputSize(int inputLen)131 int getOutputSize(int inputLen) { 132 return cipher.getOutputSize(inputLen); 133 } 134 135 /** 136 * Returns the initialization vector (IV) in a new buffer. 137 * 138 * <p> This is useful in the case where a random IV has been created 139 * (see <a href = "#init">init</a>), 140 * or in the context of password-based encryption or 141 * decryption, where the IV is derived from a user-supplied password. 142 * 143 * @return the initialization vector in a new buffer, or null if the 144 * underlying algorithm does not use an IV, or if the IV has not yet 145 * been set. 146 */ getIV()147 byte[] getIV() { 148 return cipher.getIV(); 149 } 150 151 /** 152 * Returns the parameters used with this cipher. 153 * 154 * <p>The returned parameters may be the same that were used to initialize 155 * this cipher, or may contain the default set of parameters or a set of 156 * randomly generated parameters used by the underlying cipher 157 * implementation (provided that the underlying cipher implementation 158 * uses a default set of parameters or creates new parameters if it needs 159 * parameters but was not initialized with any). 160 * 161 * @return the parameters used with this cipher, or null if this cipher 162 * does not use any parameters. 163 */ getParameters()164 AlgorithmParameters getParameters() { 165 AlgorithmParameters params = null; 166 if (salt == null) { 167 salt = new byte[8]; 168 SunJCE.getRandom().nextBytes(salt); 169 } 170 PBEParameterSpec pbeSpec = new PBEParameterSpec(salt, iCount); 171 try { 172 params = AlgorithmParameters.getInstance("PBEWithMD5And" + 173 (algo.equalsIgnoreCase("DES")? "DES":"TripleDES"), 174 SunJCE.getInstance()); 175 params.init(pbeSpec); 176 } catch (NoSuchAlgorithmException nsae) { 177 // should never happen 178 throw new RuntimeException("SunJCE called, but not configured"); 179 } catch (InvalidParameterSpecException ipse) { 180 // should never happen 181 throw new RuntimeException("PBEParameterSpec not supported"); 182 } 183 return params; 184 } 185 186 /** 187 * Initializes this cipher with a key, a set of 188 * algorithm parameters, and a source of randomness. 189 * The cipher is initialized for one of the following four operations: 190 * encryption, decryption, key wrapping or key unwrapping, depending on 191 * the value of <code>opmode</code>. 192 * 193 * <p>If this cipher (including its underlying feedback or padding scheme) 194 * requires any random bytes, it will get them from <code>random</code>. 195 * 196 * @param opmode the operation mode of this cipher (this is one of 197 * the following: 198 * <code>ENCRYPT_MODE</code>, <code>DECRYPT_MODE</code>), 199 * <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>) 200 * @param key the encryption key 201 * @param params the algorithm parameters 202 * @param random the source of randomness 203 * 204 * @exception InvalidKeyException if the given key is inappropriate for 205 * initializing this cipher 206 * @exception InvalidAlgorithmParameterException if the given algorithm 207 * parameters are inappropriate for this cipher 208 */ init(int opmode, Key key, AlgorithmParameterSpec params, SecureRandom random)209 void init(int opmode, Key key, AlgorithmParameterSpec params, 210 SecureRandom random) 211 throws InvalidKeyException, InvalidAlgorithmParameterException { 212 if (((opmode == Cipher.DECRYPT_MODE) || 213 (opmode == Cipher.UNWRAP_MODE)) && (params == null)) { 214 throw new InvalidAlgorithmParameterException("Parameters " 215 + "missing"); 216 } 217 if (key == null) { 218 throw new InvalidKeyException("Null key"); 219 } 220 221 byte[] derivedKey; 222 byte[] passwdBytes = key.getEncoded(); 223 try { 224 if ((passwdBytes == null) || 225 !(key.getAlgorithm().regionMatches(true, 0, "PBE", 0, 3))) { 226 throw new InvalidKeyException("Missing password"); 227 } 228 229 if (params == null) { 230 // create random salt and use default iteration count 231 salt = new byte[8]; 232 random.nextBytes(salt); 233 } else { 234 if (!(params instanceof PBEParameterSpec)) { 235 throw new InvalidAlgorithmParameterException 236 ("Wrong parameter type: PBE expected"); 237 } 238 salt = ((PBEParameterSpec) params).getSalt(); 239 // salt must be 8 bytes long (by definition) 240 if (salt.length != 8) { 241 throw new InvalidAlgorithmParameterException 242 ("Salt must be 8 bytes long"); 243 } 244 iCount = ((PBEParameterSpec) params).getIterationCount(); 245 if (iCount <= 0) { 246 throw new InvalidAlgorithmParameterException 247 ("IterationCount must be a positive number"); 248 } 249 } 250 derivedKey = deriveCipherKey(passwdBytes); 251 } finally { 252 if (passwdBytes != null) Arrays.fill(passwdBytes, (byte) 0x00); 253 } 254 // use all but the last 8 bytes as the key value 255 SecretKeySpec cipherKey = new SecretKeySpec(derivedKey, 0, 256 derivedKey.length-8, algo); 257 // use the last 8 bytes as the IV 258 IvParameterSpec ivSpec = new IvParameterSpec(derivedKey, 259 derivedKey.length-8, 260 8); 261 // initialize the underlying cipher 262 cipher.init(opmode, cipherKey, ivSpec, random); 263 } 264 deriveCipherKey(byte[] passwdBytes)265 private byte[] deriveCipherKey(byte[] passwdBytes) { 266 267 byte[] result = null; 268 269 if (algo.equals("DES")) { 270 // P || S (password concatenated with salt) 271 md.update(passwdBytes); 272 md.update(salt); 273 // digest P || S with iCount iterations 274 // first iteration 275 byte[] toBeHashed = md.digest(); // this resets the digest 276 // remaining (iCount - 1) iterations 277 for (int i = 1; i < iCount; ++i) { 278 md.update(toBeHashed); 279 try { 280 md.digest(toBeHashed, 0, toBeHashed.length); 281 } catch (DigestException e) { 282 throw new ProviderException("Internal error", e); 283 } 284 } 285 result = toBeHashed; 286 } else if (algo.equals("DESede")) { 287 // if the 2 salt halves are the same, invert one of them 288 int i; 289 for (i=0; i<4; i++) { 290 if (salt[i] != salt[i+4]) 291 break; 292 } 293 if (i==4) { // same, invert 1st half 294 for (i=0; i<2; i++) { 295 byte tmp = salt[i]; 296 salt[i] = salt[3-i]; 297 salt[3-i] = tmp; 298 } 299 } 300 301 // Now digest each half (concatenated with password). For each 302 // half, go through the loop as many times as specified by the 303 // iteration count parameter (inner for loop). 304 // Concatenate the output from each digest round with the 305 // password, and use the result as the input to the next digest 306 // operation. 307 byte[] toBeHashed = null; 308 result = new byte[DESedeKeySpec.DES_EDE_KEY_LEN + 309 DESConstants.DES_BLOCK_SIZE]; 310 for (i = 0; i < 2; i++) { 311 // first iteration 312 md.update(salt, i * (salt.length / 2), salt.length / 2); 313 md.update(passwdBytes); 314 toBeHashed = md.digest(); 315 // remaining (iCount - 1) iterations 316 for (int j = 1; j < iCount; ++j) { 317 md.update(toBeHashed); 318 md.update(passwdBytes); 319 try { 320 md.digest(toBeHashed, 0, toBeHashed.length); 321 } catch (DigestException e) { 322 throw new ProviderException("Internal error", e); 323 } 324 } 325 System.arraycopy(toBeHashed, 0, result, i*16, 326 toBeHashed.length); 327 } 328 } 329 // clear data used in message 330 md.reset(); 331 return result; 332 } 333 init(int opmode, Key key, AlgorithmParameters params, SecureRandom random)334 void init(int opmode, Key key, AlgorithmParameters params, 335 SecureRandom random) 336 throws InvalidKeyException, InvalidAlgorithmParameterException { 337 PBEParameterSpec pbeSpec = null; 338 if (params != null) { 339 try { 340 pbeSpec = params.getParameterSpec(PBEParameterSpec.class); 341 } catch (InvalidParameterSpecException ipse) { 342 throw new InvalidAlgorithmParameterException("Wrong parameter " 343 + "type: PBE " 344 + "expected"); 345 } 346 } 347 init(opmode, key, pbeSpec, random); 348 } 349 350 /** 351 * Continues a multiple-part encryption or decryption operation 352 * (depending on how this cipher was initialized), processing another data 353 * part. 354 * 355 * <p>The first <code>inputLen</code> bytes in the <code>input</code> 356 * buffer, starting at <code>inputOffset</code>, are processed, and the 357 * result is stored in a new buffer. 358 * 359 * @param input the input buffer 360 * @param inputOffset the offset in <code>input</code> where the input 361 * starts 362 * @param inputLen the input length 363 * 364 * @return the new buffer with the result 365 * 366 */ update(byte[] input, int inputOffset, int inputLen)367 byte[] update(byte[] input, int inputOffset, int inputLen) { 368 return cipher.update(input, inputOffset, inputLen); 369 } 370 371 /** 372 * Continues a multiple-part encryption or decryption operation 373 * (depending on how this cipher was initialized), processing another data 374 * part. 375 * 376 * <p>The first <code>inputLen</code> bytes in the <code>input</code> 377 * buffer, starting at <code>inputOffset</code>, are processed, and the 378 * result is stored in the <code>output</code> buffer, starting at 379 * <code>outputOffset</code>. 380 * 381 * @param input the input buffer 382 * @param inputOffset the offset in <code>input</code> where the input 383 * starts 384 * @param inputLen the input length 385 * @param output the buffer for the result 386 * @param outputOffset the offset in <code>output</code> where the result 387 * is stored 388 * 389 * @return the number of bytes stored in <code>output</code> 390 * 391 * @exception ShortBufferException if the given output buffer is too small 392 * to hold the result 393 */ update(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset)394 int update(byte[] input, int inputOffset, int inputLen, 395 byte[] output, int outputOffset) 396 throws ShortBufferException { 397 return cipher.update(input, inputOffset, inputLen, 398 output, outputOffset); 399 } 400 401 /** 402 * Encrypts or decrypts data in a single-part operation, 403 * or finishes a multiple-part operation. 404 * The data is encrypted or decrypted, depending on how this cipher was 405 * initialized. 406 * 407 * <p>The first <code>inputLen</code> bytes in the <code>input</code> 408 * buffer, starting at <code>inputOffset</code>, and any input bytes that 409 * may have been buffered during a previous <code>update</code> operation, 410 * are processed, with padding (if requested) being applied. 411 * The result is stored in a new buffer. 412 * 413 * <p>The cipher is reset to its initial state (uninitialized) after this 414 * call. 415 * 416 * @param input the input buffer 417 * @param inputOffset the offset in <code>input</code> where the input 418 * starts 419 * @param inputLen the input length 420 * 421 * @return the new buffer with the result 422 * 423 * @exception IllegalBlockSizeException if this cipher is a block cipher, 424 * no padding has been requested (only in encryption mode), and the total 425 * input length of the data processed by this cipher is not a multiple of 426 * block size 427 * @exception BadPaddingException if decrypting and padding is chosen, 428 * but the last input data does not have proper padding bytes. 429 */ doFinal(byte[] input, int inputOffset, int inputLen)430 byte[] doFinal(byte[] input, int inputOffset, int inputLen) 431 throws IllegalBlockSizeException, BadPaddingException { 432 return cipher.doFinal(input, inputOffset, inputLen); 433 } 434 435 /** 436 * Encrypts or decrypts data in a single-part operation, 437 * or finishes a multiple-part operation. 438 * The data is encrypted or decrypted, depending on how this cipher was 439 * initialized. 440 * 441 * <p>The first <code>inputLen</code> bytes in the <code>input</code> 442 * buffer, starting at <code>inputOffset</code>, and any input bytes that 443 * may have been buffered during a previous <code>update</code> operation, 444 * are processed, with padding (if requested) being applied. 445 * The result is stored in the <code>output</code> buffer, starting at 446 * <code>outputOffset</code>. 447 * 448 * <p>The cipher is reset to its initial state (uninitialized) after this 449 * call. 450 * 451 * @param input the input buffer 452 * @param inputOffset the offset in <code>input</code> where the input 453 * starts 454 * @param inputLen the input length 455 * @param output the buffer for the result 456 * @param outputOffset the offset in <code>output</code> where the result 457 * is stored 458 * 459 * @return the number of bytes stored in <code>output</code> 460 * 461 * @exception IllegalBlockSizeException if this cipher is a block cipher, 462 * no padding has been requested (only in encryption mode), and the total 463 * input length of the data processed by this cipher is not a multiple of 464 * block size 465 * @exception ShortBufferException if the given output buffer is too small 466 * to hold the result 467 * @exception BadPaddingException if decrypting and padding is chosen, 468 * but the last input data does not have proper padding bytes. 469 */ doFinal(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset)470 int doFinal(byte[] input, int inputOffset, int inputLen, 471 byte[] output, int outputOffset) 472 throws ShortBufferException, IllegalBlockSizeException, 473 BadPaddingException { 474 return cipher.doFinal(input, inputOffset, inputLen, 475 output, outputOffset); 476 } 477 478 /** 479 * Wrap a key. 480 * 481 * @param key the key to be wrapped. 482 * 483 * @return the wrapped key. 484 * 485 * @exception IllegalBlockSizeException if this cipher is a block 486 * cipher, no padding has been requested, and the length of the 487 * encoding of the key to be wrapped is not a 488 * multiple of the block size. 489 * 490 * @exception InvalidKeyException if it is impossible or unsafe to 491 * wrap the key with this cipher (e.g., a hardware protected key is 492 * being passed to a software only cipher). 493 */ wrap(Key key)494 byte[] wrap(Key key) 495 throws IllegalBlockSizeException, InvalidKeyException { 496 byte[] result = null; 497 byte[] encodedKey = null; 498 try { 499 encodedKey = key.getEncoded(); 500 if ((encodedKey == null) || (encodedKey.length == 0)) { 501 throw new InvalidKeyException("Cannot get an encoding of " + 502 "the key to be wrapped"); 503 } 504 505 result = doFinal(encodedKey, 0, encodedKey.length); 506 } catch (BadPaddingException e) { 507 // Should never happen 508 } finally { 509 if (encodedKey != null) Arrays.fill(encodedKey, (byte)0x00); 510 } 511 512 return result; 513 } 514 515 /** 516 * Unwrap a previously wrapped key. 517 * 518 * @param wrappedKey the key to be unwrapped. 519 * 520 * @param wrappedKeyAlgorithm the algorithm the wrapped key is for. 521 * 522 * @param wrappedKeyType the type of the wrapped key. 523 * This is one of <code>Cipher.SECRET_KEY</code>, 524 * <code>Cipher.PRIVATE_KEY</code>, or <code>Cipher.PUBLIC_KEY</code>. 525 * 526 * @return the unwrapped key. 527 * 528 * @exception NoSuchAlgorithmException if no installed providers 529 * can create keys of type <code>wrappedKeyType</code> for the 530 * <code>wrappedKeyAlgorithm</code>. 531 * 532 * @exception InvalidKeyException if <code>wrappedKey</code> does not 533 * represent a wrapped key of type <code>wrappedKeyType</code> for 534 * the <code>wrappedKeyAlgorithm</code>. 535 */ unwrap(byte[] wrappedKey, String wrappedKeyAlgorithm, int wrappedKeyType)536 Key unwrap(byte[] wrappedKey, 537 String wrappedKeyAlgorithm, 538 int wrappedKeyType) 539 throws InvalidKeyException, NoSuchAlgorithmException { 540 byte[] encodedKey; 541 try { 542 encodedKey = doFinal(wrappedKey, 0, wrappedKey.length); 543 } catch (BadPaddingException ePadding) { 544 throw new InvalidKeyException("The wrapped key is not padded " + 545 "correctly"); 546 } catch (IllegalBlockSizeException eBlockSize) { 547 throw new InvalidKeyException("The wrapped key does not have " + 548 "the correct length"); 549 } 550 return ConstructKeys.constructKey(encodedKey, wrappedKeyAlgorithm, 551 wrappedKeyType); 552 } 553 } 554