• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 Google Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 ////////////////////////////////////////////////////////////////////////////////
16 
17 package com.google.crypto.tink.subtle;
18 
19 import static org.junit.Assert.assertFalse;
20 import static org.junit.Assert.fail;
21 import static org.junit.Assume.assumeTrue;
22 
23 import com.google.crypto.tink.InsecureSecretKeyAccess;
24 import com.google.crypto.tink.StreamingAead;
25 import com.google.crypto.tink.streamingaead.AesGcmHkdfStreamingKey;
26 import com.google.crypto.tink.streamingaead.AesGcmHkdfStreamingParameters;
27 import com.google.crypto.tink.streamingaead.AesGcmHkdfStreamingParameters.HashType;
28 import com.google.crypto.tink.testing.StreamingTestUtil;
29 import com.google.crypto.tink.testing.StreamingTestUtil.SeekableByteBufferChannel;
30 import com.google.crypto.tink.testing.TestUtil;
31 import com.google.crypto.tink.util.SecretBytes;
32 import java.nio.ByteBuffer;
33 import java.nio.channels.WritableByteChannel;
34 import java.security.GeneralSecurityException;
35 import org.junit.BeforeClass;
36 import org.junit.Rule;
37 import org.junit.Test;
38 import org.junit.experimental.theories.DataPoints;
39 import org.junit.experimental.theories.FromDataPoints;
40 import org.junit.experimental.theories.Theories;
41 import org.junit.experimental.theories.Theory;
42 import org.junit.rules.TemporaryFolder;
43 import org.junit.runner.RunWith;
44 
45 /**
46  * Test for {@code AesGcmHkdfStreaming}-implementation of {@code StreamingAead}-primitive.
47  */
48 @RunWith(Theories.class)
49 public class AesGcmHkdfStreamingTest {
50   @Rule public TemporaryFolder tmpFolder = new TemporaryFolder();
51 
52   @DataPoints("vanillaImplementationTestVectors")
53   public static AesGcmHkdfStreamingTestVector[] vanillaImplementationTestVectors;
54 
55   @DataPoints("randomAccessTestVectors")
56   public static AesGcmHkdfStreamingTestVector[] randomAccessTestVectors;
57 
58   @DataPoints("singleBytesTestVectors")
59   public static AesGcmHkdfStreamingTestVector[] singleBytesTestVectors;
60 
61   @DataPoints("skipWithStreamTestVectors")
62   public static AesGcmHkdfStreamingTestVector[] skipWithStreamTestVectors;
63 
64   private static AesGcmHkdfStreaming defaultAesHkdfStreamingInstance;
65 
66   /**
67    * Encrypts and decrypts some plaintext in a stream and checks that the expected plaintext is
68    * returned.
69    */
70   @Theory
testEncryptDecrypt( @romDataPoints"vanillaImplementationTestVectors") AesGcmHkdfStreamingTestVector t)71   public void testEncryptDecrypt(
72       @FromDataPoints("vanillaImplementationTestVectors") AesGcmHkdfStreamingTestVector t)
73       throws Exception {
74     StreamingTestUtil.testEncryptDecrypt(
75         t.directConstructorAgs,
76         t.directConstructorAgs.getFirstSegmentOffset(),
77         t.plaintextSize,
78         t.chunkSize);
79   }
80 
81   @Theory
testEncryptDecryptDifferentInstances( @romDataPoints"vanillaImplementationTestVectors") AesGcmHkdfStreamingTestVector t)82   public void testEncryptDecryptDifferentInstances(
83       @FromDataPoints("vanillaImplementationTestVectors") AesGcmHkdfStreamingTestVector t)
84       throws Exception {
85     assumeTrue(t.keyObjectAgs != null);
86     StreamingTestUtil.testEncryptDecryptDifferentInstances(
87         t.directConstructorAgs,
88         t.keyObjectAgs,
89         t.keyObjectAgs.getFirstSegmentOffset(),
90         t.plaintextSize,
91         t.chunkSize);
92   }
93 
94   /** Encrypt and then decrypt partially, and check that the result is the same. */
95   @Theory
testEncryptDecryptRandomAccess( @romDataPoints"randomAccessTestVectors") AesGcmHkdfStreamingTestVector t)96   public void testEncryptDecryptRandomAccess(
97       @FromDataPoints("randomAccessTestVectors") AesGcmHkdfStreamingTestVector t) throws Exception {
98     StreamingTestUtil.testEncryptDecryptRandomAccess(
99         t.directConstructorAgs, t.directConstructorAgs.getFirstSegmentOffset(), t.plaintextSize);
100   }
101 
102   @Theory
testEncryptSingleBytes( @romDataPoints"singleBytesTestVectors") AesGcmHkdfStreamingTestVector t)103   public void testEncryptSingleBytes(
104       @FromDataPoints("singleBytesTestVectors") AesGcmHkdfStreamingTestVector t) throws Exception {
105     StreamingTestUtil.testEncryptSingleBytes(t.directConstructorAgs, t.plaintextSize);
106   }
107 
108   @Theory
testSkipWithStream( @romDataPoints"skipWithStreamTestVectors") AesGcmHkdfStreamingTestVector t)109   public void testSkipWithStream(
110       @FromDataPoints("skipWithStreamTestVectors") AesGcmHkdfStreamingTestVector t)
111       throws Exception {
112     StreamingTestUtil.testSkipWithStream(
113         t.directConstructorAgs,
114         t.directConstructorAgs.getFirstSegmentOffset(),
115         t.plaintextSize,
116         t.chunkSize);
117   }
118 
119   /**
120    * Encrypts and decrypts a with non-ASCII characters using CharsetEncoders and CharsetDecoders.
121    */
122   @Test
testEncryptDecryptString()123   public void testEncryptDecryptString() throws Exception {
124     StreamingTestUtil.testEncryptDecryptString(defaultAesHkdfStreamingInstance);
125   }
126 
127   /** Test encryption with a simulated ciphertext channel, which has only a limited capacity. */
128   @Test
testEncryptLimitedCiphertextChannel()129   public void testEncryptLimitedCiphertextChannel() throws Exception {
130     // Test vector with a suitably large plaintext size.
131     AesGcmHkdfStreamingTestVector t = singleBytesTestVectors[3];
132     byte[] aad = Hex.decode("aabbccddeeff");
133     byte[] plaintext = StreamingTestUtil.generatePlaintext(t.plaintextSize);
134     ByteBuffer ciphertext =
135         ByteBuffer.allocate((int) t.directConstructorAgs.expectedCiphertextSize(t.plaintextSize));
136     WritableByteChannel ctChannel = new SeekableByteBufferChannel(ciphertext, 100);
137     WritableByteChannel encChannel =
138         ((StreamingAead) t.directConstructorAgs).newEncryptingChannel(ctChannel, aad);
139     ByteBuffer plaintextBuffer = ByteBuffer.wrap(plaintext);
140     int loops = 0;
141     while (plaintextBuffer.remaining() > 0) {
142       encChannel.write(plaintextBuffer);
143       loops += 1;
144       if (loops > 100000) {
145         fail("Too many loops");
146       }
147     }
148     encChannel.close();
149     assertFalse(encChannel.isOpen());
150     StreamingTestUtil.isValidCiphertext(t.directConstructorAgs, plaintext, aad, ciphertext.array());
151   }
152 
153   // Modifies the ciphertext. Checks that decryption either results in correct plaintext
154   // or an exception.
155   // The following modifications are tested:
156   // (1) truncate ciphertext
157   // (2) append stuff
158   // (3) flip bits
159   // (4) remove segments
160   // (5) duplicate segments
161   // (6) modify aad
162   @Test
testModifiedCiphertext()163   public void testModifiedCiphertext() throws Exception {
164     // Test vector with a short ikm.
165     AesGcmHkdfStreamingTestVector t = vanillaImplementationTestVectors[0];
166     StreamingTestUtil.testModifiedCiphertext(
167         t.directConstructorAgs,
168         t.directConstructorAgs.getCiphertextSegmentSize(),
169         t.directConstructorAgs.getFirstSegmentOffset());
170   }
171 
172   @Test
testModifiedCiphertextWithSeekableByteChannel()173   public void testModifiedCiphertextWithSeekableByteChannel() throws Exception {
174     // Test vector with a short ikm.
175     AesGcmHkdfStreamingTestVector t = vanillaImplementationTestVectors[0];
176     StreamingTestUtil.testModifiedCiphertextWithSeekableByteChannel(
177         t.directConstructorAgs,
178         t.directConstructorAgs.getCiphertextSegmentSize(),
179         t.directConstructorAgs.getFirstSegmentOffset());
180   }
181 
182   /** Encrypt and decrypt a long ciphertext. */
183   @Test
testEncryptDecryptLong()184   public void testEncryptDecryptLong() throws Exception {
185     if (TestUtil.isAndroid()) {
186       System.out.println("testEncryptDecryptLong doesn't work on Android, skipping");
187       return;
188     }
189     long plaintextSize = (1L << 32) + 1234567;
190     StreamingTestUtil.testEncryptDecryptLong(defaultAesHkdfStreamingInstance, plaintextSize);
191   }
192 
193   /** Encrypt some plaintext to a file, then decrypt from the file */
194   @Test
testFileEncryption()195   public void testFileEncryption() throws Exception {
196     int plaintextSize = 1 << 20;
197     StreamingTestUtil.testFileEncryption(
198         defaultAesHkdfStreamingInstance, tmpFolder.newFile(), plaintextSize);
199   }
200 
201   @BeforeClass
setUp()202   public static void setUp() throws Exception {
203     vanillaImplementationTestVectors =
204         new AesGcmHkdfStreamingTestVector[] {
205           // Short initial key material.
206           new AesGcmHkdfStreamingTestVector(
207               /* keySizeInBytes= */ 16,
208               /* ciphertextSegmentSize= */ 256,
209               /* firstSegmentOffset= */ 8,
210               HashType.SHA256,
211               /* ikm= */ "000102030405060708090a0b0c0d0e0f",
212               /* plaintextSize= */ 20,
213               /* chunkSize= */ 64),
214           // Ciphertext smaller than one segment.
215           new AesGcmHkdfStreamingTestVector(
216               /* keySizeInBytes= */ 16,
217               /* ciphertextSegmentSize= */ 256,
218               /* firstSegmentOffset= */ 0,
219               HashType.SHA1,
220               /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff",
221               /* plaintextSize= */ 20,
222               /* chunkSize= */ 64),
223           new AesGcmHkdfStreamingTestVector(
224               /* keySizeInBytes= */ 16,
225               /* ciphertextSegmentSize= */ 512,
226               /* firstSegmentOffset= */ 0,
227               HashType.SHA256,
228               /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff",
229               /* plaintextSize= */ 400,
230               /* chunkSize= */ 64),
231           // Ciphertext smaller than one segment, with a non-zero offset.
232           new AesGcmHkdfStreamingTestVector(
233               /* keySizeInBytes= */ 16,
234               /* ciphertextSegmentSize= */ 256,
235               /* firstSegmentOffset= */ 8,
236               HashType.SHA512,
237               /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff",
238               /* plaintextSize= */ 20,
239               /* chunkSize= */ 64),
240           new AesGcmHkdfStreamingTestVector(
241               /* keySizeInBytes= */ 16,
242               /* ciphertextSegmentSize= */ 512,
243               /* firstSegmentOffset= */ 8,
244               HashType.SHA1,
245               /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff",
246               /* plaintextSize= */ 400,
247               /* chunkSize= */ 64),
248           // Empty plaintext.
249           new AesGcmHkdfStreamingTestVector(
250               /* keySizeInBytes= */ 16,
251               /* ciphertextSegmentSize= */ 256,
252               /* firstSegmentOffset= */ 0,
253               HashType.SHA256,
254               /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff",
255               /* plaintextSize= */ 0,
256               /* chunkSize= */ 128),
257           new AesGcmHkdfStreamingTestVector(
258               /* keySizeInBytes= */ 16,
259               /* ciphertextSegmentSize= */ 256,
260               /* firstSegmentOffset= */ 8,
261               HashType.SHA512,
262               /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff",
263               /* plaintextSize= */ 0,
264               /* chunkSize= */ 128),
265           // Ciphertext contains more than one segment.
266           new AesGcmHkdfStreamingTestVector(
267               /* keySizeInBytes= */ 16,
268               /* ciphertextSegmentSize= */ 256,
269               /* firstSegmentOffset= */ 0,
270               HashType.SHA1,
271               /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff",
272               /* plaintextSize= */ 1024,
273               /* chunkSize= */ 128),
274           new AesGcmHkdfStreamingTestVector(
275               /* keySizeInBytes= */ 16,
276               /* ciphertextSegmentSize= */ 512,
277               /* firstSegmentOffset= */ 0,
278               HashType.SHA256,
279               /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff",
280               /* plaintextSize= */ 3086,
281               /* chunkSize= */ 128),
282           new AesGcmHkdfStreamingTestVector(
283               /* keySizeInBytes= */ 32,
284               /* ciphertextSegmentSize= */ 1024,
285               /* firstSegmentOffset= */ 0,
286               HashType.SHA512,
287               /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff",
288               /* plaintextSize= */ 12345,
289               /* chunkSize= */ 128),
290           // During decryption large plaintext chunks are requested.
291           new AesGcmHkdfStreamingTestVector(
292               /* keySizeInBytes= */ 16,
293               /* ciphertextSegmentSize= */ 256,
294               /* firstSegmentOffset= */ 0,
295               HashType.SHA1,
296               /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff",
297               /* plaintextSize= */ 1024,
298               /* chunkSize= */ 4096),
299           new AesGcmHkdfStreamingTestVector(
300               /* keySizeInBytes= */ 16,
301               /* ciphertextSegmentSize= */ 512,
302               /* firstSegmentOffset= */ 0,
303               HashType.SHA256,
304               /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff",
305               /* plaintextSize= */ 3086,
306               /* chunkSize= */ 4096),
307           new AesGcmHkdfStreamingTestVector(
308               /* keySizeInBytes= */ 32,
309               /* ciphertextSegmentSize= */ 1024,
310               /* firstSegmentOffset= */ 0,
311               HashType.SHA512,
312               /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff",
313               /* plaintextSize= */ 12345,
314               /* chunkSize= */ 5000),
315           // Same as above but the offset is non-zero.
316           new AesGcmHkdfStreamingTestVector(
317               /* keySizeInBytes= */ 16,
318               /* ciphertextSegmentSize= */ 256,
319               /* firstSegmentOffset= */ 8,
320               HashType.SHA1,
321               /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff",
322               /* plaintextSize= */ 1024,
323               /* chunkSize= */ 64),
324           new AesGcmHkdfStreamingTestVector(
325               /* keySizeInBytes= */ 16,
326               /* ciphertextSegmentSize= */ 512,
327               /* firstSegmentOffset= */ 20,
328               HashType.SHA256,
329               /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff",
330               /* plaintextSize= */ 3086,
331               /* chunkSize= */ 256),
332           new AesGcmHkdfStreamingTestVector(
333               /* keySizeInBytes= */ 32,
334               /* ciphertextSegmentSize= */ 1024,
335               /* firstSegmentOffset= */ 10,
336               HashType.SHA512,
337               /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff",
338               /* plaintextSize= */ 12345,
339               /* chunkSize= */ 5000),
340           // The ciphertext ends at a segment boundary.
341           new AesGcmHkdfStreamingTestVector(
342               /* keySizeInBytes= */ 16,
343               /* ciphertextSegmentSize= */ 256,
344               /* firstSegmentOffset= */ 0,
345               HashType.SHA1,
346               /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff",
347               /* plaintextSize= */ 216,
348               /* chunkSize= */ 64),
349           new AesGcmHkdfStreamingTestVector(
350               /* keySizeInBytes= */ 16,
351               /* ciphertextSegmentSize= */ 256,
352               /* firstSegmentOffset= */ 16,
353               HashType.SHA256,
354               /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff",
355               /* plaintextSize= */ 200,
356               /* chunkSize= */ 256),
357           new AesGcmHkdfStreamingTestVector(
358               /* keySizeInBytes= */ 16,
359               /* ciphertextSegmentSize= */ 256,
360               /* firstSegmentOffset= */ 16,
361               HashType.SHA512,
362               /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff",
363               /* plaintextSize= */ 440,
364               /* chunkSize= */ 1024),
365           // During decryption single bytes are requested.
366           new AesGcmHkdfStreamingTestVector(
367               /* keySizeInBytes= */ 16,
368               /* ciphertextSegmentSize= */ 256,
369               /* firstSegmentOffset= */ 0,
370               HashType.SHA256,
371               /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff",
372               /* plaintextSize= */ 1024,
373               /* chunkSize= */ 1),
374           new AesGcmHkdfStreamingTestVector(
375               /* keySizeInBytes= */ 16,
376               /* ciphertextSegmentSize= */ 512,
377               /* firstSegmentOffset= */ 0,
378               HashType.SHA512,
379               /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff",
380               /* plaintextSize= */ 5086,
381               /* chunkSize= */ 1)
382         };
383     // In the following test vectors the chunk sizes are zeroed since they are not needed for the
384     // test.
385     randomAccessTestVectors =
386         new AesGcmHkdfStreamingTestVector[] {
387           // The ciphertext is smaller than 1 segment.
388           new AesGcmHkdfStreamingTestVector(
389               /* keySizeInBytes= */ 16,
390               /* ciphertextSegmentSize= */ 256,
391               /* firstSegmentOffset= */ 0,
392               HashType.SHA256,
393               /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff",
394               /* plaintextSize= */ 100,
395               /* chunkSize= */ 0),
396           new AesGcmHkdfStreamingTestVector(
397               /* keySizeInBytes= */ 16,
398               /* ciphertextSegmentSize= */ 512,
399               /* firstSegmentOffset= */ 0,
400               HashType.SHA256,
401               /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff",
402               /* plaintextSize= */ 400,
403               /* chunkSize= */ 0),
404           // Same as above with an offset.
405           new AesGcmHkdfStreamingTestVector(
406               /* keySizeInBytes= */ 16,
407               /* ciphertextSegmentSize= */ 256,
408               /* firstSegmentOffset= */ 8,
409               HashType.SHA256,
410               /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff",
411               /* plaintextSize= */ 20,
412               /* chunkSize= */ 0),
413           new AesGcmHkdfStreamingTestVector(
414               /* keySizeInBytes= */ 16,
415               /* ciphertextSegmentSize= */ 256,
416               /* firstSegmentOffset= */ 8,
417               HashType.SHA256,
418               /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff",
419               /* plaintextSize= */ 100,
420               /* chunkSize= */ 0),
421           new AesGcmHkdfStreamingTestVector(
422               /* keySizeInBytes= */ 16,
423               /* ciphertextSegmentSize= */ 512,
424               /* firstSegmentOffset= */ 8,
425               HashType.SHA256,
426               /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff",
427               /* plaintextSize= */ 400,
428               /* chunkSize= */ 0),
429           // Empty plaintext.
430           new AesGcmHkdfStreamingTestVector(
431               /* keySizeInBytes= */ 16,
432               /* ciphertextSegmentSize= */ 256,
433               /* firstSegmentOffset= */ 0,
434               HashType.SHA256,
435               /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff",
436               /* plaintextSize= */ 0,
437               /* chunkSize= */ 0),
438           new AesGcmHkdfStreamingTestVector(
439               /* keySizeInBytes= */ 16,
440               /* ciphertextSegmentSize= */ 256,
441               /* firstSegmentOffset= */ 8,
442               HashType.SHA256,
443               /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff",
444               /* plaintextSize= */ 0,
445               /* chunkSize= */ 0),
446           // Ciphertext contains more than one segment.
447           new AesGcmHkdfStreamingTestVector(
448               /* keySizeInBytes= */ 16,
449               /* ciphertextSegmentSize= */ 256,
450               /* firstSegmentOffset= */ 0,
451               HashType.SHA256,
452               /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff",
453               /* plaintextSize= */ 2048,
454               /* chunkSize= */ 0),
455           new AesGcmHkdfStreamingTestVector(
456               /* keySizeInBytes= */ 16,
457               /* ciphertextSegmentSize= */ 256,
458               /* firstSegmentOffset= */ 0,
459               HashType.SHA256,
460               /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff",
461               /* plaintextSize= */ 4096,
462               /* chunkSize= */ 0),
463           new AesGcmHkdfStreamingTestVector(
464               /* keySizeInBytes= */ 32,
465               /* ciphertextSegmentSize= */ 1024,
466               /* firstSegmentOffset= */ 0,
467               HashType.SHA256,
468               /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff",
469               /* plaintextSize= */ 12345,
470               /* chunkSize= */ 0),
471           new AesGcmHkdfStreamingTestVector(
472               /* keySizeInBytes= */ 16,
473               /* ciphertextSegmentSize= */ 4096,
474               /* firstSegmentOffset= */ 0,
475               HashType.SHA256,
476               /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff",
477               /* plaintextSize= */ 123456,
478               /* chunkSize= */ 0),
479           // Same as above but with an offset.
480           new AesGcmHkdfStreamingTestVector(
481               /* keySizeInBytes= */ 16,
482               /* ciphertextSegmentSize= */ 256,
483               /* firstSegmentOffset= */ 8,
484               HashType.SHA256,
485               /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff",
486               /* plaintextSize= */ 2048,
487               /* chunkSize= */ 0),
488           new AesGcmHkdfStreamingTestVector(
489               /* keySizeInBytes= */ 16,
490               /* ciphertextSegmentSize= */ 256,
491               /* firstSegmentOffset= */ 10,
492               HashType.SHA256,
493               /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff",
494               /* plaintextSize= */ 4096,
495               /* chunkSize= */ 0),
496           new AesGcmHkdfStreamingTestVector(
497               /* keySizeInBytes= */ 32,
498               /* ciphertextSegmentSize= */ 1024,
499               /* firstSegmentOffset= */ 20,
500               HashType.SHA256,
501               /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff",
502               /* plaintextSize= */ 12345,
503               /* chunkSize= */ 0),
504           // The ciphertext ends at a segment boundary.
505           new AesGcmHkdfStreamingTestVector(
506               /* keySizeInBytes= */ 16,
507               /* ciphertextSegmentSize= */ 256,
508               /* firstSegmentOffset= */ 0,
509               HashType.SHA256,
510               /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff",
511               /* plaintextSize= */ 216,
512               /* chunkSize= */ 0),
513           new AesGcmHkdfStreamingTestVector(
514               /* keySizeInBytes= */ 16,
515               /* ciphertextSegmentSize= */ 256,
516               /* firstSegmentOffset= */ 16,
517               HashType.SHA256,
518               /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff",
519               /* plaintextSize= */ 200,
520               /* chunkSize= */ 0),
521           new AesGcmHkdfStreamingTestVector(
522               /* keySizeInBytes= */ 16,
523               /* ciphertextSegmentSize= */ 256,
524               /* firstSegmentOffset= */ 16,
525               HashType.SHA256,
526               /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff",
527               /* plaintextSize= */ 440,
528               /* chunkSize= */ 0),
529         };
530     singleBytesTestVectors =
531         new AesGcmHkdfStreamingTestVector[] {
532           // Encrypting with the stream writing single bytes. Chunk size isn't used for this test.
533           new AesGcmHkdfStreamingTestVector(
534               /* keySizeInBytes= */ 16,
535               /* ciphertextSegmentSize= */ 512,
536               /* firstSegmentOffset= */ 0,
537               HashType.SHA256,
538               /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff",
539               /* plaintextSize= */ 1024,
540               /* chunkSize= */ 0),
541           new AesGcmHkdfStreamingTestVector(
542               /* keySizeInBytes= */ 32,
543               /* ciphertextSegmentSize= */ 512,
544               /* firstSegmentOffset= */ 0,
545               HashType.SHA256,
546               /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff",
547               /* plaintextSize= */ 1024,
548               /* chunkSize= */ 0),
549           new AesGcmHkdfStreamingTestVector(
550               /* keySizeInBytes= */ 16,
551               /* ciphertextSegmentSize= */ 512,
552               /* firstSegmentOffset= */ 0,
553               HashType.SHA256,
554               /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff",
555               /* plaintextSize= */ 12345,
556               /* chunkSize= */ 0),
557           new AesGcmHkdfStreamingTestVector(
558               /* keySizeInBytes= */ 16,
559               /* ciphertextSegmentSize= */ 512,
560               /* firstSegmentOffset= */ 0,
561               HashType.SHA256,
562               /* ikm= */ "000102030405060708090a0b0c0d0e0f00112233445566778899aabbccddeeff",
563               /* plaintextSize= */ 111111,
564               /* chunkSize= */ 0),
565         };
566     skipWithStreamTestVectors =
567         new AesGcmHkdfStreamingTestVector[] {
568           // Smallest chunk size.
569           new AesGcmHkdfStreamingTestVector(
570               /* keySizeInBytes= */ 16,
571               /* ciphertextSegmentSize= */ 256,
572               /* firstSegmentOffset= */ 8,
573               HashType.SHA256,
574               /* ikm= */ "000102030405060708090a0b0c0d0e0f",
575               /* plaintextSize= */ 4096,
576               /* chunkSize= */ 1),
577           // Chunk size < segmentSize.
578           new AesGcmHkdfStreamingTestVector(
579               /* keySizeInBytes= */ 16,
580               /* ciphertextSegmentSize= */ 256,
581               /* firstSegmentOffset= */ 8,
582               HashType.SHA1,
583               /* ikm= */ "000102030405060708090a0b0c0d0e0f",
584               /* plaintextSize= */ 4096,
585               /* chunkSize= */ 37),
586           // Chunk size > segmentSize.
587           new AesGcmHkdfStreamingTestVector(
588               /* keySizeInBytes= */ 16,
589               /* ciphertextSegmentSize= */ 256,
590               /* firstSegmentOffset= */ 8,
591               HashType.SHA512,
592               /* ikm= */ "000102030405060708090a0b0c0d0e0f",
593               /* plaintextSize= */ 4096,
594               /* chunkSize= */ 384),
595           // Chunk size > 3*segmentSize.
596           new AesGcmHkdfStreamingTestVector(
597               /* keySizeInBytes= */ 16,
598               /* ciphertextSegmentSize= */ 256,
599               /* firstSegmentOffset= */ 8,
600               HashType.SHA256,
601               /* ikm= */ "000102030405060708090a0b0c0d0e0f",
602               /* plaintextSize= */ 4096,
603               /* chunkSize= */ 800),
604         };
605     defaultAesHkdfStreamingInstance =
606         new AesGcmHkdfStreaming(
607             Hex.decode("000102030405060708090a0b0c0d0e0f"), "HmacSha256", 16, 4096, 0);
608   }
609 
610   private static final class AesGcmHkdfStreamingTestVector {
611     final AesGcmHkdfStreaming directConstructorAgs;
612     final AesGcmHkdfStreaming keyObjectAgs;
613     final int plaintextSize;
614     final int chunkSize;
615 
AesGcmHkdfStreamingTestVector( int keySizeInBytes, int ciphertextSegmentSize, int firstSegmentOffset, HashType hashType, String ikm, int plaintextSize, int chunkSize)616     private AesGcmHkdfStreamingTestVector(
617         int keySizeInBytes,
618         int ciphertextSegmentSize,
619         int firstSegmentOffset,
620         HashType hashType,
621         String ikm,
622         int plaintextSize,
623         int chunkSize)
624         throws GeneralSecurityException {
625       String hkdfAlgString = "";
626       if (hashType.equals(HashType.SHA1)) {
627         hkdfAlgString = "HmacSha1";
628       } else if (hashType.equals(HashType.SHA256)) {
629         hkdfAlgString = "HmacSha256";
630       } else if (hashType.equals(HashType.SHA512)) {
631         hkdfAlgString = "HmacSha512";
632       }
633       this.directConstructorAgs =
634           new AesGcmHkdfStreaming(
635               Hex.decode(ikm),
636               hkdfAlgString,
637               keySizeInBytes,
638               ciphertextSegmentSize,
639               firstSegmentOffset);
640       if (firstSegmentOffset != 0) {
641         this.keyObjectAgs = null;
642       } else {
643         AesGcmHkdfStreamingKey aesGcmHkdfStreamingKey =
644             AesGcmHkdfStreamingKey.create(
645                 AesGcmHkdfStreamingParameters.builder()
646                     .setDerivedAesGcmKeySizeBytes(keySizeInBytes)
647                     .setKeySizeBytes(Hex.decode(ikm).length)
648                     .setCiphertextSegmentSizeBytes(ciphertextSegmentSize)
649                     .setHkdfHashType(hashType)
650                     .build(),
651                 SecretBytes.copyFrom(Hex.decode(ikm), InsecureSecretKeyAccess.get()));
652         this.keyObjectAgs =
653             (AesGcmHkdfStreaming) AesGcmHkdfStreaming.create(aesGcmHkdfStreamingKey);
654       }
655       this.plaintextSize = plaintextSize;
656       this.chunkSize = chunkSize;
657     }
658   }
659 }
660