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.aead; 18 19 import static com.google.common.truth.Truth.assertThat; 20 import static com.google.crypto.tink.internal.Util.isPrefix; 21 import static org.junit.Assert.assertArrayEquals; 22 import static org.junit.Assert.assertThrows; 23 import static org.junit.Assert.assertTrue; 24 25 import com.google.crypto.tink.Aead; 26 import com.google.crypto.tink.KeyTemplate; 27 import com.google.crypto.tink.KeyTemplates; 28 import com.google.crypto.tink.KeysetHandle; 29 import com.google.crypto.tink.KmsClients; 30 import com.google.crypto.tink.RegistryConfiguration; 31 import com.google.crypto.tink.TinkProtoKeysetFormat; 32 import com.google.crypto.tink.aead.LegacyKmsEnvelopeAeadParameters.DekParsingStrategy; 33 import com.google.crypto.tink.aead.internal.AesGcmSivProtoSerialization; 34 import com.google.crypto.tink.internal.KeyManagerRegistry; 35 import com.google.crypto.tink.internal.KeyTemplateProtoConverter; 36 import com.google.crypto.tink.internal.Util; 37 import com.google.crypto.tink.proto.KmsEnvelopeAeadKeyFormat; 38 import com.google.crypto.tink.subtle.Random; 39 import com.google.crypto.tink.testing.FakeKmsClient; 40 import com.google.crypto.tink.testing.TestUtil; 41 import com.google.protobuf.ExtensionRegistryLite; 42 import java.nio.ByteBuffer; 43 import java.security.GeneralSecurityException; 44 import java.util.Arrays; 45 import javax.annotation.Nullable; 46 import org.junit.Assume; 47 import org.junit.BeforeClass; 48 import org.junit.Test; 49 import org.junit.runner.RunWith; 50 import org.junit.runners.JUnit4; 51 52 /** Tests for {@code KmsEnvelopeAead} and {@code KmsEnvelopeAeadKeyManager}. */ 53 @RunWith(JUnit4.class) 54 public class KmsEnvelopeAeadKeyManagerTest { 55 @BeforeClass setUp()56 public static void setUp() throws Exception { 57 KmsClients.add(new FakeKmsClient()); 58 AeadConfig.register(); 59 AesGcmSivProtoSerialization.register(); 60 } 61 62 @Test testKeyManagerRegistered()63 public void testKeyManagerRegistered() throws Exception { 64 assertThat( 65 KeyManagerRegistry.globalInstance() 66 .getKeyManager( 67 "type.googleapis.com/google.crypto.tink.KmsEnvelopeAeadKey", Aead.class)) 68 .isNotNull(); 69 } 70 71 @Test getPrimitiveFromLegacyKmsEnvelopeAeadKey_works()72 public void getPrimitiveFromLegacyKmsEnvelopeAeadKey_works() throws Exception { 73 String kekUri = FakeKmsClient.createFakeKeyUri(); 74 LegacyKmsEnvelopeAeadParameters parameters = 75 LegacyKmsEnvelopeAeadParameters.builder() 76 .setKekUri(kekUri) 77 .setDekParsingStrategy(DekParsingStrategy.ASSUME_AES_EAX) 78 .setDekParametersForNewKeys( 79 AesEaxParameters.builder() 80 .setIvSizeBytes(16) 81 .setKeySizeBytes(16) 82 .setTagSizeBytes(16) 83 .setVariant(AesEaxParameters.Variant.NO_PREFIX) 84 .build()) 85 .build(); 86 LegacyKmsEnvelopeAeadKey key = LegacyKmsEnvelopeAeadKey.create(parameters); 87 KeysetHandle keysetHandle = 88 KeysetHandle.newBuilder() 89 .addEntry(KeysetHandle.importKey(key).withRandomId().makePrimary()) 90 .build(); 91 92 Aead aead = keysetHandle.getPrimitive(RegistryConfiguration.get(), Aead.class); 93 94 TestUtil.runBasicAeadTests(aead); 95 96 // Also check that aead is compatible with an Aead created with KmsEnvelopeAead.create(). 97 Aead keyEncryptionAead = new FakeKmsClient().getAead(kekUri); 98 Aead aead2 = KmsEnvelopeAead.create(PredefinedAeadParameters.AES128_EAX, keyEncryptionAead); 99 byte[] plaintext = Random.randBytes(20); 100 byte[] associatedData = Random.randBytes(20); 101 byte[] ciphertext = aead.encrypt(plaintext, associatedData); 102 byte[] decrypted = aead2.decrypt(ciphertext, associatedData); 103 assertThat(decrypted).isEqualTo(plaintext); 104 } 105 106 @Test getPrimitiveFromLegacyKmsEnvelopeAeadKeyWithTinkPrefix_works()107 public void getPrimitiveFromLegacyKmsEnvelopeAeadKeyWithTinkPrefix_works() throws Exception { 108 String kekUri = FakeKmsClient.createFakeKeyUri(); 109 LegacyKmsEnvelopeAeadParameters parameters = 110 LegacyKmsEnvelopeAeadParameters.builder() 111 .setVariant(LegacyKmsEnvelopeAeadParameters.Variant.TINK) 112 .setKekUri(kekUri) 113 .setDekParsingStrategy(DekParsingStrategy.ASSUME_AES_EAX) 114 .setDekParametersForNewKeys( 115 AesEaxParameters.builder() 116 .setIvSizeBytes(16) 117 .setKeySizeBytes(16) 118 .setTagSizeBytes(16) 119 .setVariant(AesEaxParameters.Variant.NO_PREFIX) 120 .build()) 121 .build(); 122 LegacyKmsEnvelopeAeadKey key = 123 LegacyKmsEnvelopeAeadKey.create(parameters, /* idRequirement= */ 0xbbccddee); 124 KeysetHandle keysetHandle = 125 KeysetHandle.newBuilder() 126 .addEntry(KeysetHandle.importKey(key).withFixedId(0xbbccddee).makePrimary()) 127 .build(); 128 129 Aead aead = keysetHandle.getPrimitive(RegistryConfiguration.get(), Aead.class); 130 TestUtil.runBasicAeadTests(aead); 131 132 byte[] plaintext = Random.randBytes(20); 133 byte[] associatedData = Random.randBytes(20); 134 byte[] ciphertext = aead.encrypt(plaintext, associatedData); 135 assertThat( 136 isPrefix( 137 new byte[] {(byte) 0x01, (byte) 0xbb, (byte) 0xcc, (byte) 0xdd, (byte) 0xee}, 138 ciphertext)) 139 .isTrue(); 140 141 // Also check that aead is compatible with an Aead created with KmsEnvelopeAead.create(), if 142 // the 5 byte prefix is removed. 143 Aead keyEncryptionAead = new FakeKmsClient().getAead(kekUri); 144 Aead aead2 = KmsEnvelopeAead.create(PredefinedAeadParameters.AES128_EAX, keyEncryptionAead); 145 byte[] ciphertextWithoutPrefix = Arrays.copyOfRange(ciphertext, 5, ciphertext.length); 146 byte[] decrypted = aead2.decrypt(ciphertextWithoutPrefix, associatedData); 147 assertThat(decrypted).isEqualTo(plaintext); 148 } 149 150 @Test getPrimitiveFromLegacyKmsEnvelopeAeadKey_wrongUriFails()151 public void getPrimitiveFromLegacyKmsEnvelopeAeadKey_wrongUriFails() throws Exception { 152 LegacyKmsEnvelopeAeadParameters parameters = 153 LegacyKmsEnvelopeAeadParameters.builder() 154 .setKekUri("wrong uri") 155 .setDekParsingStrategy(DekParsingStrategy.ASSUME_AES_EAX) 156 .setDekParametersForNewKeys( 157 AesEaxParameters.builder() 158 .setIvSizeBytes(16) 159 .setKeySizeBytes(16) 160 .setTagSizeBytes(16) 161 .setVariant(AesEaxParameters.Variant.NO_PREFIX) 162 .build()) 163 .build(); 164 LegacyKmsEnvelopeAeadKey key = LegacyKmsEnvelopeAeadKey.create(parameters); 165 KeysetHandle keysetHandle = 166 KeysetHandle.newBuilder() 167 .addEntry(KeysetHandle.importKey(key).withRandomId().makePrimary()) 168 .build(); 169 170 assertThrows( 171 GeneralSecurityException.class, 172 () -> keysetHandle.getPrimitive(RegistryConfiguration.get(), Aead.class)); 173 } 174 175 @Test getPrimitive_parsingInvalidCiphetexts()176 public void getPrimitive_parsingInvalidCiphetexts() throws Exception { 177 String kekUri = FakeKmsClient.createFakeKeyUri(); 178 LegacyKmsEnvelopeAeadKey key = 179 LegacyKmsEnvelopeAeadKey.create( 180 LegacyKmsEnvelopeAeadParameters.builder() 181 .setKekUri(kekUri) 182 .setDekParsingStrategy(DekParsingStrategy.ASSUME_AES_CTR_HMAC) 183 .setDekParametersForNewKeys( 184 AesCtrHmacAeadParameters.builder() 185 .setAesKeySizeBytes(16) 186 .setHmacKeySizeBytes(32) 187 .setTagSizeBytes(16) 188 .setIvSizeBytes(16) 189 .setHashType(AesCtrHmacAeadParameters.HashType.SHA256) 190 .setVariant(AesCtrHmacAeadParameters.Variant.NO_PREFIX) 191 .build()) 192 .build()); 193 KeysetHandle keysetHandle = 194 KeysetHandle.newBuilder() 195 .addEntry(KeysetHandle.importKey(key).withRandomId().makePrimary()) 196 .build(); 197 Aead aead = keysetHandle.getPrimitive(RegistryConfiguration.get(), Aead.class); 198 199 byte[] plaintext = Random.randBytes(20); 200 byte[] aad = Random.randBytes(20); 201 byte[] ciphertext = aead.encrypt(plaintext, aad); 202 ByteBuffer buffer = ByteBuffer.wrap(ciphertext); 203 int encryptedDekSize = buffer.getInt(); 204 byte[] encryptedDek = new byte[encryptedDekSize]; 205 buffer.get(encryptedDek, 0, encryptedDekSize); 206 byte[] payload = new byte[buffer.remaining()]; 207 buffer.get(payload, 0, buffer.remaining()); 208 209 // valid, should work 210 byte[] ciphertext2 = ByteBuffer.allocate(ciphertext.length) 211 .putInt(encryptedDekSize) 212 .put(encryptedDek) 213 .put(payload) 214 .array(); 215 assertArrayEquals(plaintext, aead.decrypt(ciphertext2, aad)); 216 217 // negative length 218 byte[] ciphertext3 = 219 ByteBuffer.allocate(ciphertext.length) 220 .putInt(-1) 221 .put(encryptedDek) 222 .put(payload) 223 .array(); 224 assertThrows(GeneralSecurityException.class, () -> aead.decrypt(ciphertext3, aad)); 225 226 // length larger than actual value 227 byte[] ciphertext4 = 228 ByteBuffer.allocate(ciphertext.length) 229 .putInt(encryptedDek.length + 1) 230 .put(encryptedDek) 231 .put(payload) 232 .array(); 233 assertThrows(GeneralSecurityException.class, () -> aead.decrypt(ciphertext4, aad)); 234 235 // length larger than total ciphertext length 236 byte[] ciphertext5 = 237 ByteBuffer.allocate(ciphertext.length) 238 .putInt(encryptedDek.length + payload.length + 1) 239 .put(encryptedDek) 240 .put(payload) 241 .array(); 242 assertThrows(GeneralSecurityException.class, () -> aead.decrypt(ciphertext5, aad)); 243 } 244 245 @Test createKeyTemplate()246 public void createKeyTemplate() throws Exception { 247 // Intentionally using "weird" or invalid values for parameters, 248 // to test that the function correctly puts them in the resulting template. 249 String kekUri = "some example KEK URI"; 250 KeyTemplate dekTemplate = AesCtrHmacAeadKeyManager.aes128CtrHmacSha256Template(); 251 com.google.crypto.tink.proto.KeyTemplate dekTemplateProto = 252 KeyTemplateProtoConverter.toProto(dekTemplate); 253 254 KeyTemplate template = KmsEnvelopeAeadKeyManager.createKeyTemplate(kekUri, dekTemplate); 255 256 com.google.crypto.tink.proto.KeyTemplate protoTemplate = 257 KeyTemplateProtoConverter.toProto(template); 258 assertThat(KmsEnvelopeAeadKeyManager.getKeyType()).isEqualTo(protoTemplate.getTypeUrl()); 259 assertThat(com.google.crypto.tink.proto.OutputPrefixType.RAW) 260 .isEqualTo(protoTemplate.getOutputPrefixType()); 261 262 KmsEnvelopeAeadKeyFormat format = 263 KmsEnvelopeAeadKeyFormat.parseFrom( 264 protoTemplate.getValue(), ExtensionRegistryLite.getEmptyRegistry()); 265 assertThat(kekUri).isEqualTo(format.getKekUri()); 266 assertThat(dekTemplateProto.getTypeUrl()).isEqualTo(format.getDekTemplate().getTypeUrl()); 267 assertThat(dekTemplateProto.getValue()).isEqualTo(format.getDekTemplate().getValue()); 268 } 269 270 @Test createKeyTemplate_ignoresOutputPrefix()271 public void createKeyTemplate_ignoresOutputPrefix() throws Exception { 272 // When we create LegacyKmsEnvelopeAeadParameters, the underlying OutputPrefixType in the 273 // passed in dek Template is ignored. 274 KeyTemplate template1 = 275 KmsEnvelopeAeadKeyManager.createKeyTemplate( 276 "some URI", KeyTemplates.get("AES128_CTR_HMAC_SHA256")); 277 KeyTemplate template2 = 278 KmsEnvelopeAeadKeyManager.createKeyTemplate( 279 "some URI", KeyTemplates.get("AES128_CTR_HMAC_SHA256_RAW")); 280 assertThat(template1.toParameters()).isEqualTo(template2.toParameters()); 281 } 282 283 @Test createKeyTemplate_aesGcm_works()284 public void createKeyTemplate_aesGcm_works() throws Exception { 285 LegacyKmsEnvelopeAeadParameters parameters = 286 LegacyKmsEnvelopeAeadParameters.builder() 287 .setKekUri("SomeMatchingKekUri") 288 .setDekParsingStrategy( 289 LegacyKmsEnvelopeAeadParameters.DekParsingStrategy.ASSUME_AES_GCM) 290 .setDekParametersForNewKeys( 291 AesGcmParameters.builder() 292 .setIvSizeBytes(12) 293 .setKeySizeBytes(16) 294 .setTagSizeBytes(16) 295 .setVariant(AesGcmParameters.Variant.NO_PREFIX) 296 .build()) 297 .build(); 298 299 // Check with both NO_PREFIX as well as TINK to ensure the Variant is ignored. 300 KeyTemplate template1 = 301 KmsEnvelopeAeadKeyManager.createKeyTemplate( 302 "SomeMatchingKekUri", KeyTemplates.get("AES128_GCM")); 303 assertThat(template1.toParameters()).isEqualTo(parameters); 304 305 KeyTemplate template2 = 306 KmsEnvelopeAeadKeyManager.createKeyTemplate( 307 "SomeMatchingKekUri", KeyTemplates.get("AES128_GCM_RAW")); 308 assertThat(template2.toParameters()).isEqualTo(parameters); 309 } 310 311 @Test createKeyTemplate_chacha_works()312 public void createKeyTemplate_chacha_works() throws Exception { 313 LegacyKmsEnvelopeAeadParameters parameters = 314 LegacyKmsEnvelopeAeadParameters.builder() 315 .setKekUri("SomeMatchingKekUri") 316 .setDekParsingStrategy( 317 LegacyKmsEnvelopeAeadParameters.DekParsingStrategy.ASSUME_CHACHA20POLY1305) 318 .setDekParametersForNewKeys( 319 ChaCha20Poly1305Parameters.create(ChaCha20Poly1305Parameters.Variant.NO_PREFIX)) 320 .build(); 321 322 // Check with both NO_PREFIX as well as TINK to ensure the Variant is ignored. 323 KeyTemplate template1 = 324 KmsEnvelopeAeadKeyManager.createKeyTemplate( 325 "SomeMatchingKekUri", 326 KeyTemplate.createFrom( 327 ChaCha20Poly1305Parameters.create(ChaCha20Poly1305Parameters.Variant.NO_PREFIX))); 328 assertThat(template1.toParameters()).isEqualTo(parameters); 329 330 KeyTemplate template2 = 331 KmsEnvelopeAeadKeyManager.createKeyTemplate( 332 "SomeMatchingKekUri", 333 KeyTemplate.createFrom( 334 ChaCha20Poly1305Parameters.create(ChaCha20Poly1305Parameters.Variant.TINK))); 335 assertThat(template2.toParameters()).isEqualTo(parameters); 336 } 337 338 @Test createKeyTemplate_xchacha_works()339 public void createKeyTemplate_xchacha_works() throws Exception { 340 LegacyKmsEnvelopeAeadParameters parameters = 341 LegacyKmsEnvelopeAeadParameters.builder() 342 .setKekUri("SomeMatchingKekUri") 343 .setDekParsingStrategy( 344 LegacyKmsEnvelopeAeadParameters.DekParsingStrategy.ASSUME_XCHACHA20POLY1305) 345 .setDekParametersForNewKeys( 346 XChaCha20Poly1305Parameters.create(XChaCha20Poly1305Parameters.Variant.NO_PREFIX)) 347 .build(); 348 349 // Check with both NO_PREFIX as well as TINK to ensure the Variant is ignored. 350 KeyTemplate template1 = 351 KmsEnvelopeAeadKeyManager.createKeyTemplate( 352 "SomeMatchingKekUri", 353 KeyTemplate.createFrom( 354 XChaCha20Poly1305Parameters.create(XChaCha20Poly1305Parameters.Variant.NO_PREFIX))); 355 assertThat(template1.toParameters()).isEqualTo(parameters); 356 357 KeyTemplate template2 = 358 KmsEnvelopeAeadKeyManager.createKeyTemplate( 359 "SomeMatchingKekUri", 360 KeyTemplate.createFrom( 361 XChaCha20Poly1305Parameters.create(XChaCha20Poly1305Parameters.Variant.TINK))); 362 assertThat(template2.toParameters()).isEqualTo(parameters); 363 } 364 365 @Test createKeyTemplate_eax_works()366 public void createKeyTemplate_eax_works() throws Exception { 367 LegacyKmsEnvelopeAeadParameters parameters = 368 LegacyKmsEnvelopeAeadParameters.builder() 369 .setKekUri("SomeOtherKekUri") 370 .setDekParsingStrategy( 371 LegacyKmsEnvelopeAeadParameters.DekParsingStrategy.ASSUME_AES_EAX) 372 .setDekParametersForNewKeys( 373 AesEaxParameters.builder() 374 .setIvSizeBytes(16) 375 .setKeySizeBytes(16) 376 .setTagSizeBytes(16) 377 .setVariant(AesEaxParameters.Variant.NO_PREFIX) 378 .build()) 379 .build(); 380 381 // Check with both NO_PREFIX as well as TINK to ensure the Variant is ignored. 382 KeyTemplate template1 = 383 KmsEnvelopeAeadKeyManager.createKeyTemplate( 384 "SomeOtherKekUri", KeyTemplates.get("AES128_EAX_RAW")); 385 assertThat(template1.toParameters()).isEqualTo(parameters); 386 387 KeyTemplate template2 = 388 KmsEnvelopeAeadKeyManager.createKeyTemplate( 389 "SomeOtherKekUri", KeyTemplates.get("AES128_EAX")); 390 assertThat(template2.toParameters()).isEqualTo(parameters); 391 } 392 393 @Test createKeyTemplate_gcmsiv_works()394 public void createKeyTemplate_gcmsiv_works() throws Exception { 395 LegacyKmsEnvelopeAeadParameters parameters = 396 LegacyKmsEnvelopeAeadParameters.builder() 397 .setKekUri("SomeOtherKekUri") 398 .setDekParsingStrategy( 399 LegacyKmsEnvelopeAeadParameters.DekParsingStrategy.ASSUME_AES_GCM_SIV) 400 .setDekParametersForNewKeys( 401 AesGcmSivParameters.builder() 402 .setKeySizeBytes(16) 403 .setVariant(AesGcmSivParameters.Variant.NO_PREFIX) 404 .build()) 405 .build(); 406 407 // Check with both NO_PREFIX as well as TINK to ensure the Variant is ignored. 408 KeyTemplate template1 = 409 KmsEnvelopeAeadKeyManager.createKeyTemplate( 410 "SomeOtherKekUri", 411 KeyTemplate.createFrom( 412 AesGcmSivParameters.builder() 413 .setKeySizeBytes(16) 414 .setVariant(AesGcmSivParameters.Variant.NO_PREFIX) 415 .build())); 416 assertThat(template1.toParameters()).isEqualTo(parameters); 417 418 KeyTemplate template2 = 419 KmsEnvelopeAeadKeyManager.createKeyTemplate( 420 "SomeOtherKekUri", 421 KeyTemplate.createFrom( 422 AesGcmSivParameters.builder() 423 .setKeySizeBytes(16) 424 .setVariant(AesGcmSivParameters.Variant.TINK) 425 .build())); 426 assertThat(template2.toParameters()).isEqualTo(parameters); 427 } 428 429 @Test createKeyTemplate_aesctrhmac_works()430 public void createKeyTemplate_aesctrhmac_works() throws Exception { 431 LegacyKmsEnvelopeAeadParameters parameters = 432 LegacyKmsEnvelopeAeadParameters.builder() 433 .setKekUri("SomeOtherKekUri") 434 .setDekParsingStrategy( 435 LegacyKmsEnvelopeAeadParameters.DekParsingStrategy.ASSUME_AES_CTR_HMAC) 436 .setDekParametersForNewKeys( 437 AesCtrHmacAeadParameters.builder() 438 .setAesKeySizeBytes(16) 439 .setHmacKeySizeBytes(32) 440 .setTagSizeBytes(32) 441 .setIvSizeBytes(16) 442 .setHashType(AesCtrHmacAeadParameters.HashType.SHA256) 443 .setVariant(AesCtrHmacAeadParameters.Variant.NO_PREFIX) 444 .build()) 445 .build(); 446 447 // Check with both NO_PREFIX as well as TINK to ensure the Variant is ignored. 448 KeyTemplate template1 = 449 KmsEnvelopeAeadKeyManager.createKeyTemplate( 450 "SomeOtherKekUri", 451 KeyTemplate.createFrom( 452 AesCtrHmacAeadParameters.builder() 453 .setAesKeySizeBytes(16) 454 .setHmacKeySizeBytes(32) 455 .setTagSizeBytes(32) 456 .setIvSizeBytes(16) 457 .setHashType(AesCtrHmacAeadParameters.HashType.SHA256) 458 .setVariant(AesCtrHmacAeadParameters.Variant.NO_PREFIX) 459 .build())); 460 assertThat(template1.toParameters()).isEqualTo(parameters); 461 462 KeyTemplate template2 = 463 KmsEnvelopeAeadKeyManager.createKeyTemplate( 464 "SomeOtherKekUri", 465 KeyTemplate.createFrom( 466 AesCtrHmacAeadParameters.builder() 467 .setAesKeySizeBytes(16) 468 .setHmacKeySizeBytes(32) 469 .setTagSizeBytes(32) 470 .setIvSizeBytes(16) 471 .setHashType(AesCtrHmacAeadParameters.HashType.SHA256) 472 .setVariant(AesCtrHmacAeadParameters.Variant.TINK) 473 .build())); 474 assertThat(template2.toParameters()).isEqualTo(parameters); 475 } 476 477 @Test createKeyTemplateGenerateNewGetPrimitive_isSameAs_create()478 public void createKeyTemplateGenerateNewGetPrimitive_isSameAs_create() throws Exception { 479 @Nullable Integer apiLevel = Util.getAndroidApiLevel(); 480 Assume.assumeTrue(apiLevel == null || apiLevel >= 30); // Run the test on java and android >= 30 481 482 String keyUri = FakeKmsClient.createFakeKeyUri(); 483 484 // Create Aead primitive using createKeyTemplate, generateNew, and getPrimitive. 485 // This requires that a KmsClient that supports keyUri is registered. 486 KeyTemplate template = 487 KmsEnvelopeAeadKeyManager.createKeyTemplate(keyUri, KeyTemplates.get("AES128_GCM")); 488 KeysetHandle keysetHandle = KeysetHandle.generateNew(template); 489 Aead aead1 = keysetHandle.getPrimitive(RegistryConfiguration.get(), Aead.class); 490 491 // Create Aead using FakeKmsClient.getAead and KmsEnvelopeAead.create. 492 // No KmsClient needs to be registered. 493 Aead keyEncryptionAead = new FakeKmsClient().getAead(keyUri); 494 Aead aead2 = KmsEnvelopeAead.create(PredefinedAeadParameters.AES256_GCM, keyEncryptionAead); 495 496 // Test that aead1 and aead2 are the same. 497 byte[] plaintext = Random.randBytes(20); 498 byte[] associatedData = Random.randBytes(20); 499 byte[] ciphertext = aead1.encrypt(plaintext, associatedData); 500 byte[] decrypted = aead2.decrypt(ciphertext, associatedData); 501 assertThat(decrypted).isEqualTo(plaintext); 502 } 503 504 @Test multipleAeadsWithSameKekAndSameDekTemplate_canDecryptEachOther()505 public void multipleAeadsWithSameKekAndSameDekTemplate_canDecryptEachOther() throws Exception { 506 String kekUri = FakeKmsClient.createFakeKeyUri(); 507 KeyTemplate dekTemplate = AesCtrHmacAeadKeyManager.aes128CtrHmacSha256Template(); 508 509 KeysetHandle handle1 = 510 KeysetHandle.generateNew(KmsEnvelopeAeadKeyManager.createKeyTemplate(kekUri, dekTemplate)); 511 Aead aead1 = handle1.getPrimitive(RegistryConfiguration.get(), Aead.class); 512 513 KeysetHandle handle2 = 514 KeysetHandle.generateNew(KmsEnvelopeAeadKeyManager.createKeyTemplate(kekUri, dekTemplate)); 515 Aead aead2 = handle2.getPrimitive(RegistryConfiguration.get(), Aead.class); 516 517 byte[] plaintext = Random.randBytes(20); 518 byte[] associatedData = Random.randBytes(20); 519 520 assertThat(aead1.decrypt(aead2.encrypt(plaintext, associatedData), associatedData)) 521 .isEqualTo(plaintext); 522 } 523 524 @Test keysetsWithTwoKmsEnvelopeAeadKeys_canDecryptWithBoth()525 public void keysetsWithTwoKmsEnvelopeAeadKeys_canDecryptWithBoth() throws Exception { 526 KeyTemplate dekTemplate = AesCtrHmacAeadKeyManager.aes128CtrHmacSha256Template(); 527 byte[] plaintext = Random.randBytes(20); 528 byte[] associatedData = Random.randBytes(20); 529 530 String kekUri1 = FakeKmsClient.createFakeKeyUri(); 531 KeysetHandle handle1 = 532 KeysetHandle.generateNew(KmsEnvelopeAeadKeyManager.createKeyTemplate(kekUri1, dekTemplate)); 533 Aead aead1 = handle1.getPrimitive(RegistryConfiguration.get(), Aead.class); 534 byte[] ciphertext1 = aead1.encrypt(plaintext, associatedData); 535 536 String kekUri2 = FakeKmsClient.createFakeKeyUri(); 537 KeysetHandle handle2 = 538 KeysetHandle.generateNew(KmsEnvelopeAeadKeyManager.createKeyTemplate(kekUri2, dekTemplate)); 539 Aead aead2 = handle2.getPrimitive(RegistryConfiguration.get(), Aead.class); 540 byte[] ciphertext2 = aead2.encrypt(plaintext, associatedData); 541 542 KeysetHandle handle = 543 KeysetHandle.newBuilder() 544 .addEntry( 545 KeysetHandle.importKey(handle1.getAt(0).getKey()).withRandomId().makePrimary()) 546 .addEntry(KeysetHandle.importKey(handle2.getAt(0).getKey()).withRandomId()) 547 .build(); 548 Aead aead = handle.getPrimitive(RegistryConfiguration.get(), Aead.class); 549 550 assertThat(aead.decrypt(ciphertext1, associatedData)).isEqualTo(plaintext); 551 assertThat(aead.decrypt(ciphertext2, associatedData)).isEqualTo(plaintext); 552 } 553 554 @Test multipleAeadsWithSameKekAndDifferentDekTemplateOfSameKeyType_canDecryptEachOther()555 public void multipleAeadsWithSameKekAndDifferentDekTemplateOfSameKeyType_canDecryptEachOther() 556 throws Exception { 557 String kekUri = FakeKmsClient.createFakeKeyUri(); 558 559 KeyTemplate dek1Template = AesCtrHmacAeadKeyManager.aes128CtrHmacSha256Template(); 560 KeysetHandle handle1 = 561 KeysetHandle.generateNew(KmsEnvelopeAeadKeyManager.createKeyTemplate(kekUri, dek1Template)); 562 Aead aead1 = handle1.getPrimitive(RegistryConfiguration.get(), Aead.class); 563 564 KeyTemplate dek2Template = AesCtrHmacAeadKeyManager.aes256CtrHmacSha256Template(); 565 KeysetHandle handle2 = 566 KeysetHandle.generateNew(KmsEnvelopeAeadKeyManager.createKeyTemplate(kekUri, dek2Template)); 567 Aead aead2 = handle2.getPrimitive(RegistryConfiguration.get(), Aead.class); 568 569 byte[] plaintext = Random.randBytes(20); 570 byte[] associatedData = Random.randBytes(20); 571 572 byte[] ciphertext = aead1.encrypt(plaintext, associatedData); 573 574 // This works because ciphertext contains an encrypted AesCtrHmacAeadKey, which aead2 correctly 575 // decrypts and parses. The resulting key can then decrypt the ciphertext. 576 assertThat(aead2.decrypt(ciphertext, associatedData)).isEqualTo(plaintext); 577 } 578 579 @Test multipleAeadsWithSameKekAndDifferentDekTemplateKeyType_cannotDecryptEachOther()580 public void multipleAeadsWithSameKekAndDifferentDekTemplateKeyType_cannotDecryptEachOther() 581 throws Exception { 582 String kekUri = FakeKmsClient.createFakeKeyUri(); 583 584 KeyTemplate dek1Template = AesCtrHmacAeadKeyManager.aes128CtrHmacSha256Template(); 585 KeysetHandle handle1 = 586 KeysetHandle.generateNew(KmsEnvelopeAeadKeyManager.createKeyTemplate(kekUri, dek1Template)); 587 Aead aead1 = handle1.getPrimitive(RegistryConfiguration.get(), Aead.class); 588 589 KeyTemplate dek2Template = AesGcmKeyManager.aes128GcmTemplate(); 590 KeysetHandle handle2 = 591 KeysetHandle.generateNew(KmsEnvelopeAeadKeyManager.createKeyTemplate(kekUri, dek2Template)); 592 Aead aead2 = handle2.getPrimitive(RegistryConfiguration.get(), Aead.class); 593 594 byte[] plaintext = Random.randBytes(20); 595 byte[] associatedData = Random.randBytes(20); 596 597 byte[] ciphertext = aead1.encrypt(plaintext, associatedData); 598 599 // ciphertext contains an encrypted AesCtrHmacAeadKey proto. aead2 can decrypt it, but it 600 // tries to parse it as an AesGcmKey proto. Either the parsing fails or the resulting key is 601 // not able to decrypt the ciphertext. 602 assertThrows(GeneralSecurityException.class, () -> aead2.decrypt(ciphertext, associatedData)); 603 } 604 605 @Test createKeyTemplateWithEnvelopeKeyTemplateAsDekTemplate_fails()606 public void createKeyTemplateWithEnvelopeKeyTemplateAsDekTemplate_fails() throws Exception { 607 String kekUri = FakeKmsClient.createFakeKeyUri(); 608 609 KeyTemplate dekTemplate = 610 KmsEnvelopeAeadKeyManager.createKeyTemplate( 611 kekUri, AesCtrHmacAeadKeyManager.aes128CtrHmacSha256Template()); 612 assertThrows( 613 IllegalArgumentException.class, 614 () -> KmsEnvelopeAeadKeyManager.createKeyTemplate(kekUri, dekTemplate)); 615 } 616 617 @Test testSerializeAndParse_works()618 public void testSerializeAndParse_works() throws Exception { 619 String kekUri = FakeKmsClient.createFakeKeyUri(); 620 KeyTemplate dek1Template = AesCtrHmacAeadKeyManager.aes128CtrHmacSha256Template(); 621 KeysetHandle handle = 622 KeysetHandle.generateNew(KmsEnvelopeAeadKeyManager.createKeyTemplate(kekUri, dek1Template)); 623 byte[] serialized = TinkProtoKeysetFormat.serializeKeysetWithoutSecret(handle); 624 KeysetHandle parsed = TinkProtoKeysetFormat.parseKeysetWithoutSecret(serialized); 625 626 assertTrue(handle.equalsKeyset(parsed)); 627 } 628 } 629