Skip to content
This repository was archived by the owner on Apr 17, 2024. It is now read-only.

Commit

Permalink
Add a test to the MacWrapper that if a key is a MacKey, the OutputPre…
Browse files Browse the repository at this point in the history
…fix is as expected.

MacKeys are more flexible in what the output prefix can be, but if it doesn't match what the wrapper think it should be there could be bugs. So best to test.

PiperOrigin-RevId: 466373087
  • Loading branch information
tholenst authored and copybara-github committed Aug 9, 2022
1 parent dbb5ca7 commit c98c476
Show file tree
Hide file tree
Showing 4 changed files with 136 additions and 5 deletions.
4 changes: 4 additions & 0 deletions java_src/src/main/java/com/google/crypto/tink/mac/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ java_library(
name = "mac_wrapper",
srcs = ["MacWrapper.java"],
deps = [
":mac_key",
"//proto:tink_java_proto",
"//src/main/java/com/google/crypto/tink:crypto_format",
"//src/main/java/com/google/crypto/tink:mac",
Expand All @@ -109,13 +110,15 @@ java_library(
"//src/main/java/com/google/crypto/tink/monitoring:monitoring_client",
"//src/main/java/com/google/crypto/tink/monitoring:monitoring_keyset_info",
"//src/main/java/com/google/crypto/tink/subtle:bytes",
"//src/main/java/com/google/crypto/tink/util:bytes",
],
)

android_library(
name = "mac_wrapper-android",
srcs = ["MacWrapper.java"],
deps = [
":mac_key-android",
"//proto:tink_java_proto_lite",
"//src/main/java/com/google/crypto/tink:crypto_format-android",
"//src/main/java/com/google/crypto/tink:mac-android",
Expand All @@ -127,6 +130,7 @@ android_library(
"//src/main/java/com/google/crypto/tink/monitoring:monitoring_client-android",
"//src/main/java/com/google/crypto/tink/monitoring:monitoring_keyset_info-android",
"//src/main/java/com/google/crypto/tink/subtle:bytes-android",
"//src/main/java/com/google/crypto/tink/util:bytes-android",
],
)

Expand Down
31 changes: 27 additions & 4 deletions java_src/src/main/java/com/google/crypto/tink/mac/MacWrapper.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
import com.google.crypto.tink.monitoring.MonitoringClient;
import com.google.crypto.tink.monitoring.MonitoringKeysetInfo;
import com.google.crypto.tink.proto.OutputPrefixType;
import com.google.crypto.tink.subtle.Bytes;
import com.google.crypto.tink.util.Bytes;
import java.security.GeneralSecurityException;
import java.util.Arrays;
import java.util.List;
Expand Down Expand Up @@ -68,11 +68,11 @@ private WrappedMac(PrimitiveSet<Mac> primitives) {
public byte[] computeMac(final byte[] data) throws GeneralSecurityException {
byte[] data2 = data;
if (primitives.getPrimary().getOutputPrefixType().equals(OutputPrefixType.LEGACY)) {
data2 = Bytes.concat(data, FORMAT_VERSION);
data2 = com.google.crypto.tink.subtle.Bytes.concat(data, FORMAT_VERSION);
}
try {
byte[] output =
Bytes.concat(
com.google.crypto.tink.subtle.Bytes.concat(
primitives.getPrimary().getIdentifier(),
primitives.getPrimary().getPrimitive().computeMac(data2));
computeLogger.log(primitives.getPrimary().getKeyId(), data2.length);
Expand All @@ -97,7 +97,7 @@ public void verifyMac(final byte[] mac, final byte[] data) throws GeneralSecurit
for (PrimitiveSet.Entry<Mac> entry : entries) {
byte[] data2 = data;
if (entry.getOutputPrefixType().equals(OutputPrefixType.LEGACY)) {
data2 = Bytes.concat(data, FORMAT_VERSION);
data2 = com.google.crypto.tink.subtle.Bytes.concat(data, FORMAT_VERSION);
}
try {
entry.getPrimitive().verifyMac(macNoPrefix, data2);
Expand Down Expand Up @@ -128,10 +128,33 @@ public void verifyMac(final byte[] mac, final byte[] data) throws GeneralSecurit
}
}

private void validateMacKeyPrefixes(PrimitiveSet<Mac> primitives)
throws GeneralSecurityException {
for (List<PrimitiveSet.Entry<Mac>> entryList : primitives.getAll()) {
for (PrimitiveSet.Entry<Mac> entry : entryList) {
if (entry.getKey() instanceof MacKey) {
MacKey macKey = (MacKey) entry.getKey();
Bytes expectedOutputPrefix = Bytes.copyFrom(entry.getIdentifier());
if (!expectedOutputPrefix.equals(macKey.getOutputPrefix())) {
throw new GeneralSecurityException(
"Mac Key with parameters "
+ macKey.getParameters()
+ " has wrong output prefix ("
+ macKey.getOutputPrefix()
+ ") instead of ("
+ expectedOutputPrefix
+ ")");
}
}
}
}
}

MacWrapper() {}

@Override
public Mac wrap(final PrimitiveSet<Mac> primitives) throws GeneralSecurityException {
validateMacKeyPrefixes(primitives);
return new WrappedMac(primitives);
}

Expand Down
11 changes: 11 additions & 0 deletions java_src/src/test/java/com/google/crypto/tink/mac/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -106,16 +106,27 @@ java_test(
deps = [
"//proto:tink_java_proto",
"//src/main/java/com/google/crypto/tink:crypto_format",
"//src/main/java/com/google/crypto/tink:key",
"//src/main/java/com/google/crypto/tink:mac",
"//src/main/java/com/google/crypto/tink:primitive_set",
"//src/main/java/com/google/crypto/tink:secret_key_access",
"//src/main/java/com/google/crypto/tink/internal:key_parser",
"//src/main/java/com/google/crypto/tink/internal:mutable_monitoring_registry",
"//src/main/java/com/google/crypto/tink/internal:mutable_serialization_registry",
"//src/main/java/com/google/crypto/tink/internal:proto_key_serialization",
"//src/main/java/com/google/crypto/tink/internal:util",
"//src/main/java/com/google/crypto/tink/internal/testing:fake_monitoring_client",
"//src/main/java/com/google/crypto/tink/mac:mac_config",
"//src/main/java/com/google/crypto/tink/mac:mac_key",
"//src/main/java/com/google/crypto/tink/mac:mac_parameters",
"//src/main/java/com/google/crypto/tink/mac:mac_wrapper",
"//src/main/java/com/google/crypto/tink/monitoring:monitoring_annotations",
"//src/main/java/com/google/crypto/tink/subtle:bytes",
"//src/main/java/com/google/crypto/tink/subtle:random",
"//src/main/java/com/google/crypto/tink/testing:test_util",
"//src/main/java/com/google/crypto/tink/util:bytes",
"@com_google_protobuf//:protobuf_javalite",
"@maven//:com_google_code_findbugs_jsr305",
"@maven//:com_google_truth_truth",
"@maven//:junit_junit",
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,31 +17,40 @@
package com.google.crypto.tink.mac;

import static com.google.common.truth.Truth.assertThat;
import static com.google.crypto.tink.internal.Util.toBytesFromPrintableAscii;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertThrows;

import com.google.crypto.tink.CryptoFormat;
import com.google.crypto.tink.Mac;
import com.google.crypto.tink.PrimitiveSet;
import com.google.crypto.tink.SecretKeyAccess;
import com.google.crypto.tink.internal.KeyParser;
import com.google.crypto.tink.internal.MutableMonitoringRegistry;
import com.google.crypto.tink.internal.MutableSerializationRegistry;
import com.google.crypto.tink.internal.ProtoKeySerialization;
import com.google.crypto.tink.internal.testing.FakeMonitoringClient;
import com.google.crypto.tink.monitoring.MonitoringAnnotations;
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.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 com.google.protobuf.ByteString;
import java.security.GeneralSecurityException;
import java.util.Arrays;
import java.util.List;
import javax.annotation.Nullable;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

/** Tests for MacFactory. */
/** Tests for MacWrapper. */
@RunWith(JUnit4.class)
public class MacWrapperTest {
private static final int HMAC_KEY_SIZE = 20;
Expand Down Expand Up @@ -339,4 +348,88 @@ public void testAlwaysFailingWithAnnotation_hasMonitoring() throws Exception {
assertThat(verifyFailure2.getKeysetInfo().getPrimaryKeyId()).isEqualTo(42);
assertThat(verifyFailure2.getKeysetInfo().getAnnotations()).isEqualTo(annotations);
}

// Returns a key whose output prefix is taken from
private static com.google.crypto.tink.Key parseKeyWithProgrammableOutputPrefix(
ProtoKeySerialization serialization, @Nullable SecretKeyAccess access) {
com.google.crypto.tink.util.Bytes outputPrefix =
com.google.crypto.tink.util.Bytes.copyFrom(serialization.getValue().toByteArray());
return new MacKey() {
@Override
public com.google.crypto.tink.util.Bytes getOutputPrefix() {
return outputPrefix;
}

@Override
public MacParameters getParameters() {
return new MacParameters() {
@Override
public boolean hasIdRequirement() {
throw new UnsupportedOperationException("Not needed in test");
}
};
}

@Override
public Integer getIdRequirementOrNull() {
throw new UnsupportedOperationException("Not needed in test");
}

@Override
public boolean equalsKey(com.google.crypto.tink.Key k) {
throw new UnsupportedOperationException("Not needed in test");
}
};
}

private static final String TYPE_URL_FOR_PROGRAMMABLE_KEY = "typeUrlForProgrammableKey";
@BeforeClass
public static void registerProgrammableOutputPrefixKey() throws Exception {
MutableSerializationRegistry.globalInstance()
.registerKeyParser(
KeyParser.create(
MacWrapperTest::parseKeyWithProgrammableOutputPrefix,
toBytesFromPrintableAscii(TYPE_URL_FOR_PROGRAMMABLE_KEY),
ProtoKeySerialization.class));
}

@Test
public void correctOutputPrefixInKey_creatingWorks() throws Exception {
Key key =
Key.newBuilder()
.setOutputPrefixType(OutputPrefixType.TINK)
.setKeyData(
KeyData.newBuilder()
.setTypeUrl(TYPE_URL_FOR_PROGRAMMABLE_KEY)
.setValue(ByteString.copyFrom(new byte[] {0x01, 0x01, 0x02, 0x03, 0x04}))
.setKeyMaterialType(KeyMaterialType.SYMMETRIC))
.setKeyId(0x01020304)
.setStatus(KeyStatusType.ENABLED)
.build();
// Wrapping would throw before any mac is computed, so we can use any Mac for the test.
PrimitiveSet<Mac> primitives =
PrimitiveSet.newBuilder(Mac.class).addPrimaryPrimitive(new AlwaysFailingMac(), key).build();
new MacWrapper().wrap(primitives);
}

@Test
public void wrongOutputPrefixInKey_creationFails() throws Exception {
Key key =
Key.newBuilder()
.setOutputPrefixType(OutputPrefixType.TINK)
.setKeyData(
KeyData.newBuilder()
.setTypeUrl(TYPE_URL_FOR_PROGRAMMABLE_KEY)
.setValue(ByteString.copyFrom(new byte[] {0x01, 0x01, 0x02, 0x03, 0x04}))
.setKeyMaterialType(KeyMaterialType.SYMMETRIC))
.setKeyId(0x01020305)
.setStatus(KeyStatusType.ENABLED)
.build();
// Wrapping throws before any mac is computed, so we can use an AlwaysFailingMac for the test.
PrimitiveSet<Mac> primitives =
PrimitiveSet.newBuilder(Mac.class).addPrimaryPrimitive(new AlwaysFailingMac(), key).build();
GeneralSecurityException e =
assertThrows(GeneralSecurityException.class, () -> new MacWrapper().wrap(primitives));
assertThat(e).hasMessageThat().contains("has wrong output prefix");
}
}

0 comments on commit c98c476

Please sign in to comment.