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