@Test
public void testMultipleKeys() throws Exception {

  byte[] keyValue = Random.randBytes(HMAC_KEY_SIZE);
  Key tink = TestUtil.createKey(
        TestUtil.createHmacKeyData(keyValue, 16),
        42,
        KeyStatusType.ENABLED,
        OutputPrefixType.TINK);
  Key legacy = TestUtil.createKey(
        TestUtil.createHmacKeyData(keyValue, 16),
        43,
        KeyStatusType.ENABLED,
        OutputPrefixType.LEGACY);
  Key raw = TestUtil.createKey(
        TestUtil.createHmacKeyData(keyValue, 16),
        44,
        KeyStatusType.ENABLED,
        OutputPrefixType.RAW);
  Key crunchy = TestUtil.createKey(
        TestUtil.createHmacKeyData(keyValue, 16),
        45,
        KeyStatusType.ENABLED,
        OutputPrefixType.CRUNCHY);
  Key[] keys = new Key[] {tink, legacy, raw, crunchy};
  int j = keys.length;
  for (int i = 0; i < j; i++) {
    KeysetHandle keysetHandle = TestUtil.createKeysetHandle(
      TestUtil.createKeyset(
          keys[i],
          keys[(i + 1) % j],
          keys[(i + 2) % j],
          keys[(i + 3) % j]));
    Mac mac = MacFactory.getPrimitive(keysetHandle);
    byte[] plaintext = "plaintext".getBytes("UTF-8");
    byte[] tag = mac.computeMac(plaintext);
    if (!keys[i].getOutputPrefixType().equals(OutputPrefixType.RAW)) {
      byte[] prefix = Arrays.copyOfRange(tag, 0, CryptoFormat.NON_RAW_PREFIX_SIZE);
      assertArrayEquals(prefix, CryptoFormat.getOutputPrefix(keys[i]));
    }
    try {
      mac.verifyMac(tag, plaintext);
    } catch (GeneralSecurityException e) {
      fail("Valid MAC, should not throw exception: " + i);
    }
    // Modify plaintext or tag and make sure the verifyMac failed.
    byte[] plaintextAndTag = Bytes.concat(plaintext, tag);
    for (int b = 0; b < plaintextAndTag.length; b++) {
      for (int bit = 0; bit < 8; bit++) {
        byte[] modified = Arrays.copyOf(plaintextAndTag, plaintextAndTag.length);
        modified[b] ^= (byte) (1 << bit);
        try {
          mac.verifyMac(Arrays.copyOfRange(modified, plaintext.length, modified.length),
              Arrays.copyOfRange(modified, 0, plaintext.length));
          fail("Invalid tag or plaintext, should have thrown exception");
        } catch (GeneralSecurityException expected) {
          // Expected
        }
      }
    }
    // mac with a non-primary RAW key, verify with the keyset
    KeysetHandle keysetHandle2 = TestUtil.createKeysetHandle(
        TestUtil.createKeyset(raw, legacy, tink, crunchy));
    Mac mac2 = MacFactory.getPrimitive(keysetHandle2);
    tag = mac2.computeMac(plaintext);
    try {
      mac.verifyMac(tag, plaintext);
    } catch (GeneralSecurityException e) {
      fail("Valid MAC, should not throw exception");
    }
    // mac with a random key not in the keyset, verify with the keyset should fail
    byte[] keyValue2 = Random.randBytes(HMAC_KEY_SIZE);
    Key random = TestUtil.createKey(
        TestUtil.createHmacKeyData(keyValue2, 16),
        44,
        KeyStatusType.ENABLED,
        OutputPrefixType.TINK);
    keysetHandle2 = TestUtil.createKeysetHandle(
        TestUtil.createKeyset(random));
    mac2 = MacFactory.getPrimitive(keysetHandle2);
    tag = mac2.computeMac(plaintext);
    try {
      mac.verifyMac(tag, plaintext);
      fail("Invalid MAC MAC, should have thrown exception");
    } catch (GeneralSecurityException expected) {
      // Expected
    }
  }
}