// Copyright 2023 Google LLC // // 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.internal; 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.InsecureSecretKeyAccess; import com.google.crypto.tink.KeysetHandle; import com.google.crypto.tink.Mac; import com.google.crypto.tink.Registry; import com.google.crypto.tink.aead.AesEaxKey; import com.google.crypto.tink.aead.AesEaxParameters; import com.google.crypto.tink.aead.AesEaxParameters.Variant; import com.google.crypto.tink.mac.ChunkedMac; import com.google.crypto.tink.mac.ChunkedMacComputation; import com.google.crypto.tink.mac.HmacKey; import com.google.crypto.tink.mac.HmacParameters; import com.google.crypto.tink.mac.HmacParameters.HashType; import com.google.crypto.tink.mac.MacConfig; import com.google.crypto.tink.mac.internal.LegacyFullMac; import com.google.crypto.tink.proto.HmacParams; import com.google.crypto.tink.proto.KeyData; import com.google.crypto.tink.proto.KeyData.KeyMaterialType; import com.google.crypto.tink.proto.KeyStatusType; import com.google.crypto.tink.proto.Keyset; import com.google.crypto.tink.proto.OutputPrefixType; import com.google.crypto.tink.util.SecretBytes; import com.google.protobuf.ByteString; import java.nio.ByteBuffer; import java.security.GeneralSecurityException; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; /** Unit tests for {@link RegistryConfiguration}. */ @RunWith(JUnit4.class) public class RegistryConfigurationTest { private static final int HMAC_KEY_SIZE = 20; private static final int HMAC_TAG_SIZE = 10; private static HmacKey rawKey; private static KeyData rawKeyData; private static Keyset.Key rawKeysetKey; private static LegacyProtoKey legacyProtoRawKey; @Before public void setUp() throws GeneralSecurityException { MacConfig.register(); createTestKeys(); } private static void createTestKeys() { try { rawKey = HmacKey.builder() .setParameters( HmacParameters.builder() .setKeySizeBytes(HMAC_KEY_SIZE) .setTagSizeBytes(HMAC_TAG_SIZE) .setVariant(HmacParameters.Variant.NO_PREFIX) .setHashType(HashType.SHA256) .build()) .setKeyBytes(SecretBytes.randomBytes(HMAC_KEY_SIZE)) .setIdRequirement(null) .build(); // Create the proto key artefacts. KeysetHandle keysetHandle = KeysetHandle.newBuilder() .addEntry(KeysetHandle.importKey(rawKey).withRandomId().makePrimary()) .build(); rawKeyData = KeyData.newBuilder() .setValue( com.google.crypto.tink.proto.HmacKey.newBuilder() .setParams( HmacParams.newBuilder() .setHash(com.google.crypto.tink.proto.HashType.SHA256) .setTagSize(HMAC_TAG_SIZE) .build()) .setKeyValue( ByteString.copyFrom( rawKey.getKeyBytes().toByteArray(InsecureSecretKeyAccess.get()))) .build() .toByteString()) .setTypeUrl("type.googleapis.com/google.crypto.tink.HmacKey") .setKeyMaterialType(KeyMaterialType.SYMMETRIC) .build(); rawKeysetKey = Keyset.Key.newBuilder() .setKeyData(rawKeyData) .setStatus(KeyStatusType.ENABLED) .setKeyId(keysetHandle.getPrimary().getId()) .setOutputPrefixType(OutputPrefixType.RAW) .build(); legacyProtoRawKey = new LegacyProtoKey( MutableSerializationRegistry.globalInstance() .serializeKey(rawKey, ProtoKeySerialization.class, InsecureSecretKeyAccess.get()), InsecureSecretKeyAccess.get()); } catch (GeneralSecurityException e) { throw new IllegalStateException(e); } } @Test public void getLegacyPrimitive_matchesRegistry() throws Exception { byte[] plaintext = "plaintext".getBytes(UTF_8); Mac configurationMac = RegistryConfiguration.get().getLegacyPrimitive(rawKeyData, Mac.class); Mac registryMac = Registry.getPrimitive(rawKeyData, Mac.class); assertThat(configurationMac.computeMac(plaintext)).isEqualTo(registryMac.computeMac(plaintext)); } @Test public void getPrimitive_matchesRegistry() throws Exception { byte[] plaintext = "plaintext".getBytes(UTF_8); ChunkedMac configurationMac = RegistryConfiguration.get().getPrimitive(rawKey, ChunkedMac.class); ChunkedMacComputation configurationComputation = configurationMac.createComputation(); ChunkedMac registryMac = MutablePrimitiveRegistry.globalInstance().getPrimitive(rawKey, ChunkedMac.class); ChunkedMacComputation registryComputation = registryMac.createComputation(); configurationComputation.update(ByteBuffer.wrap(plaintext)); registryComputation.update(ByteBuffer.wrap(plaintext)); assertThat(configurationComputation.computeMac()).isEqualTo(registryComputation.computeMac()); } @Test public void wrap_matchesRegistry() throws Exception { byte[] plaintext = "plaintext".getBytes(UTF_8); Mac registryMac = Registry.getPrimitive(rawKeyData, Mac.class); // The following relies on the fact that internally LegacyFullMac uses RegistryConfiguration. Mac wrappedConfigurationMac = RegistryConfiguration.get() .wrap( PrimitiveSet.newBuilder(Mac.class) .addPrimaryFullPrimitive( LegacyFullMac.create(legacyProtoRawKey), legacyProtoRawKey, rawKeysetKey) .build(), Mac.class); assertThat(wrappedConfigurationMac.computeMac(plaintext)) .isEqualTo(registryMac.computeMac(plaintext)); } @Test public void getInputPrimitiveClass_matchesRegistry() throws Exception { assertThat(RegistryConfiguration.get().getInputPrimitiveClass(ChunkedMac.class)) .isEqualTo(Registry.getInputPrimitive(ChunkedMac.class)); } @Test public void getInputPrimitiveClass_returnsNullOnUnregisteredPrimitive() throws Exception { assertThat(RegistryConfiguration.get().getInputPrimitiveClass(Aead.class)) .isNull(); } @Test public void requestingUnregisteredPrimitives_throws() throws GeneralSecurityException { AesEaxKey aesEaxKey = AesEaxKey.builder() .setKeyBytes(SecretBytes.randomBytes(32)) .setIdRequirement(1234) .setParameters( AesEaxParameters.builder() .setIvSizeBytes(16) .setTagSizeBytes(16) .setKeySizeBytes(32) .setVariant(Variant.TINK) .build()) .build(); assertThrows( GeneralSecurityException.class, () -> RegistryConfiguration.get().getPrimitive(aesEaxKey, Aead.class)); assertThrows( GeneralSecurityException.class, () -> RegistryConfiguration.get() .wrap(PrimitiveSet.newBuilder(Aead.class).build(), Aead.class)); } }