xref: /aosp_15_r20/external/tink/java_src/src/test/java/com/google/crypto/tink/KeysetHandleTest.java (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
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;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 import static java.nio.charset.StandardCharsets.UTF_8;
21 import static org.junit.Assert.assertFalse;
22 import static org.junit.Assert.assertThrows;
23 import static org.junit.Assert.assertTrue;
24 import static org.junit.Assume.assumeFalse;
25 
26 import com.google.common.truth.Expect;
27 import com.google.crypto.tink.aead.AeadConfig;
28 import com.google.crypto.tink.aead.AesEaxKeyManager;
29 import com.google.crypto.tink.aead.XChaCha20Poly1305Key;
30 import com.google.crypto.tink.aead.XChaCha20Poly1305Parameters;
31 import com.google.crypto.tink.internal.InternalConfiguration;
32 import com.google.crypto.tink.internal.KeyParser;
33 import com.google.crypto.tink.internal.KeyStatusTypeProtoConverter;
34 import com.google.crypto.tink.internal.LegacyProtoKey;
35 import com.google.crypto.tink.internal.MonitoringUtil;
36 import com.google.crypto.tink.internal.MutableMonitoringRegistry;
37 import com.google.crypto.tink.internal.MutablePrimitiveRegistry;
38 import com.google.crypto.tink.internal.MutableSerializationRegistry;
39 import com.google.crypto.tink.internal.PrimitiveConstructor;
40 import com.google.crypto.tink.internal.PrimitiveRegistry;
41 import com.google.crypto.tink.internal.ProtoKeySerialization;
42 import com.google.crypto.tink.internal.testing.FakeMonitoringClient;
43 import com.google.crypto.tink.mac.AesCmacKey;
44 import com.google.crypto.tink.mac.AesCmacParameters;
45 import com.google.crypto.tink.mac.AesCmacParameters.Variant;
46 import com.google.crypto.tink.mac.ChunkedMac;
47 import com.google.crypto.tink.mac.ChunkedMacComputation;
48 import com.google.crypto.tink.mac.HmacKey;
49 import com.google.crypto.tink.mac.HmacParameters;
50 import com.google.crypto.tink.mac.MacConfig;
51 import com.google.crypto.tink.monitoring.MonitoringAnnotations;
52 import com.google.crypto.tink.monitoring.MonitoringClient;
53 import com.google.crypto.tink.prf.PrfConfig;
54 import com.google.crypto.tink.proto.AesEaxKey;
55 import com.google.crypto.tink.proto.EcdsaPrivateKey;
56 import com.google.crypto.tink.proto.HashType;
57 import com.google.crypto.tink.proto.HmacParams;
58 import com.google.crypto.tink.proto.HmacPrfKey;
59 import com.google.crypto.tink.proto.HmacPrfParams;
60 import com.google.crypto.tink.proto.KeyData;
61 import com.google.crypto.tink.proto.KeyData.KeyMaterialType;
62 import com.google.crypto.tink.proto.KeyStatusType;
63 import com.google.crypto.tink.proto.Keyset;
64 import com.google.crypto.tink.proto.OutputPrefixType;
65 import com.google.crypto.tink.signature.SignatureConfig;
66 import com.google.crypto.tink.subtle.Hex;
67 import com.google.crypto.tink.subtle.Random;
68 import com.google.crypto.tink.testing.TestUtil;
69 import com.google.crypto.tink.tinkkey.KeyAccess;
70 import com.google.crypto.tink.tinkkey.KeyHandle;
71 import com.google.crypto.tink.tinkkey.SecretKeyAccess;
72 import com.google.crypto.tink.tinkkey.internal.ProtoKey;
73 import com.google.crypto.tink.util.Bytes;
74 import com.google.crypto.tink.util.SecretBytes;
75 import com.google.errorprone.annotations.Immutable;
76 import com.google.protobuf.ByteString;
77 import com.google.protobuf.ExtensionRegistryLite;
78 import java.io.ByteArrayInputStream;
79 import java.io.ByteArrayOutputStream;
80 import java.nio.ByteBuffer;
81 import java.security.GeneralSecurityException;
82 import java.util.HashSet;
83 import java.util.List;
84 import java.util.Map;
85 import java.util.Set;
86 import java.util.TreeSet;
87 import java.util.stream.Collectors;
88 import javax.annotation.Nullable;
89 import org.junit.BeforeClass;
90 import org.junit.Rule;
91 import org.junit.Test;
92 import org.junit.runner.RunWith;
93 import org.junit.runners.JUnit4;
94 
95 /**
96  * Tests for {@link KeysetHandle}.
97  *
98  * <p>Please note, that in relation to the {@link PrimitiveSet#fullPrimitive} this file only tests
99  * the legacy scenario where the {@link PrimitiveSet#primitive} is set and {@link
100  * PrimitiveSet#fullPrimitive} isn't; the other scenarios are tested in
101  * {@link KeysetHandleFullPrimitiveTest}.
102  */
103 @RunWith(JUnit4.class)
104 @SuppressWarnings("UnnecessarilyFullyQualified") // Fully specifying proto types is more readable
105 public class KeysetHandleTest {
106 
107   @Rule public final Expect expect = Expect.create();
108 
109   private static interface EncryptOnly {
encrypt(final byte[] plaintext)110     byte[] encrypt(final byte[] plaintext) throws GeneralSecurityException;
111   }
112 
113   private static class AeadToEncryptOnlyWrapper implements PrimitiveWrapper<Aead, EncryptOnly> {
114 
115     private static final AeadToEncryptOnlyWrapper WRAPPER = new AeadToEncryptOnlyWrapper();
116 
117     private static class EncryptOnlyWithMonitoring implements EncryptOnly {
118 
119       private final MonitoringClient.Logger logger;
120       private final PrimitiveSet<Aead> primitiveSet;
121 
EncryptOnlyWithMonitoring(PrimitiveSet<Aead> primitiveSet)122       EncryptOnlyWithMonitoring(PrimitiveSet<Aead> primitiveSet) {
123         this.primitiveSet = primitiveSet;
124         MonitoringClient client = MutableMonitoringRegistry.globalInstance().getMonitoringClient();
125         logger =
126             client.createLogger(
127                 MonitoringUtil.getMonitoringKeysetInfo(primitiveSet), "encrypt_only", "encrypt");
128       }
129 
130       @Override
encrypt(final byte[] plaintext)131       public byte[] encrypt(final byte[] plaintext) throws GeneralSecurityException {
132         logger.log(primitiveSet.getPrimary().getKeyId(), plaintext.length);
133         return primitiveSet.getPrimary().getPrimitive().encrypt(plaintext, new byte[0]);
134       }
135     }
136 
137     @Override
wrap(PrimitiveSet<Aead> set)138     public EncryptOnly wrap(PrimitiveSet<Aead> set) throws GeneralSecurityException {
139       return new EncryptOnlyWithMonitoring(set);
140     }
141 
142     @Override
getPrimitiveClass()143     public Class<EncryptOnly> getPrimitiveClass() {
144       return EncryptOnly.class;
145     }
146 
147     @Override
getInputPrimitiveClass()148     public Class<Aead> getInputPrimitiveClass() {
149       return Aead.class;
150     }
151 
register()152     static void register() throws GeneralSecurityException {
153       Registry.registerPrimitiveWrapper(WRAPPER);
154     }
155   }
156 
157   private static final int HMAC_KEY_SIZE = 20;
158   private static final int HMAC_TAG_SIZE = 10;
159 
160   private static HmacKey rawKey;
161 
162   @BeforeClass
setUp()163   public static void setUp() throws GeneralSecurityException {
164     MacConfig.register();
165     AeadConfig.register();
166     PrfConfig.register();
167     SignatureConfig.register();
168     AeadToEncryptOnlyWrapper.register();
169 
170     createTestKeys();
171   }
172 
createTestKeys()173   private static void createTestKeys() {
174     try {
175       rawKey =
176           HmacKey.builder()
177               .setParameters(
178                   HmacParameters.builder()
179                       .setKeySizeBytes(HMAC_KEY_SIZE)
180                       .setTagSizeBytes(HMAC_TAG_SIZE)
181                       .setVariant(HmacParameters.Variant.NO_PREFIX)
182                       .setHashType(HmacParameters.HashType.SHA256)
183                       .build())
184               .setKeyBytes(SecretBytes.randomBytes(HMAC_KEY_SIZE))
185               .setIdRequirement(null)
186               .build();
187     } catch (GeneralSecurityException e) {
188       throw new IllegalStateException(e);
189     }
190   }
191 
192   @SuppressWarnings("deprecation") // This is a test for the deprecated function
193   @Test
deprecated_getKeys()194   public void deprecated_getKeys() throws Exception {
195     KeysetHandle handle =
196         KeysetHandle.newBuilder()
197             .addEntry(KeysetHandle.generateEntryFromParametersName("AES128_EAX").withRandomId())
198             .addEntry(
199                 KeysetHandle.generateEntryFromParametersName("AES128_EAX")
200                     .withRandomId()
201                     .makePrimary())
202             .addEntry(KeysetHandle.generateEntryFromParametersName("AES128_EAX").withRandomId())
203             .build();
204     Keyset keyset = handle.getKeyset();
205 
206     List<KeyHandle> keysetKeys = handle.getKeys();
207 
208     expect.that(keysetKeys).hasSize(3);
209     Map<Integer, KeyHandle> keysetKeysMap =
210         keysetKeys.stream().collect(Collectors.toMap(KeyHandle::getId, key -> key));
211     for (Keyset.Key key : keyset.getKeyList()) {
212       expect.that(keysetKeysMap).containsKey(key.getKeyId());
213       KeyHandle keysetKey = keysetKeysMap.get(key.getKeyId());
214       expect
215           .that(KeyStatusTypeProtoConverter.toProto(keysetKey.getStatus()))
216           .isEqualTo(key.getStatus());
217       KeyData keyData =
218           ((ProtoKey) keysetKey.getKey(SecretKeyAccess.insecureSecretAccess())).getProtoKey();
219       expect.that(keyData).isEqualTo(key.getKeyData());
220     }
221   }
222 
223   @Test
generateNew_tink_shouldWork()224   public void generateNew_tink_shouldWork() throws Exception {
225     KeyTemplate template = KeyTemplates.get("AES128_EAX");
226 
227     KeysetHandle handle = KeysetHandle.generateNew(template);
228 
229     assertThat(handle.size()).isEqualTo(1);
230     assertThat(handle.getAt(0).getKey().getParameters()).isEqualTo(template.toParameters());
231   }
232 
233   @Test
testKeysetHandleGenerateNew_parameters_works()234   public void testKeysetHandleGenerateNew_parameters_works() throws Exception {
235     AesCmacParameters parameters =
236         AesCmacParameters.builder()
237             .setVariant(Variant.CRUNCHY)
238             .setKeySizeBytes(32)
239             .setTagSizeBytes(16)
240             .build();
241     KeysetHandle h = KeysetHandle.generateNew(parameters);
242     assertThat(h.size()).isEqualTo(1);
243     assertThat(h.getAt(0).getKey().getParameters()).isEqualTo(parameters);
244   }
245 
246   @Test
testKeysetHandleGenerateNew_parameters_fails()247   public void testKeysetHandleGenerateNew_parameters_fails() throws Exception {
248     Parameters p =
249         new Parameters() {
250           @Override
251           public boolean hasIdRequirement() {
252             return false;
253           }
254         };
255 
256     assertThrows(GeneralSecurityException.class, () -> KeysetHandle.generateNew(p));
257   }
258 
259 
260   @Test
generateNew_raw_shouldWork()261   public void generateNew_raw_shouldWork() throws Exception {
262     KeyTemplate template = KeyTemplates.get("AES128_EAX_RAW");
263 
264     KeysetHandle handle = KeysetHandle.generateNew(template);
265 
266     assertThat(handle.size()).isEqualTo(1);
267     assertThat(handle.getAt(0).getKey().getParameters()).isEqualTo(template.toParameters());
268   }
269 
270   @Test
generateNew_withProtoKeyTemplate_shouldWork()271   public void generateNew_withProtoKeyTemplate_shouldWork() throws Exception {
272     KeyTemplate template = KeyTemplates.get("AES128_EAX");
273     com.google.crypto.tink.proto.KeyTemplate protoTemplate = template.getProto();
274 
275     @SuppressWarnings("deprecation") // Need to test the deprecated function
276     KeysetHandle handle = KeysetHandle.generateNew(protoTemplate);
277 
278     assertThat(handle.size()).isEqualTo(1);
279     assertThat(handle.getAt(0).getKey().getParameters()).isEqualTo(template.toParameters());
280   }
281 
282   @Test
generateNew_generatesDifferentKeys()283   public void generateNew_generatesDifferentKeys() throws Exception {
284     KeyTemplate template = KeyTemplates.get("AES128_EAX");
285     Set<String> keys = new TreeSet<>();
286 
287     int numKeys = 2;
288     for (int j = 0; j < numKeys; j++) {
289       KeysetHandle handle = KeysetHandle.generateNew(template);
290       AesEaxKey aesEaxKey =
291           AesEaxKey.parseFrom(
292               handle.getKeyset().getKey(0).getKeyData().getValue(),
293               ExtensionRegistryLite.getEmptyRegistry());
294       keys.add(aesEaxKey.getKeyValue().toStringUtf8());
295     }
296 
297     assertThat(keys).hasSize(numKeys);
298   }
299 
300   @SuppressWarnings("deprecation")  // This is a test for the deprecated function
301   @Test
deprecated_createFromKey_shouldWork()302   public void deprecated_createFromKey_shouldWork() throws Exception {
303     KeyTemplate template = KeyTemplates.get("AES128_EAX");
304     KeyHandle keyHandle = KeyHandle.generateNew(template);
305     KeyAccess token = SecretKeyAccess.insecureSecretAccess();
306 
307     KeysetHandle handle = KeysetHandle.createFromKey(keyHandle, token);
308 
309     assertThat(handle.size()).isEqualTo(1);
310     assertThat(handle.getAt(0).getKey().getParameters()).isEqualTo(template.toParameters());
311   }
312 
313   @Test
toString_containsNoKeyMaterial()314   public void toString_containsNoKeyMaterial() throws Exception {
315     String keyValue = "01234567890123456";
316     Keyset keyset =
317         TestUtil.createKeyset(
318             TestUtil.createKey(
319                 TestUtil.createHmacKeyData(keyValue.getBytes(UTF_8), 16),
320                 42,
321                 KeyStatusType.ENABLED,
322                 OutputPrefixType.TINK));
323     KeysetHandle handle = KeysetHandle.fromKeyset(keyset);
324 
325     String keysetInfo = handle.toString();
326 
327     expect.that(keysetInfo).doesNotContain(keyValue);
328     expect.that(handle.getKeyset().toString()).contains(keyValue);
329   }
330 
331   @Test
writeThenRead_returnsSameKeyset()332   public void writeThenRead_returnsSameKeyset() throws Exception {
333     KeysetHandle handle = KeysetHandle.generateNew(KeyTemplates.get("HMAC_SHA256_256BITTAG"));
334     Aead masterKey =
335         Registry.getPrimitive(Registry.newKeyData(KeyTemplates.get("AES128_EAX")), Aead.class);
336     ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
337     KeysetWriter writer = BinaryKeysetWriter.withOutputStream(outputStream);
338 
339     handle.write(writer, masterKey);
340     ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
341     KeysetReader reader = BinaryKeysetReader.withInputStream(inputStream);
342     KeysetHandle handle2 = KeysetHandle.read(reader, masterKey);
343 
344     assertThat(handle.getKeyset()).isEqualTo(handle2.getKeyset());
345   }
346 
347   @Test
writeThenReadWithAssociatedData_returnsSameKeyset()348   public void writeThenReadWithAssociatedData_returnsSameKeyset() throws Exception {
349     KeysetHandle handle = KeysetHandle.generateNew(KeyTemplates.get("HMAC_SHA256_256BITTAG"));
350     Aead masterKey =
351         Registry.getPrimitive(Registry.newKeyData(KeyTemplates.get("AES128_EAX")), Aead.class);
352     ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
353     KeysetWriter writer = BinaryKeysetWriter.withOutputStream(outputStream);
354 
355     handle.writeWithAssociatedData(writer, masterKey, new byte[] {0x01, 0x02});
356     ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
357     KeysetReader reader = BinaryKeysetReader.withInputStream(inputStream);
358     KeysetHandle handle2 =
359         KeysetHandle.readWithAssociatedData(reader, masterKey, new byte[] {0x01, 0x02});
360 
361     assertThat(handle.getKeyset()).isEqualTo(handle2.getKeyset());
362   }
363 
364   @Test
writeThenReadWithDifferentAssociatedData_shouldThrow()365   public void writeThenReadWithDifferentAssociatedData_shouldThrow() throws Exception {
366     KeysetHandle handle = KeysetHandle.generateNew(KeyTemplates.get("HMAC_SHA256_256BITTAG"));
367     Aead masterKey =
368         Registry.getPrimitive(Registry.newKeyData(KeyTemplates.get("AES128_EAX")), Aead.class);
369     ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
370     KeysetWriter writer = BinaryKeysetWriter.withOutputStream(outputStream);
371 
372     handle.writeWithAssociatedData(writer, masterKey, new byte[] {0x01, 0x02});
373     ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
374     KeysetReader reader = BinaryKeysetReader.withInputStream(inputStream);
375     assertThrows(
376         GeneralSecurityException.class,
377         () -> KeysetHandle.readWithAssociatedData(reader, masterKey, new byte[] {0x01, 0x03}));
378   }
379 
380   /**
381    * A test vector for readWithAssociatedData, generated with this implementation. It uses a
382    * AES128_EAX template for the wrapping key, and a HMAC_SHA256_128BITTAG for the mac.
383    */
384   @Test
readWithAssociatedDataTestVector()385   public void readWithAssociatedDataTestVector() throws Exception {
386     // An AEAD key, with which we encrypt the mac key below (using the encrypted keyset api).
387     final byte[] serializedWrappingKeyset =
388         Hex.decode(
389             "08b891f5a20412580a4c0a30747970652e676f6f676c65617069732e636f6d2f676f6f676c652e6372797"
390                 + "0746f2e74696e6b2e4165734561784b65791216120208101a10e5d7d0cdd649e81e7952260689b2"
391                 + "e1971801100118b891f5a2042001");
392     final byte[] associatedData = Hex.decode("abcdef330012");
393     // A Mac key, encrypted with the above, using ASSOCIATED_DATA as aad.
394     final byte[] encryptedSerializedKeyset =
395         Hex.decode(
396             "12950101445d48b8b5f591efaf73a46df9ebd7b6ac471cc0cf4f815a4f012fcaffc8f0b2b10b30c33194f"
397                 + "0b291614bd8e1d2e80118e5d6226b6c41551e104ef8cd8ee20f1c14c1b87f6eed5fb04a91feafaa"
398                 + "cbf6f368519f36f97f7d08b24c8e71b5e620c4f69615ef0479391666e2fb32e46b416893fc4e564"
399                 + "ba927b22ebff2a77bd3b5b8d5afa162cbd35c94c155cdfa13c8a9c964cde21a4208f5909ce90112"
400                 + "3a0a2e747970652e676f6f676c65617069732e636f6d2f676f6f676c652e63727970746f2e74696"
401                 + "e6b2e486d61634b6579100118f5909ce9012001");
402     // A message whose tag we computed with the wrapped key.
403     final byte[] message = Hex.decode("");
404     final byte[] tag = Hex.decode("011d270875989dd6fbd5f54dbc9520bb41efd058d5");
405 
406     KeysetReader wrappingReader = BinaryKeysetReader.withBytes(serializedWrappingKeyset);
407     Aead wrapperAead = CleartextKeysetHandle.read(wrappingReader).getPrimitive(Aead.class);
408 
409     KeysetReader encryptedReader = BinaryKeysetReader.withBytes(encryptedSerializedKeyset);
410     Mac mac =
411         KeysetHandle.readWithAssociatedData(encryptedReader, wrapperAead, associatedData)
412             .getPrimitive(Mac.class);
413     mac.verifyMac(tag, message);
414   }
415 
416   @Test
getPublicKeysetHandle_shouldWork()417   public void getPublicKeysetHandle_shouldWork() throws Exception {
418     KeysetHandle privateHandle = KeysetHandle.generateNew(KeyTemplates.get("ECDSA_P256"));
419     KeyData privateKeyData = privateHandle.getKeyset().getKey(0).getKeyData();
420     EcdsaPrivateKey privateKey =
421         EcdsaPrivateKey.parseFrom(
422             privateKeyData.getValue(), ExtensionRegistryLite.getEmptyRegistry());
423 
424     KeysetHandle publicHandle = privateHandle.getPublicKeysetHandle();
425 
426     expect.that(publicHandle.getKeyset().getKeyCount()).isEqualTo(1);
427     expect
428         .that(privateHandle.getKeyset().getPrimaryKeyId())
429         .isEqualTo(publicHandle.getKeyset().getPrimaryKeyId());
430     KeyData publicKeyData = publicHandle.getKeyset().getKey(0).getKeyData();
431     expect.that(publicKeyData.getTypeUrl()).isEqualTo(SignatureConfig.ECDSA_PUBLIC_KEY_TYPE_URL);
432     expect
433         .that(publicKeyData.getKeyMaterialType())
434         .isEqualTo(KeyData.KeyMaterialType.ASYMMETRIC_PUBLIC);
435     expect
436         .that(publicKeyData.getValue().toByteArray())
437         .isEqualTo(privateKey.getPublicKey().toByteArray());
438     PublicKeySign signer = privateHandle.getPrimitive(PublicKeySign.class);
439     PublicKeyVerify verifier = publicHandle.getPrimitive(PublicKeyVerify.class);
440     byte[] message = Random.randBytes(20);
441     verifier.verify(signer.sign(message), message);
442   }
443 
444   /** Tests that when encryption failed an exception is thrown. */
445   @Test
write_withFaultyAead_shouldThrow()446   public void write_withFaultyAead_shouldThrow() throws Exception {
447     KeysetHandle handle = KeysetHandle.generateNew(KeyTemplates.get("HMAC_SHA256_256BITTAG"));
448     TestUtil.DummyAead faultyAead = new TestUtil.DummyAead();
449     ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
450     KeysetWriter writer = BinaryKeysetWriter.withOutputStream(outputStream);
451 
452     assertThrows(GeneralSecurityException.class, () -> handle.write(writer, faultyAead));
453   }
454 
455   @Test
read_withNoMasterKeyInput_shouldThrow()456   public void read_withNoMasterKeyInput_shouldThrow() throws Exception {
457     KeysetReader reader = BinaryKeysetReader.withBytes(new byte[0]);
458 
459     assertThrows(
460         GeneralSecurityException.class, () -> KeysetHandle.read(reader, /* masterKey= */ null));
461   }
462 
463   @Test
getPrimitive_shouldWork()464   public void getPrimitive_shouldWork() throws Exception {
465     KeysetHandle handle = KeysetHandle.generateNew(KeyTemplates.get("AES128_EAX"));
466     byte[] message = Random.randBytes(20);
467     byte[] aad = Random.randBytes(20);
468 
469     Aead aead = handle.getPrimitive(Aead.class);
470 
471     assertThat(aead.decrypt(aead.encrypt(message, aad), aad)).isEqualTo(message);
472   }
473 
474   // Tests that getPrimitive does correct wrapping and not just return the primary. For this, we
475   // simply add a raw, non-primary key and encrypt directly with it.
476   @Test
getPrimitive_wrappingDoneCorrectly()477   public void getPrimitive_wrappingDoneCorrectly() throws Exception {
478     KeyData rawKeyData = Registry.newKeyData(KeyTemplates.get("AES128_EAX"));
479     Keyset keyset =
480         TestUtil.createKeyset(
481             TestUtil.createKey(
482                 Registry.newKeyData(KeyTemplates.get("AES128_EAX").getProto()),
483                 42,
484                 KeyStatusType.ENABLED,
485                 OutputPrefixType.TINK),
486             TestUtil.createKey(rawKeyData, 43, KeyStatusType.ENABLED, OutputPrefixType.RAW));
487     KeysetHandle handle = KeysetHandle.fromKeyset(keyset);
488     byte[] message = Random.randBytes(20);
489     byte[] aad = Random.randBytes(20);
490     Aead aeadToEncrypt = Registry.getPrimitive(rawKeyData, Aead.class);
491 
492     Aead aead = handle.getPrimitive(Aead.class);
493 
494     assertThat(aead.decrypt(aeadToEncrypt.encrypt(message, aad), aad)).isEqualTo(message);
495   }
496 
497   @Test
getPrimitive_differentPrimitive_shouldWork()498   public void getPrimitive_differentPrimitive_shouldWork() throws Exception {
499     // We use RAW because the EncryptOnly wrapper wraps everything RAW.
500     KeysetHandle handle = KeysetHandle.generateNew(AesEaxKeyManager.rawAes128EaxTemplate());
501     byte[] message = Random.randBytes(20);
502 
503     EncryptOnly encryptOnly = handle.getPrimitive(EncryptOnly.class);
504 
505     Aead aead = handle.getPrimitive(Aead.class);
506     assertThat(aead.decrypt(encryptOnly.encrypt(message), new byte[0])).isEqualTo(message);
507   }
508 
509   @Test
noBuilderSetMonitoringAnnotations_monitoringClientGetsAnnotationsWithKeysetInfo()510   public void noBuilderSetMonitoringAnnotations_monitoringClientGetsAnnotationsWithKeysetInfo()
511       throws Exception {
512     MutableMonitoringRegistry.globalInstance().clear();
513     FakeMonitoringClient fakeMonitoringClient = new FakeMonitoringClient();
514     MutableMonitoringRegistry.globalInstance().registerMonitoringClient(fakeMonitoringClient);
515 
516     Keyset keyset =
517         TestUtil.createKeyset(
518             TestUtil.createKey(
519                 TestUtil.createAesGcmKeyData(Hex.decode("000102030405060708090a0b0c0d0e0f")),
520                 42,
521                 KeyStatusType.ENABLED,
522                 OutputPrefixType.TINK));
523     byte[] message = Random.randBytes(123);
524     MonitoringAnnotations annotations =
525         MonitoringAnnotations.newBuilder().add("annotation_name", "annotation_value").build();
526     KeysetHandle handleWithAnnotations = KeysetHandle.fromKeysetAndAnnotations(keyset, annotations);
527     EncryptOnly encryptOnlyWithAnnotations = handleWithAnnotations.getPrimitive(EncryptOnly.class);
528     Object unused = encryptOnlyWithAnnotations.encrypt(message);
529     List<FakeMonitoringClient.LogEntry> entries = fakeMonitoringClient.getLogEntries();
530     assertThat(entries).hasSize(1);
531     assertThat(entries.get(0).getKeysetInfo().getAnnotations()).isEqualTo(annotations);
532   }
533 
534   @Test
builderSetMonitoringAnnotations_works()535   public void builderSetMonitoringAnnotations_works() throws Exception {
536     FakeMonitoringClient fakeMonitoringClient = new FakeMonitoringClient();
537     MutableMonitoringRegistry.globalInstance().clear();
538     MutableMonitoringRegistry.globalInstance().registerMonitoringClient(fakeMonitoringClient);
539     MonitoringAnnotations annotations =
540         MonitoringAnnotations.newBuilder().add("annotation_name", "annotation_value").build();
541     KeysetHandle keysetHandleWithAnnotations =
542         KeysetHandle.newBuilder()
543             .addEntry(
544                 KeysetHandle.generateEntryFromParameters(
545                         AesCmacParameters.builder()
546                             .setVariant(Variant.TINK)
547                             .setKeySizeBytes(32)
548                             .setTagSizeBytes(16)
549                             .build())
550                     .withFixedId(42)
551                     .makePrimary())
552             .setMonitoringAnnotations(annotations)
553             .build();
554     byte[] plaintext = "plaintext".getBytes(UTF_8);
555     Mac mac = keysetHandleWithAnnotations.getPrimitive(Mac.class);
556 
557     // Work triggering various code paths.
558     byte[] tag = mac.computeMac(plaintext);
559     mac.verifyMac(tag, plaintext);
560     assertThrows(GeneralSecurityException.class, () -> mac.verifyMac(tag, new byte[0]));
561     assertThrows(GeneralSecurityException.class, () -> mac.verifyMac(new byte[0], plaintext));
562 
563     // With annotations set, the events get logged.
564     List<FakeMonitoringClient.LogEntry> logEntries = fakeMonitoringClient.getLogEntries();
565     System.out.println(logEntries);
566     assertThat(logEntries).hasSize(2);
567 
568     FakeMonitoringClient.LogEntry tinkComputeEntry = logEntries.get(0);
569     assertThat(tinkComputeEntry.getKeyId()).isEqualTo(42);
570     assertThat(tinkComputeEntry.getPrimitive()).isEqualTo("mac");
571     assertThat(tinkComputeEntry.getApi()).isEqualTo("compute");
572     assertThat(tinkComputeEntry.getNumBytesAsInput()).isEqualTo(plaintext.length);
573     assertThat(tinkComputeEntry.getKeysetInfo().getAnnotations()).isEqualTo(annotations);
574 
575     FakeMonitoringClient.LogEntry rawComputeEntry = logEntries.get(1);
576     assertThat(rawComputeEntry.getKeyId()).isEqualTo(42);
577     assertThat(rawComputeEntry.getPrimitive()).isEqualTo("mac");
578     assertThat(rawComputeEntry.getApi()).isEqualTo("verify");
579     assertThat(rawComputeEntry.getNumBytesAsInput()).isEqualTo(plaintext.length);
580     assertThat(rawComputeEntry.getKeysetInfo().getAnnotations()).isEqualTo(annotations);
581   }
582 
583   @Test
builderNotSetMonitoringAnnotations_setsEmptyAnnotations()584   public void builderNotSetMonitoringAnnotations_setsEmptyAnnotations() throws Exception {
585     FakeMonitoringClient fakeMonitoringClient = new FakeMonitoringClient();
586     MutableMonitoringRegistry.globalInstance().clear();
587     MutableMonitoringRegistry.globalInstance().registerMonitoringClient(fakeMonitoringClient);
588     KeysetHandle keysetHandleWithAnnotations =
589         KeysetHandle.newBuilder()
590             .addEntry(
591                 KeysetHandle.generateEntryFromParameters(
592                         AesCmacParameters.builder()
593                             .setVariant(Variant.TINK)
594                             .setKeySizeBytes(32)
595                             .setTagSizeBytes(16)
596                             .build())
597                     .withRandomId()
598                     .makePrimary())
599             .build();
600     byte[] plaintext = "plaintext".getBytes(UTF_8);
601     Mac mac = keysetHandleWithAnnotations.getPrimitive(Mac.class);
602 
603     // Work triggering various code paths.
604     byte[] tag = mac.computeMac(plaintext);
605     mac.verifyMac(tag, plaintext);
606 
607     // Without annotations, nothing gets logged.
608     assertThat(fakeMonitoringClient.getLogEntries()).isEmpty();
609     assertThat(fakeMonitoringClient.getLogFailureEntries()).isEmpty();
610   }
611 
612   @SuppressWarnings("deprecation") // This is a test for the deprecated function
613   @Test
deprecated_readNoSecretWithBytesInput_sameAs_parseKeysetWithoutSecret()614   public void deprecated_readNoSecretWithBytesInput_sameAs_parseKeysetWithoutSecret()
615       throws Exception {
616     // Public keyset should have the same output
617     KeysetHandle privateHandle = KeysetHandle.generateNew(KeyTemplates.get("ECDSA_P256"));
618     byte[] serializedPublicKeyset = privateHandle.getPublicKeysetHandle().getKeyset().toByteArray();
619 
620     KeysetHandle readNoSecretOutput = KeysetHandle.readNoSecret(serializedPublicKeyset);
621     KeysetHandle parseKeysetWithoutSecretOutput =
622         TinkProtoKeysetFormat.parseKeysetWithoutSecret(serializedPublicKeyset);
623     expect
624         .that(readNoSecretOutput.getKeyset())
625         .isEqualTo(parseKeysetWithoutSecretOutput.getKeyset());
626 
627     // Symmetric Keyset should fail
628     byte[] serializedSymmetricKeyset =
629         TestUtil.createKeyset(
630                 TestUtil.createKey(
631                     TestUtil.createHmacKeyData("01234567890123456".getBytes(UTF_8), 16),
632                     42,
633                     KeyStatusType.ENABLED,
634                     OutputPrefixType.TINK))
635             .toByteArray();
636     assertThrows(
637         GeneralSecurityException.class, () -> KeysetHandle.readNoSecret(serializedSymmetricKeyset));
638     assertThrows(
639         GeneralSecurityException.class,
640         () -> TinkProtoKeysetFormat.parseKeysetWithoutSecret(serializedSymmetricKeyset));
641 
642     // Private Keyset should fail
643     byte[] serializedPrivateKeyset = privateHandle.getKeyset().toByteArray();
644     assertThrows(
645         GeneralSecurityException.class, () -> KeysetHandle.readNoSecret(serializedPrivateKeyset));
646     assertThrows(
647         GeneralSecurityException.class,
648         () -> TinkProtoKeysetFormat.parseKeysetWithoutSecret(serializedPrivateKeyset));
649 
650     // Empty Keyset should fail
651     assertThrows(GeneralSecurityException.class, () -> KeysetHandle.readNoSecret(new byte[0]));
652     assertThrows(
653         GeneralSecurityException.class,
654         () -> TinkProtoKeysetFormat.parseKeysetWithoutSecret(new byte[0]));
655 
656     // Invalid Keyset should fail
657     byte[] proto = new byte[] {0x00, 0x01, 0x02};
658     assertThrows(GeneralSecurityException.class, () -> KeysetHandle.readNoSecret(proto));
659     assertThrows(
660         GeneralSecurityException.class,
661         () -> TinkProtoKeysetFormat.parseKeysetWithoutSecret(proto));
662   }
663 
664   @Test
readNoSecretWithBinaryKeysetReader_shouldWork()665   public void readNoSecretWithBinaryKeysetReader_shouldWork() throws Exception {
666     KeysetHandle privateHandle = KeysetHandle.generateNew(KeyTemplates.get("ECDSA_P256"));
667     Keyset keyset = privateHandle.getPublicKeysetHandle().getKeyset();
668     byte[] serializedKeyset = keyset.toByteArray();
669 
670     Keyset readKeyset =
671         KeysetHandle.readNoSecret(BinaryKeysetReader.withBytes(serializedKeyset)).getKeyset();
672 
673     expect.that(readKeyset).isEqualTo(keyset);
674   }
675 
676   @Test
readNoSecretWithBinaryKeysetReader_withTypeSymmetric_shouldThrow()677   public void readNoSecretWithBinaryKeysetReader_withTypeSymmetric_shouldThrow() throws Exception {
678     String keyValue = "01234567890123456";
679     byte[] serializedKeyset =
680         TestUtil.createKeyset(
681             TestUtil.createKey(
682                 TestUtil.createHmacKeyData(keyValue.getBytes(UTF_8), 16),
683                 42,
684                 KeyStatusType.ENABLED,
685                 OutputPrefixType.TINK)).toByteArray();
686 
687     assertThrows(
688         GeneralSecurityException.class,
689         () -> KeysetHandle.readNoSecret(BinaryKeysetReader.withBytes(serializedKeyset)));
690   }
691 
692   @Test
readNoSecretWithBinaryKeysetReader_withTypeAsymmetricPrivate_shouldThrow()693   public void readNoSecretWithBinaryKeysetReader_withTypeAsymmetricPrivate_shouldThrow()
694       throws Exception {
695     byte[] serializedKeyset =
696         KeysetHandle.generateNew(KeyTemplates.get("ECDSA_P256")).getKeyset().toByteArray();
697 
698     assertThrows(
699         GeneralSecurityException.class,
700         () -> KeysetHandle.readNoSecret(BinaryKeysetReader.withBytes(serializedKeyset)));
701   }
702 
703   @Test
readNoSecretWithBinaryKeysetReader_withEmptyKeyset_shouldThrow()704   public void readNoSecretWithBinaryKeysetReader_withEmptyKeyset_shouldThrow() throws Exception {
705     byte[] emptySerializedKeyset = new byte[0];
706     assertThrows(
707         GeneralSecurityException.class,
708         () -> KeysetHandle.readNoSecret(BinaryKeysetReader.withBytes(emptySerializedKeyset)));
709   }
710 
711   @Test
readNoSecretWithBinaryKeysetReader_withInvalidKeyset_shouldThrow()712   public void readNoSecretWithBinaryKeysetReader_withInvalidKeyset_shouldThrow() throws Exception {
713     byte[] invalidSerializedKeyset = new byte[] {0x00, 0x01, 0x02};
714     assertThrows(
715         GeneralSecurityException.class,
716         () -> KeysetHandle.readNoSecret(BinaryKeysetReader.withBytes(invalidSerializedKeyset)));
717   }
718 
719   @Test
writeNoSecretThenReadNoSecret_returnsSameKeyset()720   public void writeNoSecretThenReadNoSecret_returnsSameKeyset() throws Exception {
721     KeysetHandle privateHandle = KeysetHandle.generateNew(KeyTemplates.get("ECDSA_P256"));
722     KeysetHandle publicHandle = privateHandle.getPublicKeysetHandle();
723     ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
724     KeysetWriter writer = BinaryKeysetWriter.withOutputStream(outputStream);
725     Keyset keyset = publicHandle.getKeyset();
726 
727     publicHandle.writeNoSecret(writer);
728     ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
729     KeysetReader reader = BinaryKeysetReader.withInputStream(inputStream);
730     Keyset keyset2 = KeysetHandle.readNoSecret(reader).getKeyset();
731 
732     assertThat(keyset).isEqualTo(keyset2);
733   }
734 
735   @Test
writeNoSecret_withTypeSymmetric_shouldThrow()736   public void writeNoSecret_withTypeSymmetric_shouldThrow() throws Exception {
737     String keyValue = "01234567890123456";
738     Keyset keyset =
739         TestUtil.createKeyset(
740             TestUtil.createKey(
741                 TestUtil.createHmacKeyData(keyValue.getBytes(UTF_8), 16),
742                 42,
743                 KeyStatusType.ENABLED,
744                 OutputPrefixType.TINK));
745     KeysetHandle handle = KeysetHandle.fromKeyset(keyset);
746 
747     assertThrows(GeneralSecurityException.class, () -> handle.writeNoSecret(/* writer= */ null));
748   }
749 
750   @Test
writeNoSecret_withTypeAsymmetricPrivate_shouldThrow()751   public void writeNoSecret_withTypeAsymmetricPrivate_shouldThrow() throws Exception {
752     KeysetHandle handle = KeysetHandle.generateNew(KeyTemplates.get("ECDSA_P256"));
753 
754     assertThrows(GeneralSecurityException.class, () -> handle.writeNoSecret(/* writer= */ null));
755   }
756 
757   @SuppressWarnings("deprecation")  // This is a test for the deprecated function
758   @Test
deprecated_primaryKey_shouldWork()759   public void deprecated_primaryKey_shouldWork() throws Exception {
760     KeysetHandle handle =
761         KeysetHandle.newBuilder()
762         .addEntry(
763             KeysetHandle.generateEntryFromParametersName("AES128_EAX").withFixedId(123))
764         .addEntry(
765             KeysetHandle.generateEntryFromParametersName("HMAC_SHA256_256BITTAG")
766                 .withFixedId(234).makePrimary())
767         .build();
768 
769     KeyHandle keyHandle = handle.primaryKey();
770     assertThat(keyHandle.getId()).isEqualTo(234);
771   }
772 
773   @SuppressWarnings("deprecation")  // This is a test for the deprecated function
774   @Test
deprecated_primaryKey_primaryNotPresent_shouldThrow()775   public void deprecated_primaryKey_primaryNotPresent_shouldThrow() throws Exception {
776     Keyset keyset =
777         TestUtil.createKeyset(
778             TestUtil.createKey(
779                 TestUtil.createHmacKeyData("01234567890123456".getBytes(UTF_8), 16),
780                 42,
781                 KeyStatusType.ENABLED,
782                 OutputPrefixType.TINK));
783     KeysetHandle handle =
784         KeysetHandle.fromKeyset(Keyset.newBuilder(keyset).setPrimaryKeyId(77).build());
785 
786     assertThrows(GeneralSecurityException.class, handle::primaryKey);
787   }
788 
789   @Test
testGetAt_singleKeyWithRegisteredProtoSerialization_works()790   public void testGetAt_singleKeyWithRegisteredProtoSerialization_works() throws Exception {
791     // HmacKey's proto serialization HmacProtoSerialization is registed in HmacKeyManager.
792     Keyset keyset =
793         TestUtil.createKeyset(
794             TestUtil.createKey(
795                 TestUtil.createHmacKeyData("01234567890123456".getBytes(UTF_8), 16),
796                 42,
797                 KeyStatusType.ENABLED,
798                 OutputPrefixType.TINK));
799     KeysetHandle handle = KeysetHandle.fromKeyset(keyset);
800     assertThat(handle.size()).isEqualTo(1);
801     KeysetHandle.Entry entry = handle.getAt(0);
802     assertThat(entry.getId()).isEqualTo(42);
803     assertThat(entry.getStatus()).isEqualTo(KeyStatus.ENABLED);
804     assertThat(entry.isPrimary()).isTrue();
805     assertThat(entry.getKey().getClass()).isEqualTo(HmacKey.class);
806   }
807 
808   @Test
getAt_invalidKeyWithRegisteredProtoSerialization_throwsIllegalStateException()809   public void getAt_invalidKeyWithRegisteredProtoSerialization_throwsIllegalStateException()
810       throws Exception {
811     // HmacKey's proto serialization HmacProtoSerialization is registed in HmacKeyManager.
812     com.google.crypto.tink.proto.HmacKey invalidProtoHmacKey =
813         com.google.crypto.tink.proto.HmacKey.newBuilder()
814             .setVersion(999)
815             .setKeyValue(ByteString.copyFromUtf8("01234567890123456"))
816             .setParams(HmacParams.newBuilder().setHash(HashType.UNKNOWN_HASH).setTagSize(0))
817             .build();
818     Keyset keyset =
819         TestUtil.createKeyset(
820             TestUtil.createKey(
821                 TestUtil.createKeyData(
822                     invalidProtoHmacKey,
823                     "type.googleapis.com/google.crypto.tink.HmacKey",
824                     KeyData.KeyMaterialType.SYMMETRIC),
825                 42,
826                 KeyStatusType.ENABLED,
827                 OutputPrefixType.TINK));
828     KeysetHandle handle = KeysetHandle.fromKeyset(keyset);
829     assertThat(handle.size()).isEqualTo(1);
830     assertThrows(IllegalStateException.class, () -> handle.getAt(0));
831   }
832 
833   @Test
testGetAt_singleKeyWithoutRegisteredProtoSerialization_wrapsToLegacyProtoKey()834   public void testGetAt_singleKeyWithoutRegisteredProtoSerialization_wrapsToLegacyProtoKey()
835       throws Exception {
836     HmacPrfKey key =
837         HmacPrfKey.newBuilder()
838             .setParams(HmacPrfParams.newBuilder().setHash(HashType.SHA256).build())
839             .setKeyValue(ByteString.copyFromUtf8("01234567890123456"))
840             .build();
841     Keyset keyset =
842         TestUtil.createKeyset(
843             TestUtil.createKey(
844                 TestUtil.createKeyData(
845                     key, "i.am.an.unregistered.key.type", KeyData.KeyMaterialType.SYMMETRIC),
846                 42,
847                 KeyStatusType.ENABLED,
848                 OutputPrefixType.RAW));
849     KeysetHandle handle = KeysetHandle.fromKeyset(keyset);
850     assertThat(handle.size()).isEqualTo(1);
851     KeysetHandle.Entry entry = handle.getAt(0);
852     assertThat(entry.getId()).isEqualTo(42);
853     assertThat(entry.getStatus()).isEqualTo(KeyStatus.ENABLED);
854     assertThat(entry.isPrimary()).isTrue();
855     assertThat(entry.getKey().getClass()).isEqualTo(LegacyProtoKey.class);
856   }
857 
858   @Test
testGetAt_multipleKeys_works()859   public void testGetAt_multipleKeys_works() throws Exception {
860     Keyset.Key key1 =
861         TestUtil.createKey(
862             TestUtil.createHmacKeyData("01234567890123456".getBytes(UTF_8), 16),
863             42,
864             KeyStatusType.DISABLED,
865             OutputPrefixType.TINK);
866     Keyset.Key key2 =
867         TestUtil.createKey(
868             TestUtil.createHmacKeyData("abcdefghijklmnopq".getBytes(UTF_8), 32),
869             44,
870             KeyStatusType.ENABLED,
871             OutputPrefixType.CRUNCHY);
872     Keyset.Key key3 =
873         TestUtil.createKey(
874             TestUtil.createHmacKeyData("ABCDEFGHIJKLMNOPQ".getBytes(UTF_8), 32),
875             46,
876             KeyStatusType.DESTROYED,
877             OutputPrefixType.TINK);
878     Keyset keyset = TestUtil.createKeyset(key1, key2, key3);
879     KeysetHandle handle =
880         KeysetHandle.fromKeyset(Keyset.newBuilder(keyset).setPrimaryKeyId(44).build());
881 
882     assertThat(handle.size()).isEqualTo(3);
883     assertThat(handle.getAt(0).getId()).isEqualTo(42);
884     assertThat(handle.getAt(0).getStatus()).isEqualTo(KeyStatus.DISABLED);
885     assertThat(handle.getAt(0).isPrimary()).isFalse();
886 
887     assertThat(handle.getAt(1).getId()).isEqualTo(44);
888     assertThat(handle.getAt(1).getStatus()).isEqualTo(KeyStatus.ENABLED);
889     assertThat(handle.getAt(1).isPrimary()).isTrue();
890 
891     assertThat(handle.getAt(2).getId()).isEqualTo(46);
892     assertThat(handle.getAt(2).getStatus()).isEqualTo(KeyStatus.DESTROYED);
893     assertThat(handle.getAt(2).isPrimary()).isFalse();
894   }
895 
896   @Test
testPrimary_multipleKeys_works()897   public void testPrimary_multipleKeys_works() throws Exception {
898     Keyset.Key key1 =
899         TestUtil.createKey(
900             TestUtil.createHmacKeyData("01234567890123456".getBytes(UTF_8), 16),
901             42,
902             KeyStatusType.ENABLED,
903             OutputPrefixType.TINK);
904     Keyset.Key key2 =
905         TestUtil.createKey(
906             TestUtil.createHmacKeyData("abcdefghijklmnopq".getBytes(UTF_8), 32),
907             44,
908             KeyStatusType.ENABLED,
909             OutputPrefixType.CRUNCHY);
910     Keyset.Key key3 =
911         TestUtil.createKey(
912             TestUtil.createHmacKeyData("ABCDEFGHIJKLMNOPQ".getBytes(UTF_8), 32),
913             46,
914             KeyStatusType.ENABLED,
915             OutputPrefixType.TINK);
916     Keyset keyset = TestUtil.createKeyset(key1, key2, key3);
917     KeysetHandle handle =
918         KeysetHandle.fromKeyset(Keyset.newBuilder(keyset).setPrimaryKeyId(44).build());
919     KeysetHandle.Entry primary = handle.getPrimary();
920     assertThat(primary.getId()).isEqualTo(44);
921     assertThat(primary.getStatus()).isEqualTo(KeyStatus.ENABLED);
922     assertThat(primary.isPrimary()).isTrue();
923   }
924 
925   @Test
testGetPrimary_noPrimary_throws()926   public void testGetPrimary_noPrimary_throws() throws Exception {
927     Keyset.Key key1 =
928         TestUtil.createKey(
929             TestUtil.createHmacKeyData("01234567890123456".getBytes(UTF_8), 16),
930             42,
931             KeyStatusType.ENABLED,
932             OutputPrefixType.TINK);
933     Keyset keyset = TestUtil.createKeyset(key1);
934     KeysetHandle handle =
935         KeysetHandle.fromKeyset(Keyset.newBuilder(keyset).setPrimaryKeyId(77).build());
936 
937     assertThrows(IllegalStateException.class, handle::getPrimary);
938   }
939 
940   @Test
testGetPrimary_disabledPrimary_throws()941   public void testGetPrimary_disabledPrimary_throws() throws Exception {
942     Keyset.Key key1 =
943         TestUtil.createKey(
944             TestUtil.createHmacKeyData("01234567890123456".getBytes(UTF_8), 16),
945             42,
946             KeyStatusType.DISABLED,
947             OutputPrefixType.TINK);
948     Keyset keyset = TestUtil.createKeyset(key1);
949     KeysetHandle handle =
950         KeysetHandle.fromKeyset(Keyset.newBuilder(keyset).setPrimaryKeyId(16).build());
951 
952     assertThrows(IllegalStateException.class, handle::getPrimary);
953   }
954 
955   @Test
testGetAt_indexOutOfBounds_throws()956   public void testGetAt_indexOutOfBounds_throws() throws Exception {
957     Keyset.Key key1 =
958         TestUtil.createKey(
959             TestUtil.createHmacKeyData("01234567890123456".getBytes(UTF_8), 16),
960             42,
961             KeyStatusType.ENABLED,
962             OutputPrefixType.TINK);
963     KeysetHandle handle = KeysetHandle.fromKeyset(TestUtil.createKeyset(key1));
964 
965     assertThrows(IndexOutOfBoundsException.class, () -> handle.getAt(-1));
966     assertThrows(IndexOutOfBoundsException.class, () -> handle.getAt(1));
967   }
968 
969   @Test
testGetAt_wrongStatus_throws()970   public void testGetAt_wrongStatus_throws() throws Exception {
971     Keyset.Key key1 =
972         TestUtil.createKey(
973             TestUtil.createHmacKeyData("01234567890123456".getBytes(UTF_8), 16),
974             42,
975             KeyStatusType.UNKNOWN_STATUS,
976             OutputPrefixType.TINK);
977     KeysetHandle handle = KeysetHandle.fromKeyset(TestUtil.createKeyset(key1));
978 
979     assertThrows(IllegalStateException.class, () -> handle.getAt(0));
980   }
981 
982   @Immutable
983   private static final class TestKey extends Key {
984     private final ByteString keymaterial;
985 
TestKey(ByteString keymaterial)986     public TestKey(ByteString keymaterial) {
987       this.keymaterial = keymaterial;
988     }
989 
990     @Override
getParameters()991     public Parameters getParameters() {
992       throw new UnsupportedOperationException("Not needed in test");
993     }
994 
995     @Override
996     @Nullable
getIdRequirementOrNull()997     public Integer getIdRequirementOrNull() {
998       throw new UnsupportedOperationException("Not needed in test");
999     }
1000 
1001     @Override
equalsKey(Key other)1002     public boolean equalsKey(Key other) {
1003       throw new UnsupportedOperationException("Not needed in test");
1004     }
1005 
getKeyMaterial()1006     public ByteString getKeyMaterial() {
1007       return keymaterial;
1008     }
1009   }
1010 
parseTestKey( ProtoKeySerialization serialization, @Nullable com.google.crypto.tink.SecretKeyAccess access)1011   private static TestKey parseTestKey(
1012       ProtoKeySerialization serialization,
1013       @Nullable com.google.crypto.tink.SecretKeyAccess access) {
1014     return new TestKey(serialization.getValue());
1015   }
1016 
1017   /**
1018    * Tests that key parsing via the serialization registry works as expected.
1019    *
1020    * <p>NOTE: This adds a parser to the MutableSerializationRegistry, which no other test uses.
1021    */
1022   @Test
testKeysAreParsed()1023   public void testKeysAreParsed() throws Exception {
1024     ByteString value = ByteString.copyFromUtf8("some value");
1025     // NOTE: This adds a parser to the MutableSerializationRegistry, which no other test uses.
1026     MutableSerializationRegistry.globalInstance()
1027         .registerKeyParser(
1028             KeyParser.create(
1029                 KeysetHandleTest::parseTestKey,
1030                 Bytes.copyFrom("testKeyTypeUrl".getBytes(UTF_8)),
1031                 ProtoKeySerialization.class));
1032     Keyset keyset =
1033         Keyset.newBuilder()
1034             .setPrimaryKeyId(1)
1035             .addKey(
1036                 Keyset.Key.newBuilder()
1037                     .setKeyId(1)
1038                     .setStatus(KeyStatusType.ENABLED)
1039                     .setKeyData(KeyData.newBuilder().setTypeUrl("testKeyTypeUrl").setValue(value)))
1040             .build();
1041     KeysetHandle handle = KeysetHandle.fromKeyset(keyset);
1042     assertThat(((TestKey) handle.getPrimary().getKey()).getKeyMaterial()).isEqualTo(value);
1043   }
1044 
1045   @Test
testBuilder_basic()1046   public void testBuilder_basic() throws Exception {
1047     KeysetHandle keysetHandle =
1048         KeysetHandle.newBuilder()
1049             .addEntry(
1050                 KeysetHandle.generateEntryFromParametersName("AES256_CMAC_RAW")
1051                     .withRandomId()
1052                     .makePrimary())
1053             .build();
1054 
1055     assertThat(keysetHandle.size()).isEqualTo(1);
1056     assertThat(keysetHandle.getAt(0).getKey().getParameters())
1057         .isEqualTo(AesCmacParameters.builder().setKeySizeBytes(32).setTagSizeBytes(16).build());
1058   }
1059 
1060   @Test
keysetRotationWithBuilder_works()1061   public void keysetRotationWithBuilder_works() throws Exception {
1062     KeysetHandle oldKeyset =
1063         KeysetHandle.newBuilder()
1064             .addEntry(
1065                 KeysetHandle.generateEntryFromParametersName("AES256_CMAC_RAW")
1066                     .withRandomId()
1067                     .makePrimary())
1068             .build();
1069 
1070     // Add new key.
1071     KeysetHandle keysetWithNewKey =
1072         KeysetHandle.newBuilder(oldKeyset)
1073             .addEntry(
1074                 KeysetHandle.generateEntryFromParametersName("AES256_CMAC_RAW").withRandomId())
1075             .build();
1076 
1077     // Make latest key primary.
1078     KeysetHandle.Builder builder = KeysetHandle.newBuilder(keysetWithNewKey);
1079     builder.getAt(builder.size() - 1).makePrimary();
1080     KeysetHandle keysetWithNewPrimary = builder.build();
1081 
1082     assertThat(oldKeyset.size()).isEqualTo(1);
1083 
1084     assertThat(keysetWithNewKey.size()).isEqualTo(2);
1085     assertThat(keysetWithNewKey.getAt(0).isPrimary()).isTrue();
1086     assertThat(keysetWithNewKey.getAt(1).isPrimary()).isFalse();
1087 
1088     assertThat(keysetWithNewPrimary.size()).isEqualTo(2);
1089     assertThat(keysetWithNewPrimary.getAt(0).isPrimary()).isFalse();
1090     assertThat(keysetWithNewPrimary.getAt(1).isPrimary()).isTrue();
1091   }
1092 
1093   @Test
testBuilder_multipleKeys()1094   public void testBuilder_multipleKeys() throws Exception {
1095     KeysetHandle keysetHandle =
1096         KeysetHandle.newBuilder()
1097             .addEntry(
1098                 KeysetHandle.generateEntryFromParametersName("AES256_CMAC_RAW")
1099                     .withRandomId()
1100                     .setStatus(KeyStatus.DISABLED))
1101             .addEntry(
1102                 KeysetHandle.generateEntryFromParameters(
1103                         AesCmacParameters.builder().setKeySizeBytes(32).setTagSizeBytes(10)
1104                             .setVariant(Variant.CRUNCHY).build())
1105                     .withRandomId()
1106                     .makePrimary())
1107             .addEntry(
1108                 KeysetHandle.generateEntryFromParameters(
1109                         AesCmacParameters.builder().setKeySizeBytes(32).setTagSizeBytes(13)
1110                             .setVariant(Variant.LEGACY).build())
1111                     .withRandomId())
1112             .build();
1113     assertThat(keysetHandle.size()).isEqualTo(3);
1114     KeysetHandle.Entry entry0 = keysetHandle.getAt(0);
1115     assertThat(entry0.getKey().getParameters())
1116         .isEqualTo(AesCmacParameters.builder().setKeySizeBytes(32).setTagSizeBytes(16).build());
1117     assertThat(entry0.isPrimary()).isFalse();
1118     assertThat(entry0.getStatus()).isEqualTo(KeyStatus.DISABLED);
1119 
1120     KeysetHandle.Entry entry1 = keysetHandle.getAt(1);
1121     assertThat(entry1.isPrimary()).isTrue();
1122     assertThat(entry1.getStatus()).isEqualTo(KeyStatus.ENABLED);
1123     assertThat(entry1.getKey().getParameters())
1124         .isEqualTo(
1125             AesCmacParameters.builder().setKeySizeBytes(32).setTagSizeBytes(10)
1126                 .setVariant(Variant.CRUNCHY).build());
1127 
1128     KeysetHandle.Entry entry2 = keysetHandle.getAt(2);
1129     assertThat(entry2.isPrimary()).isFalse();
1130     assertThat(entry2.getStatus()).isEqualTo(KeyStatus.ENABLED);
1131     assertThat(keysetHandle.getAt(2).getKey().getParameters())
1132         .isEqualTo(
1133             AesCmacParameters.builder().setKeySizeBytes(32).setTagSizeBytes(13)
1134                 .setVariant(Variant.LEGACY).build());
1135   }
1136 
1137   @Test
testBuilder_isPrimary_works()1138   public void testBuilder_isPrimary_works() throws Exception {
1139     KeysetHandle.Builder builder = KeysetHandle.newBuilder();
1140     builder.addEntry(KeysetHandle.generateEntryFromParametersName("AES256_CMAC").withRandomId());
1141     assertThat(builder.getAt(0).isPrimary()).isFalse();
1142     builder.getAt(0).makePrimary();
1143     assertThat(builder.getAt(0).isPrimary()).isTrue();
1144   }
1145 
1146   @Test
testBuilder_setStatus_getStatus_works()1147   public void testBuilder_setStatus_getStatus_works() throws Exception {
1148     KeysetHandle.Builder.Entry entry =
1149         KeysetHandle.generateEntryFromParametersName("AES256_CMAC").withRandomId();
1150     assertThat(entry.getStatus()).isEqualTo(KeyStatus.ENABLED);
1151     entry.setStatus(KeyStatus.DISABLED);
1152     assertThat(entry.getStatus()).isEqualTo(KeyStatus.DISABLED);
1153     entry.setStatus(KeyStatus.DESTROYED);
1154     assertThat(entry.getStatus()).isEqualTo(KeyStatus.DESTROYED);
1155   }
1156 
1157   @Test
1158   // Tests that withRandomId avoids collisions. We use 2^16 keys to make collision likely. The test
1159   // is about 4 seconds like this.
testBuilder_withRandomId_doesNotHaveCollisions()1160   public void testBuilder_withRandomId_doesNotHaveCollisions() throws Exception {
1161     // Test takes longer on Android; and a simple Java test suffices.
1162     assumeFalse(TestUtil.isAndroid());
1163     int numNonPrimaryKeys = 1 << 16;
1164     KeysetHandle.Builder builder = KeysetHandle.newBuilder();
1165     builder.addEntry(
1166         KeysetHandle.generateEntryFromParametersName("AES256_CMAC").withRandomId().makePrimary());
1167     for (int i = 0; i < numNonPrimaryKeys; i++) {
1168       builder.addEntry(KeysetHandle.generateEntryFromParametersName("AES256_CMAC").withRandomId());
1169     }
1170     KeysetHandle handle = builder.build();
1171     Set<Integer> idSet = new HashSet<>();
1172     for (int i = 0; i < handle.size(); ++i) {
1173       idSet.add(handle.getAt(i).getId());
1174     }
1175     assertThat(idSet).hasSize(numNonPrimaryKeys + 1);
1176   }
1177 
1178   @Test
testBuilder_randomIdAfterFixedId_works()1179   public void testBuilder_randomIdAfterFixedId_works() throws Exception {
1180     KeysetHandle handle =
1181         KeysetHandle.newBuilder()
1182             .addEntry(KeysetHandle.generateEntryFromParametersName("AES256_CMAC").withFixedId(777))
1183             .addEntry(
1184                 KeysetHandle.generateEntryFromParametersName("AES256_CMAC")
1185                     .withRandomId()
1186                     .makePrimary())
1187             .build();
1188     assertThat(handle.size()).isEqualTo(2);
1189     assertThat(handle.getAt(0).getId()).isEqualTo(777);
1190   }
1191 
1192   @Test
testBuilder_fixedIdAfterRandomId_throws()1193   public void testBuilder_fixedIdAfterRandomId_throws() throws Exception {
1194     KeysetHandle.Builder builder = KeysetHandle.newBuilder();
1195     builder.addEntry(
1196         KeysetHandle.generateEntryFromParametersName("AES256_CMAC").withRandomId().makePrimary());
1197     builder.addEntry(KeysetHandle.generateEntryFromParametersName("AES256_CMAC").withFixedId(777));
1198     assertThrows(GeneralSecurityException.class, builder::build);
1199   }
1200 
1201   @Test
testBuilder_deprecated_removeAt_works()1202   public void testBuilder_deprecated_removeAt_works() throws Exception {
1203     KeysetHandle.Builder builder = KeysetHandle.newBuilder();
1204     builder.addEntry(
1205         KeysetHandle.generateEntryFromParametersName("AES256_CMAC")
1206             .withRandomId()
1207             .setStatus(KeyStatus.DISABLED));
1208     builder.addEntry(
1209         KeysetHandle.generateEntryFromParameters(
1210                 AesCmacParameters.builder().setKeySizeBytes(32).setTagSizeBytes(13).build())
1211             .withRandomId()
1212             .makePrimary()
1213             .setStatus(KeyStatus.ENABLED));
1214     KeysetHandle.Builder.Entry removedEntry = builder.removeAt(0);
1215     assertThat(removedEntry.getStatus()).isEqualTo(KeyStatus.DISABLED);
1216     KeysetHandle handle = builder.build();
1217     assertThat(handle.size()).isEqualTo(1);
1218     assertThat(handle.getAt(0).getKey().getParameters())
1219         .isEqualTo(AesCmacParameters.builder().setKeySizeBytes(32).setTagSizeBytes(13).build());
1220   }
1221 
1222   @Test
testBuilder_deprecated_removeAtInvalidIndex_throws()1223   public void testBuilder_deprecated_removeAtInvalidIndex_throws() throws Exception {
1224     KeysetHandle.Builder builder = KeysetHandle.newBuilder();
1225     builder.addEntry(KeysetHandle.generateEntryFromParametersName("AES256_CMAC").withRandomId());
1226     builder.addEntry(
1227         KeysetHandle.generateEntryFromParametersName("AES256_CMAC").withRandomId().makePrimary());
1228     assertThrows(IndexOutOfBoundsException.class, () -> builder.removeAt(2));
1229   }
1230 
1231   @Test
testBuilder_deleteAt_works()1232   public void testBuilder_deleteAt_works() throws Exception {
1233     KeysetHandle handle =
1234         KeysetHandle.newBuilder()
1235             .addEntry(KeysetHandle.generateEntryFromParametersName("AES256_CMAC").withRandomId())
1236             .addEntry(
1237                 KeysetHandle.generateEntryFromParameters(
1238                         AesCmacParameters.builder().setKeySizeBytes(32).setTagSizeBytes(13).build())
1239                     .withRandomId()
1240                     .makePrimary())
1241             .build();
1242     assertThat(handle.size()).isEqualTo(2);
1243 
1244     KeysetHandle handle2 = KeysetHandle.newBuilder(handle).deleteAt(0).build();
1245 
1246     assertThat(handle2.size()).isEqualTo(1);
1247     assertThat(handle2.getAt(0).getKey().getParameters())
1248         .isEqualTo(AesCmacParameters.builder().setKeySizeBytes(32).setTagSizeBytes(13).build());
1249   }
1250 
1251   @Test
testBuilder_deleteAtInvalidIndex_works()1252   public void testBuilder_deleteAtInvalidIndex_works() throws Exception {
1253     KeysetHandle handle =
1254         KeysetHandle.newBuilder()
1255             .addEntry(KeysetHandle.generateEntryFromParametersName("AES256_CMAC").withRandomId())
1256             .addEntry(
1257                 KeysetHandle.generateEntryFromParametersName("AES256_CMAC")
1258                     .withRandomId()
1259                     .makePrimary())
1260             .build();
1261     assertThat(handle.size()).isEqualTo(2);
1262 
1263     assertThrows(
1264         IndexOutOfBoundsException.class, () -> KeysetHandle.newBuilder(handle).deleteAt(2));
1265   }
1266 
1267   @Test
testBuilder_size_works()1268   public void testBuilder_size_works() throws Exception {
1269     KeysetHandle.Builder builder = KeysetHandle.newBuilder();
1270     assertThat(builder.size()).isEqualTo(0);
1271     builder.addEntry(
1272         KeysetHandle.generateEntryFromParametersName("AES256_CMAC").withRandomId().makePrimary());
1273     assertThat(builder.size()).isEqualTo(1);
1274     builder.addEntry(KeysetHandle.generateEntryFromParametersName("AES256_CMAC").withRandomId());
1275     assertThat(builder.size()).isEqualTo(2);
1276   }
1277 
1278   @Test
testBuilder_noPrimary_throws()1279   public void testBuilder_noPrimary_throws() throws Exception {
1280     KeysetHandle.Builder builder = KeysetHandle.newBuilder();
1281     builder.addEntry(KeysetHandle.generateEntryFromParametersName("AES256_CMAC").withRandomId());
1282     builder.addEntry(KeysetHandle.generateEntryFromParametersName("AES256_CMAC").withRandomId());
1283     assertThrows(GeneralSecurityException.class, builder::build);
1284   }
1285 
1286   @Test
testBuilder_removedPrimary_throws()1287   public void testBuilder_removedPrimary_throws() throws Exception {
1288     KeysetHandle.Builder builder = KeysetHandle.newBuilder();
1289     builder.addEntry(
1290         KeysetHandle.generateEntryFromParametersName("AES256_CMAC").withRandomId().makePrimary());
1291     builder.addEntry(KeysetHandle.generateEntryFromParametersName("AES256_CMAC").withRandomId());
1292     builder.removeAt(0);
1293     assertThrows(GeneralSecurityException.class, builder::build);
1294   }
1295 
1296   @Test
testBuilder_deletedPrimary_throws()1297   public void testBuilder_deletedPrimary_throws() throws Exception {
1298     KeysetHandle.Builder builder =
1299         KeysetHandle.newBuilder()
1300             .addEntry(
1301                 KeysetHandle.generateEntryFromParametersName("AES256_CMAC")
1302                     .withRandomId()
1303                     .makePrimary())
1304             .addEntry(KeysetHandle.generateEntryFromParametersName("AES256_CMAC").withRandomId())
1305             .deleteAt(0);
1306     assertThrows(GeneralSecurityException.class, builder::build);
1307   }
1308 
1309   @Test
testBuilder_addPrimary_clearsOtherPrimary()1310   public void testBuilder_addPrimary_clearsOtherPrimary() throws Exception {
1311     KeysetHandle.Builder builder = KeysetHandle.newBuilder();
1312     builder.addEntry(
1313         KeysetHandle.generateEntryFromParametersName("AES256_CMAC").withRandomId().makePrimary());
1314     builder.addEntry(
1315         KeysetHandle.generateEntryFromParametersName("AES256_CMAC").withRandomId().makePrimary());
1316     assertThat(builder.getAt(0).isPrimary()).isFalse();
1317   }
1318 
1319   @Test
testBuilder_setPrimary_clearsOtherPrimary()1320   public void testBuilder_setPrimary_clearsOtherPrimary() throws Exception {
1321     KeysetHandle.Builder builder = KeysetHandle.newBuilder();
1322     builder.addEntry(
1323         KeysetHandle.generateEntryFromParametersName("AES256_CMAC").withRandomId().makePrimary());
1324     builder.addEntry(KeysetHandle.generateEntryFromParametersName("AES256_CMAC").withRandomId());
1325     builder.getAt(1).makePrimary();
1326     assertThat(builder.getAt(0).isPrimary()).isFalse();
1327   }
1328 
1329   @Test
testBuilder_noIdSet_throws()1330   public void testBuilder_noIdSet_throws() throws Exception {
1331     KeysetHandle.Builder builder = KeysetHandle.newBuilder();
1332     builder.addEntry(KeysetHandle.generateEntryFromParametersName("AES256_CMAC").makePrimary());
1333     assertThrows(GeneralSecurityException.class, builder::build);
1334   }
1335 
1336   @Test
testBuilder_doubleId_throws()1337   public void testBuilder_doubleId_throws() throws Exception {
1338     KeysetHandle.Builder builder = KeysetHandle.newBuilder();
1339     builder.addEntry(
1340         KeysetHandle.generateEntryFromParametersName("AES256_CMAC").makePrimary().withFixedId(777));
1341     builder.addEntry(KeysetHandle.generateEntryFromParametersName("AES256_CMAC").withFixedId(777));
1342     assertThrows(GeneralSecurityException.class, builder::build);
1343   }
1344 
1345   @Test
testBuilder_createFromKeysetHandle_works()1346   public void testBuilder_createFromKeysetHandle_works() throws Exception {
1347     KeysetHandle.Builder builder = KeysetHandle.newBuilder();
1348     builder.addEntry(
1349         KeysetHandle.generateEntryFromParametersName("AES256_CMAC").makePrimary().withRandomId());
1350     builder.addEntry(KeysetHandle.generateEntryFromParametersName("AES256_CMAC").withRandomId());
1351     KeysetHandle originalKeyset = builder.build();
1352 
1353     builder = KeysetHandle.newBuilder(originalKeyset);
1354     KeysetHandle secondKeyset = builder.build();
1355 
1356     assertThat(secondKeyset.size()).isEqualTo(2);
1357     assertThat(secondKeyset.getAt(0).getKey().equalsKey(originalKeyset.getAt(0).getKey())).isTrue();
1358     assertThat(secondKeyset.getAt(1).getKey().equalsKey(originalKeyset.getAt(1).getKey())).isTrue();
1359     assertThat(secondKeyset.getAt(0).getStatus()).isEqualTo(originalKeyset.getAt(0).getStatus());
1360     assertThat(secondKeyset.getAt(1).getStatus()).isEqualTo(originalKeyset.getAt(1).getStatus());
1361     assertThat(secondKeyset.getAt(0).isPrimary()).isTrue();
1362   }
1363 
1364   @Test
testBuilder_copyKeyset_works()1365   public void testBuilder_copyKeyset_works() throws Exception {
1366     KeysetHandle original =
1367         KeysetHandle.newBuilder()
1368             .addEntry(KeysetHandle.generateEntryFromParametersName("AES256_CMAC").withFixedId(777))
1369             .addEntry(
1370                 KeysetHandle.generateEntryFromParametersName("AES256_CMAC")
1371                     .makePrimary()
1372                     .withFixedId(778))
1373             .build();
1374     KeysetHandle copy = KeysetHandle.newBuilder(original).build();
1375     assertThat(copy.size()).isEqualTo(2);
1376     assertThat(copy.getAt(0).getId()).isEqualTo(777);
1377     assertThat(copy.getAt(0).getKey().equalsKey(original.getAt(0).getKey())).isTrue();
1378     assertThat(copy.getAt(0).getStatus()).isEqualTo(original.getAt(0).getStatus());
1379     assertThat(copy.getAt(1).getId()).isEqualTo(778);
1380     assertThat(copy.getAt(1).getKey().equalsKey(original.getAt(1).getKey())).isTrue();
1381     assertThat(copy.getAt(1).getStatus()).isEqualTo(original.getAt(1).getStatus());
1382   }
1383 
1384   @Test
testBuilder_copyKeyset_originalHasInvalidKey_throws()1385   public void testBuilder_copyKeyset_originalHasInvalidKey_throws() throws Exception {
1386     Keyset keyset =
1387         Keyset.newBuilder()
1388             .setPrimaryKeyId(1)
1389             .addKey(
1390                 Keyset.Key.newBuilder()
1391                     .setKeyId(1)
1392                     .setStatus(KeyStatusType.ENABLED)
1393                     .setKeyData(
1394                         KeyData.newBuilder()
1395                             .setTypeUrl("type.googleapis.com/google.crypto.tink.AesGcmKey")
1396                             .setValue(ByteString.EMPTY)))
1397             .build();
1398     KeysetHandle.Builder builder = KeysetHandle.newBuilder(KeysetHandle.fromKeyset(keyset));
1399     GeneralSecurityException thrown = assertThrows(GeneralSecurityException.class, builder::build);
1400     assertThat(thrown)
1401         .hasCauseThat()
1402         .hasMessageThat()
1403         .contains("wrong status or key parsing failed");
1404   }
1405 
1406   @Test
testBuilder_copyKeyset_originalHasNoPrimary_throws()1407   public void testBuilder_copyKeyset_originalHasNoPrimary_throws() throws Exception {
1408     KeysetHandle original =
1409         KeysetHandle.newBuilder()
1410             .addEntry(
1411                 KeysetHandle.generateEntryFromParametersName("AES256_CMAC")
1412                     .makePrimary()
1413                     .withFixedId(778))
1414             .build();
1415     Keyset keyset = original.getKeyset();
1416     Keyset keysetWithoutPrimary = keyset.toBuilder().setPrimaryKeyId(3843).build();
1417 
1418     KeysetHandle.Builder builder =
1419         KeysetHandle.newBuilder(KeysetHandle.fromKeyset(keysetWithoutPrimary));
1420     GeneralSecurityException thrown = assertThrows(GeneralSecurityException.class, builder::build);
1421     assertThat(thrown).hasMessageThat().contains("No primary was set");
1422   }
1423 
1424   @Test
testBuilder_buildTwice_fails()1425   public void testBuilder_buildTwice_fails() throws Exception {
1426     KeysetHandle.Builder builder =
1427         KeysetHandle.newBuilder()
1428             .addEntry(
1429                 KeysetHandle.generateEntryFromParametersName("AES256_CMAC_RAW")
1430                     .withRandomId()
1431                     .makePrimary());
1432 
1433     Object unused = builder.build();
1434     // We disallow calling build on the same builder twice. The reason is that build assigns IDs
1435     // which were marked with "withRandomId()". Doing this twice results in incompatible keysets,
1436     // which would be confusing.
1437     assertThrows(GeneralSecurityException.class, builder::build);
1438   }
1439 
1440   @Test
testImportKey_withoutIdRequirement_withFixedId_works()1441   public void testImportKey_withoutIdRequirement_withFixedId_works() throws Exception {
1442     AesCmacParameters params = AesCmacParameters.builder().setKeySizeBytes(32).setTagSizeBytes(10)
1443         .build();
1444     AesCmacKey key = AesCmacKey.builder().setParameters(params)
1445         .setAesKeyBytes(SecretBytes.randomBytes(32)).build();
1446     KeysetHandle handle =
1447         KeysetHandle.newBuilder()
1448             .addEntry(KeysetHandle.importKey(key).withFixedId(102).makePrimary())
1449             .build();
1450     assertThat(handle.size()).isEqualTo(1);
1451     assertThat(handle.getAt(0).getId()).isEqualTo(102);
1452     assertThat(handle.getAt(0).getKey().equalsKey(key)).isTrue();
1453   }
1454 
1455   @Test
testImportKey_withoutIdRequirement_noIdAssigned_throws()1456   public void testImportKey_withoutIdRequirement_noIdAssigned_throws() throws Exception {
1457     AesCmacParameters params = AesCmacParameters.builder().setKeySizeBytes(32).setTagSizeBytes(10)
1458         .build();
1459     AesCmacKey key = AesCmacKey.builder().setParameters(params)
1460         .setAesKeyBytes(SecretBytes.randomBytes(32)).build();
1461     KeysetHandle.Builder builder =
1462         KeysetHandle.newBuilder().addEntry(KeysetHandle.importKey(key).makePrimary());
1463     assertThrows(GeneralSecurityException.class, builder::build);
1464   }
1465 
1466   @Test
testImportKey_withoutIdRequirement_withRandomId_works()1467   public void testImportKey_withoutIdRequirement_withRandomId_works() throws Exception {
1468     AesCmacParameters params = AesCmacParameters.builder().setKeySizeBytes(32).setTagSizeBytes(10)
1469         .build();
1470     AesCmacKey key = AesCmacKey.builder().setParameters(params)
1471         .setAesKeyBytes(SecretBytes.randomBytes(32)).build();
1472     KeysetHandle handle =
1473         KeysetHandle.newBuilder()
1474             .addEntry(KeysetHandle.importKey(key).withRandomId().makePrimary())
1475             .build();
1476     assertThat(handle.size()).isEqualTo(1);
1477     assertThat(handle.getAt(0).getKey().equalsKey(key)).isTrue();
1478   }
1479 
1480   @Test
testImportKey_withIdRequirement_noId_works()1481   public void testImportKey_withIdRequirement_noId_works() throws Exception {
1482     AesCmacParameters params =
1483         AesCmacParameters.builder().setKeySizeBytes(32).setTagSizeBytes(10).setVariant(Variant.TINK)
1484             .build();
1485     AesCmacKey key =
1486         AesCmacKey.builder()
1487             .setParameters(params)
1488             .setAesKeyBytes(SecretBytes.randomBytes(32))
1489             .setIdRequirement(105)
1490             .build();
1491     KeysetHandle handle =
1492         KeysetHandle.newBuilder().addEntry(KeysetHandle.importKey(key).makePrimary()).build();
1493     assertThat(handle.size()).isEqualTo(1);
1494     assertThat(handle.getAt(0).getId()).isEqualTo(105);
1495     assertThat(handle.getAt(0).getKey().equalsKey(key)).isTrue();
1496   }
1497 
1498   @Test
testImportKey_withIdRequirement_randomId_throws()1499   public void testImportKey_withIdRequirement_randomId_throws() throws Exception {
1500     AesCmacParameters params =
1501         AesCmacParameters.builder().setKeySizeBytes(32).setTagSizeBytes(10).setVariant(Variant.TINK)
1502             .build();
1503     AesCmacKey key =
1504         AesCmacKey.builder()
1505             .setParameters(params)
1506             .setAesKeyBytes(SecretBytes.randomBytes(32))
1507             .setIdRequirement(105)
1508             .build();
1509     KeysetHandle.Builder builder =
1510         KeysetHandle.newBuilder()
1511             .addEntry(KeysetHandle.importKey(key).withRandomId().makePrimary());
1512     assertThrows(GeneralSecurityException.class, builder::build);
1513   }
1514 
1515   @Test
testImportKey_withIdRequirement_explicitlySetToCorrectId_works()1516   public void testImportKey_withIdRequirement_explicitlySetToCorrectId_works() throws Exception {
1517     AesCmacParameters params =
1518         AesCmacParameters.builder().setKeySizeBytes(32).setTagSizeBytes(10).setVariant(Variant.TINK)
1519             .build();
1520     AesCmacKey key =
1521         AesCmacKey.builder()
1522             .setParameters(params)
1523             .setAesKeyBytes(SecretBytes.randomBytes(32))
1524             .setIdRequirement(105)
1525             .build();
1526     KeysetHandle handle =
1527         KeysetHandle.newBuilder()
1528             .addEntry(KeysetHandle.importKey(key).withFixedId(105).makePrimary())
1529             .build();
1530     assertThat(handle.size()).isEqualTo(1);
1531     assertThat(handle.getAt(0).getId()).isEqualTo(105);
1532     assertThat(handle.getAt(0).getKey().equalsKey(key)).isTrue();
1533   }
1534 
1535   @Test
testImportKey_withIdRequirement_explicitlySetToWrongId_throws()1536   public void testImportKey_withIdRequirement_explicitlySetToWrongId_throws() throws Exception {
1537     AesCmacParameters params =
1538         AesCmacParameters.builder().setKeySizeBytes(32).setTagSizeBytes(10).setVariant(Variant.TINK)
1539             .build();
1540     AesCmacKey key =
1541         AesCmacKey.builder()
1542             .setParameters(params)
1543             .setAesKeyBytes(SecretBytes.randomBytes(32))
1544             .setIdRequirement(105)
1545             .build();
1546     KeysetHandle.Builder builder =
1547         KeysetHandle.newBuilder()
1548             .addEntry(KeysetHandle.importKey(key).withFixedId(106).makePrimary());
1549     assertThrows(GeneralSecurityException.class, builder::build);
1550   }
1551 
1552   @Test
testAddEntry_addTwice_throws()1553   public void testAddEntry_addTwice_throws() throws Exception {
1554     KeysetHandle.Builder builder = KeysetHandle.newBuilder();
1555     KeysetHandle.Builder.Entry entry =
1556         KeysetHandle.generateEntryFromParametersName("AES256_CMAC").makePrimary().withRandomId();
1557     builder.addEntry(entry);
1558     assertThrows(IllegalStateException.class, () -> builder.addEntry(entry));
1559   }
1560 
1561   @Test
testSetStatusNull_throws()1562   public void testSetStatusNull_throws() throws Exception {
1563     KeysetHandle.Builder builder = KeysetHandle.newBuilder();
1564     builder.addEntry(
1565         KeysetHandle.generateEntryFromParametersName("AES256_CMAC")
1566             .makePrimary()
1567             .withRandomId()
1568             .setStatus(null));
1569     assertThrows(GeneralSecurityException.class, builder::build);
1570   }
1571 
1572   @Test
testStatusNotSet_getPrimitive_throws()1573   public void testStatusNotSet_getPrimitive_throws() throws Exception {
1574     Keyset keyset =
1575         Keyset.newBuilder()
1576             .setPrimaryKeyId(1)
1577             .addKey(
1578                 Keyset.Key.newBuilder()
1579                     .setKeyId(1)
1580                     .setStatus(KeyStatusType.ENABLED)
1581                     .setOutputPrefixType(OutputPrefixType.TINK)
1582                     .setKeyData(KeyData.newBuilder().setTypeUrl("unregisteredTypeUrl")))
1583             .build();
1584     KeysetHandle handle = KeysetHandle.fromKeyset(keyset);
1585     GeneralSecurityException e =
1586         assertThrows(GeneralSecurityException.class, () -> handle.getPrimitive(Aead.class));
1587     assertThat(e).hasMessageThat().contains("Unable to get primitive");
1588     assertThat(e).hasMessageThat().contains("unregisteredTypeUrl");
1589   }
1590 
1591   @Immutable
1592   private static final class TestPrimitiveA {
TestPrimitiveA()1593     public TestPrimitiveA() {}
1594   }
1595 
1596   @Immutable
1597   private static final class TestPrimitiveB {
TestPrimitiveB()1598     public TestPrimitiveB() {}
1599   }
1600 
1601   @Immutable
1602   private static final class TestWrapperA
1603       implements PrimitiveWrapper<TestPrimitiveA, TestPrimitiveB> {
1604 
1605     @Override
wrap(final PrimitiveSet<TestPrimitiveA> primitives)1606     public TestPrimitiveB wrap(final PrimitiveSet<TestPrimitiveA> primitives) {
1607       return new TestPrimitiveB();
1608     }
1609 
1610     @Override
getPrimitiveClass()1611     public Class<TestPrimitiveB> getPrimitiveClass() {
1612       return TestPrimitiveB.class;
1613     }
1614 
1615     @Override
getInputPrimitiveClass()1616     public Class<TestPrimitiveA> getInputPrimitiveClass() {
1617       return TestPrimitiveA.class;
1618     }
1619   }
1620 
getPrimitiveAHmacKey(HmacKey key)1621   private static TestPrimitiveA getPrimitiveAHmacKey(HmacKey key) {
1622     return new TestPrimitiveA();
1623   }
1624 
1625   @Test
getPrimitive_usesProvidedConfigurationWhenProvided()1626   public void getPrimitive_usesProvidedConfigurationWhenProvided() throws Exception {
1627     PrimitiveRegistry registry =
1628         PrimitiveRegistry.builder()
1629             .registerPrimitiveConstructor(
1630                 PrimitiveConstructor.create(
1631                     KeysetHandleTest::getPrimitiveAHmacKey,
1632                     HmacKey.class,
1633                     TestPrimitiveA.class))
1634             .registerPrimitiveWrapper(new TestWrapperA())
1635             .build();
1636     InternalConfiguration configuration =
1637         InternalConfiguration.createFromPrimitiveRegistry(registry);
1638     HmacKey hmacKey =
1639         HmacKey.builder()
1640             .setParameters(
1641                 HmacParameters.builder()
1642                     .setKeySizeBytes(20)
1643                     .setTagSizeBytes(10)
1644                     .setVariant(HmacParameters.Variant.NO_PREFIX)
1645                     .setHashType(HmacParameters.HashType.SHA256)
1646                     .build())
1647             .setKeyBytes(SecretBytes.randomBytes(20))
1648             .setIdRequirement(null)
1649             .build();
1650     KeysetHandle keysetHandle =
1651         KeysetHandle.newBuilder()
1652             .addEntry(KeysetHandle.importKey(hmacKey).withRandomId().makePrimary())
1653             .build();
1654 
1655     assertThrows(
1656         GeneralSecurityException.class, () -> keysetHandle.getPrimitive(TestPrimitiveB.class));
1657     assertThat(keysetHandle.getPrimitive(configuration, TestPrimitiveB.class)).isNotNull();
1658   }
1659 
1660   @Test
getPrimitive_usesRegistryWhenNoConfigurationProvided()1661   public void getPrimitive_usesRegistryWhenNoConfigurationProvided() throws Exception {
1662     KeysetHandle keysetHandle =
1663         KeysetHandle.newBuilder()
1664             .addEntry(KeysetHandle.importKey(rawKey).withRandomId().makePrimary())
1665             .build();
1666     byte[] plaintext = "plaintext".getBytes(UTF_8);
1667 
1668     ChunkedMac registryMac =
1669         MutablePrimitiveRegistry.globalInstance().getPrimitive(rawKey, ChunkedMac.class);
1670     ChunkedMacComputation registryMacComputation = registryMac.createComputation();
1671     registryMacComputation.update(ByteBuffer.wrap(plaintext));
1672     ChunkedMac keysetHandleMac = keysetHandle.getPrimitive(ChunkedMac.class);
1673     ChunkedMacComputation keysetHandleMacComputation = keysetHandleMac.createComputation();
1674     keysetHandleMacComputation.update(ByteBuffer.wrap(plaintext));
1675 
1676     assertThat(keysetHandleMacComputation.computeMac())
1677         .isEqualTo(registryMacComputation.computeMac());
1678   }
1679 
1680   @Test
getLegacyPrimitive_usesRegistryWhenNoConfigurationProvided()1681   public void getLegacyPrimitive_usesRegistryWhenNoConfigurationProvided()
1682       throws Exception {
1683     KeysetHandle keysetHandle =
1684         KeysetHandle.newBuilder()
1685             .addEntry(KeysetHandle.importKey(rawKey).withRandomId().makePrimary())
1686             .build();
1687     KeyData rawKeyData =
1688         KeyData.newBuilder()
1689             .setValue(
1690                 com.google.crypto.tink.proto.HmacKey.newBuilder()
1691                     .setParams(
1692                         HmacParams.newBuilder()
1693                             .setHash(com.google.crypto.tink.proto.HashType.SHA256)
1694                             .setTagSize(HMAC_TAG_SIZE)
1695                             .build())
1696                     .setKeyValue(
1697                         ByteString.copyFrom(
1698                             rawKey.getKeyBytes().toByteArray(InsecureSecretKeyAccess.get())))
1699                     .build()
1700                     .toByteString())
1701             .setTypeUrl(keysetHandle.getKeysetInfo().getKeyInfo(0).getTypeUrl())
1702             .setKeyMaterialType(KeyMaterialType.SYMMETRIC)
1703             .build();
1704 
1705     byte[] plaintext = "plaintext".getBytes(UTF_8);
1706 
1707     Mac registryMac = Registry.getPrimitive(rawKeyData, Mac.class);
1708     Mac keysetHandleMac = keysetHandle.getPrimitive(Mac.class);
1709 
1710     assertThat(keysetHandleMac.computeMac(plaintext)).isEqualTo(registryMac.computeMac(plaintext));
1711   }
1712 
1713   @Test
keysetEquality_singleKeyEquals_returnsTrue()1714   public void keysetEquality_singleKeyEquals_returnsTrue() throws Exception {
1715     SecretBytes bytes = SecretBytes.randomBytes(32);
1716 
1717     KeysetHandle keysetHandle1 =
1718         KeysetHandle.newBuilder()
1719             .addEntry(
1720                 KeysetHandle.importKey(XChaCha20Poly1305Key.create(bytes))
1721                     .withFixedId(101)
1722                     .makePrimary())
1723             .build();
1724     KeysetHandle keysetHandle2 =
1725         KeysetHandle.newBuilder()
1726             .addEntry(
1727                 KeysetHandle.importKey(XChaCha20Poly1305Key.create(bytes))
1728                     .withFixedId(101)
1729                     .makePrimary())
1730             .build();
1731 
1732     assertTrue(keysetHandle1.equalsKeyset(keysetHandle2));
1733   }
1734 
1735   @Test
keysetEquality_singleKeyDifferentKeys_returnsFalse()1736   public void keysetEquality_singleKeyDifferentKeys_returnsFalse() throws Exception {
1737     SecretBytes bytes = SecretBytes.randomBytes(32);
1738 
1739     KeysetHandle keysetHandle1 =
1740         KeysetHandle.newBuilder()
1741             .addEntry(
1742                 KeysetHandle.importKey(
1743                         XChaCha20Poly1305Key.create(
1744                             XChaCha20Poly1305Parameters.Variant.TINK, bytes, 101))
1745                     .withFixedId(101)
1746                     .makePrimary())
1747             .build();
1748     KeysetHandle keysetHandle2 =
1749         KeysetHandle.newBuilder()
1750             .addEntry(
1751                 KeysetHandle.importKey(
1752                         XChaCha20Poly1305Key.create(
1753                             XChaCha20Poly1305Parameters.Variant.CRUNCHY, bytes, 101))
1754                     .withFixedId(101)
1755                     .makePrimary())
1756             .build();
1757 
1758     assertFalse(keysetHandle1.equalsKeyset(keysetHandle2));
1759   }
1760 
1761   @Test
keysetEquality_singleKeyDifferentId_returnsFalse()1762   public void keysetEquality_singleKeyDifferentId_returnsFalse() throws Exception {
1763     SecretBytes bytes = SecretBytes.randomBytes(32);
1764 
1765     KeysetHandle keysetHandle1 =
1766         KeysetHandle.newBuilder()
1767             .addEntry(
1768                 KeysetHandle.importKey(XChaCha20Poly1305Key.create(bytes))
1769                     .withFixedId(102)
1770                     .makePrimary())
1771             .build();
1772     KeysetHandle keysetHandle2 =
1773         KeysetHandle.newBuilder()
1774             .addEntry(
1775                 KeysetHandle.importKey(XChaCha20Poly1305Key.create(bytes))
1776                     .withFixedId(103)
1777                     .makePrimary())
1778             .build();
1779 
1780     assertFalse(keysetHandle1.equalsKeyset(keysetHandle2));
1781   }
1782 
1783   @Test
keysetEquality_twoKeysEquals_returnsTrue()1784   public void keysetEquality_twoKeysEquals_returnsTrue() throws Exception {
1785     SecretBytes bytes1 = SecretBytes.randomBytes(32);
1786     SecretBytes bytes2 = SecretBytes.randomBytes(32);
1787 
1788     KeysetHandle keysetHandle1 =
1789         KeysetHandle.newBuilder()
1790             .addEntry(
1791                 KeysetHandle.importKey(XChaCha20Poly1305Key.create(bytes1))
1792                     .withFixedId(101)
1793                     .makePrimary())
1794             .addEntry(KeysetHandle.importKey(XChaCha20Poly1305Key.create(bytes2)).withFixedId(102))
1795             .build();
1796     KeysetHandle keysetHandle2 =
1797         KeysetHandle.newBuilder()
1798             .addEntry(
1799                 KeysetHandle.importKey(XChaCha20Poly1305Key.create(bytes1))
1800                     .withFixedId(101)
1801                     .makePrimary())
1802             .addEntry(KeysetHandle.importKey(XChaCha20Poly1305Key.create(bytes2)).withFixedId(102))
1803             .build();
1804 
1805     assertTrue(keysetHandle1.equalsKeyset(keysetHandle2));
1806   }
1807 
1808   @Test
keysetEquality_twoKeysDifferentPrimaries_returnsFalse()1809   public void keysetEquality_twoKeysDifferentPrimaries_returnsFalse() throws Exception {
1810     SecretBytes bytes1 = SecretBytes.randomBytes(32);
1811     SecretBytes bytes2 = SecretBytes.randomBytes(32);
1812 
1813     KeysetHandle keysetHandle1 =
1814         KeysetHandle.newBuilder()
1815             .addEntry(KeysetHandle.importKey(XChaCha20Poly1305Key.create(bytes1)).withFixedId(101))
1816             .addEntry(
1817                 KeysetHandle.importKey(XChaCha20Poly1305Key.create(bytes2))
1818                     .withFixedId(102)
1819                     .makePrimary())
1820             .build();
1821     KeysetHandle keysetHandle2 =
1822         KeysetHandle.newBuilder()
1823             .addEntry(
1824                 KeysetHandle.importKey(XChaCha20Poly1305Key.create(bytes1))
1825                     .withFixedId(101)
1826                     .makePrimary())
1827             .addEntry(KeysetHandle.importKey(XChaCha20Poly1305Key.create(bytes2)).withFixedId(102))
1828             .build();
1829 
1830     assertFalse(keysetHandle1.equalsKeyset(keysetHandle2));
1831   }
1832 
1833   @Test
keysetEquality_twoKeysDifferentOrder_returnsFalse()1834   public void keysetEquality_twoKeysDifferentOrder_returnsFalse() throws Exception {
1835     SecretBytes bytes1 = SecretBytes.randomBytes(32);
1836     SecretBytes bytes2 = SecretBytes.randomBytes(32);
1837 
1838     KeysetHandle keysetHandle1 =
1839         KeysetHandle.newBuilder()
1840             .addEntry(
1841                 KeysetHandle.importKey(XChaCha20Poly1305Key.create(bytes1))
1842                     .withFixedId(101)
1843                     .makePrimary())
1844             .addEntry(KeysetHandle.importKey(XChaCha20Poly1305Key.create(bytes2)).withFixedId(102))
1845             .build();
1846     KeysetHandle keysetHandle2 =
1847         KeysetHandle.newBuilder()
1848             .addEntry(KeysetHandle.importKey(XChaCha20Poly1305Key.create(bytes2)).withFixedId(102))
1849             .addEntry(
1850                 KeysetHandle.importKey(XChaCha20Poly1305Key.create(bytes1))
1851                     .withFixedId(101)
1852                     .makePrimary())
1853             .build();
1854 
1855     assertFalse(keysetHandle1.equalsKeyset(keysetHandle2));
1856   }
1857 
1858   @Test
keysetEquality_twoKeysDifferentStatuses_returnsFalse()1859   public void keysetEquality_twoKeysDifferentStatuses_returnsFalse() throws Exception {
1860     SecretBytes bytes1 = SecretBytes.randomBytes(32);
1861     SecretBytes bytes2 = SecretBytes.randomBytes(32);
1862 
1863     KeysetHandle keysetHandle1 =
1864         KeysetHandle.newBuilder()
1865             .addEntry(
1866                 KeysetHandle.importKey(XChaCha20Poly1305Key.create(bytes1))
1867                     .withFixedId(101)
1868                     .makePrimary())
1869             .addEntry(
1870                 KeysetHandle.importKey(XChaCha20Poly1305Key.create(bytes2))
1871                     .withFixedId(102)
1872                     .setStatus(KeyStatus.DISABLED))
1873             .build();
1874     KeysetHandle keysetHandle2 =
1875         KeysetHandle.newBuilder()
1876             .addEntry(
1877                 KeysetHandle.importKey(XChaCha20Poly1305Key.create(bytes1))
1878                     .withFixedId(101)
1879                     .makePrimary())
1880             .addEntry(KeysetHandle.importKey(XChaCha20Poly1305Key.create(bytes2)).withFixedId(102))
1881             .build();
1882 
1883     assertFalse(keysetHandle1.equalsKeyset(keysetHandle2));
1884   }
1885 
1886   @Test
keysetEquality_twoKeysDifferentSizes_returnsFalse()1887   public void keysetEquality_twoKeysDifferentSizes_returnsFalse() throws Exception {
1888     SecretBytes bytes1 = SecretBytes.randomBytes(32);
1889     SecretBytes bytes2 = SecretBytes.randomBytes(32);
1890 
1891     KeysetHandle keysetHandle1 =
1892         KeysetHandle.newBuilder()
1893             .addEntry(
1894                 KeysetHandle.importKey(XChaCha20Poly1305Key.create(bytes1))
1895                     .withFixedId(101)
1896                     .makePrimary())
1897             .addEntry(KeysetHandle.importKey(XChaCha20Poly1305Key.create(bytes2)).withFixedId(102))
1898             .build();
1899     KeysetHandle keysetHandle2 =
1900         KeysetHandle.newBuilder()
1901             .addEntry(
1902                 KeysetHandle.importKey(XChaCha20Poly1305Key.create(bytes1))
1903                     .withFixedId(101)
1904                     .makePrimary())
1905             .build();
1906 
1907     assertFalse(keysetHandle1.equalsKeyset(keysetHandle2));
1908   }
1909 
1910   @Test
keysetEquality_unparseableStatus_returnsFalse()1911   public void keysetEquality_unparseableStatus_returnsFalse() throws Exception {
1912     Keyset.Key key1 =
1913         TestUtil.createKey(
1914             TestUtil.createHmacKeyData("01234567890123456".getBytes(UTF_8), 16),
1915             42,
1916             KeyStatusType.UNKNOWN_STATUS,
1917             OutputPrefixType.TINK);
1918     KeysetHandle badKeyset = KeysetHandle.fromKeyset(TestUtil.createKeyset(key1));
1919     assertFalse(badKeyset.equalsKeyset(badKeyset));
1920   }
1921 
1922   @Test
keysetEquality_noPrimary_returnsFalse()1923   public void keysetEquality_noPrimary_returnsFalse() throws Exception {
1924     Keyset.Key key1 =
1925         TestUtil.createKey(
1926             TestUtil.createHmacKeyData("01234567890123456".getBytes(UTF_8), 16),
1927             42,
1928             KeyStatusType.ENABLED,
1929             OutputPrefixType.TINK);
1930     Keyset keyset = TestUtil.createKeyset(key1);
1931     KeysetHandle badKeyset =
1932         KeysetHandle.fromKeyset(Keyset.newBuilder(keyset).setPrimaryKeyId(77).build());
1933     assertFalse(badKeyset.equalsKeyset(badKeyset));
1934   }
1935 
1936   @Test
keysetEquality_monitoringAnnotationIgnored_returnsTrue()1937   public void keysetEquality_monitoringAnnotationIgnored_returnsTrue() throws Exception {
1938     SecretBytes bytes = SecretBytes.randomBytes(32);
1939 
1940     KeysetHandle keysetHandle1 =
1941         KeysetHandle.newBuilder()
1942             .addEntry(
1943                 KeysetHandle.importKey(XChaCha20Poly1305Key.create(bytes))
1944                     .withFixedId(101)
1945                     .makePrimary())
1946             .setMonitoringAnnotations(MonitoringAnnotations.newBuilder().add("k1", "v1").build())
1947             .build();
1948     KeysetHandle keysetHandle2 =
1949         KeysetHandle.newBuilder()
1950             .addEntry(
1951                 KeysetHandle.importKey(XChaCha20Poly1305Key.create(bytes))
1952                     .withFixedId(101)
1953                     .makePrimary())
1954             .setMonitoringAnnotations(MonitoringAnnotations.newBuilder().add("k2", "v2").build())
1955             .build();
1956 
1957     assertTrue(keysetHandle1.equalsKeyset(keysetHandle2));
1958   }
1959 }
1960