1 /* 2 * Copyright (c) 2002, 2017, 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 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 byte[] concat = new byte[Math.addExact(passwdBytes.length, salt.length)]; 272 System.arraycopy(passwdBytes, 0, concat, 0, passwdBytes.length); 273 System.arraycopy(salt, 0, concat, passwdBytes.length, salt.length); 274 275 // digest P || S with c iterations 276 byte[] toBeHashed = concat; 277 for (int i = 0; i < iCount; i++) { 278 md.update(toBeHashed); 279 toBeHashed = md.digest(); // this resets the digest 280 } 281 Arrays.fill(concat, (byte)0x00); 282 result = toBeHashed; 283 } else if (algo.equals("DESede")) { 284 // if the 2 salt halves are the same, invert one of them 285 int i; 286 for (i=0; i<4; i++) { 287 if (salt[i] != salt[i+4]) 288 break; 289 } 290 if (i==4) { // same, invert 1st half 291 for (i=0; i<2; i++) { 292 byte tmp = salt[i]; 293 salt[i] = salt[3-i]; 294 salt[3-i] = tmp; 295 } 296 } 297 298 // Now digest each half (concatenated with password). For each 299 // half, go through the loop as many times as specified by the 300 // iteration count parameter (inner for loop). 301 // Concatenate the output from each digest round with the 302 // password, and use the result as the input to the next digest 303 // operation. 304 byte[] toBeHashed = null; 305 result = new byte[DESedeKeySpec.DES_EDE_KEY_LEN + 306 DESConstants.DES_BLOCK_SIZE]; 307 for (i = 0; i < 2; i++) { 308 toBeHashed = new byte[salt.length/2]; 309 System.arraycopy(salt, i*(salt.length/2), toBeHashed, 0, 310 toBeHashed.length); 311 for (int j=0; j < iCount; j++) { 312 md.update(toBeHashed); 313 md.update(passwdBytes); 314 toBeHashed = md.digest(); 315 } 316 System.arraycopy(toBeHashed, 0, result, i*16, 317 toBeHashed.length); 318 } 319 } 320 // clear data used in message 321 md.reset(); 322 return result; 323 } 324 325 void init(int opmode, Key key, AlgorithmParameters params, 326 SecureRandom random) 327 throws InvalidKeyException, InvalidAlgorithmParameterException { 328 PBEParameterSpec pbeSpec = null; 329 if (params != null) { 330 try { 331 pbeSpec = params.getParameterSpec(PBEParameterSpec.class); 332 } catch (InvalidParameterSpecException ipse) { 333 throw new InvalidAlgorithmParameterException("Wrong parameter " 334 + "type: PBE " 335 + "expected"); 336 } 337 } 338 init(opmode, key, pbeSpec, random); 339 } 340 341 /** 342 * Continues a multiple-part encryption or decryption operation 343 * (depending on how this cipher was initialized), processing another data 344 * part. 345 * 346 * <p>The first <code>inputLen</code> bytes in the <code>input</code> 347 * buffer, starting at <code>inputOffset</code>, are processed, and the 348 * result is stored in a new buffer. 349 * 350 * @param input the input buffer 351 * @param inputOffset the offset in <code>input</code> where the input 352 * starts 353 * @param inputLen the input length 354 * 355 * @return the new buffer with the result 356 * 357 */ 358 byte[] update(byte[] input, int inputOffset, int inputLen) { 359 return cipher.update(input, inputOffset, inputLen); 360 } 361 362 /** 363 * Continues a multiple-part encryption or decryption operation 364 * (depending on how this cipher was initialized), processing another data 365 * part. 366 * 367 * <p>The first <code>inputLen</code> bytes in the <code>input</code> 368 * buffer, starting at <code>inputOffset</code>, are processed, and the 369 * result is stored in the <code>output</code> buffer, starting at 370 * <code>outputOffset</code>. 371 * 372 * @param input the input buffer 373 * @param inputOffset the offset in <code>input</code> where the input 374 * starts 375 * @param inputLen the input length 376 * @param output the buffer for the result 377 * @param outputOffset the offset in <code>output</code> where the result 378 * is stored 379 * 380 * @return the number of bytes stored in <code>output</code> 381 * 382 * @exception ShortBufferException if the given output buffer is too small 383 * to hold the result 384 */ 385 int update(byte[] input, int inputOffset, int inputLen, 386 byte[] output, int outputOffset) 387 throws ShortBufferException { 388 return cipher.update(input, inputOffset, inputLen, 389 output, outputOffset); 390 } 391 392 /** 393 * Encrypts or decrypts data in a single-part operation, 394 * or finishes a multiple-part operation. 395 * The data is encrypted or decrypted, depending on how this cipher was 396 * initialized. 397 * 398 * <p>The first <code>inputLen</code> bytes in the <code>input</code> 399 * buffer, starting at <code>inputOffset</code>, and any input bytes that 400 * may have been buffered during a previous <code>update</code> operation, 401 * are processed, with padding (if requested) being applied. 402 * The result is stored in a new buffer. 403 * 404 * <p>The cipher is reset to its initial state (uninitialized) after this 405 * call. 406 * 407 * @param input the input buffer 408 * @param inputOffset the offset in <code>input</code> where the input 409 * starts 410 * @param inputLen the input length 411 * 412 * @return the new buffer with the result 413 * 414 * @exception IllegalBlockSizeException if this cipher is a block cipher, 415 * no padding has been requested (only in encryption mode), and the total 416 * input length of the data processed by this cipher is not a multiple of 417 * block size 418 * @exception BadPaddingException if decrypting and padding is chosen, 419 * but the last input data does not have proper padding bytes. 420 */ 421 byte[] doFinal(byte[] input, int inputOffset, int inputLen) 422 throws IllegalBlockSizeException, BadPaddingException { 423 return cipher.doFinal(input, inputOffset, inputLen); 424 } 425 426 /** 427 * Encrypts or decrypts data in a single-part operation, 428 * or finishes a multiple-part operation. 429 * The data is encrypted or decrypted, depending on how this cipher was 430 * initialized. 431 * 432 * <p>The first <code>inputLen</code> bytes in the <code>input</code> 433 * buffer, starting at <code>inputOffset</code>, and any input bytes that 434 * may have been buffered during a previous <code>update</code> operation, 435 * are processed, with padding (if requested) being applied. 436 * The result is stored in the <code>output</code> buffer, starting at 437 * <code>outputOffset</code>. 438 * 439 * <p>The cipher is reset to its initial state (uninitialized) after this 440 * call. 441 * 442 * @param input the input buffer 443 * @param inputOffset the offset in <code>input</code> where the input 444 * starts 445 * @param inputLen the input length 446 * @param output the buffer for the result 447 * @param outputOffset the offset in <code>output</code> where the result 448 * is stored 449 * 450 * @return the number of bytes stored in <code>output</code> 451 * 452 * @exception IllegalBlockSizeException if this cipher is a block cipher, 453 * no padding has been requested (only in encryption mode), and the total 454 * input length of the data processed by this cipher is not a multiple of 455 * block size 456 * @exception ShortBufferException if the given output buffer is too small 457 * to hold the result 458 * @exception BadPaddingException if decrypting and padding is chosen, 459 * but the last input data does not have proper padding bytes. 460 */ 461 int doFinal(byte[] input, int inputOffset, int inputLen, 462 byte[] output, int outputOffset) 463 throws ShortBufferException, IllegalBlockSizeException, 464 BadPaddingException { 465 return cipher.doFinal(input, inputOffset, inputLen, 466 output, outputOffset); 467 } 468 469 /** 470 * Wrap a key. 471 * 472 * @param key the key to be wrapped. 473 * 474 * @return the wrapped key. 475 * 476 * @exception IllegalBlockSizeException if this cipher is a block 477 * cipher, no padding has been requested, and the length of the 478 * encoding of the key to be wrapped is not a 479 * multiple of the block size. 480 * 481 * @exception InvalidKeyException if it is impossible or unsafe to 482 * wrap the key with this cipher (e.g., a hardware protected key is 483 * being passed to a software only cipher). 484 */ 485 byte[] wrap(Key key) 486 throws IllegalBlockSizeException, InvalidKeyException { 487 byte[] result = null; 488 byte[] encodedKey = null; 489 try { 490 encodedKey = key.getEncoded(); 491 if ((encodedKey == null) || (encodedKey.length == 0)) { 492 throw new InvalidKeyException("Cannot get an encoding of " + 493 "the key to be wrapped"); 494 } 495 496 result = doFinal(encodedKey, 0, encodedKey.length); 497 } catch (BadPaddingException e) { 498 // Should never happen 499 } finally { 500 if (encodedKey != null) Arrays.fill(encodedKey, (byte)0x00); 501 } 502 503 return result; 504 } 505 506 /** 507 * Unwrap a previously wrapped key. 508 * 509 * @param wrappedKey the key to be unwrapped. 510 * 511 * @param wrappedKeyAlgorithm the algorithm the wrapped key is for. 512 * 513 * @param wrappedKeyType the type of the wrapped key. 514 * This is one of <code>Cipher.SECRET_KEY</code>, 515 * <code>Cipher.PRIVATE_KEY</code>, or <code>Cipher.PUBLIC_KEY</code>. 516 * 517 * @return the unwrapped key. 518 * 519 * @exception NoSuchAlgorithmException if no installed providers 520 * can create keys of type <code>wrappedKeyType</code> for the 521 * <code>wrappedKeyAlgorithm</code>. 522 * 523 * @exception InvalidKeyException if <code>wrappedKey</code> does not 524 * represent a wrapped key of type <code>wrappedKeyType</code> for 525 * the <code>wrappedKeyAlgorithm</code>. 526 */ 527 Key unwrap(byte[] wrappedKey, 528 String wrappedKeyAlgorithm, 529 int wrappedKeyType) 530 throws InvalidKeyException, NoSuchAlgorithmException { 531 byte[] encodedKey; 532 try { 533 encodedKey = doFinal(wrappedKey, 0, wrappedKey.length); 534 } catch (BadPaddingException ePadding) { 535 throw new InvalidKeyException("The wrapped key is not padded " + 536 "correctly"); 537 } catch (IllegalBlockSizeException eBlockSize) { 538 throw new InvalidKeyException("The wrapped key does not have " + 539 "the correct length"); 540 } 541 return ConstructKeys.constructKey(encodedKey, wrappedKeyAlgorithm, 542 wrappedKeyType); 543 } 544 }