1 /*
2  * Copyright (c) 2003, 2016, 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.math.BigInteger;
29 import java.security.*;
30 import java.security.spec.*;
31 import java.util.Arrays;
32 import javax.crypto.*;
33 import javax.crypto.spec.*;
34 
35 /**
36  * This class implements password-base encryption algorithm with
37  * SHA1 digest and the following Ciphers (in CBC mode, where applicable):
38  * - DESede cipher and
39  * - RC2 Cipher with 40-bit or 128-bit effective key length and
40  * - RC4 Cipher with 40-bit or 128-bit effective key length
41  * as defined by PKCS #12 version 1.0 standard.
42  *
43  * @author Valerie Peng
44  * @see javax.crypto.CipherSpi
45  */
46 final class PKCS12PBECipherCore {
47 
48     // TBD: replace CipherCore with a CipherSpi object to simplify maintenance
49 
50     private CipherCore cipher;
51     private int blockSize;
52     private int keySize;
53     private int keyLength; // in bits
54     private String algo = null;
55     private String pbeAlgo = null;
56     private byte[] salt = null;
57     private int iCount = 0;
58 
59     private static final int DEFAULT_SALT_LENGTH = 20;
60     private static final int DEFAULT_COUNT = 1024;
61 
62     static final int CIPHER_KEY = 1;
63     static final int CIPHER_IV = 2;
64     static final int MAC_KEY = 3;
65 
66     // Uses default hash algorithm (SHA-1)
derive(char[] chars, byte[] salt, int ic, int n, int type)67     static byte[] derive(char[] chars, byte[] salt,
68                          int ic, int n, int type) {
69         return derive(chars, salt, ic, n, type, "SHA-1", 64);
70     }
71 
72     // Uses supplied hash algorithm
derive(char[] chars, byte[] salt, int ic, int n, int type, String hashAlgo, int blockLength)73     static byte[] derive(char[] chars, byte[] salt, int ic, int n, int type,
74         String hashAlgo, int blockLength) {
75 
76         // Add in trailing NULL terminator.  Special case:
77         // no terminator if password is "\0".
78         int length = chars.length*2;
79         if (length == 2 && chars[0] == 0) {
80             chars = new char[0];
81             length = 0;
82         } else {
83             length += 2;
84         }
85 
86         byte[] passwd = new byte[length];
87         for (int i = 0, j = 0; i < chars.length; i++, j+=2) {
88             passwd[j] = (byte) ((chars[i] >>> 8) & 0xFF);
89             passwd[j+1] = (byte) (chars[i] & 0xFF);
90         }
91         byte[] key = new byte[n];
92 
93         try {
94             MessageDigest sha = MessageDigest.getInstance(hashAlgo);
95 
96             int v = blockLength;
97             int u = sha.getDigestLength();
98             int c = roundup(n, u) / u;
99             byte[] D = new byte[v];
100             int s = roundup(salt.length, v);
101             int p = roundup(passwd.length, v);
102             byte[] I = new byte[s + p];
103 
104             Arrays.fill(D, (byte)type);
105             concat(salt, I, 0, s);
106             concat(passwd, I, s, p);
107             Arrays.fill(passwd, (byte) 0x00);
108 
109             byte[] Ai;
110             byte[] B = new byte[v];
111             byte[] tmp = new byte[v];
112 
113             int i = 0;
114             for (; ; i++, n -= u) {
115                 sha.update(D);
116                 sha.update(I);
117                 Ai = sha.digest();
118                 for (int r = 1; r < ic; r++)
119                     Ai = sha.digest(Ai);
120                 System.arraycopy(Ai, 0, key, u * i, Math.min(n, u));
121                 if (i + 1 == c)
122                     break;
123                 concat(Ai, B, 0, B.length);
124                 BigInteger B1;
125                 B1 = new BigInteger(1, B).add(BigInteger.ONE);
126 
127                 for (int j = 0; j < I.length; j += v) {
128                     BigInteger Ij;
129                     int trunc;
130 
131                     if (tmp.length != v)
132                         tmp = new byte[v];
133                     System.arraycopy(I, j, tmp, 0, v);
134                     Ij = new BigInteger(1, tmp);
135                     Ij = Ij.add(B1);
136                     tmp = Ij.toByteArray();
137                     trunc = tmp.length - v;
138                     if (trunc >= 0) {
139                         System.arraycopy(tmp, trunc, I, j, v);
140                     } else if (trunc < 0) {
141                         Arrays.fill(I, j, j + (-trunc), (byte)0);
142                         System.arraycopy(tmp, 0, I, j + (-trunc), tmp.length);
143                     }
144                 }
145             }
146         } catch (Exception e) {
147             throw new RuntimeException("internal error: " + e);
148         }
149         return key;
150     }
151 
roundup(int x, int y)152     private static int roundup(int x, int y) {
153         return ((x + (y - 1)) / y) * y;
154     }
155 
concat(byte[] src, byte[] dst, int start, int len)156     private static void concat(byte[] src, byte[] dst, int start, int len) {
157         if (src.length == 0) {
158             return;
159         }
160         int loop = len / src.length;
161         int off, i;
162         for (i = 0, off = 0; i < loop; i++, off += src.length)
163             System.arraycopy(src, 0, dst, off + start, src.length);
164         System.arraycopy(src, 0, dst, off + start, len - off);
165     }
166 
PKCS12PBECipherCore(String symmCipherAlg, int defKeySize)167     PKCS12PBECipherCore(String symmCipherAlg, int defKeySize)
168         throws NoSuchAlgorithmException {
169 
170         algo = symmCipherAlg;
171         keyLength = defKeySize * 8;
172         if (algo.equals("RC4")) {
173             pbeAlgo = "PBEWithSHA1AndRC4_" + keyLength;
174         } else {
175             SymmetricCipher symmCipher = null;
176             if (algo.equals("DESede")) {
177                 symmCipher = new DESedeCrypt();
178                 pbeAlgo = "PBEWithSHA1AndDESede";
179                 keyLength = 112; // effective key length
180             } else if (algo.equals("RC2")) {
181                 symmCipher = new RC2Crypt();
182                 pbeAlgo = "PBEWithSHA1AndRC2_" + keyLength;
183             } else {
184                 throw new NoSuchAlgorithmException("No Cipher implementation " +
185                        "for PBEWithSHA1And" + algo);
186             }
187             blockSize = symmCipher.getBlockSize();
188             cipher = new CipherCore(symmCipher, blockSize);
189             cipher.setMode("CBC");
190             try {
191                 cipher.setPadding("PKCS5Padding");
192             } catch (NoSuchPaddingException nspe) {
193                 // should not happen
194             }
195         }
196         keySize = defKeySize;
197     }
198 
implSetMode(String mode)199     void implSetMode(String mode) throws NoSuchAlgorithmException {
200         if ((mode != null) && (!mode.equalsIgnoreCase("CBC"))) {
201             throw new NoSuchAlgorithmException("Invalid cipher mode: "
202                                                + mode);
203         }
204     }
205 
implSetPadding(String padding)206     void implSetPadding(String padding) throws NoSuchPaddingException {
207         if ((padding != null) &&
208             (!padding.equalsIgnoreCase("PKCS5Padding"))) {
209             throw new NoSuchPaddingException("Invalid padding scheme: " +
210                                              padding);
211         }
212     }
213 
implGetBlockSize()214     int implGetBlockSize() {
215         return blockSize;
216     }
217 
implGetOutputSize(int inLen)218     int implGetOutputSize(int inLen) {
219         return cipher.getOutputSize(inLen);
220     }
221 
implGetIV()222     byte[] implGetIV() {
223         return cipher.getIV();
224     }
225 
implGetParameters()226     AlgorithmParameters implGetParameters() {
227         AlgorithmParameters params = null;
228         if (salt == null) {
229             // Cipher is not initialized with parameters;
230             // follow the recommendation in PKCS12 v1.0
231             // section B.4 to generate salt and iCount.
232             salt = new byte[DEFAULT_SALT_LENGTH];
233             SunJCE.getRandom().nextBytes(salt);
234             iCount = DEFAULT_COUNT;
235         }
236         PBEParameterSpec pbeSpec = new PBEParameterSpec(salt, iCount);
237         try {
238             params = AlgorithmParameters.getInstance(pbeAlgo,
239                 SunJCE.getInstance());
240             params.init(pbeSpec);
241         } catch (NoSuchAlgorithmException nsae) {
242             // should never happen
243             throw new RuntimeException(
244                 "SunJCE provider is not configured properly");
245         } catch (InvalidParameterSpecException ipse) {
246             // should never happen
247             throw new RuntimeException("PBEParameterSpec not supported");
248         }
249         return params;
250     }
251 
implInit(int opmode, Key key, AlgorithmParameterSpec params, SecureRandom random)252     void implInit(int opmode, Key key, AlgorithmParameterSpec params,
253                   SecureRandom random) throws InvalidKeyException,
254         InvalidAlgorithmParameterException {
255         implInit(opmode, key, params, random, null);
256     }
257 
implInit(int opmode, Key key, AlgorithmParameterSpec params, SecureRandom random, CipherSpi cipherImpl)258     void implInit(int opmode, Key key, AlgorithmParameterSpec params,
259                   SecureRandom random, CipherSpi cipherImpl)
260                       throws InvalidKeyException,
261         InvalidAlgorithmParameterException {
262         char[] passwdChars = null;
263         salt = null;
264         iCount = 0;
265         if (key instanceof javax.crypto.interfaces.PBEKey) {
266             javax.crypto.interfaces.PBEKey pbeKey =
267                 (javax.crypto.interfaces.PBEKey) key;
268             passwdChars = pbeKey.getPassword();
269             salt = pbeKey.getSalt(); // maybe null if unspecified
270             iCount = pbeKey.getIterationCount(); // maybe 0 if unspecified
271         } else if (key instanceof SecretKey) {
272             byte[] passwdBytes;
273             if (!(key.getAlgorithm().regionMatches(true, 0, "PBE", 0, 3)) ||
274                     (passwdBytes = key.getEncoded()) == null) {
275                 throw new InvalidKeyException("Missing password");
276             }
277             passwdChars = new char[passwdBytes.length];
278             for (int i=0; i<passwdChars.length; i++) {
279                 passwdChars[i] = (char) (passwdBytes[i] & 0x7f);
280             }
281             Arrays.fill(passwdBytes, (byte)0x00);
282         } else {
283             throw new InvalidKeyException("SecretKey of PBE type required");
284         }
285 
286         try {
287             if (((opmode == Cipher.DECRYPT_MODE) ||
288                     (opmode == Cipher.UNWRAP_MODE)) &&
289                     ((params == null) && ((salt == null) || (iCount == 0)))) {
290                 throw new InvalidAlgorithmParameterException
291                         ("Parameters missing");
292             }
293 
294             if (params == null) {
295                 // generate default for salt and iteration count if necessary
296                 if (salt == null) {
297                     salt = new byte[DEFAULT_SALT_LENGTH];
298                     if (random != null) {
299                         random.nextBytes(salt);
300                     } else {
301                         SunJCE.getRandom().nextBytes(salt);
302                     }
303                 }
304                 if (iCount == 0) iCount = DEFAULT_COUNT;
305             } else if (!(params instanceof PBEParameterSpec)) {
306                 throw new InvalidAlgorithmParameterException
307                         ("PBEParameterSpec type required");
308             } else {
309                 PBEParameterSpec pbeParams = (PBEParameterSpec) params;
310                 // make sure the parameter values are consistent
311                 if (salt != null) {
312                     if (!Arrays.equals(salt, pbeParams.getSalt())) {
313                         throw new InvalidAlgorithmParameterException
314                                 ("Inconsistent value of salt between key and params");
315                     }
316                 } else {
317                     salt = pbeParams.getSalt();
318                 }
319                 if (iCount != 0) {
320                     if (iCount != pbeParams.getIterationCount()) {
321                         throw new InvalidAlgorithmParameterException
322                                 ("Different iteration count between key and params");
323                     }
324                 } else {
325                     iCount = pbeParams.getIterationCount();
326                 }
327             }
328             // salt is recommended to be ideally as long as the output
329             // of the hash function. However, it may be too strict to
330             // force this; so instead, we'll just require the minimum
331             // salt length to be 8-byte which is what PKCS#5 recommends
332             // and openssl does.
333             if (salt.length < 8) {
334                 throw new InvalidAlgorithmParameterException
335                         ("Salt must be at least 8 bytes long");
336             }
337             if (iCount <= 0) {
338                 throw new InvalidAlgorithmParameterException
339                         ("IterationCount must be a positive number");
340             }
341             byte[] derivedKey = derive(passwdChars, salt, iCount,
342                     keySize, CIPHER_KEY);
343             SecretKey cipherKey = new SecretKeySpec(derivedKey, algo);
344 
345             if (cipherImpl != null && cipherImpl instanceof ARCFOURCipher) {
346                 ((ARCFOURCipher)cipherImpl).engineInit(opmode, cipherKey, random);
347 
348             } else {
349                 byte[] derivedIv = derive(passwdChars, salt, iCount, 8,
350                         CIPHER_IV);
351                 IvParameterSpec ivSpec = new IvParameterSpec(derivedIv, 0, 8);
352 
353                 // initialize the underlying cipher
354                 cipher.init(opmode, cipherKey, ivSpec, random);
355             }
356         } finally {
357            Arrays.fill(passwdChars, '\0');
358         }
359     }
360 
implInit(int opmode, Key key, AlgorithmParameters params, SecureRandom random)361     void implInit(int opmode, Key key, AlgorithmParameters params,
362                   SecureRandom random)
363         throws InvalidKeyException, InvalidAlgorithmParameterException {
364         implInit(opmode, key, params, random, null);
365     }
366 
implInit(int opmode, Key key, AlgorithmParameters params, SecureRandom random, CipherSpi cipherImpl)367     void implInit(int opmode, Key key, AlgorithmParameters params,
368                   SecureRandom random, CipherSpi cipherImpl)
369         throws InvalidKeyException, InvalidAlgorithmParameterException {
370         AlgorithmParameterSpec paramSpec = null;
371         if (params != null) {
372             try {
373                 paramSpec = params.getParameterSpec(PBEParameterSpec.class);
374             } catch (InvalidParameterSpecException ipse) {
375                 throw new InvalidAlgorithmParameterException(
376                     "requires PBE parameters");
377             }
378         }
379         implInit(opmode, key, paramSpec, random, cipherImpl);
380     }
381 
implInit(int opmode, Key key, SecureRandom random)382     void implInit(int opmode, Key key, SecureRandom random)
383         throws InvalidKeyException {
384         implInit(opmode, key, random, null);
385     }
386 
implInit(int opmode, Key key, SecureRandom random, CipherSpi cipherImpl)387     void implInit(int opmode, Key key, SecureRandom random,
388         CipherSpi cipherImpl) throws InvalidKeyException {
389         try {
390             implInit(opmode, key, (AlgorithmParameterSpec) null, random,
391                 cipherImpl);
392         } catch (InvalidAlgorithmParameterException iape) {
393             throw new InvalidKeyException("requires PBE parameters");
394         }
395     }
396 
implUpdate(byte[] in, int inOff, int inLen)397     byte[] implUpdate(byte[] in, int inOff, int inLen) {
398         return cipher.update(in, inOff, inLen);
399     }
400 
implUpdate(byte[] in, int inOff, int inLen, byte[] out, int outOff)401     int implUpdate(byte[] in, int inOff, int inLen, byte[] out, int outOff)
402         throws ShortBufferException {
403         return cipher.update(in, inOff, inLen, out, outOff);
404     }
405 
implDoFinal(byte[] in, int inOff, int inLen)406     byte[] implDoFinal(byte[] in, int inOff, int inLen)
407         throws IllegalBlockSizeException, BadPaddingException {
408         return cipher.doFinal(in, inOff, inLen);
409     }
410 
implDoFinal(byte[] in, int inOff, int inLen, byte[] out, int outOff)411     int implDoFinal(byte[] in, int inOff, int inLen, byte[] out, int outOff)
412         throws ShortBufferException, IllegalBlockSizeException,
413                BadPaddingException {
414         return cipher.doFinal(in, inOff, inLen, out, outOff);
415     }
416 
implGetKeySize(Key key)417     int implGetKeySize(Key key) throws InvalidKeyException {
418         return keyLength;
419     }
420 
implWrap(Key key)421     byte[] implWrap(Key key) throws IllegalBlockSizeException,
422         InvalidKeyException {
423         return cipher.wrap(key);
424     }
425 
implUnwrap(byte[] wrappedKey, String wrappedKeyAlgorithm, int wrappedKeyType)426     Key implUnwrap(byte[] wrappedKey, String wrappedKeyAlgorithm,
427                    int wrappedKeyType)
428         throws InvalidKeyException, NoSuchAlgorithmException {
429         return cipher.unwrap(wrappedKey, wrappedKeyAlgorithm,
430                              wrappedKeyType);
431     }
432 
433     public static final class PBEWithSHA1AndDESede extends CipherSpi {
434         private final PKCS12PBECipherCore core;
PBEWithSHA1AndDESede()435         public PBEWithSHA1AndDESede() throws NoSuchAlgorithmException {
436             core = new PKCS12PBECipherCore("DESede", 24);
437         }
engineDoFinal(byte[] in, int inOff, int inLen)438         protected byte[] engineDoFinal(byte[] in, int inOff, int inLen)
439             throws IllegalBlockSizeException, BadPaddingException {
440             return core.implDoFinal(in, inOff, inLen);
441         }
engineDoFinal(byte[] in, int inOff, int inLen, byte[] out, int outOff)442         protected int engineDoFinal(byte[] in, int inOff, int inLen,
443                                     byte[] out, int outOff)
444             throws ShortBufferException, IllegalBlockSizeException,
445                    BadPaddingException {
446             return core.implDoFinal(in, inOff, inLen, out, outOff);
447         }
engineGetBlockSize()448         protected int engineGetBlockSize() {
449             return core.implGetBlockSize();
450         }
engineGetIV()451         protected byte[] engineGetIV() {
452             return core.implGetIV();
453         }
engineGetKeySize(Key key)454         protected int engineGetKeySize(Key key) throws InvalidKeyException {
455             return core.implGetKeySize(key);
456         }
engineGetOutputSize(int inLen)457         protected int engineGetOutputSize(int inLen) {
458             return core.implGetOutputSize(inLen);
459         }
engineGetParameters()460         protected AlgorithmParameters engineGetParameters() {
461             return core.implGetParameters();
462         }
engineInit(int opmode, Key key, AlgorithmParameterSpec params, SecureRandom random)463         protected void engineInit(int opmode, Key key,
464                                   AlgorithmParameterSpec params,
465                                   SecureRandom random)
466             throws InvalidKeyException, InvalidAlgorithmParameterException {
467             core.implInit(opmode, key, params, random);
468         }
engineInit(int opmode, Key key, AlgorithmParameters params, SecureRandom random)469         protected void engineInit(int opmode, Key key,
470                                   AlgorithmParameters params,
471                                   SecureRandom random)
472             throws InvalidKeyException, InvalidAlgorithmParameterException {
473             core.implInit(opmode, key, params, random);
474         }
engineInit(int opmode, Key key, SecureRandom random)475         protected void engineInit(int opmode, Key key, SecureRandom random)
476             throws InvalidKeyException {
477             core.implInit(opmode, key, random);
478         }
engineSetMode(String mode)479         protected void engineSetMode(String mode)
480             throws NoSuchAlgorithmException {
481             core.implSetMode(mode);
482         }
engineSetPadding(String paddingScheme)483         protected void engineSetPadding(String paddingScheme)
484             throws NoSuchPaddingException {
485             core.implSetPadding(paddingScheme);
486         }
engineUnwrap(byte[] wrappedKey, String wrappedKeyAlgorithm, int wrappedKeyType)487         protected Key engineUnwrap(byte[] wrappedKey,
488                                    String wrappedKeyAlgorithm,
489                                    int wrappedKeyType)
490             throws InvalidKeyException, NoSuchAlgorithmException {
491             return core.implUnwrap(wrappedKey, wrappedKeyAlgorithm,
492                                    wrappedKeyType);
493         }
engineUpdate(byte[] in, int inOff, int inLen)494         protected byte[] engineUpdate(byte[] in, int inOff, int inLen) {
495             return core.implUpdate(in, inOff, inLen);
496         }
engineUpdate(byte[] in, int inOff, int inLen, byte[] out, int outOff)497         protected int engineUpdate(byte[] in, int inOff, int inLen,
498                                    byte[] out, int outOff)
499             throws ShortBufferException {
500             return core.implUpdate(in, inOff, inLen, out, outOff);
501         }
engineWrap(Key key)502         protected byte[] engineWrap(Key key)
503             throws IllegalBlockSizeException, InvalidKeyException {
504             return core.implWrap(key);
505         }
506     }
507 
508     public static final class PBEWithSHA1AndRC2_40 extends CipherSpi {
509         private final PKCS12PBECipherCore core;
PBEWithSHA1AndRC2_40()510         public PBEWithSHA1AndRC2_40() throws NoSuchAlgorithmException {
511             core = new PKCS12PBECipherCore("RC2", 5);
512         }
engineDoFinal(byte[] in, int inOff, int inLen)513         protected byte[] engineDoFinal(byte[] in, int inOff, int inLen)
514             throws IllegalBlockSizeException, BadPaddingException {
515             return core.implDoFinal(in, inOff, inLen);
516         }
engineDoFinal(byte[] in, int inOff, int inLen, byte[] out, int outOff)517         protected int engineDoFinal(byte[] in, int inOff, int inLen,
518                                     byte[] out, int outOff)
519             throws ShortBufferException, IllegalBlockSizeException,
520                    BadPaddingException {
521             return core.implDoFinal(in, inOff, inLen, out, outOff);
522         }
engineGetBlockSize()523         protected int engineGetBlockSize() {
524             return core.implGetBlockSize();
525         }
engineGetIV()526         protected byte[] engineGetIV() {
527             return core.implGetIV();
528         }
engineGetKeySize(Key key)529         protected int engineGetKeySize(Key key) throws InvalidKeyException {
530             return core.implGetKeySize(key);
531         }
engineGetOutputSize(int inLen)532         protected int engineGetOutputSize(int inLen) {
533             return core.implGetOutputSize(inLen);
534         }
engineGetParameters()535         protected AlgorithmParameters engineGetParameters() {
536             return core.implGetParameters();
537         }
engineInit(int opmode, Key key, AlgorithmParameterSpec params, SecureRandom random)538         protected void engineInit(int opmode, Key key,
539                                   AlgorithmParameterSpec params,
540                                   SecureRandom random)
541             throws InvalidKeyException, InvalidAlgorithmParameterException {
542             core.implInit(opmode, key, params, random);
543         }
engineInit(int opmode, Key key, AlgorithmParameters params, SecureRandom random)544         protected void engineInit(int opmode, Key key,
545                                   AlgorithmParameters params,
546                                   SecureRandom random)
547             throws InvalidKeyException, InvalidAlgorithmParameterException {
548             core.implInit(opmode, key, params, random);
549         }
engineInit(int opmode, Key key, SecureRandom random)550         protected void engineInit(int opmode, Key key, SecureRandom random)
551             throws InvalidKeyException {
552             core.implInit(opmode, key, random);
553         }
engineSetMode(String mode)554         protected void engineSetMode(String mode)
555             throws NoSuchAlgorithmException {
556             core.implSetMode(mode);
557         }
engineSetPadding(String paddingScheme)558         protected void engineSetPadding(String paddingScheme)
559             throws NoSuchPaddingException {
560             core.implSetPadding(paddingScheme);
561         }
engineUnwrap(byte[] wrappedKey, String wrappedKeyAlgorithm, int wrappedKeyType)562         protected Key engineUnwrap(byte[] wrappedKey,
563                                    String wrappedKeyAlgorithm,
564                                    int wrappedKeyType)
565             throws InvalidKeyException, NoSuchAlgorithmException {
566             return core.implUnwrap(wrappedKey, wrappedKeyAlgorithm,
567                                    wrappedKeyType);
568         }
engineUpdate(byte[] in, int inOff, int inLen)569         protected byte[] engineUpdate(byte[] in, int inOff, int inLen) {
570             return core.implUpdate(in, inOff, inLen);
571         }
engineUpdate(byte[] in, int inOff, int inLen, byte[] out, int outOff)572         protected int engineUpdate(byte[] in, int inOff, int inLen,
573                                    byte[] out, int outOff)
574             throws ShortBufferException {
575             return core.implUpdate(in, inOff, inLen, out, outOff);
576         }
engineWrap(Key key)577         protected byte[] engineWrap(Key key)
578             throws IllegalBlockSizeException, InvalidKeyException {
579             return core.implWrap(key);
580         }
581     }
582 
583     public static final class PBEWithSHA1AndRC2_128 extends CipherSpi {
584         private final PKCS12PBECipherCore core;
PBEWithSHA1AndRC2_128()585         public PBEWithSHA1AndRC2_128() throws NoSuchAlgorithmException {
586             core = new PKCS12PBECipherCore("RC2", 16);
587         }
engineDoFinal(byte[] in, int inOff, int inLen)588         protected byte[] engineDoFinal(byte[] in, int inOff, int inLen)
589             throws IllegalBlockSizeException, BadPaddingException {
590             return core.implDoFinal(in, inOff, inLen);
591         }
engineDoFinal(byte[] in, int inOff, int inLen, byte[] out, int outOff)592         protected int engineDoFinal(byte[] in, int inOff, int inLen,
593                                     byte[] out, int outOff)
594             throws ShortBufferException, IllegalBlockSizeException,
595                    BadPaddingException {
596             return core.implDoFinal(in, inOff, inLen, out, outOff);
597         }
engineGetBlockSize()598         protected int engineGetBlockSize() {
599             return core.implGetBlockSize();
600         }
engineGetIV()601         protected byte[] engineGetIV() {
602             return core.implGetIV();
603         }
engineGetKeySize(Key key)604         protected int engineGetKeySize(Key key) throws InvalidKeyException {
605             return core.implGetKeySize(key);
606         }
engineGetOutputSize(int inLen)607         protected int engineGetOutputSize(int inLen) {
608             return core.implGetOutputSize(inLen);
609         }
engineGetParameters()610         protected AlgorithmParameters engineGetParameters() {
611             return core.implGetParameters();
612         }
engineInit(int opmode, Key key, AlgorithmParameterSpec params, SecureRandom random)613         protected void engineInit(int opmode, Key key,
614                                   AlgorithmParameterSpec params,
615                                   SecureRandom random)
616             throws InvalidKeyException, InvalidAlgorithmParameterException {
617             core.implInit(opmode, key, params, random);
618         }
engineInit(int opmode, Key key, AlgorithmParameters params, SecureRandom random)619         protected void engineInit(int opmode, Key key,
620                                   AlgorithmParameters params,
621                                   SecureRandom random)
622             throws InvalidKeyException, InvalidAlgorithmParameterException {
623             core.implInit(opmode, key, params, random);
624         }
engineInit(int opmode, Key key, SecureRandom random)625         protected void engineInit(int opmode, Key key, SecureRandom random)
626             throws InvalidKeyException {
627             core.implInit(opmode, key, random);
628         }
engineSetMode(String mode)629         protected void engineSetMode(String mode)
630             throws NoSuchAlgorithmException {
631             core.implSetMode(mode);
632         }
engineSetPadding(String paddingScheme)633         protected void engineSetPadding(String paddingScheme)
634             throws NoSuchPaddingException {
635             core.implSetPadding(paddingScheme);
636         }
engineUnwrap(byte[] wrappedKey, String wrappedKeyAlgorithm, int wrappedKeyType)637         protected Key engineUnwrap(byte[] wrappedKey,
638                                    String wrappedKeyAlgorithm,
639                                    int wrappedKeyType)
640             throws InvalidKeyException, NoSuchAlgorithmException {
641             return core.implUnwrap(wrappedKey, wrappedKeyAlgorithm,
642                                    wrappedKeyType);
643         }
engineUpdate(byte[] in, int inOff, int inLen)644         protected byte[] engineUpdate(byte[] in, int inOff, int inLen) {
645             return core.implUpdate(in, inOff, inLen);
646         }
engineUpdate(byte[] in, int inOff, int inLen, byte[] out, int outOff)647         protected int engineUpdate(byte[] in, int inOff, int inLen,
648                                    byte[] out, int outOff)
649             throws ShortBufferException {
650             return core.implUpdate(in, inOff, inLen, out, outOff);
651         }
engineWrap(Key key)652         protected byte[] engineWrap(Key key)
653             throws IllegalBlockSizeException, InvalidKeyException {
654             return core.implWrap(key);
655         }
656     }
657 
658     public static final class PBEWithSHA1AndRC4_40 extends CipherSpi {
659         private static final int RC4_KEYSIZE = 5;
660         private final PKCS12PBECipherCore core;
661         private final ARCFOURCipher cipher;
662 
PBEWithSHA1AndRC4_40()663         public PBEWithSHA1AndRC4_40() throws NoSuchAlgorithmException {
664             core = new PKCS12PBECipherCore("RC4", RC4_KEYSIZE);
665             cipher = new ARCFOURCipher();
666         }
engineDoFinal(byte[] in, int inOff, int inLen)667         protected byte[] engineDoFinal(byte[] in, int inOff, int inLen)
668             throws IllegalBlockSizeException, BadPaddingException {
669             return cipher.engineDoFinal(in, inOff, inLen);
670         }
engineDoFinal(byte[] in, int inOff, int inLen, byte[] out, int outOff)671         protected int engineDoFinal(byte[] in, int inOff, int inLen,
672                                     byte[] out, int outOff)
673             throws ShortBufferException, IllegalBlockSizeException,
674                    BadPaddingException {
675             return cipher.engineDoFinal(in, inOff, inLen, out, outOff);
676         }
engineGetBlockSize()677         protected int engineGetBlockSize() {
678             return cipher.engineGetBlockSize();
679         }
engineGetIV()680         protected byte[] engineGetIV() {
681             return cipher.engineGetIV();
682         }
engineGetKeySize(Key key)683         protected int engineGetKeySize(Key key) throws InvalidKeyException {
684             return RC4_KEYSIZE;
685         }
engineGetOutputSize(int inLen)686         protected int engineGetOutputSize(int inLen) {
687             return cipher.engineGetOutputSize(inLen);
688         }
engineGetParameters()689         protected AlgorithmParameters engineGetParameters() {
690             return core.implGetParameters();
691         }
engineInit(int opmode, Key key, AlgorithmParameterSpec params, SecureRandom random)692         protected void engineInit(int opmode, Key key,
693                                   AlgorithmParameterSpec params,
694                                   SecureRandom random)
695             throws InvalidKeyException, InvalidAlgorithmParameterException {
696             core.implInit(opmode, key, params, random, cipher);
697         }
engineInit(int opmode, Key key, AlgorithmParameters params, SecureRandom random)698         protected void engineInit(int opmode, Key key,
699                                   AlgorithmParameters params,
700                                   SecureRandom random)
701             throws InvalidKeyException, InvalidAlgorithmParameterException {
702             core.implInit(opmode, key, params, random, cipher);
703         }
engineInit(int opmode, Key key, SecureRandom random)704         protected void engineInit(int opmode, Key key, SecureRandom random)
705             throws InvalidKeyException {
706             core.implInit(opmode, key, random, cipher);
707         }
engineSetMode(String mode)708         protected void engineSetMode(String mode)
709             throws NoSuchAlgorithmException {
710             if (mode.equalsIgnoreCase("ECB") == false) {
711                 throw new NoSuchAlgorithmException("Unsupported mode " + mode);
712             }
713         }
engineSetPadding(String paddingScheme)714         protected void engineSetPadding(String paddingScheme)
715             throws NoSuchPaddingException {
716             if (paddingScheme.equalsIgnoreCase("NoPadding") == false) {
717                 throw new NoSuchPaddingException("Padding must be NoPadding");
718             }
719         }
engineUnwrap(byte[] wrappedKey, String wrappedKeyAlgorithm, int wrappedKeyType)720         protected Key engineUnwrap(byte[] wrappedKey,
721                                    String wrappedKeyAlgorithm,
722                                    int wrappedKeyType)
723             throws InvalidKeyException, NoSuchAlgorithmException {
724             return cipher.engineUnwrap(wrappedKey, wrappedKeyAlgorithm,
725                                    wrappedKeyType);
726         }
engineUpdate(byte[] in, int inOff, int inLen)727         protected byte[] engineUpdate(byte[] in, int inOff, int inLen) {
728             return cipher.engineUpdate(in, inOff, inLen);
729         }
engineUpdate(byte[] in, int inOff, int inLen, byte[] out, int outOff)730         protected int engineUpdate(byte[] in, int inOff, int inLen,
731                                    byte[] out, int outOff)
732             throws ShortBufferException {
733             return cipher.engineUpdate(in, inOff, inLen, out, outOff);
734         }
engineWrap(Key key)735         protected byte[] engineWrap(Key key)
736             throws IllegalBlockSizeException, InvalidKeyException {
737             return cipher.engineWrap(key);
738         }
739     }
740 
741     public static final class PBEWithSHA1AndRC4_128 extends CipherSpi {
742         private static final int RC4_KEYSIZE = 16;
743         private final PKCS12PBECipherCore core;
744         private final ARCFOURCipher cipher;
745 
PBEWithSHA1AndRC4_128()746         public PBEWithSHA1AndRC4_128() throws NoSuchAlgorithmException {
747             core = new PKCS12PBECipherCore("RC4", RC4_KEYSIZE);
748             cipher = new ARCFOURCipher();
749         }
engineDoFinal(byte[] in, int inOff, int inLen)750         protected byte[] engineDoFinal(byte[] in, int inOff, int inLen)
751             throws IllegalBlockSizeException, BadPaddingException {
752             return cipher.engineDoFinal(in, inOff, inLen);
753         }
engineDoFinal(byte[] in, int inOff, int inLen, byte[] out, int outOff)754         protected int engineDoFinal(byte[] in, int inOff, int inLen,
755                                     byte[] out, int outOff)
756             throws ShortBufferException, IllegalBlockSizeException,
757                    BadPaddingException {
758             return cipher.engineDoFinal(in, inOff, inLen, out, outOff);
759         }
engineGetBlockSize()760         protected int engineGetBlockSize() {
761             return cipher.engineGetBlockSize();
762         }
engineGetIV()763         protected byte[] engineGetIV() {
764             return cipher.engineGetIV();
765         }
engineGetKeySize(Key key)766         protected int engineGetKeySize(Key key) throws InvalidKeyException {
767             return RC4_KEYSIZE;
768         }
engineGetOutputSize(int inLen)769         protected int engineGetOutputSize(int inLen) {
770             return cipher.engineGetOutputSize(inLen);
771         }
engineGetParameters()772         protected AlgorithmParameters engineGetParameters() {
773             return core.implGetParameters();
774         }
engineInit(int opmode, Key key, AlgorithmParameterSpec params, SecureRandom random)775         protected void engineInit(int opmode, Key key,
776                                   AlgorithmParameterSpec params,
777                                   SecureRandom random)
778             throws InvalidKeyException, InvalidAlgorithmParameterException {
779             core.implInit(opmode, key, params, random, cipher);
780         }
engineInit(int opmode, Key key, AlgorithmParameters params, SecureRandom random)781         protected void engineInit(int opmode, Key key,
782                                   AlgorithmParameters params,
783                                   SecureRandom random)
784             throws InvalidKeyException, InvalidAlgorithmParameterException {
785             core.implInit(opmode, key, params, random, cipher);
786         }
engineInit(int opmode, Key key, SecureRandom random)787         protected void engineInit(int opmode, Key key, SecureRandom random)
788             throws InvalidKeyException {
789             core.implInit(opmode, key, random, cipher);
790         }
engineSetMode(String mode)791         protected void engineSetMode(String mode)
792             throws NoSuchAlgorithmException {
793             if (mode.equalsIgnoreCase("ECB") == false) {
794                 throw new NoSuchAlgorithmException("Unsupported mode " + mode);
795             }
796         }
engineSetPadding(String paddingScheme)797         protected void engineSetPadding(String paddingScheme)
798             throws NoSuchPaddingException {
799             if (paddingScheme.equalsIgnoreCase("NoPadding") == false) {
800                 throw new NoSuchPaddingException("Padding must be NoPadding");
801             }
802         }
engineUnwrap(byte[] wrappedKey, String wrappedKeyAlgorithm, int wrappedKeyType)803         protected Key engineUnwrap(byte[] wrappedKey,
804                                    String wrappedKeyAlgorithm,
805                                    int wrappedKeyType)
806             throws InvalidKeyException, NoSuchAlgorithmException {
807             return cipher.engineUnwrap(wrappedKey, wrappedKeyAlgorithm,
808                                    wrappedKeyType);
809         }
engineUpdate(byte[] in, int inOff, int inLen)810         protected byte[] engineUpdate(byte[] in, int inOff, int inLen) {
811             return cipher.engineUpdate(in, inOff, inLen);
812         }
engineUpdate(byte[] in, int inOff, int inLen, byte[] out, int outOff)813         protected int engineUpdate(byte[] in, int inOff, int inLen,
814                                    byte[] out, int outOff)
815             throws ShortBufferException {
816             return cipher.engineUpdate(in, inOff, inLen, out, outOff);
817         }
engineWrap(Key key)818         protected byte[] engineWrap(Key key)
819             throws IllegalBlockSizeException, InvalidKeyException {
820             return cipher.engineWrap(key);
821         }
822     }
823 }
824