• 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 com.google.common.truth.Truth.assertThat;
20 import static com.google.crypto.tink.internal.TinkBugException.exceptionIsBug;
21 import static org.junit.Assert.assertArrayEquals;
22 import static org.junit.Assert.assertEquals;
23 import static org.junit.Assert.assertThrows;
24 import static org.junit.Assert.fail;
25 
26 import com.google.crypto.tink.Aead;
27 import com.google.crypto.tink.InsecureSecretKeyAccess;
28 import com.google.crypto.tink.aead.AesGcmKey;
29 import com.google.crypto.tink.aead.AesGcmParameters;
30 import com.google.crypto.tink.config.TinkFips;
31 import com.google.crypto.tink.config.internal.TinkFipsUtil;
32 import com.google.crypto.tink.internal.Util;
33 import com.google.crypto.tink.testing.TestUtil;
34 import com.google.crypto.tink.testing.TestUtil.BytesMutation;
35 import com.google.crypto.tink.testing.WycheproofTestUtil;
36 import com.google.crypto.tink.util.SecretBytes;
37 import com.google.gson.JsonArray;
38 import com.google.gson.JsonObject;
39 import java.security.GeneralSecurityException;
40 import java.security.Security;
41 import java.util.Arrays;
42 import java.util.HashSet;
43 import javax.annotation.Nullable;
44 import org.conscrypt.Conscrypt;
45 import org.junit.Assume;
46 import org.junit.Before;
47 import org.junit.Test;
48 import org.junit.experimental.theories.DataPoints;
49 import org.junit.experimental.theories.FromDataPoints;
50 import org.junit.experimental.theories.Theories;
51 import org.junit.experimental.theories.Theory;
52 import org.junit.runner.RunWith;
53 
54 /** Unit tests for AesGcm. */
55 @RunWith(Theories.class)
56 public class AesGcmJceTest {
57 
58   private Integer[] keySizeInBytes;
59 
60   @Before
setUp()61   public void setUp() throws Exception {
62     keySizeInBytes = new Integer[] {16, 32};
63   }
64 
65   @Before
useConscrypt()66   public void useConscrypt() throws Exception {
67     // If Tink is build in FIPS-only mode, then we register Conscrypt for the tests.
68     if (TinkFips.useOnlyFips()) {
69       try {
70         Conscrypt.checkAvailability();
71         Security.addProvider(Conscrypt.newProvider());
72       } catch (Throwable cause) {
73         throw new IllegalStateException(
74             "Cannot test AesGcm in FIPS-mode without Conscrypt Provider", cause);
75       }
76     }
77   }
78 
79   @Test
testEncryptDecrypt()80   public void testEncryptDecrypt() throws Exception {
81     Assume.assumeTrue(!TinkFips.useOnlyFips() || TinkFipsUtil.fipsModuleAvailable());
82 
83     byte[] aad = generateAssociatedData();
84     for (int keySize : keySizeInBytes) {
85       byte[] key = Random.randBytes(keySize);
86       AesGcmJce gcm = new AesGcmJce(key);
87       for (int messageSize = 0; messageSize < 75; messageSize++) {
88         byte[] message = Random.randBytes(messageSize);
89         byte[] ciphertext = gcm.encrypt(message, aad);
90         byte[] decrypted = gcm.decrypt(ciphertext, aad);
91         assertArrayEquals(message, decrypted);
92       }
93     }
94   }
95 
96   @Test
97   /* BC had a bug, where GCM failed for messages of size > 8192 */
testLongMessages()98   public void testLongMessages() throws Exception {
99     Assume.assumeTrue(!TinkFips.useOnlyFips() || TinkFipsUtil.fipsModuleAvailable());
100     Assume.assumeFalse(TestUtil.isAndroid()); // doesn't work on Android
101 
102     int dataSize = 16;
103     while (dataSize <= (1 << 24)) {
104       byte[] plaintext = Random.randBytes(dataSize);
105       byte[] aad = Random.randBytes(dataSize / 3);
106       for (int keySize : keySizeInBytes) {
107         byte[] key = Random.randBytes(keySize);
108         AesGcmJce gcm = new AesGcmJce(key);
109         byte[] ciphertext = gcm.encrypt(plaintext, aad);
110         byte[] decrypted = gcm.decrypt(ciphertext, aad);
111         assertArrayEquals(plaintext, decrypted);
112       }
113       dataSize += 5 * dataSize / 11;
114     }
115   }
116 
117   @Test
testModifyCiphertext()118   public void testModifyCiphertext() throws Exception {
119     Assume.assumeTrue(!TinkFips.useOnlyFips() || TinkFipsUtil.fipsModuleAvailable());
120 
121     byte[] aad = generateAssociatedData();
122     byte[] key = Random.randBytes(16);
123     byte[] message = Random.randBytes(32);
124     AesGcmJce gcm = new AesGcmJce(key);
125     byte[] ciphertext = gcm.encrypt(message, aad);
126 
127     for (BytesMutation mutation : TestUtil.generateMutations(ciphertext)) {
128       assertThrows(
129           String.format(
130               "Decrypting modified ciphertext should fail : ciphertext = %s, aad = %s,"
131                   + " description = %s",
132               Hex.encode(mutation.value), Hex.encode(aad), mutation.description),
133           GeneralSecurityException.class,
134           () -> {
135             byte[] unused = gcm.decrypt(mutation.value, aad);
136           });
137     }
138 
139     // Modify AAD
140     if (aad != null && aad.length != 0) {
141       for (BytesMutation mutation : TestUtil.generateMutations(aad)) {
142         assertThrows(
143             String.format(
144                 "Decrypting with modified aad should fail: ciphertext = %s, aad = %s,"
145                     + " description = %s",
146                 Arrays.toString(ciphertext), Arrays.toString(mutation.value), mutation.description),
147             GeneralSecurityException.class,
148             () -> {
149               byte[] unused = gcm.decrypt(ciphertext, mutation.value);
150             });
151       }
152     }
153   }
154 
155   @Test
testWithAesGcmKey_noPrefix_works()156   public void testWithAesGcmKey_noPrefix_works() throws Exception {
157     Assume.assumeTrue(!TinkFips.useOnlyFips() || TinkFipsUtil.fipsModuleAvailable());
158     AesGcmParameters parameters =
159         AesGcmParameters.builder()
160             .setKeySizeBytes(16)
161             .setTagSizeBytes(16)
162             .setIvSizeBytes(12)
163             .setVariant(AesGcmParameters.Variant.NO_PREFIX)
164             .build();
165 
166     AesGcmKey key =
167         AesGcmKey.builder()
168             .setParameters(parameters)
169             .setKeyBytes(
170                 SecretBytes.copyFrom(
171                     Hex.decode("5b9604fe14eadba931b0ccf34843dab9"), InsecureSecretKeyAccess.get()))
172             .build();
173     Aead aead = AesGcmJce.create(key);
174     byte[] ciphertext = aead.encrypt(new byte[] {}, new byte[] {});
175     assertThat(ciphertext).hasLength(parameters.getIvSizeBytes() + parameters.getTagSizeBytes());
176 
177     assertThat(aead.decrypt(ciphertext, new byte[] {})).isEmpty();
178 
179     byte[] fixedCiphertext = Hex.decode("c3561ce7f48b8a6b9b8d5ef957d2e512368f7da837bcf2aeebe176e3");
180     assertThat(aead.decrypt(fixedCiphertext, new byte[] {})).isEmpty();
181   }
182 
183   @Test
testWithAesGcmKey_tinkPrefix_works()184   public void testWithAesGcmKey_tinkPrefix_works() throws Exception {
185     Assume.assumeTrue(!TinkFips.useOnlyFips() || TinkFipsUtil.fipsModuleAvailable());
186     AesGcmParameters parameters =
187         AesGcmParameters.builder()
188             .setKeySizeBytes(16)
189             .setTagSizeBytes(16)
190             .setIvSizeBytes(12)
191             .setVariant(AesGcmParameters.Variant.TINK)
192             .build();
193 
194     AesGcmKey key =
195         AesGcmKey.builder()
196             .setParameters(parameters)
197             .setKeyBytes(
198                 SecretBytes.copyFrom(
199                     Hex.decode("5b9604fe14eadba931b0ccf34843dab9"), InsecureSecretKeyAccess.get()))
200             .setIdRequirement(0x9943243)
201             .build();
202     Aead aead = AesGcmJce.create(key);
203     byte[] ciphertext = aead.encrypt(new byte[] {}, new byte[] {});
204     assertThat(ciphertext)
205         .hasLength(
206             key.getOutputPrefix().size()
207                 + parameters.getIvSizeBytes()
208                 + parameters.getTagSizeBytes());
209     assertThat(aead.decrypt(ciphertext, new byte[] {})).isEmpty();
210 
211     byte[] fixedCiphertext =
212         Hex.decode("0109943243c3561ce7f48b8a6b9b8d5ef957d2e512368f7da837bcf2aeebe176e3");
213     assertThat(aead.decrypt(fixedCiphertext, new byte[] {})).isEmpty();
214   }
215 
216   @Test
testWithAesGcmKey_crunchyPrefix_works()217   public void testWithAesGcmKey_crunchyPrefix_works() throws Exception {
218     Assume.assumeTrue(!TinkFips.useOnlyFips() || TinkFipsUtil.fipsModuleAvailable());
219     AesGcmParameters parameters =
220         AesGcmParameters.builder()
221             .setKeySizeBytes(16)
222             .setTagSizeBytes(16)
223             .setIvSizeBytes(12)
224             .setVariant(AesGcmParameters.Variant.CRUNCHY)
225             .build();
226 
227     AesGcmKey key =
228         AesGcmKey.builder()
229             .setParameters(parameters)
230             .setKeyBytes(
231                 SecretBytes.copyFrom(
232                     Hex.decode("5b9604fe14eadba931b0ccf34843dab9"), InsecureSecretKeyAccess.get()))
233             .setIdRequirement(0x9943243)
234             .build();
235     Aead aead = AesGcmJce.create(key);
236     byte[] ciphertext = aead.encrypt(new byte[] {}, new byte[] {});
237     assertThat(ciphertext)
238         .hasLength(
239             key.getOutputPrefix().size()
240                 + parameters.getIvSizeBytes()
241                 + parameters.getTagSizeBytes());
242     assertThat(aead.decrypt(ciphertext, new byte[] {})).isEmpty();
243 
244     byte[] fixedCiphertext =
245         Hex.decode("0009943243c3561ce7f48b8a6b9b8d5ef957d2e512368f7da837bcf2aeebe176e3");
246     assertThat(aead.decrypt(fixedCiphertext, new byte[] {})).isEmpty();
247   }
248 
249   @Test
testWycheproofVectors()250   public void testWycheproofVectors() throws Exception {
251     Assume.assumeTrue(!TinkFips.useOnlyFips() || TinkFipsUtil.fipsModuleAvailable());
252 
253     JsonObject json =
254         WycheproofTestUtil.readJson("../wycheproof/testvectors/aes_gcm_test.json");
255     int errors = 0;
256     int cntSkippedTests = 0;
257     JsonArray testGroups = json.get("testGroups").getAsJsonArray();
258     for (int i = 0; i < testGroups.size(); i++) {
259       JsonObject group = testGroups.get(i).getAsJsonObject();
260       int keySize = group.get("keySize").getAsInt();
261       JsonArray tests = group.get("tests").getAsJsonArray();
262       if (!Arrays.asList(keySizeInBytes).contains(keySize / 8)) {
263         cntSkippedTests += tests.size();
264         continue;
265       }
266       for (int j = 0; j < tests.size(); j++) {
267         JsonObject testcase = tests.get(j).getAsJsonObject();
268         String tcId =
269             String.format("testcase %d (%s)",
270                 testcase.get("tcId").getAsInt(), testcase.get("comment").getAsString());
271         byte[] iv = Hex.decode(testcase.get("iv").getAsString());
272         byte[] key = Hex.decode(testcase.get("key").getAsString());
273         byte[] msg = Hex.decode(testcase.get("msg").getAsString());
274         byte[] aad = Hex.decode(testcase.get("aad").getAsString());
275         @Nullable Integer apiLevel = Util.getAndroidApiLevel();
276         if (apiLevel != null && apiLevel <= 19 && aad.length != 0) {
277           cntSkippedTests++;
278           continue;
279         }
280         byte[] ct = Hex.decode(testcase.get("ct").getAsString());
281         byte[] tag = Hex.decode(testcase.get("tag").getAsString());
282         byte[] ciphertext = Bytes.concat(iv, ct, tag);
283         // Result is one of "valid", "invalid", "acceptable".
284         // "valid" are test vectors with matching plaintext, ciphertext and tag.
285         // "invalid" are test vectors with invalid parameters or invalid ciphertext and tag.
286         // "acceptable" are test vectors with weak parameters or legacy formats.
287         String result = testcase.get("result").getAsString();
288         // Tink only supports 12-byte iv.
289         if (iv.length != 12) {
290           result = "invalid";
291         }
292 
293         try {
294           AesGcmJce gcm = new AesGcmJce(key);
295           byte[] decrypted = gcm.decrypt(ciphertext, aad);
296           boolean eq = TestUtil.arrayEquals(decrypted, msg);
297           if (result.equals("invalid")) {
298             System.out.printf(
299                 "FAIL %s: accepting invalid ciphertext, cleartext: %s, decrypted: %s%n",
300                 tcId, Hex.encode(msg), Hex.encode(decrypted));
301             errors++;
302           } else {
303             if (!eq) {
304               System.out.printf(
305                   "FAIL %s: incorrect decryption, result: %s, expected: %s%n",
306                   tcId, Hex.encode(decrypted), Hex.encode(msg));
307               errors++;
308             }
309           }
310         } catch (GeneralSecurityException ex) {
311           if (result.equals("valid")) {
312             System.out.printf("FAIL %s: cannot decrypt, exception %s%n", tcId, ex);
313             errors++;
314           }
315         }
316       }
317     }
318     System.out.printf("Number of tests skipped: %d", cntSkippedTests);
319     assertEquals(0, errors);
320   }
321 
322   @Test
testNullPlaintextOrCiphertext()323   public void testNullPlaintextOrCiphertext() throws Exception {
324     Assume.assumeTrue(!TinkFips.useOnlyFips() || TinkFipsUtil.fipsModuleAvailable());
325 
326     for (int keySize : keySizeInBytes) {
327       AesGcmJce gcm = new AesGcmJce(Random.randBytes(keySize));
328       byte[] aad = generateAssociatedData();
329       assertThrows(
330           NullPointerException.class,
331           () -> {
332             byte[] unused = gcm.encrypt(null, aad);
333           });
334       assertThrows(
335           NullPointerException.class,
336           () -> {
337             byte[] unused = gcm.encrypt(null, null);
338           });
339       assertThrows(
340           NullPointerException.class,
341           () -> {
342             byte[] unused = gcm.decrypt(null, aad);
343           });
344       assertThrows(
345           NullPointerException.class,
346           () -> {
347             byte[] unused = gcm.decrypt(null, null);
348           });
349     }
350   }
351 
352   @Test
testEmptyAssociatedData()353   public void testEmptyAssociatedData() throws Exception {
354     Assume.assumeTrue(!TinkFips.useOnlyFips() || TinkFipsUtil.fipsModuleAvailable());
355 
356     byte[] aad = new byte[0];
357     for (int keySize : keySizeInBytes) {
358       byte[] key = Random.randBytes(keySize);
359       AesGcmJce gcm = new AesGcmJce(key);
360       for (int messageSize = 0; messageSize < 75; messageSize++) {
361         byte[] message = Random.randBytes(messageSize);
362         {  // encrypting with aad as a 0-length array
363           byte[] ciphertext = gcm.encrypt(message, aad);
364           byte[] decrypted = gcm.decrypt(ciphertext, aad);
365           assertArrayEquals(message, decrypted);
366           byte[] decrypted2 = gcm.decrypt(ciphertext, null);
367           assertArrayEquals(message, decrypted2);
368           try {
369             byte[] badAad = new byte[] {1, 2, 3};
370             byte[] unused = gcm.decrypt(ciphertext, badAad);
371             fail("Decrypting with modified aad should fail");
372           } catch (GeneralSecurityException ex) {
373             // This is expected.
374             // This could be a AeadBadTagException when the tag verification
375             // fails or some not yet specified Exception when the ciphertext is too short.
376             // In all cases a GeneralSecurityException or a subclass of it must be thrown.
377           }
378         }
379         {  // encrypting with aad equal to null
380           byte[] ciphertext = gcm.encrypt(message, null);
381           byte[] decrypted = gcm.decrypt(ciphertext, aad);
382           assertArrayEquals(message, decrypted);
383           byte[] decrypted2 = gcm.decrypt(ciphertext, null);
384           assertArrayEquals(message, decrypted2);
385           try {
386             byte[] badAad = new byte[] {1, 2, 3};
387             byte[] unused = gcm.decrypt(ciphertext, badAad);
388             fail("Decrypting with modified aad should fail");
389           } catch (GeneralSecurityException ex) {
390             // This is expected.
391             // This could be a AeadBadTagException when the tag verification
392             // fails or some not yet specified Exception when the ciphertext is too short.
393             // In all cases a GeneralSecurityException or a subclass of it must be thrown.
394           }
395         }
396       }
397     }
398   }
399 
400   @Test
401   /*
402    * This is a very simple test for the randomness of the nonce. The test simply checks that the
403    * multiple ciphertexts of the same message are distinct.
404    */
testRandomNonce()405   public void testRandomNonce() throws Exception {
406     Assume.assumeTrue(!TinkFips.useOnlyFips() || TinkFipsUtil.fipsModuleAvailable());
407 
408     final int samples = 1 << 17;
409     byte[] key = Random.randBytes(16);
410     byte[] message = new byte[0];
411     byte[] aad = generateAssociatedData();
412     AesGcmJce gcm = new AesGcmJce(key);
413     HashSet<String> ciphertexts = new HashSet<>();
414     for (int i = 0; i < samples; i++) {
415       byte[] ct = gcm.encrypt(message, aad);
416       String ctHex = Hex.encode(ct);
417       assertThat(ciphertexts).doesNotContain(ctHex);
418       ciphertexts.add(ctHex);
419     }
420   }
421 
generateAssociatedData()422   private static byte[] generateAssociatedData() {
423     return Random.randBytes(20);
424   }
425 
426   @Test
testFailIfFipsModuleNotAvailable()427   public void testFailIfFipsModuleNotAvailable() throws Exception {
428     Assume.assumeTrue(TinkFips.useOnlyFips() && !TinkFipsUtil.fipsModuleAvailable());
429 
430     byte[] key = Random.randBytes(16);
431     assertThrows(GeneralSecurityException.class, () -> new AesGcmJce(key));
432   }
433 
createValidAesGcmParameters()434   private static AesGcmParameters[] createValidAesGcmParameters() {
435     return exceptionIsBug(
436         () ->
437             new AesGcmParameters[] {
438               AesGcmParameters.builder()
439                   .setKeySizeBytes(16)
440                   .setIvSizeBytes(12)
441                   .setTagSizeBytes(16)
442                   .setVariant(AesGcmParameters.Variant.NO_PREFIX)
443                   .build(),
444               AesGcmParameters.builder()
445                   .setKeySizeBytes(16)
446                   .setIvSizeBytes(12)
447                   .setTagSizeBytes(16)
448                   .setVariant(AesGcmParameters.Variant.TINK)
449                   .build(),
450               AesGcmParameters.builder()
451                   .setKeySizeBytes(16)
452                   .setIvSizeBytes(12)
453                   .setTagSizeBytes(16)
454                   .setVariant(AesGcmParameters.Variant.CRUNCHY)
455                   .build(),
456               AesGcmParameters.builder()
457                   .setKeySizeBytes(32)
458                   .setIvSizeBytes(12)
459                   .setTagSizeBytes(16)
460                   .setVariant(AesGcmParameters.Variant.NO_PREFIX)
461                   .build(),
462               AesGcmParameters.builder()
463                   .setKeySizeBytes(32)
464                   .setIvSizeBytes(12)
465                   .setTagSizeBytes(16)
466                   .setVariant(AesGcmParameters.Variant.TINK)
467                   .build(),
468               AesGcmParameters.builder()
469                   .setKeySizeBytes(32)
470                   .setIvSizeBytes(12)
471                   .setTagSizeBytes(16)
472                   .setVariant(AesGcmParameters.Variant.CRUNCHY)
473                   .build(),
474             });
475   }
476 
477   @DataPoints("validParameters")
478   public static final AesGcmParameters[] parameters = createValidAesGcmParameters();
479 
createRandomKey(AesGcmParameters parameters)480   private static AesGcmKey createRandomKey(AesGcmParameters parameters) throws Exception {
481     AesGcmKey.Builder builder =
482         AesGcmKey.builder()
483             .setParameters(parameters)
484             .setKeyBytes(SecretBytes.randomBytes(parameters.getKeySizeBytes()));
485     if (parameters.hasIdRequirement()) {
486       builder.setIdRequirement(Random.randInt());
487     }
488     return builder.build();
489   }
490 
491   @Theory
ciphertextStartsWithOutputPrefix( @romDataPoints"validParameters") AesGcmParameters parameters)492   public void ciphertextStartsWithOutputPrefix(
493       @FromDataPoints("validParameters") AesGcmParameters parameters) throws Exception {
494     if (TinkFips.useOnlyFips() && !TinkFipsUtil.fipsModuleAvailable()) {
495       return;
496     }
497     AesGcmKey key = createRandomKey(parameters);
498     Aead aead = AesGcmJce.create(key);
499 
500     byte[] ciphertext = aead.encrypt(Random.randBytes(10), generateAssociatedData());
501 
502     assertThat(
503             com.google.crypto.tink.util.Bytes.copyFrom(ciphertext, 0, key.getOutputPrefix().size()))
504         .isEqualTo(key.getOutputPrefix());
505   }
506 
507   @Theory
encryptThenDecrypt_works( @romDataPoints"validParameters") AesGcmParameters parameters)508   public void encryptThenDecrypt_works(
509       @FromDataPoints("validParameters") AesGcmParameters parameters) throws Exception {
510     if (TinkFips.useOnlyFips() && !TinkFipsUtil.fipsModuleAvailable()) {
511       return;
512     }
513     AesGcmKey key = createRandomKey(parameters);
514     Aead aead = AesGcmJce.create(key);
515 
516     byte[] plaintext = Random.randBytes(100);
517     byte[] associatedData = generateAssociatedData();
518 
519     byte[] ciphertext = aead.encrypt(plaintext, associatedData);
520 
521     assertThat(aead.decrypt(ciphertext, associatedData)).isEqualTo(plaintext);
522   }
523 
524   @Theory
computedLength_isAsExpected( @romDataPoints"validParameters") AesGcmParameters parameters)525   public void computedLength_isAsExpected(
526       @FromDataPoints("validParameters") AesGcmParameters parameters) throws Exception {
527     if (TinkFips.useOnlyFips() && !TinkFipsUtil.fipsModuleAvailable()) {
528       return;
529     }
530     AesGcmKey key = createRandomKey(parameters);
531     Aead aead = AesGcmJce.create(key);
532 
533     byte[] plaintext = Random.randBytes(100);
534     byte[] associatedData = generateAssociatedData();
535 
536     byte[] ciphertext = aead.encrypt(plaintext, associatedData);
537 
538     assertThat(ciphertext)
539         .hasLength(
540             key.getOutputPrefix().size()
541                 + parameters.getIvSizeBytes()
542                 + plaintext.length
543                 + parameters.getTagSizeBytes());
544   }
545 
546   @Test
create_wrongIvSize_throws()547   public void create_wrongIvSize_throws() throws Exception {
548     Assume.assumeTrue(!TinkFips.useOnlyFips() || TinkFipsUtil.fipsModuleAvailable());
549     AesGcmKey key =
550         createRandomKey(
551             AesGcmParameters.builder()
552                 .setKeySizeBytes(32)
553                 .setIvSizeBytes(16)
554                 .setTagSizeBytes(16)
555                 .setVariant(AesGcmParameters.Variant.NO_PREFIX)
556                 .build());
557     assertThrows(GeneralSecurityException.class, () -> AesGcmJce.create(key));
558   }
559 
560   @Test
create_wrongTagSize_throws()561   public void create_wrongTagSize_throws() throws Exception {
562     Assume.assumeTrue(!TinkFips.useOnlyFips() || TinkFipsUtil.fipsModuleAvailable());
563     AesGcmKey key =
564         createRandomKey(
565             AesGcmParameters.builder()
566                 .setKeySizeBytes(32)
567                 .setIvSizeBytes(12)
568                 .setTagSizeBytes(12)
569                 .setVariant(AesGcmParameters.Variant.NO_PREFIX)
570                 .build());
571     assertThrows(GeneralSecurityException.class, () -> AesGcmJce.create(key));
572   }
573 }
574