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