1 /*
2  * Copyright (c) 2002, 2020, 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 paddingScheme 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