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