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 }