1 // Copyright 2023 Google LLC 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; 18 19 import static com.google.common.truth.Truth.assertThat; 20 import static org.junit.Assert.assertThrows; 21 22 import com.google.crypto.tink.internal.LegacyProtoParameters; 23 import com.google.crypto.tink.internal.ProtoParametersSerialization; 24 import com.google.crypto.tink.mac.AesCmacParameters; 25 import com.google.crypto.tink.mac.MacConfig; 26 import com.google.crypto.tink.proto.AesCmacKeyFormat; 27 import com.google.crypto.tink.proto.AesCmacParams; 28 import com.google.crypto.tink.proto.KeyTemplate; 29 import com.google.crypto.tink.proto.OutputPrefixType; 30 import com.google.crypto.tink.subtle.Hex; 31 import com.google.protobuf.ByteString; 32 import com.google.protobuf.ExtensionRegistryLite; 33 import java.security.GeneralSecurityException; 34 import org.junit.BeforeClass; 35 import org.junit.Test; 36 import org.junit.runner.RunWith; 37 import org.junit.runners.JUnit4; 38 39 @RunWith(JUnit4.class) 40 public final class TinkProtoParametersFormatTest { 41 42 @BeforeClass setUp()43 public static void setUp() throws GeneralSecurityException { 44 MacConfig.register(); 45 } 46 47 @Test testParseAesCmacFormat()48 public void testParseAesCmacFormat() throws GeneralSecurityException { 49 AesCmacKeyFormat format = 50 AesCmacKeyFormat.newBuilder() 51 .setKeySize(32) 52 .setParams(AesCmacParams.newBuilder().setTagSize(16)) 53 .build(); 54 KeyTemplate template = 55 KeyTemplate.newBuilder() 56 .setValue(format.toByteString()) 57 .setOutputPrefixType(OutputPrefixType.TINK) 58 .setTypeUrl("type.googleapis.com/google.crypto.tink.AesCmacKey") 59 .build(); 60 assertThat(TinkProtoParametersFormat.parse(template.toByteArray())) 61 .isEqualTo( 62 AesCmacParameters.builder() 63 .setKeySizeBytes(32) 64 .setTagSizeBytes(16) 65 .setVariant(AesCmacParameters.Variant.TINK) 66 .build()); 67 } 68 69 @Test testParseInvalidAesCmacFormat_throws()70 public void testParseInvalidAesCmacFormat_throws() throws GeneralSecurityException { 71 AesCmacKeyFormat format = 72 AesCmacKeyFormat.newBuilder() 73 .setKeySize(37) // Invalid Key Size 74 .setParams(AesCmacParams.newBuilder().setTagSize(16)) 75 .build(); 76 KeyTemplate template = 77 KeyTemplate.newBuilder() 78 .setValue(format.toByteString()) 79 .setOutputPrefixType(OutputPrefixType.TINK) 80 .setTypeUrl("type.googleapis.com/google.crypto.tink.AesCmacKey") 81 .build(); 82 assertThrows( 83 GeneralSecurityException.class, 84 () -> TinkProtoParametersFormat.parse(template.toByteArray())); 85 } 86 87 @Test testSerializeAesCmacFormat()88 public void testSerializeAesCmacFormat() throws Exception { 89 AesCmacParameters params = 90 AesCmacParameters.builder() 91 .setKeySizeBytes(32) 92 .setTagSizeBytes(16) 93 .setVariant(AesCmacParameters.Variant.TINK) 94 .build(); 95 96 byte[] serialized = TinkProtoParametersFormat.serialize(params); 97 98 KeyTemplate template = 99 KeyTemplate.parseFrom(serialized, ExtensionRegistryLite.getEmptyRegistry()); 100 101 assertThat(template.getOutputPrefixType()).isEqualTo(OutputPrefixType.TINK); 102 assertThat(template.getTypeUrl()) 103 .isEqualTo("type.googleapis.com/google.crypto.tink.AesCmacKey"); 104 assertThat(AesCmacKeyFormat.parseFrom(template.getValue())) 105 .isEqualTo( 106 AesCmacKeyFormat.newBuilder() 107 .setKeySize(32) 108 .setParams(AesCmacParams.newBuilder().setTagSize(16)) 109 .build()); 110 } 111 112 /** When parsing, if a TypeURL is not recognized we currently always parse into a Legacy object */ 113 @Test testParseToLegacyFormat()114 public void testParseToLegacyFormat() throws Exception { 115 KeyTemplate template = 116 KeyTemplate.newBuilder() 117 .setValue(ByteString.copyFrom(Hex.decode("80"))) 118 .setOutputPrefixType(OutputPrefixType.TINK) 119 .setTypeUrl("SomeInvalidTypeURL") 120 .build(); 121 Parameters parsed = TinkProtoParametersFormat.parse(template.toByteArray()); 122 123 LegacyProtoParameters expected = 124 new LegacyProtoParameters(ProtoParametersSerialization.create(template)); 125 126 assertThat(parsed).isEqualTo(expected); 127 } 128 129 /** When serializing a legacy object, we always succeed, even if an object is registered. */ 130 @Test testSerializeFromLegacyFormat()131 public void testSerializeFromLegacyFormat() throws Exception { 132 KeyTemplate template = 133 KeyTemplate.newBuilder() 134 .setValue(ByteString.copyFrom(Hex.decode("80"))) 135 .setOutputPrefixType(OutputPrefixType.TINK) 136 .setTypeUrl("SomeInvalidTypeURL") 137 .build(); 138 LegacyProtoParameters legacyParameters = 139 new LegacyProtoParameters(ProtoParametersSerialization.create(template)); 140 141 byte[] serialized = TinkProtoParametersFormat.serialize(legacyParameters); 142 143 assertThat(KeyTemplate.parseFrom(serialized, ExtensionRegistryLite.getEmptyRegistry())) 144 .isEqualTo(template); 145 } 146 147 @Test testParseWithSpaceTypeUrl_throws()148 public void testParseWithSpaceTypeUrl_throws() throws Exception { 149 KeyTemplate template = 150 KeyTemplate.newBuilder() 151 .setValue(ByteString.EMPTY) 152 .setOutputPrefixType(OutputPrefixType.TINK) 153 .setTypeUrl("SomeTypeUrlWhichHas OneSpace") 154 .build(); 155 assertThrows( 156 GeneralSecurityException.class, 157 () -> TinkProtoParametersFormat.parse(template.toByteArray())); 158 } 159 } 160