xref: /aosp_15_r20/external/tink/java_src/src/test/java/com/google/crypto/tink/mac/MacWrapperTest.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.mac;
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.assertThrows;
22 
23 import com.google.crypto.tink.InsecureSecretKeyAccess;
24 import com.google.crypto.tink.KeysetHandle;
25 import com.google.crypto.tink.Mac;
26 import com.google.crypto.tink.Registry;
27 import com.google.crypto.tink.internal.MutableMonitoringRegistry;
28 import com.google.crypto.tink.internal.MutablePrimitiveRegistry;
29 import com.google.crypto.tink.internal.PrimitiveConstructor;
30 import com.google.crypto.tink.internal.testing.FakeMonitoringClient;
31 import com.google.crypto.tink.mac.HmacParameters.HashType;
32 import com.google.crypto.tink.mac.internal.HmacProtoSerialization;
33 import com.google.crypto.tink.monitoring.MonitoringAnnotations;
34 import com.google.crypto.tink.subtle.Hex;
35 import com.google.crypto.tink.util.SecretBytes;
36 import java.security.GeneralSecurityException;
37 import java.util.List;
38 import org.junit.BeforeClass;
39 import org.junit.Test;
40 import org.junit.runner.RunWith;
41 import org.junit.runners.JUnit4;
42 
43 /** Tests for MacWrapper. */
44 @RunWith(JUnit4.class)
45 public class MacWrapperTest {
46   private static final int HMAC_KEY_SIZE = 20;
47   private static final int HMAC_TAG_SIZE = 10;
48   private static final int AES_CMAC_KEY_SIZE = 32;
49   private static final int AES_CMAC_TAG_SIZE = 10;
50 
51   private static HmacKey rawKey0;
52   private static HmacKey rawKey1;
53   private static AesCmacKey rawKey2;
54   private static AesCmacKey rawKey3;
55   private static HmacKey tinkKey0;
56   private static AesCmacKey tinkKey1;
57   private static HmacKey crunchyKey0;
58   private static AesCmacKey crunchyKey1;
59   private static HmacKey legacyKey0;
60   private static AesCmacKey legacyKey1;
61 
62   @BeforeClass
setUp()63   public static void setUp() throws Exception {
64     MacConfig.register();
65     AesCmacProtoSerialization.register();
66     HmacProtoSerialization.register();
67     createTestKeys();
68   }
69 
createTestKeys()70   private static void createTestKeys() {
71     final HmacParameters noPrefixHmacParameters =
72         createDefaultHmacParameters(HmacParameters.Variant.NO_PREFIX);
73     final HmacParameters legacyHmacParameters =
74         createDefaultHmacParameters(HmacParameters.Variant.LEGACY);
75     final HmacParameters crunchyHmacParameters =
76         createDefaultHmacParameters(HmacParameters.Variant.CRUNCHY);
77     final HmacParameters tinkHmacParameters =
78         createDefaultHmacParameters(HmacParameters.Variant.TINK);
79     final AesCmacParameters noPrefixAesCmacParameters =
80         createDefaultAesCmacParameters(AesCmacParameters.Variant.NO_PREFIX);
81     final AesCmacParameters legacyAesCmacParameters =
82         createDefaultAesCmacParameters(AesCmacParameters.Variant.LEGACY);
83     final AesCmacParameters crunchyAesCmacParameters =
84         createDefaultAesCmacParameters(AesCmacParameters.Variant.CRUNCHY);
85     final AesCmacParameters tinkAesCmacParameters =
86         createDefaultAesCmacParameters(AesCmacParameters.Variant.TINK);
87 
88     try {
89       rawKey0 =
90           HmacKey.builder()
91               .setParameters(noPrefixHmacParameters)
92               .setKeyBytes(SecretBytes.randomBytes(HMAC_KEY_SIZE))
93               .setIdRequirement(null)
94               .build();
95       rawKey1 =
96           HmacKey.builder()
97               .setParameters(noPrefixHmacParameters)
98               .setKeyBytes(SecretBytes.randomBytes(HMAC_KEY_SIZE))
99               .setIdRequirement(null)
100               .build();
101       rawKey2 =
102           AesCmacKey.builder()
103               .setParameters(noPrefixAesCmacParameters)
104               .setAesKeyBytes(SecretBytes.randomBytes(AES_CMAC_KEY_SIZE))
105               .setIdRequirement(null)
106               .build();
107       rawKey3 =
108           AesCmacKey.builder()
109               .setParameters(noPrefixAesCmacParameters)
110               .setAesKeyBytes(SecretBytes.randomBytes(AES_CMAC_KEY_SIZE))
111               .setIdRequirement(null)
112               .build();
113       tinkKey0 =
114           HmacKey.builder()
115               .setParameters(tinkHmacParameters)
116               .setKeyBytes(SecretBytes.randomBytes(HMAC_KEY_SIZE))
117               .setIdRequirement(4)
118               .build();
119       tinkKey1 =
120           AesCmacKey.builder()
121               .setParameters(tinkAesCmacParameters)
122               .setAesKeyBytes(SecretBytes.randomBytes(AES_CMAC_KEY_SIZE))
123               .setIdRequirement(5)
124               .build();
125       crunchyKey0 =
126           HmacKey.builder()
127               .setParameters(crunchyHmacParameters)
128               .setKeyBytes(SecretBytes.randomBytes(HMAC_KEY_SIZE))
129               .setIdRequirement(6)
130               .build();
131       crunchyKey1 =
132           AesCmacKey.builder()
133               .setParameters(crunchyAesCmacParameters)
134               .setAesKeyBytes(SecretBytes.randomBytes(AES_CMAC_KEY_SIZE))
135               .setIdRequirement(7)
136               .build();
137       legacyKey0 =
138           HmacKey.builder()
139               .setParameters(legacyHmacParameters)
140               .setKeyBytes(SecretBytes.randomBytes(HMAC_KEY_SIZE))
141               .setIdRequirement(8)
142               .build();
143       legacyKey1 =
144           AesCmacKey.builder()
145               .setParameters(legacyAesCmacParameters)
146               .setAesKeyBytes(SecretBytes.randomBytes(AES_CMAC_KEY_SIZE))
147               .setIdRequirement(9)
148               .build();
149     } catch (GeneralSecurityException e) {
150       throw new IllegalStateException(e);
151     }
152   }
153 
createDefaultAesCmacParameters( AesCmacParameters.Variant variant)154   private static AesCmacParameters createDefaultAesCmacParameters(
155       AesCmacParameters.Variant variant) {
156     try {
157       return AesCmacParameters.builder()
158           .setKeySizeBytes(AES_CMAC_KEY_SIZE)
159           .setTagSizeBytes(AES_CMAC_TAG_SIZE)
160           .setVariant(variant)
161           .build();
162     } catch (GeneralSecurityException e) {
163       throw new IllegalStateException(e);
164     }
165   }
166 
createDefaultHmacParameters(HmacParameters.Variant variant)167   private static HmacParameters createDefaultHmacParameters(HmacParameters.Variant variant) {
168     try {
169       return HmacParameters.builder()
170           .setKeySizeBytes(HMAC_KEY_SIZE)
171           .setTagSizeBytes(HMAC_TAG_SIZE)
172           .setVariant(variant)
173           .setHashType(HashType.SHA1)
174           .build();
175     } catch (GeneralSecurityException e) {
176       throw new IllegalArgumentException("Incorrect parameters creation arguments", e);
177     }
178   }
179 
180   @Test
testComputeVerifyMac_works()181   public void testComputeVerifyMac_works() throws Exception {
182     byte[] plaintext = "plaintext".getBytes(UTF_8);
183     KeysetHandle smallKeysetHandle =
184         KeysetHandle.newBuilder()
185             .addEntry(KeysetHandle.importKey(rawKey0).withFixedId(1234).makePrimary())
186             .addEntry(KeysetHandle.importKey(tinkKey1))
187             .build();
188     Mac mac = smallKeysetHandle.getPrimitive(Mac.class);
189 
190     byte[] tag = mac.computeMac(plaintext);
191 
192     mac.verifyMac(tag, plaintext);
193   }
194 
195   @Test
testComputeVerifyMac_throwsOnWrongKey()196   public void testComputeVerifyMac_throwsOnWrongKey() throws Exception {
197     MutablePrimitiveRegistry.resetGlobalInstanceTestOnly();
198     MacConfig.register();
199 
200     byte[] plaintext = "plaintext".getBytes(UTF_8);
201     KeysetHandle computeKeysetHandle =
202         KeysetHandle.newBuilder()
203             .addEntry(KeysetHandle.importKey(rawKey0).withFixedId(1234).makePrimary())
204             .build();
205     KeysetHandle verifyKeysetHandle =
206         KeysetHandle.newBuilder()
207             .addEntry(KeysetHandle.importKey(rawKey1).withFixedId(1235).makePrimary())
208             .build();
209     Mac computingMac = computeKeysetHandle.getPrimitive(Mac.class);
210     Mac verifyingMac = verifyKeysetHandle.getPrimitive(Mac.class);
211 
212     byte[] tag = computingMac.computeMac(plaintext);
213 
214     assertThrows(GeneralSecurityException.class, () -> verifyingMac.verifyMac(tag, plaintext));
215   }
216 
217   @Test
testVerifyMac_checksAllNecessaryRawKeys()218   public void testVerifyMac_checksAllNecessaryRawKeys() throws Exception {
219     MutablePrimitiveRegistry.resetGlobalInstanceTestOnly();
220     MacConfig.register();
221 
222     byte[] plaintext = "plaintext".getBytes(UTF_8);
223     KeysetHandle computeKeysetHandle =
224         KeysetHandle.newBuilder()
225             .addEntry(KeysetHandle.importKey(rawKey3).withFixedId(1237).makePrimary())
226             .build();
227     KeysetHandle verifyKeysetHandle =
228         KeysetHandle.newBuilder()
229             .addEntry(KeysetHandle.importKey(rawKey1).withFixedId(1235).makePrimary())
230             .addEntry(KeysetHandle.importKey(rawKey3).withFixedId(1237))
231             .build();
232     Mac computingMac = computeKeysetHandle.getPrimitive(Mac.class);
233     Mac verifyingMac = verifyKeysetHandle.getPrimitive(Mac.class);
234 
235     byte[] tag = computingMac.computeMac(plaintext);
236 
237     verifyingMac.verifyMac(tag, plaintext);
238   }
239 
240   @Test
testVerifyMac_checksRawKeysWhenTagHasTinkKeyPrefix()241   public void testVerifyMac_checksRawKeysWhenTagHasTinkKeyPrefix() throws Exception {
242     MutablePrimitiveRegistry.resetGlobalInstanceTestOnly();
243     MacConfig.register();
244 
245     byte[] plaintext = "plaintext".getBytes(UTF_8);
246     byte[] tag = Hex.decode("0152af9740d2fab0cf3f");
247     HmacKey rawKey5 =
248         HmacKey.builder()
249             .setParameters(createDefaultHmacParameters(HmacParameters.Variant.NO_PREFIX))
250             .setKeyBytes(
251                 SecretBytes.copyFrom(
252                     Hex.decode("7d40a4d7c192ca113f403b8703e1b7b93fecf99a"),
253                     InsecureSecretKeyAccess.get()))
254             .setIdRequirement(null)
255             .build();
256     // Note: 0x52af97f0 are bytes 1 to 4 in the tag.
257     HmacKey tinkKey2 =
258         HmacKey.builder()
259             .setParameters(createDefaultHmacParameters(HmacParameters.Variant.TINK))
260             .setKeyBytes(SecretBytes.randomBytes(HMAC_KEY_SIZE))
261             .setIdRequirement(0x52af9740)
262             .build();
263     KeysetHandle verifyKeysetHandle =
264         KeysetHandle.newBuilder()
265             .addEntry(KeysetHandle.importKey(rawKey5).withFixedId(1235))
266             .addEntry(KeysetHandle.importKey(tinkKey2).makePrimary())
267             .build();
268 
269     Mac mac = verifyKeysetHandle.getPrimitive(Mac.class);
270 
271     mac.verifyMac(tag, plaintext);
272   }
273 
274   @Test
computeMac_usesPrimaryKey()275   public void computeMac_usesPrimaryKey() throws Exception {
276     MutablePrimitiveRegistry.resetGlobalInstanceTestOnly();
277     MacConfig.register();
278 
279     byte[] plaintext = "plaintext".getBytes(UTF_8);
280     KeysetHandle keysetHandle =
281         KeysetHandle.newBuilder()
282             .addEntry(KeysetHandle.importKey(rawKey2).withFixedId(1236).makePrimary())
283             .addEntry(KeysetHandle.importKey(rawKey3).withFixedId(1237))
284             .addEntry(KeysetHandle.importKey(tinkKey1))
285             .build();
286     KeysetHandle keysetHandlePrimary =
287         KeysetHandle.newBuilder()
288             .addEntry(KeysetHandle.importKey(rawKey2).withFixedId(1236).makePrimary())
289             .build();
290     Mac computingMac = keysetHandle.getPrimitive(Mac.class);
291     Mac verifyingMac = keysetHandlePrimary.getPrimitive(Mac.class);
292 
293     byte[] tag = computingMac.computeMac(plaintext);
294 
295     verifyingMac.verifyMac(tag, plaintext);
296   }
297 
298   @Test
testComputeVerifyMac_manyKeysWork()299   public void testComputeVerifyMac_manyKeysWork() throws Exception {
300     MutablePrimitiveRegistry.resetGlobalInstanceTestOnly();
301     MacConfig.register();
302 
303     byte[] plaintext = "plaintext".getBytes(UTF_8);
304     KeysetHandle assortedKeysetHandle =
305         KeysetHandle.newBuilder()
306             .addEntry(KeysetHandle.importKey(rawKey0).withFixedId(1234))
307             .addEntry(KeysetHandle.importKey(rawKey1).withFixedId(1235))
308             .addEntry(KeysetHandle.importKey(rawKey2).withFixedId(1236))
309             .addEntry(KeysetHandle.importKey(rawKey3).withFixedId(1237))
310             .addEntry(KeysetHandle.importKey(tinkKey0))
311             .addEntry(KeysetHandle.importKey(tinkKey1))
312             .addEntry(KeysetHandle.importKey(crunchyKey0))
313             .addEntry(KeysetHandle.importKey(crunchyKey1).makePrimary())
314             .addEntry(KeysetHandle.importKey(legacyKey0))
315             .addEntry(KeysetHandle.importKey(legacyKey1))
316             .build();
317     Mac mac = assortedKeysetHandle.getPrimitive(Mac.class);
318 
319     byte[] tag = mac.computeMac(plaintext);
320 
321     mac.verifyMac(tag, plaintext);
322   }
323 
324   @Test
testVerifyMac_shiftedPrimaryWithManyKeysWorks()325   public void testVerifyMac_shiftedPrimaryWithManyKeysWorks() throws Exception {
326     MutablePrimitiveRegistry.resetGlobalInstanceTestOnly();
327     MacConfig.register();
328 
329     byte[] plaintext = "plaintext".getBytes(UTF_8);
330     KeysetHandle assortedKeysetHandle0 =
331         KeysetHandle.newBuilder()
332             .addEntry(KeysetHandle.importKey(rawKey0).withFixedId(1234))
333             .addEntry(KeysetHandle.importKey(rawKey1).withFixedId(1235))
334             .addEntry(KeysetHandle.importKey(rawKey2).withFixedId(1236))
335             .addEntry(KeysetHandle.importKey(rawKey3).withFixedId(1237))
336             .addEntry(KeysetHandle.importKey(tinkKey0))
337             .addEntry(KeysetHandle.importKey(tinkKey1))
338             .addEntry(KeysetHandle.importKey(crunchyKey0))
339             .addEntry(KeysetHandle.importKey(crunchyKey1).makePrimary())
340             .addEntry(KeysetHandle.importKey(legacyKey0))
341             .addEntry(KeysetHandle.importKey(legacyKey1))
342             .build();
343     KeysetHandle.Builder assortedBuilder = KeysetHandle.newBuilder(assortedKeysetHandle0);
344     assortedBuilder.getAt(4).makePrimary();
345     KeysetHandle assortedKeysetHandle1 = assortedBuilder.build();
346     Mac mac = assortedKeysetHandle1.getPrimitive(Mac.class);
347 
348     byte[] tag = mac.computeMac(plaintext);
349 
350     mac.verifyMac(tag, plaintext);
351   }
352 
353   // ------------------------------------------------------------------------------ Monitoring tests
354 
355   @Test
testMultipleKeysWithoutAnnotation()356   public void testMultipleKeysWithoutAnnotation() throws Exception {
357     MutablePrimitiveRegistry.resetGlobalInstanceTestOnly();
358     MacConfig.register();
359 
360     FakeMonitoringClient fakeMonitoringClient = new FakeMonitoringClient();
361     MutableMonitoringRegistry.globalInstance().clear();
362     MutableMonitoringRegistry.globalInstance().registerMonitoringClient(fakeMonitoringClient);
363 
364     byte[] plaintext = "plaintext".getBytes(UTF_8);
365     KeysetHandle mainKeysetHandle =
366         KeysetHandle.newBuilder()
367             .addEntry(KeysetHandle.importKey(rawKey0).withFixedId(1234))
368             .addEntry(KeysetHandle.importKey(rawKey1).withFixedId(1235))
369             .addEntry(KeysetHandle.importKey(rawKey2).withFixedId(1236))
370             .addEntry(KeysetHandle.importKey(rawKey3).withFixedId(1237))
371             .addEntry(KeysetHandle.importKey(tinkKey0))
372             .addEntry(KeysetHandle.importKey(tinkKey1))
373             .addEntry(KeysetHandle.importKey(crunchyKey0))
374             .addEntry(KeysetHandle.importKey(crunchyKey1).makePrimary())
375             .addEntry(KeysetHandle.importKey(legacyKey1))
376             .build();
377     KeysetHandle noPrefixKeyKeyset =
378         KeysetHandle.newBuilder()
379             .addEntry(KeysetHandle.importKey(rawKey2).withFixedId(1236).makePrimary())
380             .build();
381     KeysetHandle prefixedKeyKeyset =
382         KeysetHandle.newBuilder()
383             .addEntry(KeysetHandle.importKey(crunchyKey1).makePrimary())
384             .build();
385     KeysetHandle missingKeyKeyset =
386         KeysetHandle.newBuilder()
387             .addEntry(KeysetHandle.importKey(legacyKey0).makePrimary())
388             .build();
389     Mac mac = mainKeysetHandle.getPrimitive(Mac.class);
390     Mac noPrefixMac = noPrefixKeyKeyset.getPrimitive(Mac.class);
391     Mac prefixedMac = prefixedKeyKeyset.getPrimitive(Mac.class);
392     Mac missingMac = missingKeyKeyset.getPrimitive(Mac.class);
393 
394     // Busy work triggering different code paths.
395     byte[] tag = noPrefixMac.computeMac(plaintext);
396     mac.verifyMac(tag, plaintext);
397     tag = prefixedMac.computeMac(plaintext);
398     mac.verifyMac(tag, plaintext);
399     byte[] missingTag = missingMac.computeMac(plaintext);
400     assertThrows(GeneralSecurityException.class, () -> mac.verifyMac(missingTag, plaintext));
401 
402     // Without annotations, nothing gets logged.
403     assertThat(fakeMonitoringClient.getLogEntries()).isEmpty();
404     assertThat(fakeMonitoringClient.getLogFailureEntries()).isEmpty();
405   }
406 
407   @Test
testWithAnnotation_hasMonitoring()408   public void testWithAnnotation_hasMonitoring() throws Exception {
409     MutablePrimitiveRegistry.resetGlobalInstanceTestOnly();
410     MacConfig.register();
411 
412     FakeMonitoringClient fakeMonitoringClient = new FakeMonitoringClient();
413     MutableMonitoringRegistry.globalInstance().clear();
414     MutableMonitoringRegistry.globalInstance().registerMonitoringClient(fakeMonitoringClient);
415 
416     MonitoringAnnotations annotations =
417         MonitoringAnnotations.newBuilder().add("annotation_name", "annotation_value").build();
418     KeysetHandle rawKeysetHandle =
419         KeysetHandle.newBuilder()
420             .addEntry(KeysetHandle.importKey(rawKey0).withFixedId(43).makePrimary())
421             .setMonitoringAnnotations(annotations)
422             .build();
423     KeysetHandle legacyKeysetHandle =
424         KeysetHandle.newBuilder()
425             .addEntry(KeysetHandle.importKey(legacyKey0).makePrimary())
426             .setMonitoringAnnotations(annotations)
427             .build();
428     KeysetHandle mixedKeysetHandle =
429         KeysetHandle.newBuilder()
430             .addEntry(KeysetHandle.importKey(tinkKey1).makePrimary())
431             .addEntry(KeysetHandle.importKey(rawKey0).withFixedId(43))
432             .addEntry(KeysetHandle.importKey(legacyKey0))
433             .setMonitoringAnnotations(annotations)
434             .build();
435     Mac rawMac = rawKeysetHandle.getPrimitive(Mac.class);
436     Mac legacyMac = legacyKeysetHandle.getPrimitive(Mac.class);
437     Mac mac = mixedKeysetHandle.getPrimitive(Mac.class);
438 
439     byte[] plaintext = "plaintext".getBytes(UTF_8);
440     byte[] tinkTag = mac.computeMac(plaintext);
441     byte[] rawTag = rawMac.computeMac(plaintext);
442     byte[] legacyTag = legacyMac.computeMac(plaintext);
443     mac.verifyMac(tinkTag, plaintext);
444     mac.verifyMac(rawTag, plaintext);
445     mac.verifyMac(legacyTag, plaintext);
446     assertThrows(GeneralSecurityException.class, () -> mac.verifyMac(tinkTag, new byte[0]));
447 
448     List<FakeMonitoringClient.LogEntry> logEntries = fakeMonitoringClient.getLogEntries();
449     assertThat(logEntries).hasSize(6);
450 
451     FakeMonitoringClient.LogEntry tinkComputeEntry = logEntries.get(0);
452     // 5 is tinkKey1's id.
453     assertThat(tinkComputeEntry.getKeyId()).isEqualTo(5);
454     assertThat(tinkComputeEntry.getPrimitive()).isEqualTo("mac");
455     assertThat(tinkComputeEntry.getApi()).isEqualTo("compute");
456     assertThat(tinkComputeEntry.getNumBytesAsInput()).isEqualTo(plaintext.length);
457     assertThat(tinkComputeEntry.getKeysetInfo().getAnnotations()).isEqualTo(annotations);
458 
459     FakeMonitoringClient.LogEntry rawComputeEntry = logEntries.get(1);
460     assertThat(rawComputeEntry.getKeyId()).isEqualTo(43);
461     assertThat(rawComputeEntry.getPrimitive()).isEqualTo("mac");
462     assertThat(rawComputeEntry.getApi()).isEqualTo("compute");
463     assertThat(rawComputeEntry.getNumBytesAsInput()).isEqualTo(plaintext.length);
464     assertThat(rawComputeEntry.getKeysetInfo().getAnnotations()).isEqualTo(annotations);
465 
466     FakeMonitoringClient.LogEntry legacyComputeEntry = logEntries.get(2);
467     // 8 is legacyKey0's id.
468     assertThat(legacyComputeEntry.getKeyId()).isEqualTo(8);
469     assertThat(legacyComputeEntry.getPrimitive()).isEqualTo("mac");
470     assertThat(legacyComputeEntry.getApi()).isEqualTo("compute");
471     assertThat(legacyComputeEntry.getNumBytesAsInput()).isEqualTo(plaintext.length);
472     assertThat(legacyComputeEntry.getKeysetInfo().getAnnotations()).isEqualTo(annotations);
473 
474     FakeMonitoringClient.LogEntry tinkVerifyEntry = logEntries.get(3);
475     // 5 is tinkKey1's id.
476     assertThat(tinkVerifyEntry.getKeyId()).isEqualTo(5);
477     assertThat(tinkVerifyEntry.getPrimitive()).isEqualTo("mac");
478     assertThat(tinkVerifyEntry.getApi()).isEqualTo("verify");
479     assertThat(tinkVerifyEntry.getNumBytesAsInput()).isEqualTo(plaintext.length);
480     assertThat(tinkVerifyEntry.getKeysetInfo().getAnnotations()).isEqualTo(annotations);
481 
482     FakeMonitoringClient.LogEntry rawVerifyEntry = logEntries.get(4);
483     assertThat(rawVerifyEntry.getKeyId()).isEqualTo(43);
484     assertThat(rawVerifyEntry.getPrimitive()).isEqualTo("mac");
485     assertThat(rawVerifyEntry.getApi()).isEqualTo("verify");
486     assertThat(rawVerifyEntry.getNumBytesAsInput()).isEqualTo(plaintext.length);
487     assertThat(rawVerifyEntry.getKeysetInfo().getAnnotations()).isEqualTo(annotations);
488 
489     FakeMonitoringClient.LogEntry legacyVerifyEntry = logEntries.get(5);
490     // 8 is legacyKey0's id.
491     assertThat(legacyVerifyEntry.getKeyId()).isEqualTo(8);
492     assertThat(legacyVerifyEntry.getPrimitive()).isEqualTo("mac");
493     assertThat(legacyVerifyEntry.getApi()).isEqualTo("verify");
494     assertThat(legacyVerifyEntry.getNumBytesAsInput()).isEqualTo(plaintext.length);
495     assertThat(legacyVerifyEntry.getKeysetInfo().getAnnotations()).isEqualTo(annotations);
496 
497     List<FakeMonitoringClient.LogFailureEntry> failures =
498         fakeMonitoringClient.getLogFailureEntries();
499     assertThat(failures).hasSize(1);
500     FakeMonitoringClient.LogFailureEntry verifyFailure = failures.get(0);
501     assertThat(verifyFailure.getPrimitive()).isEqualTo("mac");
502     assertThat(verifyFailure.getApi()).isEqualTo("verify");
503     // 5 is tinkKey1's id.
504     assertThat(verifyFailure.getKeysetInfo().getPrimaryKeyId()).isEqualTo(5);
505     assertThat(verifyFailure.getKeysetInfo().getAnnotations()).isEqualTo(annotations);
506   }
507 
508   public static class AlwaysFailingMac implements Mac {
509 
AlwaysFailingMac(HmacKey key)510     AlwaysFailingMac(HmacKey key) {}
511 
512     @Override
computeMac(final byte[] data)513     public byte[] computeMac(final byte[] data) throws GeneralSecurityException {
514       throw new GeneralSecurityException("fail");
515     }
516 
517     @Override
verifyMac(final byte[] mac, final byte[] data)518     public void verifyMac(final byte[] mac, final byte[] data) throws GeneralSecurityException {
519       throw new GeneralSecurityException("fail");
520     }
521   }
522 
523   @Test
testAlwaysFailingWithAnnotation_hasMonitoring()524   public void testAlwaysFailingWithAnnotation_hasMonitoring() throws Exception {
525     // Test setup.
526     MutablePrimitiveRegistry.resetGlobalInstanceTestOnly();
527     MutablePrimitiveRegistry.globalInstance()
528         .registerPrimitiveConstructor(
529             PrimitiveConstructor.create(AlwaysFailingMac::new, HmacKey.class, Mac.class));
530     MacWrapper.register();
531     HmacProtoSerialization.register();
532     Registry.registerKeyManager(new HmacKeyManager(), true);
533 
534     FakeMonitoringClient fakeMonitoringClient = new FakeMonitoringClient();
535     MutableMonitoringRegistry.globalInstance().clear();
536     MutableMonitoringRegistry.globalInstance().registerMonitoringClient(fakeMonitoringClient);
537 
538     MonitoringAnnotations annotations =
539         MonitoringAnnotations.newBuilder().add("annotation_name", "annotation_value").build();
540     KeysetHandle keysetHandle =
541         KeysetHandle.newBuilder()
542             .addEntry(KeysetHandle.importKey(tinkKey0).makePrimary())
543             .setMonitoringAnnotations(annotations)
544             .build();
545     Mac mac = keysetHandle.getPrimitive(Mac.class);
546 
547     byte[] data = "some data".getBytes(UTF_8);
548     byte[] invalidTag = "an invalid tag".getBytes(UTF_8);
549     byte[] shortInvalidTag = "t".getBytes(UTF_8);
550 
551     // Test active work, including a test with a short tag, because there is a different code path
552     // for this.
553     assertThrows(GeneralSecurityException.class, () -> mac.computeMac(data));
554     assertThrows(GeneralSecurityException.class, () -> mac.verifyMac(invalidTag, data));
555     assertThrows(GeneralSecurityException.class, () -> mac.verifyMac(shortInvalidTag, data));
556 
557     // Assert correctness.
558     assertThat(fakeMonitoringClient.getLogEntries()).isEmpty();
559 
560     List<FakeMonitoringClient.LogFailureEntry> failures =
561         fakeMonitoringClient.getLogFailureEntries();
562     assertThat(failures).hasSize(3);
563     FakeMonitoringClient.LogFailureEntry compFailure = failures.get(0);
564     assertThat(compFailure.getPrimitive()).isEqualTo("mac");
565     assertThat(compFailure.getApi()).isEqualTo("compute");
566     // 4 is tinkKey0's id.
567     assertThat(compFailure.getKeysetInfo().getPrimaryKeyId()).isEqualTo(4);
568     assertThat(compFailure.getKeysetInfo().getAnnotations()).isEqualTo(annotations);
569 
570     FakeMonitoringClient.LogFailureEntry verifyFailure = failures.get(1);
571     assertThat(verifyFailure.getPrimitive()).isEqualTo("mac");
572     assertThat(verifyFailure.getApi()).isEqualTo("verify");
573     // 4 is tinkKey0's id.
574     assertThat(verifyFailure.getKeysetInfo().getPrimaryKeyId()).isEqualTo(4);
575     assertThat(verifyFailure.getKeysetInfo().getAnnotations()).isEqualTo(annotations);
576 
577     FakeMonitoringClient.LogFailureEntry verifyFailure2 = failures.get(2);
578     assertThat(verifyFailure2.getPrimitive()).isEqualTo("mac");
579     assertThat(verifyFailure2.getApi()).isEqualTo("verify");
580     // 4 is tinkKey0's id.
581     assertThat(verifyFailure2.getKeysetInfo().getPrimaryKeyId()).isEqualTo(4);
582     assertThat(verifyFailure2.getKeysetInfo().getAnnotations()).isEqualTo(annotations);
583   }
584 }
585