• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.bouncycastle.jcajce.provider.symmetric.util;
2 
3 import java.lang.reflect.Constructor;
4 import java.lang.reflect.Method;
5 import java.nio.ByteBuffer;
6 import java.security.AlgorithmParameters;
7 import java.security.InvalidAlgorithmParameterException;
8 import java.security.InvalidKeyException;
9 import java.security.InvalidParameterException;
10 import java.security.Key;
11 import java.security.NoSuchAlgorithmException;
12 import java.security.SecureRandom;
13 import java.security.spec.AlgorithmParameterSpec;
14 
15 import javax.crypto.BadPaddingException;
16 import javax.crypto.Cipher;
17 import javax.crypto.IllegalBlockSizeException;
18 import javax.crypto.NoSuchPaddingException;
19 import javax.crypto.SecretKey;
20 import javax.crypto.ShortBufferException;
21 import javax.crypto.interfaces.PBEKey;
22 import javax.crypto.spec.IvParameterSpec;
23 // BEGIN android-added
24 import javax.crypto.spec.PBEKeySpec;
25 // END android-added
26 import javax.crypto.spec.PBEParameterSpec;
27 // BEGIN android-removed
28 // import javax.crypto.spec.RC2ParameterSpec;
29 // import javax.crypto.spec.RC5ParameterSpec;
30 // END android-removed
31 
32 import org.bouncycastle.asn1.cms.GCMParameters;
33 import org.bouncycastle.crypto.BlockCipher;
34 import org.bouncycastle.crypto.BufferedBlockCipher;
35 import org.bouncycastle.crypto.CipherParameters;
36 import org.bouncycastle.crypto.DataLengthException;
37 import org.bouncycastle.crypto.InvalidCipherTextException;
38 import org.bouncycastle.crypto.OutputLengthException;
39 import org.bouncycastle.crypto.modes.AEADBlockCipher;
40 import org.bouncycastle.crypto.modes.CBCBlockCipher;
41 import org.bouncycastle.crypto.modes.CCMBlockCipher;
42 import org.bouncycastle.crypto.modes.CFBBlockCipher;
43 import org.bouncycastle.crypto.modes.CTSBlockCipher;
44 // BEGIN android-removed
45 // import org.bouncycastle.crypto.modes.EAXBlockCipher;
46 // import org.bouncycastle.crypto.modes.GCFBBlockCipher;
47 // END android-removed
48 import org.bouncycastle.crypto.modes.GCMBlockCipher;
49 // BEGIN android-removed
50 // import org.bouncycastle.crypto.modes.GOFBBlockCipher;
51 // import org.bouncycastle.crypto.modes.OCBBlockCipher;
52 // END android-removed
53 import org.bouncycastle.crypto.modes.OFBBlockCipher;
54 // BEGIN android-removed
55 // import org.bouncycastle.crypto.modes.OpenPGPCFBBlockCipher;
56 // import org.bouncycastle.crypto.modes.PGPCFBBlockCipher;
57 // END android-removed
58 import org.bouncycastle.crypto.modes.SICBlockCipher;
59 import org.bouncycastle.crypto.paddings.BlockCipherPadding;
60 import org.bouncycastle.crypto.paddings.ISO10126d2Padding;
61 import org.bouncycastle.crypto.paddings.ISO7816d4Padding;
62 import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher;
63 import org.bouncycastle.crypto.paddings.TBCPadding;
64 import org.bouncycastle.crypto.paddings.X923Padding;
65 import org.bouncycastle.crypto.paddings.ZeroBytePadding;
66 import org.bouncycastle.crypto.params.AEADParameters;
67 import org.bouncycastle.crypto.params.KeyParameter;
68 import org.bouncycastle.crypto.params.ParametersWithIV;
69 import org.bouncycastle.crypto.params.ParametersWithRandom;
70 // BEGIN android-removed
71 // import org.bouncycastle.crypto.params.ParametersWithSBox;
72 // END android-removed
73 import org.bouncycastle.crypto.params.RC2Parameters;
74 // BEGIN android-removed
75 // import org.bouncycastle.crypto.params.RC5Parameters;
76 // import org.bouncycastle.jcajce.PBKDF1Key;
77 // import org.bouncycastle.jcajce.PBKDF1KeyWithParameters;
78 // END android-removed
79 import org.bouncycastle.jcajce.PKCS12Key;
80 import org.bouncycastle.jcajce.PKCS12KeyWithParameters;
81 import org.bouncycastle.jcajce.spec.AEADParameterSpec;
82 // BEGIN android-removed
83 // import org.bouncycastle.jcajce.spec.GOST28147ParameterSpec;
84 // import org.bouncycastle.jcajce.spec.RepeatedSecretKeySpec;
85 // END android-removed
86 import org.bouncycastle.util.Strings;
87 
88 public class BaseBlockCipher
89     extends BaseWrapCipher
90     implements PBE
91 {
92     private static final Class gcmSpecClass = lookup("javax.crypto.spec.GCMParameterSpec");
93 
94     //
95     // specs we can handle.
96     //
97     private Class[]                 availableSpecs =
98                                     {
99                                         // BEGIN android-removed
100                                         // RC2ParameterSpec.class,
101                                         // RC5ParameterSpec.class,
102                                         // END android-removed
103                                         gcmSpecClass,
104                                         IvParameterSpec.class,
105                                         PBEParameterSpec.class,
106                                         // BEGIN android-removed
107                                         // GOST28147ParameterSpec.class
108                                         // END android-removed
109                                     };
110 
111     private BlockCipher             baseEngine;
112     private BlockCipherProvider     engineProvider;
113     private GenericBlockCipher      cipher;
114     private ParametersWithIV        ivParam;
115     private AEADParameters          aeadParams;
116 
117     private int keySizeInBits;
118     private int scheme = -1;
119     private int digest;
120 
121     private int                     ivLength = 0;
122 
123     private boolean                 padded;
124     private boolean                 fixedIv = true;
125     private PBEParameterSpec        pbeSpec = null;
126     private String                  pbeAlgorithm = null;
127 
128     private String                  modeName = null;
129 
lookup(String className)130     private static Class lookup(String className)
131     {
132         try
133         {
134             Class def = BaseBlockCipher.class.getClassLoader().loadClass(className);
135 
136             return def;
137         }
138         catch (Exception e)
139         {
140             return null;
141         }
142     }
143 
BaseBlockCipher( BlockCipher engine)144     protected BaseBlockCipher(
145         BlockCipher engine)
146     {
147         baseEngine = engine;
148 
149         cipher = new BufferedGenericBlockCipher(engine);
150     }
151 
BaseBlockCipher( BlockCipher engine, int scheme, int digest, int keySizeInBits, int ivLength)152     protected BaseBlockCipher(
153         BlockCipher engine,
154         int scheme,
155         int digest,
156         int keySizeInBits,
157         int ivLength)
158     {
159         baseEngine = engine;
160 
161         this.scheme = scheme;
162         this.digest = digest;
163         this.keySizeInBits = keySizeInBits;
164         this.ivLength = ivLength;
165 
166         cipher = new BufferedGenericBlockCipher(engine);
167     }
168 
BaseBlockCipher( BlockCipherProvider provider)169     protected BaseBlockCipher(
170         BlockCipherProvider provider)
171     {
172         baseEngine = provider.get();
173         engineProvider = provider;
174 
175         cipher = new BufferedGenericBlockCipher(provider.get());
176     }
177 
BaseBlockCipher( AEADBlockCipher engine)178     protected BaseBlockCipher(
179         AEADBlockCipher engine)
180     {
181         this.baseEngine = engine.getUnderlyingCipher();
182         this.ivLength = baseEngine.getBlockSize();
183         this.cipher = new AEADGenericBlockCipher(engine);
184     }
185 
BaseBlockCipher( AEADBlockCipher engine, boolean fixedIv, int ivLength)186     protected BaseBlockCipher(
187         AEADBlockCipher engine,
188         boolean fixedIv,
189         int ivLength)
190     {
191         this.baseEngine = engine.getUnderlyingCipher();
192         this.fixedIv = fixedIv;
193         this.ivLength = ivLength;
194         this.cipher = new AEADGenericBlockCipher(engine);
195     }
196 
BaseBlockCipher( org.bouncycastle.crypto.BlockCipher engine, int ivLength)197     protected BaseBlockCipher(
198         org.bouncycastle.crypto.BlockCipher engine,
199         int ivLength)
200     {
201         baseEngine = engine;
202 
203         this.cipher = new BufferedGenericBlockCipher(engine);
204         this.ivLength = ivLength / 8;
205     }
206 
BaseBlockCipher( BufferedBlockCipher engine, int ivLength)207     protected BaseBlockCipher(
208         BufferedBlockCipher engine,
209         int ivLength)
210     {
211         baseEngine = engine.getUnderlyingCipher();
212 
213         this.cipher = new BufferedGenericBlockCipher(engine);
214         this.ivLength = ivLength / 8;
215     }
216 
engineGetBlockSize()217     protected int engineGetBlockSize()
218     {
219         return baseEngine.getBlockSize();
220     }
221 
engineGetIV()222     protected byte[] engineGetIV()
223     {
224         if (aeadParams != null)
225         {
226             return aeadParams.getNonce();
227         }
228 
229         return (ivParam != null) ? ivParam.getIV() : null;
230     }
231 
engineGetKeySize( Key key)232     protected int engineGetKeySize(
233         Key     key)
234     {
235         return key.getEncoded().length * 8;
236     }
237 
engineGetOutputSize( int inputLen)238     protected int engineGetOutputSize(
239         int     inputLen)
240     {
241         return cipher.getOutputSize(inputLen);
242     }
243 
engineGetParameters()244     protected AlgorithmParameters engineGetParameters()
245     {
246         if (engineParams == null)
247         {
248             if (pbeSpec != null)
249             {
250                 try
251                 {
252                     engineParams = createParametersInstance(pbeAlgorithm);
253                     engineParams.init(pbeSpec);
254                 }
255                 catch (Exception e)
256                 {
257                     return null;
258                 }
259             }
260             else if (aeadParams != null)
261             {
262                 try
263                 {
264                     engineParams = createParametersInstance("GCM");
265                     engineParams.init(new GCMParameters(aeadParams.getNonce(), aeadParams.getMacSize() / 8).getEncoded());
266                 }
267                 catch (Exception e)
268                 {
269                     throw new RuntimeException(e.toString());
270                 }
271             }
272             else if (ivParam != null)
273             {
274                 String  name = cipher.getUnderlyingCipher().getAlgorithmName();
275 
276                 if (name.indexOf('/') >= 0)
277                 {
278                     name = name.substring(0, name.indexOf('/'));
279                 }
280 
281                 try
282                 {
283                     engineParams = createParametersInstance(name);
284                     engineParams.init(ivParam.getIV());
285                 }
286                 catch (Exception e)
287                 {
288                     throw new RuntimeException(e.toString());
289                 }
290             }
291         }
292 
293         return engineParams;
294     }
295 
engineSetMode( String mode)296     protected void engineSetMode(
297         String  mode)
298         throws NoSuchAlgorithmException
299     {
300         modeName = Strings.toUpperCase(mode);
301 
302         if (modeName.equals("ECB"))
303         {
304             ivLength = 0;
305             cipher = new BufferedGenericBlockCipher(baseEngine);
306         }
307         else if (modeName.equals("CBC"))
308         {
309             ivLength = baseEngine.getBlockSize();
310             cipher = new BufferedGenericBlockCipher(
311                             new CBCBlockCipher(baseEngine));
312         }
313         else if (modeName.startsWith("OFB"))
314         {
315             ivLength = baseEngine.getBlockSize();
316             if (modeName.length() != 3)
317             {
318                 int wordSize = Integer.parseInt(modeName.substring(3));
319 
320                 cipher = new BufferedGenericBlockCipher(
321                                 new OFBBlockCipher(baseEngine, wordSize));
322             }
323             else
324             {
325                 cipher = new BufferedGenericBlockCipher(
326                         new OFBBlockCipher(baseEngine, 8 * baseEngine.getBlockSize()));
327             }
328         }
329         else if (modeName.startsWith("CFB"))
330         {
331             ivLength = baseEngine.getBlockSize();
332             if (modeName.length() != 3)
333             {
334                 int wordSize = Integer.parseInt(modeName.substring(3));
335 
336                 cipher = new BufferedGenericBlockCipher(
337                                 new CFBBlockCipher(baseEngine, wordSize));
338             }
339             else
340             {
341                 cipher = new BufferedGenericBlockCipher(
342                         new CFBBlockCipher(baseEngine, 8 * baseEngine.getBlockSize()));
343             }
344         }
345         // BEGIN android-removed
346         // else if (modeName.startsWith("PGP"))
347         // {
348         //     boolean inlineIV = modeName.equalsIgnoreCase("PGPCFBwithIV");
349         //
350         //     ivLength = baseEngine.getBlockSize();
351         //     cipher = new BufferedGenericBlockCipher(
352         //         new PGPCFBBlockCipher(baseEngine, inlineIV));
353         // }
354         // else if (modeName.equalsIgnoreCase("OpenPGPCFB"))
355         // {
356         //     ivLength = 0;
357         //     cipher = new BufferedGenericBlockCipher(
358         //         new OpenPGPCFBBlockCipher(baseEngine));
359         // }
360         // else if (modeName.startsWith("SIC"))
361         // {
362         //     ivLength = baseEngine.getBlockSize();
363         //     if (ivLength < 16)
364         //     {
365         //         throw new IllegalArgumentException("Warning: SIC-Mode can become a twotime-pad if the blocksize of the cipher is too small. Use a cipher with a block size of at least 128 bits (e.g. AES)");
366         //     }
367         //     fixedIv = false;
368         //     cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher(
369         //                 new SICBlockCipher(baseEngine)));
370         // }
371         // END android-removed
372         else if (modeName.startsWith("CTR"))
373         {
374             ivLength = baseEngine.getBlockSize();
375             fixedIv = false;
376             cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher(
377                         new SICBlockCipher(baseEngine)));
378         }
379         // BEGIN android-removed
380         // else if (modeName.startsWith("GOFB"))
381         // {
382         //     ivLength = baseEngine.getBlockSize();
383         //     cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher(
384         //                 new GOFBBlockCipher(baseEngine)));
385         // }
386         // else if (modeName.startsWith("GCFB"))
387         // {
388         //     ivLength = baseEngine.getBlockSize();
389         //     cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher(
390         //                 new GCFBBlockCipher(baseEngine)));
391         // }
392         // END android-removed
393         else if (modeName.startsWith("CTS"))
394         {
395             ivLength = baseEngine.getBlockSize();
396             cipher = new BufferedGenericBlockCipher(new CTSBlockCipher(new CBCBlockCipher(baseEngine)));
397         }
398         else if (modeName.startsWith("CCM"))
399         {
400             ivLength = 13; // CCM nonce 7..13 bytes
401             cipher = new AEADGenericBlockCipher(new CCMBlockCipher(baseEngine));
402         }
403         // BEGIN android-removed
404         // else if (modeName.startsWith("OCB"))
405         // {
406         //     if (engineProvider != null)
407         //     {
408         //         /*
409         //          * RFC 7253 4.2. Nonce is a string of no more than 120 bits
410         //          */
411         //         ivLength = 15;
412         //         cipher = new AEADGenericBlockCipher(new OCBBlockCipher(baseEngine, engineProvider.get()));
413         //     }
414         //     else
415         //     {
416         //         throw new NoSuchAlgorithmException("can't support mode " + mode);
417         //     }
418         // }
419         // else if (modeName.startsWith("EAX"))
420         // {
421         //     ivLength = baseEngine.getBlockSize();
422         //     cipher = new AEADGenericBlockCipher(new EAXBlockCipher(baseEngine));
423         // }
424         // END android-removed
425         else if (modeName.startsWith("GCM"))
426         {
427             ivLength = baseEngine.getBlockSize();
428             cipher = new AEADGenericBlockCipher(new GCMBlockCipher(baseEngine));
429         }
430         else
431         {
432             throw new NoSuchAlgorithmException("can't support mode " + mode);
433         }
434     }
435 
engineSetPadding( String padding)436     protected void engineSetPadding(
437         String  padding)
438     throws NoSuchPaddingException
439     {
440         String  paddingName = Strings.toUpperCase(padding);
441 
442         if (paddingName.equals("NOPADDING"))
443         {
444             if (cipher.wrapOnNoPadding())
445             {
446                 cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher(cipher.getUnderlyingCipher()));
447             }
448         }
449         else if (paddingName.equals("WITHCTS"))
450         {
451             cipher = new BufferedGenericBlockCipher(new CTSBlockCipher(cipher.getUnderlyingCipher()));
452         }
453         else
454         {
455             padded = true;
456 
457             if (isAEADModeName(modeName))
458             {
459                 throw new NoSuchPaddingException("Only NoPadding can be used with AEAD modes.");
460             }
461             else if (paddingName.equals("PKCS5PADDING") || paddingName.equals("PKCS7PADDING"))
462             {
463                 cipher = new BufferedGenericBlockCipher(cipher.getUnderlyingCipher());
464             }
465             else if (paddingName.equals("ZEROBYTEPADDING"))
466             {
467                 cipher = new BufferedGenericBlockCipher(cipher.getUnderlyingCipher(), new ZeroBytePadding());
468             }
469             else if (paddingName.equals("ISO10126PADDING") || paddingName.equals("ISO10126-2PADDING"))
470             {
471                 cipher = new BufferedGenericBlockCipher(cipher.getUnderlyingCipher(), new ISO10126d2Padding());
472             }
473             else if (paddingName.equals("X9.23PADDING") || paddingName.equals("X923PADDING"))
474             {
475                 cipher = new BufferedGenericBlockCipher(cipher.getUnderlyingCipher(), new X923Padding());
476             }
477             else if (paddingName.equals("ISO7816-4PADDING") || paddingName.equals("ISO9797-1PADDING"))
478             {
479                 cipher = new BufferedGenericBlockCipher(cipher.getUnderlyingCipher(), new ISO7816d4Padding());
480             }
481             else if (paddingName.equals("TBCPADDING"))
482             {
483                 cipher = new BufferedGenericBlockCipher(cipher.getUnderlyingCipher(), new TBCPadding());
484             }
485             else
486             {
487                 throw new NoSuchPaddingException("Padding " + padding + " unknown.");
488             }
489         }
490     }
491 
492     // BEGIN android-added
493     // TODO(27995180): This might need to be removed if we drop support for BCPBE keys without IV
494     // in PKCS12
isBCPBEKeyWithoutIV(Key key)495     private boolean isBCPBEKeyWithoutIV(Key key) {
496         return (key instanceof BCPBEKey) && !(((BCPBEKey)key).getParam() instanceof ParametersWithIV);
497     }
498     // END android-added
499 
engineInit( int opmode, Key key, AlgorithmParameterSpec params, SecureRandom random)500     protected void engineInit(
501         int                     opmode,
502         Key                     key,
503         AlgorithmParameterSpec  params,
504         SecureRandom            random)
505         throws InvalidKeyException, InvalidAlgorithmParameterException
506     {
507         CipherParameters        param;
508 
509         this.pbeSpec = null;
510         this.pbeAlgorithm = null;
511         this.engineParams = null;
512         this.aeadParams = null;
513 
514         //
515         // basic key check
516         //
517         if (!(key instanceof SecretKey))
518         {
519             throw new InvalidKeyException("Key for algorithm " + ((key != null) ? key.getAlgorithm() : null) + " not suitable for symmetric enryption.");
520         }
521 
522         //
523         // for RC5-64 we must have some default parameters
524         //
525         if (params == null && baseEngine.getAlgorithmName().startsWith("RC5-64"))
526         {
527             throw new InvalidAlgorithmParameterException("RC5 requires an RC5ParametersSpec to be passed in.");
528         }
529 
530         //
531         // a note on iv's - if ivLength is zero the IV gets ignored (we don't use it).
532         //
533         // BEGIN android-changed
534         // Was: if (scheme == PKCS12 || key instanceof PKCS12Key)
535         // If the key is a BCPBE one without an IV, ignore the fact that the scheme is PKCS12.
536         // TODO(27995180): consider whether we want to keep support for these keys and PKCS12.
537         if ((scheme == PKCS12 || key instanceof PKCS12Key) && !isBCPBEKeyWithoutIV(key))
538         // END android-changed
539         {
540             SecretKey k;
541             try
542             {
543                 k = (SecretKey)key;
544             }
545             catch (Exception e)
546             {
547                 throw new InvalidKeyException("PKCS12 requires a SecretKey/PBEKey");
548             }
549 
550             if (params instanceof  PBEParameterSpec)
551             {
552                 pbeSpec = (PBEParameterSpec)params;
553             }
554 
555             if (k instanceof PBEKey && pbeSpec == null)
556             {
557                 PBEKey pbeKey = (PBEKey)k;
558                 if (pbeKey.getSalt() == null)
559                 {
560                     throw new InvalidAlgorithmParameterException("PBEKey requires parameters to specify salt");
561                 }
562                 pbeSpec = new PBEParameterSpec(pbeKey.getSalt(), pbeKey.getIterationCount());
563             }
564 
565             if (pbeSpec == null && !(k instanceof PBEKey))
566             {
567                 throw new InvalidKeyException("Algorithm requires a PBE key");
568             }
569 
570             if (key instanceof BCPBEKey)
571             {
572                 // PKCS#12 sets an IV, if we get a key that doesn't have ParametersWithIV we need to reject it. If the
573                 // key has no parameters it means it's an old-school JCE PBE Key - we use getEncoded() on it.
574                 CipherParameters pbeKeyParam = ((BCPBEKey)key).getParam();
575                 if (pbeKeyParam instanceof ParametersWithIV)
576                 {
577                     param = pbeKeyParam;
578                 }
579                 else if (pbeKeyParam == null)
580                 {
581                     // BEGIN android-changed
582                     // Was: param = PBE.Util.makePBEParameters(k.getEncoded(), PKCS12, digest, keySizeInBits, ivLength * 8, pbeSpec, cipher.getAlgorithmName());
583                     // TODO(27995180): consider rejecting such keys for PKCS12
584                     // See above for the android-changed with a TODO for the same bug that makes
585                     // this code unreachable.
586                     // END android-changed
587                     throw new IllegalStateException("Unreachable code");
588                 }
589                 else
590                 {
591                     throw new InvalidKeyException("Algorithm requires a PBE key suitable for PKCS12");
592                 }
593             }
594             else
595             {
596                 param = PBE.Util.makePBEParameters(k.getEncoded(), PKCS12, digest, keySizeInBits, ivLength * 8, pbeSpec, cipher.getAlgorithmName());
597             }
598             if (param instanceof ParametersWithIV)
599             {
600                 ivParam = (ParametersWithIV)param;
601             }
602         }
603         // BEGIN android-removed
604         // else if (key instanceof PBKDF1Key)
605         // {
606         //     PBKDF1Key k = (PBKDF1Key)key;
607 
608         //     if (params instanceof PBEParameterSpec)
609         //     {
610         //         pbeSpec = (PBEParameterSpec)params;
611         //     }
612         //     if (k instanceof PBKDF1KeyWithParameters && pbeSpec == null)
613         //     {
614         //         pbeSpec = new PBEParameterSpec(((PBKDF1KeyWithParameters)k).getSalt(), ((PBKDF1KeyWithParameters)k).getIterationCount());
615         //     }
616 
617         //     param = PBE.Util.makePBEParameters(k.getEncoded(), PKCS5S1, digest, keySizeInBits, ivLength * 8, pbeSpec, cipher.getAlgorithmName());
618         //     if (param instanceof ParametersWithIV)
619         //     {
620         //         ivParam = (ParametersWithIV)param;
621         //     }
622         // }
623         // END android-removed
624         else if (key instanceof BCPBEKey)
625         {
626             BCPBEKey k = (BCPBEKey)key;
627 
628             if (k.getOID() != null)
629             {
630                 pbeAlgorithm = k.getOID().getId();
631             }
632             else
633             {
634                 pbeAlgorithm = k.getAlgorithm();
635             }
636 
637             if (k.getParam() != null)
638             {
639                 param = adjustParameters(params, k.getParam());
640             }
641             else if (params instanceof PBEParameterSpec)
642             {
643                 pbeSpec = (PBEParameterSpec)params;
644                 // BEGIN android-added
645                 // At this point, k.getParam() == null, so the key hasn't been generated.  If
646                 // the parameters have non-default values, recreate the BCPBEKey from algorithm
647                 // parameters as to generate the key.
648                 if ((pbeSpec.getSalt().length != 0) && (pbeSpec.getIterationCount() > 0)) {
649                     k = new BCPBEKey(k.getAlgorithm(), k.getOID(), k.getType(), k.getDigest(),
650                             k.getKeySize(), k.getIvSize(),
651                             new PBEKeySpec(
652                                     k.getPassword(), pbeSpec.getSalt(), pbeSpec.getIterationCount(),
653                                     k.getKeySize()),
654                             null /* CipherParameters */);
655                 }
656                 // END android-added
657                 param = PBE.Util.makePBEParameters(k, params, cipher.getUnderlyingCipher().getAlgorithmName());
658             }
659             else
660             {
661                 throw new InvalidAlgorithmParameterException("PBE requires PBE parameters to be set.");
662             }
663 
664             if (param instanceof ParametersWithIV)
665             {
666                 ivParam = (ParametersWithIV)param;
667             }
668         }
669         else if (key instanceof PBEKey)
670         {
671             PBEKey k = (PBEKey)key;
672             pbeSpec = (PBEParameterSpec)params;
673             if (k instanceof PKCS12KeyWithParameters && pbeSpec == null)
674             {
675                 pbeSpec = new PBEParameterSpec(k.getSalt(), k.getIterationCount());
676             }
677 
678             param = PBE.Util.makePBEParameters(k.getEncoded(), scheme, digest, keySizeInBits, ivLength * 8, pbeSpec, cipher.getAlgorithmName());
679             if (param instanceof ParametersWithIV)
680             {
681                 ivParam = (ParametersWithIV)param;
682             }
683         }
684         // BEGIN android-changed
685         // Was: else if (!(key instanceof RepeatedSecretKeySpec))
686         else
687         // END android-changed
688         {
689             if (scheme == PKCS5S1 || scheme == PKCS5S1_UTF8 || scheme == PKCS5S2 || scheme == PKCS5S2_UTF8)
690             {
691                 throw new InvalidKeyException("Algorithm requires a PBE key");
692             }
693             param = new KeyParameter(key.getEncoded());
694         }
695         // BEGIN android-removed
696         // else
697         // {
698         //    param = null;
699         // }
700         // END android-removed
701 
702         if (params instanceof AEADParameterSpec)
703         {
704             if (!isAEADModeName(modeName) && !(cipher instanceof AEADGenericBlockCipher))
705             {
706                 throw new InvalidAlgorithmParameterException("AEADParameterSpec can only be used with AEAD modes.");
707             }
708 
709             AEADParameterSpec aeadSpec = (AEADParameterSpec)params;
710 
711             KeyParameter keyParam;
712             if (param instanceof ParametersWithIV)
713             {
714                 keyParam = (KeyParameter)((ParametersWithIV)param).getParameters();
715             }
716             else
717             {
718                 keyParam = (KeyParameter)param;
719             }
720             param = aeadParams = new AEADParameters(keyParam, aeadSpec.getMacSizeInBits(), aeadSpec.getNonce(), aeadSpec.getAssociatedData());
721         }
722         else if (params instanceof IvParameterSpec)
723         {
724             if (ivLength != 0)
725             {
726                 IvParameterSpec p = (IvParameterSpec)params;
727 
728                 if (p.getIV().length != ivLength && !(cipher instanceof AEADGenericBlockCipher) && fixedIv)
729                 {
730                     throw new InvalidAlgorithmParameterException("IV must be " + ivLength + " bytes long.");
731                 }
732 
733                 if (param instanceof ParametersWithIV)
734                 {
735                     param = new ParametersWithIV(((ParametersWithIV)param).getParameters(), p.getIV());
736                 }
737                 else
738                 {
739                     param = new ParametersWithIV(param, p.getIV());
740                 }
741                 ivParam = (ParametersWithIV)param;
742             }
743             else
744             {
745                 if (modeName != null && modeName.equals("ECB"))
746                 {
747                     throw new InvalidAlgorithmParameterException("ECB mode does not use an IV");
748                 }
749             }
750         }
751         // BEGIN android-removed
752         // else if (params instanceof GOST28147ParameterSpec)
753         // {
754         //     GOST28147ParameterSpec    gost28147Param = (GOST28147ParameterSpec)params;
755         //
756         //     param = new ParametersWithSBox(
757         //                new KeyParameter(key.getEncoded()), ((GOST28147ParameterSpec)params).getSbox());
758         //
759         //     if (gost28147Param.getIV() != null && ivLength != 0)
760         //     {
761         //         if (param instanceof ParametersWithIV)
762         //         {
763         //             param = new ParametersWithIV(((ParametersWithIV)param).getParameters(), gost28147Param.getIV());
764         //         }
765         //         else
766         //         {
767         //             param = new ParametersWithIV(param, gost28147Param.getIV());
768         //         }
769         //         ivParam = (ParametersWithIV)param;
770         //     }
771         // }
772         // else if (params instanceof RC2ParameterSpec)
773         // {
774         //     RC2ParameterSpec    rc2Param = (RC2ParameterSpec)params;
775         //
776         //     param = new RC2Parameters(key.getEncoded(), ((RC2ParameterSpec)params).getEffectiveKeyBits());
777         //
778         //     if (rc2Param.getIV() != null && ivLength != 0)
779         //     {
780         //         if (param instanceof ParametersWithIV)
781         //         {
782         //             param = new ParametersWithIV(((ParametersWithIV)param).getParameters(), rc2Param.getIV());
783         //         }
784         //         else
785         //         {
786         //             param = new ParametersWithIV(param, rc2Param.getIV());
787         //         }
788         //         ivParam = (ParametersWithIV)param;
789         //     }
790         // }
791         // else if (params instanceof RC5ParameterSpec)
792         // {
793         //     RC5ParameterSpec    rc5Param = (RC5ParameterSpec)params;
794         //
795         //     param = new RC5Parameters(key.getEncoded(), ((RC5ParameterSpec)params).getRounds());
796         //     if (baseEngine.getAlgorithmName().startsWith("RC5"))
797         //     {
798         //         if (baseEngine.getAlgorithmName().equals("RC5-32"))
799         //         {
800         //             if (rc5Param.getWordSize() != 32)
801         //             {
802         //                 throw new InvalidAlgorithmParameterException("RC5 already set up for a word size of 32 not " + rc5Param.getWordSize() + ".");
803         //             }
804         //         }
805         //         else if (baseEngine.getAlgorithmName().equals("RC5-64"))
806         //         {
807         //             if (rc5Param.getWordSize() != 64)
808         //             {
809         //                 throw new InvalidAlgorithmParameterException("RC5 already set up for a word size of 64 not " + rc5Param.getWordSize() + ".");
810         //             }
811         //         }
812         //     }
813         //     else
814         //     {
815         //         throw new InvalidAlgorithmParameterException("RC5 parameters passed to a cipher that is not RC5.");
816         //     }
817         //     if ((rc5Param.getIV() != null) && (ivLength != 0))
818         //     {
819         //         if (param instanceof ParametersWithIV)
820         //         {
821         //             param = new ParametersWithIV(((ParametersWithIV)param).getParameters(), rc5Param.getIV());
822         //         }
823         //         else
824         //         {
825         //             param = new ParametersWithIV(param, rc5Param.getIV());
826         //         }
827         //         ivParam = (ParametersWithIV)param;
828         //     }
829         // }
830         // END android-removed
831         else if (gcmSpecClass != null && gcmSpecClass.isInstance(params))
832         {
833             if (!isAEADModeName(modeName) && !(cipher instanceof AEADGenericBlockCipher))
834             {
835                 throw new InvalidAlgorithmParameterException("GCMParameterSpec can only be used with AEAD modes.");
836             }
837 
838             try
839             {
840                 Method tLen = gcmSpecClass.getDeclaredMethod("getTLen", new Class[0]);
841                 Method iv= gcmSpecClass.getDeclaredMethod("getIV", new Class[0]);
842 
843                 KeyParameter keyParam;
844                 if (param instanceof ParametersWithIV)
845                 {
846                     keyParam = (KeyParameter)((ParametersWithIV)param).getParameters();
847                 }
848                 else
849                 {
850                     keyParam = (KeyParameter)param;
851                 }
852                 param = aeadParams = new AEADParameters(keyParam, ((Integer)tLen.invoke(params, new Object[0])).intValue(), (byte[])iv.invoke(params, new Object[0]));
853             }
854             catch (Exception e)
855             {
856                 throw new InvalidAlgorithmParameterException("Cannot process GCMParameterSpec.");
857             }
858         }
859         else if (params != null && !(params instanceof PBEParameterSpec))
860         {
861             throw new InvalidAlgorithmParameterException("unknown parameter type.");
862         }
863 
864         if ((ivLength != 0) && !(param instanceof ParametersWithIV) && !(param instanceof AEADParameters))
865         {
866             SecureRandom    ivRandom = random;
867 
868             if (ivRandom == null)
869             {
870                 ivRandom = new SecureRandom();
871             }
872             if ((opmode == Cipher.ENCRYPT_MODE) || (opmode == Cipher.WRAP_MODE))
873             {
874                 byte[]  iv = new byte[ivLength];
875 
876                 // BEGIN android-changed
877                 // Was: ivRandom.nextBytes(iv);
878                 // TODO(27995180): for such keys, consider whether we want to reject them or
879                 // allow them if the IV is passed in the parameters
880                 if (!isBCPBEKeyWithoutIV(key)) {
881                     ivRandom.nextBytes(iv);
882                 }
883                 // END android-changed
884                 param = new ParametersWithIV(param, iv);
885                 ivParam = (ParametersWithIV)param;
886             }
887             else if (cipher.getUnderlyingCipher().getAlgorithmName().indexOf("PGPCFB") < 0)
888             {
889                 // BEGIN android-changed
890                 // Was: throw new InvalidAlgorithmParameterException("no IV set when one expected");
891                 // TODO(27995180): for such keys, consider whether we want to reject them or
892                 // allow them if the IV is passed in the parameters
893                 if (!isBCPBEKeyWithoutIV(key)) {
894                     throw new InvalidAlgorithmParameterException("no IV set when one expected");
895                 } else {
896                     // Mimic behaviour in 1.52 by using an IV of 0's
897                     param = new ParametersWithIV(param, new byte[ivLength]);
898                     ivParam = (ParametersWithIV)param;
899                 }
900                 // END android-changed
901             }
902         }
903 
904 
905 
906         if (random != null && padded)
907         {
908             param = new ParametersWithRandom(param, random);
909         }
910 
911         try
912         {
913             switch (opmode)
914             {
915             case Cipher.ENCRYPT_MODE:
916             case Cipher.WRAP_MODE:
917                 cipher.init(true, param);
918                 break;
919             case Cipher.DECRYPT_MODE:
920             case Cipher.UNWRAP_MODE:
921                 cipher.init(false, param);
922                 break;
923             default:
924                 throw new InvalidParameterException("unknown opmode " + opmode + " passed");
925             }
926 
927             if (cipher instanceof AEADGenericBlockCipher && aeadParams == null)
928             {
929                 AEADBlockCipher aeadCipher = ((AEADGenericBlockCipher)cipher).cipher;
930 
931                 aeadParams = new AEADParameters((KeyParameter)ivParam.getParameters(), aeadCipher.getMac().length * 8, ivParam.getIV());
932             }
933         }
934         catch (final Exception e)
935         {
936             throw new InvalidKeyOrParametersException(e.getMessage(), e);
937         }
938     }
939 
adjustParameters(AlgorithmParameterSpec params, CipherParameters param)940     private CipherParameters adjustParameters(AlgorithmParameterSpec params, CipherParameters param)
941     {
942         CipherParameters key;
943 
944         if (param instanceof ParametersWithIV)
945         {
946             key = ((ParametersWithIV)param).getParameters();
947             if (params instanceof IvParameterSpec)
948             {
949                 IvParameterSpec iv = (IvParameterSpec)params;
950 
951                 ivParam = new ParametersWithIV(key, iv.getIV());
952                 param = ivParam;
953             }
954             // BEGIN android-removed
955             // else if (params instanceof GOST28147ParameterSpec)
956             // {
957             //     // need to pick up IV and SBox.
958             //     GOST28147ParameterSpec gost28147Param = (GOST28147ParameterSpec)params;
959             //
960             //     param = new ParametersWithSBox(param, gost28147Param.getSbox());
961             //
962             //     if (gost28147Param.getIV() != null && ivLength != 0)
963             //     {
964             //         ivParam = new ParametersWithIV(key, gost28147Param.getIV());
965             //         param = ivParam;
966             //     }
967             // }
968             // END android-removed
969         }
970         else
971         {
972             if (params instanceof IvParameterSpec)
973             {
974                 IvParameterSpec iv = (IvParameterSpec)params;
975 
976                 ivParam = new ParametersWithIV(param, iv.getIV());
977                 param = ivParam;
978             }
979             // BEGIN android-removed
980             // else if (params instanceof GOST28147ParameterSpec)
981             // {
982             //     // need to pick up IV and SBox.
983             //     GOST28147ParameterSpec gost28147Param = (GOST28147ParameterSpec)params;
984             //
985             //     param = new ParametersWithSBox(param, gost28147Param.getSbox());
986             //
987             //     if (gost28147Param.getIV() != null && ivLength != 0)
988             //     {
989             //         param = new ParametersWithIV(param, gost28147Param.getIV());
990             //     }
991             // }
992             // END android-removed
993         }
994         return param;
995     }
996 
engineInit( int opmode, Key key, AlgorithmParameters params, SecureRandom random)997     protected void engineInit(
998         int                 opmode,
999         Key                 key,
1000         AlgorithmParameters params,
1001         SecureRandom        random)
1002     throws InvalidKeyException, InvalidAlgorithmParameterException
1003     {
1004         AlgorithmParameterSpec  paramSpec = null;
1005 
1006         if (params != null)
1007         {
1008             for (int i = 0; i != availableSpecs.length; i++)
1009             {
1010                 if (availableSpecs[i] == null)
1011                 {
1012                     continue;
1013                 }
1014 
1015                 try
1016                 {
1017                     paramSpec = params.getParameterSpec(availableSpecs[i]);
1018                     break;
1019                 }
1020                 catch (Exception e)
1021                 {
1022                     // try again if possible
1023                 }
1024             }
1025 
1026             if (paramSpec == null)
1027             {
1028                 throw new InvalidAlgorithmParameterException("can't handle parameter " + params.toString());
1029             }
1030         }
1031 
1032         engineInit(opmode, key, paramSpec, random);
1033 
1034         engineParams = params;
1035     }
1036 
engineInit( int opmode, Key key, SecureRandom random)1037     protected void engineInit(
1038         int                 opmode,
1039         Key                 key,
1040         SecureRandom        random)
1041         throws InvalidKeyException
1042     {
1043         try
1044         {
1045             engineInit(opmode, key, (AlgorithmParameterSpec)null, random);
1046         }
1047         catch (InvalidAlgorithmParameterException e)
1048         {
1049             throw new InvalidKeyException(e.getMessage());
1050         }
1051     }
1052 
engineUpdateAAD(byte[] input, int offset, int length)1053     protected void engineUpdateAAD(byte[] input, int offset, int length)
1054     {
1055         cipher.updateAAD(input, offset, length);
1056     }
1057 
engineUpdateAAD(ByteBuffer bytebuffer)1058     protected void engineUpdateAAD(ByteBuffer bytebuffer)
1059     {
1060         int offset = bytebuffer.arrayOffset() + bytebuffer.position();
1061         int length = bytebuffer.limit() - bytebuffer.position();
1062         engineUpdateAAD(bytebuffer.array(), offset, length);
1063     }
1064 
engineUpdate( byte[] input, int inputOffset, int inputLen)1065     protected byte[] engineUpdate(
1066         byte[]  input,
1067         int     inputOffset,
1068         int     inputLen)
1069     {
1070         int     length = cipher.getUpdateOutputSize(inputLen);
1071 
1072         if (length > 0)
1073         {
1074                 byte[]  out = new byte[length];
1075 
1076                 int len = cipher.processBytes(input, inputOffset, inputLen, out, 0);
1077 
1078                 if (len == 0)
1079                 {
1080                     return null;
1081                 }
1082                 else if (len != out.length)
1083                 {
1084                     byte[]  tmp = new byte[len];
1085 
1086                     System.arraycopy(out, 0, tmp, 0, len);
1087 
1088                     return tmp;
1089                 }
1090 
1091                 return out;
1092         }
1093 
1094         cipher.processBytes(input, inputOffset, inputLen, null, 0);
1095 
1096         return null;
1097     }
1098 
engineUpdate( byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset)1099     protected int engineUpdate(
1100         byte[]  input,
1101         int     inputOffset,
1102         int     inputLen,
1103         byte[]  output,
1104         int     outputOffset)
1105         throws ShortBufferException
1106     {
1107         if (outputOffset + cipher.getUpdateOutputSize(inputLen) > output.length)
1108         {
1109             throw new ShortBufferException("output buffer too short for input.");
1110         }
1111 
1112         try
1113         {
1114             return cipher.processBytes(input, inputOffset, inputLen, output, outputOffset);
1115         }
1116         catch (DataLengthException e)
1117         {
1118             // should never occur
1119             throw new IllegalStateException(e.toString());
1120         }
1121     }
1122 
engineDoFinal( byte[] input, int inputOffset, int inputLen)1123     protected byte[] engineDoFinal(
1124         byte[]  input,
1125         int     inputOffset,
1126         int     inputLen)
1127         throws IllegalBlockSizeException, BadPaddingException
1128     {
1129         int     len = 0;
1130         byte[]  tmp = new byte[engineGetOutputSize(inputLen)];
1131 
1132         if (inputLen != 0)
1133         {
1134             len = cipher.processBytes(input, inputOffset, inputLen, tmp, 0);
1135         }
1136 
1137         try
1138         {
1139             len += cipher.doFinal(tmp, len);
1140         }
1141         catch (DataLengthException e)
1142         {
1143             throw new IllegalBlockSizeException(e.getMessage());
1144         }
1145 
1146         if (len == tmp.length)
1147         {
1148             return tmp;
1149         }
1150 
1151         byte[]  out = new byte[len];
1152 
1153         System.arraycopy(tmp, 0, out, 0, len);
1154 
1155         return out;
1156     }
1157 
engineDoFinal( byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset)1158     protected int engineDoFinal(
1159         byte[]  input,
1160         int     inputOffset,
1161         int     inputLen,
1162         byte[]  output,
1163         int     outputOffset)
1164         throws IllegalBlockSizeException, BadPaddingException, ShortBufferException
1165     {
1166         int     len = 0;
1167 
1168         if (outputOffset + engineGetOutputSize(inputLen) > output.length)
1169         {
1170             throw new ShortBufferException("output buffer too short for input.");
1171         }
1172 
1173         try
1174         {
1175             if (inputLen != 0)
1176             {
1177                 len = cipher.processBytes(input, inputOffset, inputLen, output, outputOffset);
1178             }
1179 
1180             return (len + cipher.doFinal(output, outputOffset + len));
1181         }
1182         catch (OutputLengthException e)
1183         {
1184             throw new IllegalBlockSizeException(e.getMessage());
1185         }
1186         catch (DataLengthException e)
1187         {
1188             throw new IllegalBlockSizeException(e.getMessage());
1189         }
1190     }
1191 
isAEADModeName( String modeName)1192     private boolean isAEADModeName(
1193         String modeName)
1194     {
1195         // BEGIN android-changed
1196         return "CCM".equals(modeName) || "GCM".equals(modeName);
1197         // END android-changed
1198     }
1199 
1200     /*
1201      * The ciphers that inherit from us.
1202      */
1203 
1204     static private interface GenericBlockCipher
1205     {
init(boolean forEncryption, CipherParameters params)1206         public void init(boolean forEncryption, CipherParameters params)
1207             throws IllegalArgumentException;
1208 
wrapOnNoPadding()1209         public boolean wrapOnNoPadding();
1210 
getAlgorithmName()1211         public String getAlgorithmName();
1212 
getUnderlyingCipher()1213         public org.bouncycastle.crypto.BlockCipher getUnderlyingCipher();
1214 
getOutputSize(int len)1215         public int getOutputSize(int len);
1216 
getUpdateOutputSize(int len)1217         public int getUpdateOutputSize(int len);
1218 
updateAAD(byte[] input, int offset, int length)1219         public void updateAAD(byte[] input, int offset, int length);
1220 
processByte(byte in, byte[] out, int outOff)1221         public int processByte(byte in, byte[] out, int outOff)
1222             throws DataLengthException;
1223 
processBytes(byte[] in, int inOff, int len, byte[] out, int outOff)1224         public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff)
1225             throws DataLengthException;
1226 
doFinal(byte[] out, int outOff)1227         public int doFinal(byte[] out, int outOff)
1228             throws IllegalStateException,
1229             BadPaddingException;
1230     }
1231 
1232     private static class BufferedGenericBlockCipher
1233         implements GenericBlockCipher
1234     {
1235         private BufferedBlockCipher cipher;
1236 
BufferedGenericBlockCipher(BufferedBlockCipher cipher)1237         BufferedGenericBlockCipher(BufferedBlockCipher cipher)
1238         {
1239             this.cipher = cipher;
1240         }
1241 
BufferedGenericBlockCipher(org.bouncycastle.crypto.BlockCipher cipher)1242         BufferedGenericBlockCipher(org.bouncycastle.crypto.BlockCipher cipher)
1243         {
1244             this.cipher = new PaddedBufferedBlockCipher(cipher);
1245         }
1246 
BufferedGenericBlockCipher(org.bouncycastle.crypto.BlockCipher cipher, BlockCipherPadding padding)1247         BufferedGenericBlockCipher(org.bouncycastle.crypto.BlockCipher cipher, BlockCipherPadding padding)
1248         {
1249             this.cipher = new PaddedBufferedBlockCipher(cipher, padding);
1250         }
1251 
init(boolean forEncryption, CipherParameters params)1252         public void init(boolean forEncryption, CipherParameters params)
1253             throws IllegalArgumentException
1254         {
1255             cipher.init(forEncryption, params);
1256         }
1257 
wrapOnNoPadding()1258         public boolean wrapOnNoPadding()
1259         {
1260             return !(cipher instanceof CTSBlockCipher);
1261         }
1262 
getAlgorithmName()1263         public String getAlgorithmName()
1264         {
1265             return cipher.getUnderlyingCipher().getAlgorithmName();
1266         }
1267 
getUnderlyingCipher()1268         public org.bouncycastle.crypto.BlockCipher getUnderlyingCipher()
1269         {
1270             return cipher.getUnderlyingCipher();
1271         }
1272 
getOutputSize(int len)1273         public int getOutputSize(int len)
1274         {
1275             return cipher.getOutputSize(len);
1276         }
1277 
getUpdateOutputSize(int len)1278         public int getUpdateOutputSize(int len)
1279         {
1280             return cipher.getUpdateOutputSize(len);
1281         }
1282 
updateAAD(byte[] input, int offset, int length)1283         public void updateAAD(byte[] input, int offset, int length)
1284         {
1285             throw new UnsupportedOperationException("AAD is not supported in the current mode.");
1286         }
1287 
processByte(byte in, byte[] out, int outOff)1288         public int processByte(byte in, byte[] out, int outOff) throws DataLengthException
1289         {
1290             return cipher.processByte(in, out, outOff);
1291         }
1292 
processBytes(byte[] in, int inOff, int len, byte[] out, int outOff)1293         public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff) throws DataLengthException
1294         {
1295             return cipher.processBytes(in, inOff, len, out, outOff);
1296         }
1297 
doFinal(byte[] out, int outOff)1298         public int doFinal(byte[] out, int outOff) throws IllegalStateException, BadPaddingException
1299         {
1300             try
1301             {
1302                 return cipher.doFinal(out, outOff);
1303             }
1304             catch (InvalidCipherTextException e)
1305             {
1306                 throw new BadPaddingException(e.getMessage());
1307             }
1308         }
1309     }
1310 
1311     private static class AEADGenericBlockCipher
1312         implements GenericBlockCipher
1313     {
1314         private static final Constructor aeadBadTagConstructor;
1315 
1316         static {
1317             Class aeadBadTagClass = lookup("javax.crypto.AEADBadTagException");
1318             if (aeadBadTagClass != null)
1319             {
1320                 aeadBadTagConstructor = findExceptionConstructor(aeadBadTagClass);
1321             }
1322             else
1323             {
1324                 aeadBadTagConstructor = null;
1325             }
1326         }
1327 
findExceptionConstructor(Class clazz)1328         private static Constructor findExceptionConstructor(Class clazz)
1329         {
1330             try
1331             {
1332                 return clazz.getConstructor(new Class[]{String.class});
1333             }
1334             catch (Exception e)
1335             {
1336                 return null;
1337             }
1338         }
1339 
1340         private AEADBlockCipher cipher;
1341 
AEADGenericBlockCipher(AEADBlockCipher cipher)1342         AEADGenericBlockCipher(AEADBlockCipher cipher)
1343         {
1344             this.cipher = cipher;
1345         }
1346 
init(boolean forEncryption, CipherParameters params)1347         public void init(boolean forEncryption, CipherParameters params)
1348             throws IllegalArgumentException
1349         {
1350             cipher.init(forEncryption, params);
1351         }
1352 
getAlgorithmName()1353         public String getAlgorithmName()
1354         {
1355             return cipher.getUnderlyingCipher().getAlgorithmName();
1356         }
1357 
wrapOnNoPadding()1358         public boolean wrapOnNoPadding()
1359         {
1360             return false;
1361         }
1362 
getUnderlyingCipher()1363         public org.bouncycastle.crypto.BlockCipher getUnderlyingCipher()
1364         {
1365             return cipher.getUnderlyingCipher();
1366         }
1367 
getOutputSize(int len)1368         public int getOutputSize(int len)
1369         {
1370             return cipher.getOutputSize(len);
1371         }
1372 
getUpdateOutputSize(int len)1373         public int getUpdateOutputSize(int len)
1374         {
1375             return cipher.getUpdateOutputSize(len);
1376         }
1377 
updateAAD(byte[] input, int offset, int length)1378         public void updateAAD(byte[] input, int offset, int length)
1379         {
1380             cipher.processAADBytes(input, offset, length);
1381         }
1382 
processByte(byte in, byte[] out, int outOff)1383         public int processByte(byte in, byte[] out, int outOff) throws DataLengthException
1384         {
1385             return cipher.processByte(in, out, outOff);
1386         }
1387 
processBytes(byte[] in, int inOff, int len, byte[] out, int outOff)1388         public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff) throws DataLengthException
1389         {
1390             return cipher.processBytes(in, inOff, len, out, outOff);
1391         }
1392 
doFinal(byte[] out, int outOff)1393         public int doFinal(byte[] out, int outOff) throws IllegalStateException, BadPaddingException
1394         {
1395             try
1396             {
1397                 return cipher.doFinal(out, outOff);
1398             }
1399             catch (InvalidCipherTextException e)
1400             {
1401                 if (aeadBadTagConstructor != null)
1402                 {
1403                     BadPaddingException aeadBadTag = null;
1404                     try
1405                     {
1406                         aeadBadTag = (BadPaddingException)aeadBadTagConstructor
1407                                 .newInstance(new Object[]{e.getMessage()});
1408                     }
1409                     catch (Exception i)
1410                     {
1411                         // Shouldn't happen, but fall through to BadPaddingException
1412                     }
1413                     if (aeadBadTag != null)
1414                     {
1415                         throw aeadBadTag;
1416                     }
1417                 }
1418                 throw new BadPaddingException(e.getMessage());
1419             }
1420         }
1421     }
1422 
1423     private static class InvalidKeyOrParametersException
1424         extends InvalidKeyException
1425     {
1426         private final Throwable cause;
1427 
InvalidKeyOrParametersException(String msg, Throwable cause)1428         InvalidKeyOrParametersException(String msg, Throwable cause)
1429         {
1430              super(msg);
1431             this.cause = cause;
1432         }
1433 
getCause()1434         public Throwable getCause()
1435         {
1436             return cause;
1437         }
1438     }
1439 }
1440