1 /*
2  * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 import java.nio.ByteBuffer;
25 import java.security.AlgorithmParameters;
26 import java.security.Provider;
27 import java.security.Security;
28 import java.util.ArrayList;
29 import java.util.Arrays;
30 import java.util.List;
31 import javax.crypto.SecretKey;
32 import javax.crypto.Cipher;
33 import javax.crypto.KeyGenerator;
34 
35 /*
36  * @test
37  * @bug 8048596
38  * @summary AEAD encryption/decryption test
39  */
40 
41 /*
42  * The test does the following:
43  *   - create an input text and additional data
44  *   - generate a secret key
45  *   - instantiate a cipher according to the GCM transformation
46  *   - generate an outputText using a single-part encryption/decryption
47  *     in AEAD mode
48  *   - perform 16 different combinations of multiple-part encryption/decryption
49  *     operation in AEAD mode (in encryption mode new Cipher object is created
50  *     and initialized with the same secret key and parameters)
51  *   - check that all 17 results are equal
52  *
53  * Combinations:
54  *
55  * combination #1
56  *   updateAAD(byte[] src)
57  *   update(byte[], int, int)
58  *   doFinal(byte[], int, int)
59  *
60  * combination #2
61  *   updateAAD(byte[] src)
62  *   update(byte[], int, int)
63  *   doFinal(byte[], int, int, byte[], int)
64  *
65  * combination #3
66  *   updateAAD(byte[] src)
67  *   update(byte[], int, int, byte[], int)
68  *   doFinal(byte[], int, int)
69  *
70  * combination #4
71  *   updateAAD(byte[] src)
72  *   update(byte[], int, int, byte[], int)
73  *   doFinal(byte[], int, int, byte[], int)
74  *
75  * combination #5 - #8 are similar to #1 -#4,
76  * but with updateAAD(byte[] src, int offset, int len)
77  *
78  * combination #9 - #12 are similar to #1 - #4,
79  * but with updateAAD(ByteBuffer src)
80  *
81  * combination #13 - #16 are similar to #9 - #12 but with directly allocated
82  * ByteBuffer and update(ByteBuffer input, ByteBuffer output)
83  *
84  */
85 public class Encrypt {
86 
87     private static final String ALGORITHMS[] = { "AES", "Rijndael" };
88     private static final int KEY_STRENGTHS[] = { 128, 192, 256 };
89     private static final int TEXT_LENGTHS[] = { 0, 256, 1024 };
90     private static final int AAD_LENGTHS[] = { 0, 8, 128, 256, 1024 };
91     private static final int ARRAY_OFFSET = 8;
92 
93     private final String transformation;
94     private final Provider provider;
95     private final SecretKey key;
96     private final int textLength;
97     private final int AADLength;
98 
99     /**
100      * @param provider Security provider
101      * @param algorithm Security algorithm to test
102      * @param mode The mode (GCM is only expected)
103      * @param padding Algorithm padding
104      * @param keyStrength key length
105      * @param textLength Plain text length
106      * @param AADLength Additional data length
107      */
Encrypt(Provider provider, String algorithm, String mode, String padding, int keyStrength, int textLength, int AADLength)108     public Encrypt(Provider provider, String algorithm, String mode,
109             String padding, int keyStrength, int textLength, int AADLength)
110             throws Exception {
111 
112         // init a secret Key
113         KeyGenerator kg = KeyGenerator.getInstance(algorithm, provider);
114         kg.init(keyStrength);
115         key = kg.generateKey();
116 
117         this.provider = provider;
118         this.transformation = algorithm + "/" + mode + "/" + padding;
119         this.textLength = textLength;
120         this.AADLength = AADLength;
121     }
122 
main(String[] args)123     public static void main(String[] args) throws Exception {
124         Provider p = Security.getProvider("SunJCE");
125         for (String alg : ALGORITHMS) {
126             for (int keyStrength : KEY_STRENGTHS) {
127                 if (keyStrength > Cipher.getMaxAllowedKeyLength(alg)) {
128                     // skip this if this key length is larger than what's
129                     // configured in the JCE jurisdiction policy files
130                     continue;
131                 }
132                 for (int textLength : TEXT_LENGTHS) {
133                     for (int AADLength : AAD_LENGTHS) {
134                         Encrypt test = new Encrypt(p, alg,
135                                 "GCM", "NoPadding", keyStrength, textLength,
136                                 AADLength);
137                         Cipher cipher = test.createCipher(Cipher.ENCRYPT_MODE,
138                                 null);
139                         AlgorithmParameters params = cipher.getParameters();
140                         test.doTest(params);
141                         System.out.println("Test " + alg + ":"
142                                 + keyStrength + ":" + textLength + ":"
143                                 + AADLength + " passed");
144                     }
145                 }
146             }
147         }
148     }
149 
doTest(AlgorithmParameters params)150     public void doTest(AlgorithmParameters params) throws Exception {
151         System.out.println("Test transformation = " + transformation
152                 + ", textLength = " + textLength
153                 + ", AADLength = " + AADLength);
154         byte[] input = Helper.generateBytes(textLength);
155         byte[] AAD = Helper.generateBytes(AADLength);
156         byte[] result = execute(Cipher.ENCRYPT_MODE, AAD, input, params);
157         result = execute(Cipher.DECRYPT_MODE, AAD, result, params);
158         if (!Arrays.equals(input, result)) {
159             throw new RuntimeException("Test failed");
160         }
161         System.out.println("Test passed");
162     }
163 
164     /**
165      * Create a Cipher object for the requested encryption/decryption mode.
166      *
167      * @param mode encryption or decryption mode
168      * @return Cipher object initiated to perform requested mode operation
169      */
createCipher(int mode, AlgorithmParameters params)170     private Cipher createCipher(int mode, AlgorithmParameters params)
171             throws Exception {
172         Cipher ci;
173         if (Cipher.ENCRYPT_MODE == mode) {
174             // create a new Cipher object for encryption
175             ci = Cipher.getInstance(transformation, provider);
176 
177             // initiate it with the saved parameters
178             if (params != null) {
179                 ci.init(Cipher.ENCRYPT_MODE, key, params);
180             } else {
181                 // initiate the cipher without parameters
182                 ci.init(Cipher.ENCRYPT_MODE, key);
183             }
184         } else {
185             // it is expected that parameters already generated
186             // before decryption
187             ci = Cipher.getInstance(transformation, provider);
188             ci.init(Cipher.DECRYPT_MODE, key, params);
189         }
190 
191         return ci;
192     }
193 
194     /**
195      * Test AEAD combinations
196      *
197      * @param mode decryption or encryption
198      * @param AAD additional data for AEAD operations
199      * @param inputText plain text to decrypt/encrypt
200      * @return output text after encrypt/decrypt
201      */
execute(int mode, byte[] AAD, byte[] inputText, AlgorithmParameters params)202     public byte[] execute(int mode, byte[] AAD, byte[] inputText,
203             AlgorithmParameters params) throws Exception {
204 
205         Cipher cipher = createCipher(mode, params);
206 
207         // results of each combination will be saved in the outputTexts
208         List<byte[]> outputTexts = new ArrayList<>();
209 
210         // generate a standard outputText using a single-part en/de-cryption
211         cipher.updateAAD(AAD);
212         byte[] output = cipher.doFinal(inputText);
213 
214         // execute multiple-part encryption/decryption combinations
215         combination_1(outputTexts, mode, AAD, inputText, params);
216         combination_2(outputTexts, mode, AAD, inputText, params);
217         combination_3(outputTexts, mode, AAD, inputText, params);
218         combination_4(outputTexts, mode, AAD, inputText, params);
219         combination_5(outputTexts, mode, AAD, inputText, params);
220         combination_6(outputTexts, mode, AAD, inputText, params);
221         combination_7(outputTexts, mode, AAD, inputText, params);
222         combination_8(outputTexts, mode, AAD, inputText, params);
223         combination_9(outputTexts, mode, AAD, inputText, params);
224         combination_10(outputTexts, mode, AAD, inputText, params);
225         combination_11(outputTexts, mode, AAD, inputText, params);
226         combination_12(outputTexts, mode, AAD, inputText, params);
227         combination_13(outputTexts, mode, AAD, inputText, params);
228         combination_14(outputTexts, mode, AAD, inputText, params);
229         combination_15(outputTexts, mode, AAD, inputText, params);
230         combination_16(outputTexts, mode, AAD, inputText, params);
231 
232         for (int k = 0; k < outputTexts.size(); k++) {
233             if (!Arrays.equals(output, outputTexts.get(k))) {
234                 throw new RuntimeException("Combination #" + k + " failed");
235             }
236         }
237         return output;
238     }
239 
240     /*
241      * Execute multiple-part encryption/decryption combination #1:
242      *   updateAAD(byte[] src)
243      *   update(byte[], int, int)
244      *   doFinal(byte[], int, int)
245      */
combination_1(List<byte[]> results, int mode, byte[] AAD, byte[] plainText, AlgorithmParameters params)246     private void combination_1(List<byte[]> results, int mode, byte[] AAD,
247             byte[] plainText, AlgorithmParameters params) throws Exception {
248         Cipher c = createCipher(mode, params);
249         c.updateAAD(AAD);
250         byte[] part11 = c.update(plainText, 0, plainText.length);
251         int part11_length = part11 == null ? 0 : part11.length;
252         byte[] part12 = c.doFinal();
253         byte[] outputText1 = new byte[part11_length + part12.length];
254         if (part11 != null) {
255             System.arraycopy(part11, 0, outputText1, 0, part11_length);
256         }
257         System.arraycopy(part12, 0, outputText1, part11_length, part12.length);
258         results.add(outputText1);
259     }
260 
261     /*
262      * Execute multiple-part encryption/decryption combination #2:
263      *   updateAAD(byte[] src)
264      *   update(byte[], int, int)
265      *   doFinal(byte[], int, int, byte[], int)
266      */
combination_2(List<byte[]> results, int mode, byte[] AAD, byte[] plainText, AlgorithmParameters params)267     private void combination_2(List<byte[]> results, int mode, byte[] AAD,
268             byte[] plainText, AlgorithmParameters params) throws Exception {
269         Cipher c = createCipher(mode, params);
270         c.updateAAD(AAD);
271         int t = 0;
272         int offset = 0;
273         if (plainText.length > ARRAY_OFFSET) {
274             t = plainText.length - ARRAY_OFFSET;
275             offset = ARRAY_OFFSET;
276         }
277         byte[] part21 = c.update(plainText, 0, t);
278         byte[] part22 = new byte[c.getOutputSize(plainText.length)];
279         int len2 = c.doFinal(plainText, t, offset, part22, 0);
280         int part21Length = part21 != null ? part21.length : 0;
281         byte[] outputText2 = new byte[part21Length + len2];
282         if (part21 != null) {
283             System.arraycopy(part21, 0, outputText2, 0, part21Length);
284         }
285         System.arraycopy(part22, 0, outputText2, part21Length, len2);
286         results.add(outputText2);
287     }
288 
289     /*
290      * Execute multiple-part encryption/decryption combination #3
291      *   updateAAD(byte[] src)
292      *   update(byte[], int, int, byte[], int)
293      *   doFinal(byte[], int, int)
294      */
combination_3(List<byte[]> results, int mode, byte[] AAD, byte[] plainText, AlgorithmParameters params)295     private void combination_3(List<byte[]> results, int mode, byte[] AAD,
296             byte[] plainText, AlgorithmParameters params) throws Exception {
297         Cipher ci = createCipher(mode, params);
298         ci.updateAAD(AAD);
299         byte[] part31 = new byte[ci.getOutputSize(plainText.length)];
300         int offset = plainText.length > ARRAY_OFFSET ? ARRAY_OFFSET : 0;
301         int len = ci.update(plainText, 0, plainText.length - offset, part31, 0);
302         byte[] part32 = ci.doFinal(plainText, plainText.length - offset,
303                 offset);
304         byte[] outputText3 = new byte[len + part32.length];
305         System.arraycopy(part31, 0, outputText3, 0, len);
306         System.arraycopy(part32, 0, outputText3, len, part32.length);
307         results.add(outputText3);
308     }
309 
310     /*
311      * Execute multiple-part encryption/decryption combination #4:
312      *   updateAAD(byte[] src)
313      *   update(byte[], int, int, byte[], int)
314      *   doFinal(byte[], int, int, byte[], int)
315      */
combination_4(List<byte[]> results, int mode, byte[] AAD, byte[] plainText, AlgorithmParameters params)316     private void combination_4(List<byte[]> results, int mode, byte[] AAD,
317             byte[] plainText, AlgorithmParameters params) throws Exception {
318         Cipher ci = createCipher(mode, params);
319         ci.updateAAD(AAD);
320         byte[] part41 = new byte[ci.getOutputSize(plainText.length)];
321         int offset = plainText.length > ARRAY_OFFSET ? ARRAY_OFFSET : 0;
322         int len = ci.update(plainText, 0, plainText.length - offset, part41, 0);
323         int rest4 = ci.doFinal(plainText, plainText.length - offset, offset,
324                 part41, len);
325         byte[] outputText4 = new byte[len + rest4];
326         System.arraycopy(part41, 0, outputText4, 0, outputText4.length);
327         results.add(outputText4);
328     }
329 
330     /*
331      * Execute multiple-part encryption/decryption combination #5:
332      *   updateAAD(byte[] src, int offset, int len)
333      *   update(byte[], int, int)
334      *   doFinal(byte[], int, int)
335      */
combination_5(List<byte[]> results, int mode, byte[] AAD, byte[] plainText, AlgorithmParameters params)336     private void combination_5(List<byte[]> results, int mode, byte[] AAD,
337             byte[] plainText, AlgorithmParameters params) throws Exception {
338         Cipher c = createCipher(mode, params);
339         c.updateAAD(AAD, 0, AAD.length);
340         byte[] part51 = c.update(plainText, 0, plainText.length);
341         byte[] part52 = c.doFinal();
342         int part51Length = part51 != null ? part51.length : 0;
343         byte[] outputText5 = new byte[part51Length + part52.length];
344         if (part51 != null) {
345             System.arraycopy(part51, 0, outputText5, 0, part51Length);
346         }
347         System.arraycopy(part52, 0, outputText5, part51Length, part52.length);
348         results.add(outputText5);
349     }
350 
351     /*
352      * Execute multiple-part encryption/decryption combination #6:
353      *   updateAAD(byte[] src, int offset, int len)
354      *   updateAAD(byte[] src, int offset, int len)
355      *   update(byte[], int, int) doFinal(byte[], int, int, byte[], int)
356      */
combination_6(List<byte[]> results, int mode, byte[] AAD, byte[] plainText, AlgorithmParameters params)357     private void combination_6(List<byte[]> results, int mode, byte[] AAD,
358             byte[] plainText, AlgorithmParameters params) throws Exception {
359         Cipher c = createCipher(mode, params);
360         c.updateAAD(AAD, 0, AAD.length / 2);
361         c.updateAAD(AAD, AAD.length / 2, AAD.length - AAD.length / 2);
362         int t = 0;
363         int offset = 0;
364         if (plainText.length > ARRAY_OFFSET) {
365             t = plainText.length - ARRAY_OFFSET;
366             offset = ARRAY_OFFSET;
367         }
368         byte[] part61 = c.update(plainText, 0, t);
369         byte[] part62 = new byte[c.getOutputSize(plainText.length)];
370         int len = c.doFinal(plainText, t, offset, part62, 0);
371         int part61Length = part61 != null ? part61.length : 0;
372         byte[] outputText6 = new byte[part61Length + len];
373         if (part61 != null) {
374             System.arraycopy(part61, 0, outputText6, 0, part61Length);
375         }
376         System.arraycopy(part62, 0, outputText6, part61Length, len);
377         results.add(outputText6);
378     }
379 
380     /*
381      * Execute multiple-part encryption/decryption combination #7
382      *   updateAAD(byte[] src, int offset, int len)
383      *   updateAAD(byte[] src, src.length, 0)
384      *   update(byte[], int, int, byte[], int) doFinal(byte[],int, int)
385      */
combination_7(List<byte[]> results, int mode, byte[] AAD, byte[] plainText, AlgorithmParameters params)386     private void combination_7(List<byte[]> results, int mode, byte[] AAD,
387             byte[] plainText, AlgorithmParameters params) throws Exception {
388         Cipher ci = createCipher(mode, params);
389         ci.updateAAD(AAD, 0, AAD.length);
390         ci.updateAAD(AAD, AAD.length, 0);
391         byte[] part71 = new byte[ci.getOutputSize(plainText.length)];
392         int offset = plainText.length > ARRAY_OFFSET ? ARRAY_OFFSET : 0;
393         int len = ci.update(plainText, 0, plainText.length - offset, part71, 0);
394         byte[] part72 = ci.doFinal(plainText, plainText.length - offset, offset);
395         byte[] outputText7 = new byte[len + part72.length];
396         System.arraycopy(part71, 0, outputText7, 0, len);
397         System.arraycopy(part72, 0, outputText7, len, part72.length);
398         results.add(outputText7);
399     }
400 
401     /*
402      * Execute multiple-part encryption/decryption combination #8:
403      *   updateAAD(byte[] src, 0, 0)
404      *   updateAAD(byte[] src, 0, src.length)
405      *   update(byte[], int, int, byte[], int)
406      *   doFinal(byte[], int, int, byte[], int)
407      */
combination_8(List<byte[]> results, int mode, byte[] AAD, byte[] plainText, AlgorithmParameters params)408     private void combination_8(List<byte[]> results, int mode, byte[] AAD,
409             byte[] plainText, AlgorithmParameters params) throws Exception {
410         Cipher ci = createCipher(mode, params);
411         ci.updateAAD(AAD, 0, 0);
412         ci.updateAAD(AAD, 0, AAD.length);
413         byte[] part81 = new byte[ci.getOutputSize(plainText.length)];
414         int offset = plainText.length > ARRAY_OFFSET ? ARRAY_OFFSET : 0;
415         int len = ci.update(plainText, 0, plainText.length - offset, part81, 0);
416         int rest = ci.doFinal(plainText, plainText.length - offset, offset,
417                 part81, len);
418         byte[] outputText8 = new byte[len + rest];
419         System.arraycopy(part81, 0, outputText8, 0, outputText8.length);
420         results.add(outputText8);
421     }
422 
423     /*
424      * Execute multiple-part encryption/decryption combination #9:
425      *   updateAAD(ByteBuffer src)
426      *   update(byte[], int, int) doFinal(byte[], int, int)
427      */
combination_9(List<byte[]> results, int mode, byte[] AAD, byte[] plainText, AlgorithmParameters params)428     private void combination_9(List<byte[]> results, int mode, byte[] AAD,
429             byte[] plainText, AlgorithmParameters params) throws Exception {
430 
431         // prepare ByteBuffer to test
432         ByteBuffer buf = ByteBuffer.allocate(AAD.length);
433         buf.put(AAD);
434         buf.position(0);
435         buf.limit(AAD.length);
436 
437         // Get Cipher object and do the combination
438         Cipher c = createCipher(mode, params);
439         c.updateAAD(buf);
440         byte[] part91 = c.update(plainText, 0, plainText.length);
441         int part91_length = part91 == null ? 0 : part91.length;
442         byte[] part92 = c.doFinal();
443         byte[] outputText9 = new byte[part91_length + part92.length];
444 
445         // form result of the combination
446         if (part91 != null) {
447             System.arraycopy(part91, 0, outputText9, 0, part91_length);
448         }
449         System.arraycopy(part92, 0, outputText9, part91_length, part92.length);
450         results.add(outputText9);
451     }
452 
453     /*
454      * Execute multiple-part encryption/decryption combination #10:
455      *   updateAAD(ByteBuffer src)
456      *   updateAAD(ByteBuffer src) update(byte[], int, int)
457      *   doFinal(byte[], int, int, byte[], int)
458      */
combination_10(List<byte[]> results, int mode, byte[] AAD, byte[] plainText, AlgorithmParameters params)459     private void combination_10(List<byte[]> results, int mode, byte[] AAD,
460             byte[] plainText, AlgorithmParameters params) throws Exception {
461 
462         // prepare ByteBuffer to test
463         ByteBuffer buf = ByteBuffer.allocate(AAD.length);
464         buf.put(AAD);
465         buf.position(0);
466         buf.limit(AAD.length / 2);
467 
468         // get a Cipher object and do the combination
469         Cipher c = createCipher(mode, params);
470 
471         // process the first half of AAD data
472         c.updateAAD(buf);
473 
474         // process the rest of AAD data
475         buf.limit(AAD.length);
476         c.updateAAD(buf);
477 
478         // prapare variables for the combination
479         int t = 0;
480         int offset = 0;
481         if (plainText.length > ARRAY_OFFSET) {
482             t = plainText.length - ARRAY_OFFSET;
483             offset = ARRAY_OFFSET;
484         }
485 
486         // encrypt the text
487         byte[] part10_1 = c.update(plainText, 0, t);
488         int part10_1_Length = part10_1 != null ? part10_1.length : 0;
489         byte[] part10_2 = new byte[c.getOutputSize(plainText.length)];
490         int len2 = c.doFinal(plainText, t, offset, part10_2, 0);
491 
492         // form the combination's result
493         byte[] outputText10 = new byte[part10_1_Length + len2];
494         if (part10_1 != null) {
495             System.arraycopy(part10_1, 0, outputText10, 0, part10_1_Length);
496         }
497         System.arraycopy(part10_2, 0, outputText10, part10_1_Length, len2);
498         results.add(outputText10);
499     }
500 
501     /*
502      * Execute multiple-part encryption/decryption combination #11
503      *   updateAAD(ByteBuffer src1)
504      *   updateAAD(ByteBuffer src2)
505      *   update(byte[],int, int, byte[], int)
506      *   doFinal(byte[], int, int)
507      */
combination_11(List<byte[]> results, int mode, byte[] AAD, byte[] plainText, AlgorithmParameters params)508     private void combination_11(List<byte[]> results, int mode, byte[] AAD,
509             byte[] plainText, AlgorithmParameters params) throws Exception {
510 
511         // prepare ByteBuffer1 to test
512         ByteBuffer buf1 = ByteBuffer.allocate(AAD.length / 2);
513         buf1.put(AAD, 0, AAD.length / 2);
514         buf1.position(0);
515         buf1.limit(AAD.length / 2);
516 
517         // get a Cipher object and do combination
518         Cipher ci = createCipher(mode, params);
519 
520         // process the first half of AAD data
521         ci.updateAAD(buf1);
522 
523         // prepare ByteBuffer2 to test
524         ByteBuffer buf2 = ByteBuffer.allocate(AAD.length - AAD.length / 2);
525         buf2.put(AAD, AAD.length / 2, AAD.length - AAD.length / 2);
526         buf2.position(0);
527         buf2.limit(AAD.length - AAD.length / 2);
528 
529         // process the rest of AAD data
530         ci.updateAAD(buf2);
531 
532         // encrypt plain text
533         byte[] part11_1 = new byte[ci.getOutputSize(plainText.length)];
534         int offset = plainText.length > ARRAY_OFFSET ? ARRAY_OFFSET : 0;
535         int len_11 = ci.update(plainText, 0, plainText.length - offset,
536                 part11_1, 0);
537         byte[] part11_2 = ci.doFinal(plainText, plainText.length - offset,
538                 offset);
539         byte[] outputText11 = new byte[len_11 + part11_2.length];
540         System.arraycopy(part11_1, 0, outputText11, 0, len_11);
541         System.arraycopy(part11_2, 0, outputText11, len_11, part11_2.length);
542         results.add(outputText11);
543     }
544 
545     /*
546      * Execute multiple-part encryption/decryption combination #12:
547      *   updateAAD(ByteBuffer src)
548      *   updateAAD(ByteBuffer emptyByteBuffer)
549      *   update(byte[], int, int, byte[], int)
550      *   doFinal(byte[], int, int, byte[], int)
551      */
combination_12(List<byte[]> results, int mode, byte[] AAD, byte[] plainText, AlgorithmParameters params)552     private void combination_12(List<byte[]> results, int mode, byte[] AAD,
553             byte[] plainText, AlgorithmParameters params) throws Exception {
554 
555         // prepare ByteBuffer to test
556         ByteBuffer buf = ByteBuffer.allocate(AAD.length);
557         buf.put(AAD);
558         buf.position(0);
559         buf.limit(AAD.length);
560         Cipher ci = createCipher(mode, params);
561         ci.updateAAD(buf);
562 
563         // prepare an empty ByteBuffer
564         ByteBuffer emptyBuf = ByteBuffer.allocate(0);
565         emptyBuf.put(new byte[0]);
566         ci.updateAAD(emptyBuf);
567         byte[] part12_1 = new byte[ci.getOutputSize(plainText.length)];
568         int offset = plainText.length > ARRAY_OFFSET ? ARRAY_OFFSET : 0;
569         int len12 = ci.update(plainText, 0, plainText.length - offset,
570                 part12_1, 0);
571         int rest12 = ci.doFinal(plainText, plainText.length - offset, offset,
572                 part12_1, len12);
573         byte[] outputText12 = new byte[len12 + rest12];
574         System.arraycopy(part12_1, 0, outputText12, 0, outputText12.length);
575         results.add(outputText12);
576     }
577 
578     /*
579      * Execute multiple-part encryption/decryption combination #13:
580      *   updateAAD(ByteBuffer src), where src is directly allocated
581      *   update(ByteBuffer input, ByteBuffer out)
582      *   doFinal(ByteBuffer input, ByteBuffer out)
583      */
combination_13(List<byte[]> results, int mode, byte[] AAD, byte[] plainText, AlgorithmParameters params)584     private void combination_13(List<byte[]> results, int mode, byte[] AAD,
585             byte[] plainText, AlgorithmParameters params) throws Exception {
586         Cipher c = createCipher(mode, params);
587 
588         // prepare ByteBuffer to test
589         ByteBuffer buf = ByteBuffer.allocateDirect(AAD.length);
590         buf.put(AAD);
591         buf.position(0);
592         buf.limit(AAD.length);
593         c.updateAAD(buf);
594 
595         // prepare buffers to encrypt/decrypt
596         ByteBuffer in = ByteBuffer.allocateDirect(plainText.length);
597         in.put(plainText);
598         in.position(0);
599         in.limit(plainText.length);
600         ByteBuffer output = ByteBuffer.allocateDirect(
601                 c.getOutputSize(in.limit()));
602         output.position(0);
603         output.limit(c.getOutputSize(in.limit()));
604 
605         // process input text
606         c.update(in, output);
607         c.doFinal(in, output);
608         int resultSize = output.position();
609         byte[] result13 = new byte[resultSize];
610         output.position(0);
611         output.limit(resultSize);
612         output.get(result13, 0, resultSize);
613         results.add(result13);
614     }
615 
616     /*
617      * Execute multiple-part encryption/decryption combination #14:
618      *   updateAAD(ByteBuffer src) updateAAD(ByteBuffer src),
619      *       where src is directly allocated
620      *   update(ByteBuffer input, ByteBuffer out)
621      *   doFinal(ByteBuffer input, ByteBuffer out)
622      */
combination_14(List<byte[]> results, int mode, byte[] AAD, byte[] plainText, AlgorithmParameters params)623     private void combination_14(List<byte[]> results, int mode, byte[] AAD,
624             byte[] plainText, AlgorithmParameters params) throws Exception {
625         Cipher c = createCipher(mode, params);
626         // prepare ByteBuffer to test
627         ByteBuffer buf = ByteBuffer.allocateDirect(AAD.length);
628         buf.put(AAD);
629 
630         // process the first half of AAD data
631         buf.position(0);
632         buf.limit(AAD.length / 2);
633         c.updateAAD(buf);
634 
635         // process the rest of AAD data
636         buf.limit(AAD.length);
637         c.updateAAD(buf);
638 
639         // prepare buffers to encrypt/decrypt
640         ByteBuffer in = ByteBuffer.allocate(plainText.length);
641         in.put(plainText);
642         in.position(0);
643         in.limit(plainText.length);
644         ByteBuffer out = ByteBuffer.allocate(c.getOutputSize(in.limit()));
645         out.position(0);
646         out.limit(c.getOutputSize(in.limit()));
647 
648         // process input text
649         c.update(in, out);
650         c.doFinal(in, out);
651         int resultSize = out.position();
652         byte[] result14 = new byte[resultSize];
653         out.position(0);
654         out.limit(resultSize);
655         out.get(result14, 0, resultSize);
656         results.add(result14);
657     }
658 
659     /*
660      * Execute multiple-part encryption/decryption combination #15
661      *   updateAAD(ByteBuffer src1), where src1 is directly allocated
662      *   updateAAD(ByteBuffer src2), where src2 is directly allocated
663      *   doFinal(ByteBuffer input, ByteBuffer out)
664      */
combination_15(List<byte[]> results, int mode, byte[] AAD, byte[] plainText, AlgorithmParameters params)665     private void combination_15(List<byte[]> results, int mode, byte[] AAD,
666             byte[] plainText, AlgorithmParameters params) throws Exception {
667         Cipher c = createCipher(mode, params);
668 
669         // prepare ByteBuffer1 to test
670         ByteBuffer buf1 = ByteBuffer.allocateDirect(AAD.length / 2);
671         buf1.put(AAD, 0, AAD.length / 2);
672         buf1.position(0);
673         buf1.limit(AAD.length / 2);
674 
675         // process the first half of AAD data
676         c.updateAAD(buf1);
677 
678         // prepare ByteBuffer2 to test
679         ByteBuffer buf2 = ByteBuffer.allocateDirect(
680                 AAD.length - AAD.length / 2);
681         buf2.put(AAD, AAD.length / 2, AAD.length - AAD.length / 2);
682         buf2.position(0);
683         buf2.limit(AAD.length - AAD.length / 2);
684 
685         // process the rest of AAD data
686         c.updateAAD(buf2);
687 
688         // prepare buffers to encrypt/decrypt
689         ByteBuffer in = ByteBuffer.allocateDirect(plainText.length);
690         in.put(plainText);
691         in.position(0);
692         in.limit(plainText.length);
693         ByteBuffer output = ByteBuffer.allocateDirect(
694                 c.getOutputSize(in.limit()));
695         output.position(0);
696         output.limit(c.getOutputSize(in.limit()));
697 
698         // process input text
699         c.doFinal(in, output);
700         int resultSize = output.position();
701         byte[] result15 = new byte[resultSize];
702         output.position(0);
703         output.limit(resultSize);
704         output.get(result15, 0, resultSize);
705         results.add(result15);
706     }
707 
708     /*
709      * Execute multiple-part encryption/decryption combination #16:
710      *   updateAAD(ByteBuffer src)
711      *   updateAAD(ByteBuffer emptyByteBuffer)
712      *   update(ByteBuffer input, ByteBuffer out)
713      *   doFinal(EmptyByteBuffer, ByteBuffer out)
714      */
combination_16(List<byte[]> results, int mode, byte[] AAD, byte[] plainText, AlgorithmParameters params)715     private void combination_16(List<byte[]> results, int mode, byte[] AAD,
716             byte[] plainText, AlgorithmParameters params) throws Exception {
717         Cipher c = createCipher(mode, params);
718 
719         // prepare ByteBuffer to test
720         ByteBuffer buf = ByteBuffer.allocateDirect(AAD.length);
721         buf.put(AAD);
722         buf.position(0);
723         buf.limit(AAD.length);
724         c.updateAAD(buf);
725 
726         // prepare empty ByteBuffer
727         ByteBuffer emptyBuf = ByteBuffer.allocateDirect(0);
728         emptyBuf.put(new byte[0]);
729         c.updateAAD(emptyBuf);
730 
731         // prepare buffers to encrypt/decrypt
732         ByteBuffer in = ByteBuffer.allocateDirect(plainText.length);
733         in.put(plainText);
734         in.position(0);
735         in.limit(plainText.length);
736         ByteBuffer output = ByteBuffer.allocateDirect(
737                 c.getOutputSize(in.limit()));
738         output.position(0);
739         output.limit(c.getOutputSize(in.limit()));
740 
741         // process input text with an empty buffer
742         c.update(in, output);
743         ByteBuffer emptyBuf2 = ByteBuffer.allocate(0);
744         emptyBuf2.put(new byte[0]);
745         c.doFinal(emptyBuf2, output);
746         int resultSize = output.position();
747         byte[] result16 = new byte[resultSize];
748         output.position(0);
749         output.limit(resultSize);
750         output.get(result16, 0, resultSize);
751         results.add(result16);
752     }
753 }
754