blob: 42e517f671d43789e453f67e348356fd2a1d4152 [file] [log] [blame]
// Copyright 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////
package com.google.crypto.tink.aead;
import static com.google.common.truth.Truth.assertThat;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.junit.Assert.assertThrows;
import com.google.crypto.tink.Aead;
import com.google.crypto.tink.CleartextKeysetHandle;
import com.google.crypto.tink.CryptoFormat;
import com.google.crypto.tink.KeysetHandle;
import com.google.crypto.tink.PrimitiveSet;
import com.google.crypto.tink.Registry;
import com.google.crypto.tink.internal.MutableMonitoringRegistry;
import com.google.crypto.tink.internal.testing.FakeMonitoringClient;
import com.google.crypto.tink.monitoring.MonitoringAnnotations;
import com.google.crypto.tink.proto.AesCtrHmacAeadKey;
import com.google.crypto.tink.proto.KeyData;
import com.google.crypto.tink.proto.KeyStatusType;
import com.google.crypto.tink.proto.Keyset;
import com.google.crypto.tink.proto.Keyset.Key;
import com.google.crypto.tink.proto.OutputPrefixType;
import com.google.crypto.tink.subtle.Bytes;
import com.google.crypto.tink.subtle.Random;
import com.google.crypto.tink.testing.TestUtil;
import java.security.GeneralSecurityException;
import java.util.Arrays;
import java.util.List;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.experimental.theories.DataPoints;
import org.junit.experimental.theories.FromDataPoints;
import org.junit.experimental.theories.Theories;
import org.junit.experimental.theories.Theory;
import org.junit.runner.RunWith;
/** Unit tests for {@link AeadWrapper}. */
@RunWith(Theories.class)
public class AeadWrapperTest {
private static AesCtrHmacAeadKey aesCtrHmacAeadKey;
private static AesCtrHmacAeadKey aesCtrHmacAeadKey2;
@BeforeClass
public static void setUpClass() throws Exception {
AeadConfig.register();
int aesKeySize = 16;
int hmacKeySize = 20;
int ivSize = 12;
int tagSize = 16;
aesCtrHmacAeadKey =
AesCtrHmacAeadKey.newBuilder()
.setAesCtrKey(TestUtil.createAesCtrKey(Random.randBytes(aesKeySize), ivSize))
.setHmacKey(TestUtil.createHmacKey(Random.randBytes(hmacKeySize), tagSize)).build();
aesCtrHmacAeadKey2 =
AesCtrHmacAeadKey.newBuilder()
.setAesCtrKey(TestUtil.createAesCtrKey(Random.randBytes(aesKeySize), ivSize))
.setHmacKey(TestUtil.createHmacKey(Random.randBytes(hmacKeySize), tagSize)).build();
}
private static Key getKey(
AesCtrHmacAeadKey aesCtrHmacAeadKey, int keyId, OutputPrefixType prefixType)
throws Exception {
return TestUtil.createKey(
TestUtil.createKeyData(
aesCtrHmacAeadKey,
"type.googleapis.com/google.crypto.tink.AesCtrHmacAeadKey",
KeyData.KeyMaterialType.SYMMETRIC),
keyId,
KeyStatusType.ENABLED,
prefixType);
}
@Theory
public void wrappedRawEncrypt_canBeDecryptedByRawPrimitive() throws Exception {
Key key = getKey(aesCtrHmacAeadKey, /*keyId=*/ 0x66AABBCC, OutputPrefixType.RAW);
Aead rawAead = Registry.getPrimitive(key.getKeyData(), Aead.class);
PrimitiveSet<Aead> primitives =
PrimitiveSet.newBuilder(Aead.class)
.addPrimaryPrimitive(rawAead, key)
.build();
Aead wrappedAead = new AeadWrapper().wrap(primitives);
byte[] plaintext = "plaintext".getBytes(UTF_8);
byte[] associatedData = "associatedData".getBytes(UTF_8);
byte[] ciphertext = wrappedAead.encrypt(plaintext, associatedData);
assertThat(rawAead.decrypt(ciphertext, associatedData)).isEqualTo(plaintext);
}
@Theory
public void wrappedRawDecrypt_decryptsRawCiphertext() throws Exception {
Key key = getKey(aesCtrHmacAeadKey, /*keyId=*/ 0x66AABBCC, OutputPrefixType.RAW);
Aead rawAead = Registry.getPrimitive(key.getKeyData(), Aead.class);
byte[] plaintext = "plaintext".getBytes(UTF_8);
byte[] associatedData = "associatedData".getBytes(UTF_8);
byte[] rawCiphertext = rawAead.encrypt(plaintext, associatedData);
PrimitiveSet<Aead> primitives =
PrimitiveSet.newBuilder(Aead.class)
.addPrimaryPrimitive(rawAead, key)
.build();
Aead wrappedAead = new AeadWrapper().wrap(primitives);
assertThat(wrappedAead.decrypt(rawCiphertext, associatedData)).isEqualTo(plaintext);
byte[] invalid = "invalid".getBytes(UTF_8);
assertThrows(
GeneralSecurityException.class, () -> wrappedAead.decrypt(rawCiphertext, invalid));
assertThrows(
GeneralSecurityException.class, () -> wrappedAead.decrypt(invalid, associatedData));
byte[] ciphertextWithTinkPrefix = Bytes.concat(TestUtil.hexDecode("0166AABBCC"), rawCiphertext);
assertThrows(
GeneralSecurityException.class,
() -> wrappedAead.decrypt(ciphertextWithTinkPrefix, associatedData));
assertThrows(
GeneralSecurityException.class,
() -> wrappedAead.decrypt("".getBytes(UTF_8), associatedData));
}
@Theory
public void wrappedNonRawEncrypt_addsPrefixToRawCiphertext() throws Exception {
Key key = getKey(aesCtrHmacAeadKey, /*keyId=*/ 0x66AABBCC, OutputPrefixType.TINK);
Aead rawAead = Registry.getPrimitive(key.getKeyData(), Aead.class);
PrimitiveSet<Aead> primitives =
PrimitiveSet.newBuilder(Aead.class)
.addPrimaryPrimitive(rawAead, key)
.build();
Aead wrappedAead = new AeadWrapper().wrap(primitives);
byte[] plaintext = "plaintext".getBytes(UTF_8);
byte[] associatedData = "associatedData".getBytes(UTF_8);
byte[] ciphertext = wrappedAead.encrypt(plaintext, associatedData);
byte[] tinkPrefix = Arrays.copyOf(ciphertext, 5);
byte[] ciphertextWithoutPrefix =
Arrays.copyOfRange(ciphertext, 5, ciphertext.length);
assertThat(tinkPrefix).isEqualTo(TestUtil.hexDecode("0166AABBCC"));
assertThat(rawAead.decrypt(ciphertextWithoutPrefix, associatedData)).isEqualTo(plaintext);
}
@Theory
public void wrappedNonRawDecrypt_decryptsRawCiphertextWithPrefix() throws Exception {
Key key = getKey(aesCtrHmacAeadKey, /*keyId=*/ 0x66AABBCC, OutputPrefixType.TINK);
Aead rawAead = Registry.getPrimitive(key.getKeyData(), Aead.class);
PrimitiveSet<Aead> primitives =
PrimitiveSet.newBuilder(Aead.class)
.addPrimaryPrimitive(rawAead, key)
.build();
Aead wrappedAead = new AeadWrapper().wrap(primitives);
byte[] plaintext = "plaintext".getBytes(UTF_8);
byte[] associatedData = "associatedData".getBytes(UTF_8);
byte[] rawCiphertext = rawAead.encrypt(plaintext, associatedData);
byte[] rawCiphertextWithTinkPrefix =
Bytes.concat(TestUtil.hexDecode("0166AABBCC"), rawCiphertext);
assertThat(wrappedAead.decrypt(rawCiphertextWithTinkPrefix, associatedData))
.isEqualTo(plaintext);
byte[] invalid = "invalid".getBytes(UTF_8);
assertThrows(
GeneralSecurityException.class,
() -> wrappedAead.decrypt(rawCiphertextWithTinkPrefix, invalid));
assertThrows(
GeneralSecurityException.class,
() -> wrappedAead.decrypt(invalid, associatedData));
assertThrows(
GeneralSecurityException.class,
() -> wrappedAead.decrypt("".getBytes(UTF_8), associatedData));
}
@DataPoints("outputPrefixType")
public static final OutputPrefixType[] OUTPUT_PREFIX_TYPES =
new OutputPrefixType[] {
OutputPrefixType.LEGACY,
OutputPrefixType.CRUNCHY,
OutputPrefixType.TINK,
OutputPrefixType.RAW
};
@Theory
public void encrytAndDecrypt_success(
@FromDataPoints("outputPrefixType") OutputPrefixType prefix) throws Exception {
Key key = getKey(aesCtrHmacAeadKey, /*keyId=*/ 123, prefix);
Aead aead =
new AeadWrapper()
.wrap(TestUtil.createPrimitiveSet(TestUtil.createKeyset(key), Aead.class));
byte[] plaintext = "plaintext".getBytes(UTF_8);
byte[] associatedData = "associatedData".getBytes(UTF_8);
byte[] ciphertext = aead.encrypt(plaintext, associatedData);
assertThat(aead.decrypt(ciphertext, associatedData)).isEqualTo(plaintext);
byte[] invalid = "invalid".getBytes(UTF_8);
assertThrows(GeneralSecurityException.class, () -> aead.decrypt(ciphertext, invalid));
assertThrows(
GeneralSecurityException.class,
() -> aead.decrypt(invalid, associatedData));
assertThrows(
GeneralSecurityException.class,
() -> aead.decrypt("".getBytes(UTF_8), associatedData));
// decrypt with a different key should fail
Key otherKey = getKey(aesCtrHmacAeadKey2, /*keyId=*/ 234, prefix);
Aead otherAead =
new AeadWrapper()
.wrap(TestUtil.createPrimitiveSet(TestUtil.createKeyset(otherKey), Aead.class));
assertThrows(
GeneralSecurityException.class, () -> otherAead.decrypt(ciphertext, associatedData));
}
@Theory
public void decryptWorksIfCiphertextIsValidForAnyPrimitiveInThePrimitiveSet(
@FromDataPoints("outputPrefixType") OutputPrefixType prefix1,
@FromDataPoints("outputPrefixType") OutputPrefixType prefix2)
throws Exception {
Key key1 = getKey(aesCtrHmacAeadKey, /*keyId=*/ 123, prefix1);
Key key2 = getKey(aesCtrHmacAeadKey2, /*keyId=*/ 234, prefix2);
Aead aead1 =
new AeadWrapper()
.wrap(TestUtil.createPrimitiveSet(TestUtil.createKeyset(key1), Aead.class));
Aead aead2 =
new AeadWrapper()
.wrap(TestUtil.createPrimitiveSet(TestUtil.createKeyset(key2), Aead.class));
Aead aead12 =
new AeadWrapper()
.wrap(TestUtil.createPrimitiveSet(TestUtil.createKeyset(key1, key2), Aead.class));
byte[] plaintext = "plaintext".getBytes(UTF_8);
byte[] associatedData = "associatedData".getBytes(UTF_8);
byte[] ciphertext1 = aead1.encrypt(plaintext, associatedData);
byte[] ciphertext2 = aead2.encrypt(plaintext, associatedData);
assertThat(aead12.decrypt(ciphertext1, associatedData)).isEqualTo(plaintext);
assertThat(aead12.decrypt(ciphertext2, associatedData)).isEqualTo(plaintext);
}
@Theory
public void encryptUsesPrimaryPrimitive()
throws Exception {
Key key1 = getKey(aesCtrHmacAeadKey, /*keyId=*/ 123, OutputPrefixType.TINK);
Key key2 = getKey(aesCtrHmacAeadKey2, /*keyId=*/ 234, OutputPrefixType.TINK);
Aead aead1 =
new AeadWrapper()
.wrap(TestUtil.createPrimitiveSet(TestUtil.createKeyset(key1), Aead.class));
Aead aead2 =
new AeadWrapper()
.wrap(TestUtil.createPrimitiveSet(TestUtil.createKeyset(key2), Aead.class));
Aead aead12 =
new AeadWrapper()
.wrap(
TestUtil.createPrimitiveSet(
TestUtil.createKeyset(/*primary=*/ key1, key2), Aead.class));
byte[] plaintext = "plaintext".getBytes(UTF_8);
byte[] associatedData = "associatedData".getBytes(UTF_8);
byte[] ciphertext = aead12.encrypt(plaintext, associatedData);
// key1 is the primary key of aead12. Therefore, aead1 should be able to decrypt, and aead2 not.
assertThat(aead1.decrypt(ciphertext, associatedData)).isEqualTo(plaintext);
assertThrows(
GeneralSecurityException.class, () -> aead2.decrypt(ciphertext, associatedData));
}
@Theory
public void decryptFailsIfEncryptedWithOtherKeyEvenIfKeyIdsAreEqual(
@FromDataPoints("outputPrefixType") OutputPrefixType prefix) throws Exception {
Key key1 = getKey(aesCtrHmacAeadKey, /*keyId=*/ 123, prefix);
Key key2 = getKey(aesCtrHmacAeadKey2, /*keyId=*/ 123, prefix);
Aead aead =
new AeadWrapper()
.wrap(TestUtil.createPrimitiveSet(TestUtil.createKeyset(key1), Aead.class));
Aead aead2 =
new AeadWrapper()
.wrap(TestUtil.createPrimitiveSet(TestUtil.createKeyset(key2), Aead.class));
byte[] plaintext = "plaintext".getBytes(UTF_8);
byte[] associatedData = "associatedData".getBytes(UTF_8);
byte[] ciphertext = aead.encrypt(plaintext, associatedData);
assertThrows(
GeneralSecurityException.class, () -> aead2.decrypt(ciphertext, associatedData));
}
@DataPoints("nonRawOutputPrefixType")
public static final OutputPrefixType[] NON_RAW_OUTPUT_PREFIX_TYPES =
new OutputPrefixType[] {
OutputPrefixType.LEGACY, OutputPrefixType.CRUNCHY, OutputPrefixType.TINK
};
@Theory
public void nonRawKeysWithSameKeyMaterialButDifferentKeyIds_decryptFails(
@FromDataPoints("nonRawOutputPrefixType") OutputPrefixType prefix) throws Exception {
Key key1 = getKey(aesCtrHmacAeadKey, /*keyId=*/ 123, prefix);
Key key2 = getKey(aesCtrHmacAeadKey, /*keyId=*/ 234, prefix);
Aead aead =
new AeadWrapper()
.wrap(TestUtil.createPrimitiveSet(TestUtil.createKeyset(key1), Aead.class));
Aead aead2 =
new AeadWrapper()
.wrap(TestUtil.createPrimitiveSet(TestUtil.createKeyset(key2), Aead.class));
byte[] plaintext = "plaintext".getBytes(UTF_8);
byte[] associatedData = "associatedData".getBytes(UTF_8);
byte[] ciphertext = aead.encrypt(plaintext, associatedData);
assertThrows(
GeneralSecurityException.class, () -> aead2.decrypt(ciphertext, associatedData));
}
@Theory
public void rawKeysWithSameKeyMaterialButDifferentKeyIds_decryptWorks() throws Exception {
Key key1 = getKey(aesCtrHmacAeadKey, /*keyId=*/ 123, OutputPrefixType.RAW);
Key key2 = getKey(aesCtrHmacAeadKey, /*keyId=*/ 234, OutputPrefixType.RAW);
Aead aead =
new AeadWrapper()
.wrap(TestUtil.createPrimitiveSet(TestUtil.createKeyset(key1), Aead.class));
Aead aead2 =
new AeadWrapper()
.wrap(TestUtil.createPrimitiveSet(TestUtil.createKeyset(key2), Aead.class));
byte[] plaintext = "plaintext".getBytes(UTF_8);
byte[] associatedData = "associatedData".getBytes(UTF_8);
byte[] ciphertext = aead.encrypt(plaintext, associatedData);
assertThat(aead2.decrypt(ciphertext, associatedData)).isEqualTo(plaintext);
}
@Theory
public void noPrimary_decryptWorks() throws Exception {
Key key = getKey(aesCtrHmacAeadKey, /*keyId=*/ 123, OutputPrefixType.TINK);
Aead rawAead = Registry.getPrimitive(key.getKeyData(), Aead.class);
Aead wrappedAead = new AeadWrapper().wrap(
PrimitiveSet.newBuilder(Aead.class)
.addPrimaryPrimitive(rawAead, key)
.build());
Aead wrappedAeadWithoutPrimary = new AeadWrapper().wrap(
PrimitiveSet.newBuilder(Aead.class)
.addPrimitive(rawAead, key)
.build());
byte[] plaintext = "plaintext".getBytes(UTF_8);
byte[] associatedData = "associatedData".getBytes(UTF_8);
byte[] ciphertext = wrappedAead.encrypt(plaintext, associatedData);
assertThat(wrappedAeadWithoutPrimary.decrypt(ciphertext, associatedData)).isEqualTo(plaintext);
}
@Theory
public void noPrimary_encryptThrowsNullPointerException() throws Exception {
Key key = getKey(aesCtrHmacAeadKey, /*keyId=*/ 123, OutputPrefixType.TINK);
Aead rawAead = Registry.getPrimitive(key.getKeyData(), Aead.class);
Aead wrappedAeadWithoutPrimary = new AeadWrapper().wrap(
PrimitiveSet.newBuilder(Aead.class)
.addPrimitive(rawAead, key)
.build());
byte[] plaintext = "plaintext".getBytes(UTF_8);
byte[] associatedData = "associatedData".getBytes(UTF_8);
// This usually should not happen, since the wrapper is generated by KeysetHandle,
// which validates the keyset. See getPrimitiveFromKeysetHandleWithoutPrimary_throws test.
assertThrows(
NullPointerException.class,
() -> wrappedAeadWithoutPrimary.encrypt(plaintext, associatedData));
}
@Theory
public void getPrimitiveFromKeysetHandleWithoutPrimary_throws() throws Exception {
Keyset keysetWithoutPrimary =
Keyset.newBuilder()
.addKey(getKey(aesCtrHmacAeadKey, /*keyId=*/ 123, OutputPrefixType.TINK))
.build();
KeysetHandle keysetHandle = CleartextKeysetHandle.fromKeyset(keysetWithoutPrimary);
assertThrows(
GeneralSecurityException.class, () -> keysetHandle.getPrimitive(Aead.class));
}
@Test
public void testAeadWithoutAnnotations_hasNoMonitoring() throws Exception {
FakeMonitoringClient fakeMonitoringClient = new FakeMonitoringClient();
MutableMonitoringRegistry.globalInstance().clear();
MutableMonitoringRegistry.globalInstance().registerMonitoringClient(fakeMonitoringClient);
Aead aead =
new AeadWrapper()
.wrap(
TestUtil.createPrimitiveSet(
TestUtil.createKeyset(
getKey(aesCtrHmacAeadKey, /*keyId=*/ 123, OutputPrefixType.TINK)),
Aead.class));
byte[] plaintext = "plaintext".getBytes(UTF_8);
byte[] associatedData = "associatedData".getBytes(UTF_8);
byte[] ciphertext = aead.encrypt(plaintext, associatedData);
assertThat(aead.decrypt(ciphertext, associatedData)).isEqualTo(plaintext);
assertThrows(
GeneralSecurityException.class, () -> aead.decrypt(ciphertext, "invalid".getBytes(UTF_8)));
// Without annotations, nothing gets logged.
assertThat(fakeMonitoringClient.getLogEntries()).isEmpty();
assertThat(fakeMonitoringClient.getLogFailureEntries()).isEmpty();
}
@Test
public void testAeadWithAnnotations_hasMonitoring() throws Exception {
FakeMonitoringClient fakeMonitoringClient = new FakeMonitoringClient();
MutableMonitoringRegistry.globalInstance().clear();
MutableMonitoringRegistry.globalInstance().registerMonitoringClient(fakeMonitoringClient);
Key key1 = getKey(aesCtrHmacAeadKey, /*keyId=*/ 42, OutputPrefixType.TINK);
Key key2 = getKey(aesCtrHmacAeadKey, /*keyId=*/ 43, OutputPrefixType.RAW);
byte[] plaintext = Random.randBytes(20);
byte[] plaintext2 = Random.randBytes(30);
byte[] associatedData = Random.randBytes(40);
// generate ciphertext2 using key2
Aead aead2 =
new AeadWrapper()
.wrap(TestUtil.createPrimitiveSet(TestUtil.createKeyset(key2), Aead.class));
byte[] ciphertext2 = aead2.encrypt(plaintext2, associatedData);
MonitoringAnnotations annotations =
MonitoringAnnotations.newBuilder().add("annotation_name", "annotation_value").build();
PrimitiveSet<Aead> primitives =
TestUtil.createPrimitiveSetWithAnnotations(
TestUtil.createKeyset(key1, key2), // key1 is the primary key
annotations,
Aead.class);
Aead aead = new AeadWrapper().wrap(primitives);
byte[] ciphertext = aead.encrypt(plaintext, associatedData); // uses key1 to encrypt
byte[] decrypted = aead.decrypt(ciphertext, associatedData);
assertThat(decrypted).isEqualTo(plaintext);
byte[] decrypted2 = aead.decrypt(ciphertext2, associatedData);
assertThat(decrypted2).isEqualTo(plaintext2);
assertThrows(GeneralSecurityException.class, () -> aead.decrypt(ciphertext, new byte[0]));
List<FakeMonitoringClient.LogEntry> logEntries = fakeMonitoringClient.getLogEntries();
assertThat(logEntries).hasSize(3);
FakeMonitoringClient.LogEntry encEntry = logEntries.get(0);
assertThat(encEntry.getKeyId()).isEqualTo(42);
assertThat(encEntry.getPrimitive()).isEqualTo("aead");
assertThat(encEntry.getApi()).isEqualTo("encrypt");
assertThat(encEntry.getNumBytesAsInput()).isEqualTo(plaintext.length);
assertThat(encEntry.getKeysetInfo().getAnnotations()).isEqualTo(annotations);
FakeMonitoringClient.LogEntry decEntry = logEntries.get(1);
assertThat(decEntry.getKeyId()).isEqualTo(42);
assertThat(decEntry.getPrimitive()).isEqualTo("aead");
assertThat(decEntry.getApi()).isEqualTo("decrypt");
// ciphertext was encrypted with key1, which has a TINK ouput prefix. This adds a 5 bytes prefix
// to the ciphertext. This prefix is not included in getNumBytesAsInput.
assertThat(decEntry.getNumBytesAsInput())
.isEqualTo(ciphertext.length - CryptoFormat.NON_RAW_PREFIX_SIZE);
assertThat(decEntry.getKeysetInfo().getAnnotations()).isEqualTo(annotations);
FakeMonitoringClient.LogEntry dec2Entry = logEntries.get(2);
assertThat(dec2Entry.getKeyId()).isEqualTo(43);
assertThat(dec2Entry.getPrimitive()).isEqualTo("aead");
assertThat(dec2Entry.getApi()).isEqualTo("decrypt");
// ciphertext2 was encrypted with key2, which has a RAW ouput prefix.
assertThat(dec2Entry.getNumBytesAsInput()).isEqualTo(ciphertext2.length);
assertThat(dec2Entry.getKeysetInfo().getAnnotations()).isEqualTo(annotations);
List<FakeMonitoringClient.LogFailureEntry> failures =
fakeMonitoringClient.getLogFailureEntries();
assertThat(failures).hasSize(1);
FakeMonitoringClient.LogFailureEntry decFailure = failures.get(0);
assertThat(decFailure.getPrimitive()).isEqualTo("aead");
assertThat(decFailure.getApi()).isEqualTo("decrypt");
assertThat(decFailure.getKeysetInfo().getPrimaryKeyId()).isEqualTo(42);
assertThat(decFailure.getKeysetInfo().getAnnotations()).isEqualTo(annotations);
}
private static class AlwaysFailingAead implements Aead {
public AlwaysFailingAead() {}
@Override
public byte[] encrypt(byte[] plaintext, byte[] aad) throws GeneralSecurityException {
throw new GeneralSecurityException("fail");
}
@Override
public byte[] decrypt(byte[] ciphertext, byte[] aad) throws GeneralSecurityException {
throw new GeneralSecurityException("fail");
}
}
@Test
public void testFailingAeadWithAnnotations_hasMonitoring() throws Exception {
FakeMonitoringClient fakeMonitoringClient = new FakeMonitoringClient();
MutableMonitoringRegistry.globalInstance().clear();
MutableMonitoringRegistry.globalInstance().registerMonitoringClient(fakeMonitoringClient);
MonitoringAnnotations annotations =
MonitoringAnnotations.newBuilder().add("annotation_name", "annotation_value").build();
PrimitiveSet<Aead> primitives =
PrimitiveSet.newBuilder(Aead.class)
.setAnnotations(annotations)
.addPrimaryPrimitive(
new AlwaysFailingAead(),
getKey(aesCtrHmacAeadKey, /*keyId=*/ 42, OutputPrefixType.TINK))
.build();
Aead aead = new AeadWrapper().wrap(primitives);
byte[] randomBytes = Random.randBytes(20);
byte[] associatedData = Random.randBytes(20);
assertThrows(GeneralSecurityException.class, () -> aead.encrypt(randomBytes, associatedData));
assertThrows(GeneralSecurityException.class, () -> aead.decrypt(randomBytes, associatedData));
assertThat(fakeMonitoringClient.getLogEntries()).isEmpty();
List<FakeMonitoringClient.LogFailureEntry> failures =
fakeMonitoringClient.getLogFailureEntries();
assertThat(failures).hasSize(2);
FakeMonitoringClient.LogFailureEntry encFailure = failures.get(0);
assertThat(encFailure.getPrimitive()).isEqualTo("aead");
assertThat(encFailure.getApi()).isEqualTo("encrypt");
assertThat(encFailure.getKeysetInfo().getPrimaryKeyId()).isEqualTo(42);
assertThat(encFailure.getKeysetInfo().getAnnotations()).isEqualTo(annotations);
FakeMonitoringClient.LogFailureEntry decFailure = failures.get(1);
assertThat(decFailure.getPrimitive()).isEqualTo("aead");
assertThat(decFailure.getApi()).isEqualTo("decrypt");
assertThat(decFailure.getKeysetInfo().getPrimaryKeyId()).isEqualTo(42);
assertThat(decFailure.getKeysetInfo().getAnnotations()).isEqualTo(annotations);
}
}