• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 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.mac;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 import static org.junit.Assert.assertTrue;
21 
22 import com.google.crypto.tink.InsecureSecretKeyAccess;
23 import com.google.crypto.tink.Key;
24 import com.google.crypto.tink.KeyTemplate;
25 import com.google.crypto.tink.KeyTemplates;
26 import com.google.crypto.tink.KeysetHandle;
27 import com.google.crypto.tink.Mac;
28 import com.google.crypto.tink.Parameters;
29 import com.google.crypto.tink.RegistryConfiguration;
30 import com.google.crypto.tink.TinkProtoKeysetFormat;
31 import com.google.crypto.tink.internal.KeyManagerRegistry;
32 import com.google.crypto.tink.internal.SlowInputStream;
33 import com.google.crypto.tink.mac.internal.HmacTestUtil;
34 import com.google.crypto.tink.mac.internal.HmacTestUtil.HmacTestVector;
35 import com.google.crypto.tink.subtle.Hex;
36 import com.google.crypto.tink.util.SecretBytes;
37 import java.io.ByteArrayInputStream;
38 import java.nio.ByteBuffer;
39 import java.util.Arrays;
40 import java.util.Set;
41 import java.util.TreeSet;
42 import javax.annotation.Nullable;
43 import org.junit.Before;
44 import org.junit.Test;
45 import org.junit.experimental.theories.DataPoints;
46 import org.junit.experimental.theories.FromDataPoints;
47 import org.junit.experimental.theories.Theories;
48 import org.junit.experimental.theories.Theory;
49 import org.junit.runner.RunWith;
50 
51 /** Unit tests for {@link HmacKeyManager}. */
52 @RunWith(Theories.class)
53 public class HmacKeyManagerTest {
54   @Before
register()55   public void register() throws Exception {
56     MacConfig.register();
57   }
58 
59   @Test
testKeyManagerRegistered()60   public void testKeyManagerRegistered() throws Exception {
61     assertThat(
62             KeyManagerRegistry.globalInstance()
63                 .getKeyManager("type.googleapis.com/google.crypto.tink.HmacKey", Mac.class))
64         .isNotNull();
65   }
66 
67   @Test
createKey_multipleTimes()68   public void createKey_multipleTimes() throws Exception {
69     HmacParameters parameters =
70         HmacParameters.builder()
71             .setKeySizeBytes(32)
72             .setTagSizeBytes(16)
73             .setHashType(HmacParameters.HashType.SHA256)
74             .setVariant(HmacParameters.Variant.TINK)
75             .build();
76     int numKeys = 100;
77     Set<String> keys = new TreeSet<>();
78     for (int i = 0; i < numKeys; ++i) {
79       KeysetHandle handle = KeysetHandle.generateNew(parameters);
80       com.google.crypto.tink.mac.HmacKey macKey =
81           (com.google.crypto.tink.mac.HmacKey) handle.getAt(0).getKey();
82       keys.add(Hex.encode(macKey.getKeyBytes().toByteArray(InsecureSecretKeyAccess.get())));
83     }
84     assertThat(keys).hasSize(numKeys);
85   }
86 
87   @Test
testHmacSha256HalfDigestTemplate()88   public void testHmacSha256HalfDigestTemplate() throws Exception {
89     KeyTemplate template = HmacKeyManager.hmacSha256HalfDigestTemplate();
90     assertThat(template.toParameters())
91         .isEqualTo(
92             HmacParameters.builder()
93                 .setKeySizeBytes(32)
94                 .setTagSizeBytes(16)
95                 .setHashType(HmacParameters.HashType.SHA256)
96                 .setVariant(HmacParameters.Variant.TINK)
97                 .build());
98   }
99 
100   @Test
testHmacSha256Template()101   public void testHmacSha256Template() throws Exception {
102     KeyTemplate template = HmacKeyManager.hmacSha256Template();
103     assertThat(template.toParameters())
104         .isEqualTo(
105             HmacParameters.builder()
106                 .setKeySizeBytes(32)
107                 .setTagSizeBytes(32)
108                 .setHashType(HmacParameters.HashType.SHA256)
109                 .setVariant(HmacParameters.Variant.TINK)
110                 .build());
111   }
112 
113   @Test
testHmacSha512HalfDigestTemplate()114   public void testHmacSha512HalfDigestTemplate() throws Exception {
115     KeyTemplate template = HmacKeyManager.hmacSha512HalfDigestTemplate();
116     assertThat(template.toParameters())
117         .isEqualTo(
118             HmacParameters.builder()
119                 .setKeySizeBytes(64)
120                 .setTagSizeBytes(32)
121                 .setHashType(HmacParameters.HashType.SHA512)
122                 .setVariant(HmacParameters.Variant.TINK)
123                 .build());
124   }
125 
126   @Test
testHmacSha512Template()127   public void testHmacSha512Template() throws Exception {
128     KeyTemplate template = HmacKeyManager.hmacSha512Template();
129     assertThat(template.toParameters())
130         .isEqualTo(
131             HmacParameters.builder()
132                 .setKeySizeBytes(64)
133                 .setTagSizeBytes(64)
134                 .setHashType(HmacParameters.HashType.SHA512)
135                 .setVariant(HmacParameters.Variant.TINK)
136                 .build());
137   }
138 
139   @Test
testKeyTemplatesWork()140   public void testKeyTemplatesWork() throws Exception {
141     Parameters p = HmacKeyManager.hmacSha256Template().toParameters();
142     assertThat(KeysetHandle.generateNew(p).getAt(0).getKey().getParameters()).isEqualTo(p);
143 
144     p = HmacKeyManager.hmacSha256HalfDigestTemplate().toParameters();
145     assertThat(KeysetHandle.generateNew(p).getAt(0).getKey().getParameters()).isEqualTo(p);
146 
147     p = HmacKeyManager.hmacSha512Template().toParameters();
148     assertThat(KeysetHandle.generateNew(p).getAt(0).getKey().getParameters()).isEqualTo(p);
149 
150     p = HmacKeyManager.hmacSha512HalfDigestTemplate().toParameters();
151     assertThat(KeysetHandle.generateNew(p).getAt(0).getKey().getParameters()).isEqualTo(p);
152   }
153 
154   @DataPoints("templateNames")
155   public static final String[] KEY_TEMPLATES =
156       new String[] {
157         "HMAC_SHA256_128BITTAG",
158         "HMAC_SHA256_128BITTAG_RAW",
159         "HMAC_SHA256_256BITTAG",
160         "HMAC_SHA256_256BITTAG_RAW",
161         "HMAC_SHA512_128BITTAG",
162         "HMAC_SHA512_128BITTAG_RAW",
163         "HMAC_SHA512_256BITTAG",
164         "HMAC_SHA512_256BITTAG_RAW",
165         "HMAC_SHA512_512BITTAG",
166         "HMAC_SHA512_512BITTAG_RAW"
167       };
168 
169   @Theory
testTemplates(@romDataPoints"templateNames") String templateName)170   public void testTemplates(@FromDataPoints("templateNames") String templateName) throws Exception {
171     KeysetHandle h = KeysetHandle.generateNew(KeyTemplates.get(templateName));
172     assertThat(h.size()).isEqualTo(1);
173     assertThat(h.getAt(0).getKey().getParameters())
174         .isEqualTo(KeyTemplates.get(templateName).toParameters());
175   }
176 
177   @Theory
testCreateKeyFromRandomness(@romDataPoints"templateNames") String templateName)178   public void testCreateKeyFromRandomness(@FromDataPoints("templateNames") String templateName)
179       throws Exception {
180     byte[] keyMaterial =
181         new byte[] {
182           0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
183           25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46,
184           47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68,
185         };
186     HmacParameters parameters = (HmacParameters) KeyTemplates.get(templateName).toParameters();
187     com.google.crypto.tink.mac.HmacKey key =
188         HmacKeyManager.createHmacKeyFromRandomness(
189             parameters,
190             new ByteArrayInputStream(keyMaterial),
191             parameters.hasIdRequirement() ? 123 : null,
192             InsecureSecretKeyAccess.get());
193     byte[] expectedKeyBytes = Arrays.copyOf(keyMaterial, parameters.getKeySizeBytes());
194     Key expectedKey =
195         com.google.crypto.tink.mac.HmacKey.builder()
196             .setParameters(parameters)
197             .setIdRequirement(parameters.hasIdRequirement() ? 123 : null)
198             .setKeyBytes(SecretBytes.copyFrom(expectedKeyBytes, InsecureSecretKeyAccess.get()))
199             .build();
200     assertTrue(key.equalsKey(expectedKey));
201   }
202 
203   @Test
testCreateKeyFromRandomness_slowInputStream_works()204   public void testCreateKeyFromRandomness_slowInputStream_works() throws Exception {
205     byte[] keyMaterial =
206         new byte[] {
207           0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
208           25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46,
209           47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68,
210         };
211     HmacParameters parameters =
212         HmacParameters.builder()
213             .setKeySizeBytes(64)
214             .setTagSizeBytes(64)
215             .setHashType(HmacParameters.HashType.SHA512)
216             .setVariant(HmacParameters.Variant.TINK)
217             .build();
218     com.google.crypto.tink.mac.HmacKey key =
219         HmacKeyManager.createHmacKeyFromRandomness(
220             parameters, SlowInputStream.copyFrom(keyMaterial), 7975, InsecureSecretKeyAccess.get());
221     byte[] expectedKeyBytes = Arrays.copyOf(keyMaterial, parameters.getKeySizeBytes());
222     Key expectedKey =
223         com.google.crypto.tink.mac.HmacKey.builder()
224             .setParameters(parameters)
225             .setIdRequirement(7975)
226             .setKeyBytes(SecretBytes.copyFrom(expectedKeyBytes, InsecureSecretKeyAccess.get()))
227             .build();
228     assertTrue(key.equalsKey(expectedKey));
229   }
230 
231   @DataPoints("hmacTestVectors")
232   public static final HmacTestVector[] HMAC_TEST_VECTORS = HmacTestUtil.HMAC_TEST_VECTORS;
233 
234   @Theory
testGetPrimitive_chunkedMac_works(@romDataPoints"hmacTestVectors") HmacTestVector t)235   public void testGetPrimitive_chunkedMac_works(@FromDataPoints("hmacTestVectors") HmacTestVector t)
236       throws Exception {
237     KeysetHandle.Builder.Entry entry = KeysetHandle.importKey(t.key).makePrimary();
238     @Nullable Integer id = t.key.getIdRequirementOrNull();
239     if (id == null) {
240       entry.withRandomId();
241     } else {
242       entry.withFixedId(id);
243     }
244     KeysetHandle handle = KeysetHandle.newBuilder().addEntry(entry).build();
245     ChunkedMac chunkedMac = handle.getPrimitive(RegistryConfiguration.get(), ChunkedMac.class);
246 
247     ChunkedMacComputation chunkedMacComputation = chunkedMac.createComputation();
248     chunkedMacComputation.update(ByteBuffer.wrap(t.message).asReadOnlyBuffer());
249     assertThat(t.tag).isEqualTo(chunkedMacComputation.computeMac());
250 
251     ChunkedMacVerification chunkedHmacVerification = chunkedMac.createVerification(t.tag);
252     chunkedHmacVerification.update(ByteBuffer.wrap(t.message));
253     chunkedHmacVerification.verifyMac();
254   }
255 
256   @Theory
testGetPrimitive_mac_works(@romDataPoints"hmacTestVectors") HmacTestVector t)257   public void testGetPrimitive_mac_works(@FromDataPoints("hmacTestVectors") HmacTestVector t)
258       throws Exception {
259     KeysetHandle.Builder.Entry entry = KeysetHandle.importKey(t.key).makePrimary();
260     @Nullable Integer id = t.key.getIdRequirementOrNull();
261     if (id == null) {
262       entry.withRandomId();
263     } else {
264       entry.withFixedId(id);
265     }
266     KeysetHandle handle = KeysetHandle.newBuilder().addEntry(entry).build();
267     Mac mac = handle.getPrimitive(RegistryConfiguration.get(), Mac.class);
268 
269     assertThat(t.tag).isEqualTo(mac.computeMac(t.message));
270     mac.verifyMac(t.tag, t.message);
271   }
272 
273   @Test
testSerializeAndParse_works()274   public void testSerializeAndParse_works() throws Exception {
275     HmacParameters parameters =
276         HmacParameters.builder()
277             .setKeySizeBytes(64)
278             .setTagSizeBytes(64)
279             .setHashType(HmacParameters.HashType.SHA512)
280             .setVariant(HmacParameters.Variant.TINK)
281             .build();
282     KeysetHandle handle = KeysetHandle.generateNew(parameters);
283     byte[] serialized =
284         TinkProtoKeysetFormat.serializeKeyset(handle, InsecureSecretKeyAccess.get());
285     KeysetHandle parsed =
286         TinkProtoKeysetFormat.parseKeyset(serialized, InsecureSecretKeyAccess.get());
287 
288     assertTrue(handle.equalsKeyset(parsed));
289   }
290 }
291