• 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.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