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