• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 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 package com.google.crypto.tink.prf;
17 
18 import static com.google.common.truth.Truth.assertThat;
19 import static java.nio.charset.StandardCharsets.UTF_8;
20 import static org.junit.Assert.assertArrayEquals;
21 import static org.junit.Assert.assertThrows;
22 
23 import com.google.crypto.tink.InsecureSecretKeyAccess;
24 import com.google.crypto.tink.KeysetHandle;
25 import com.google.crypto.tink.Registry;
26 import com.google.crypto.tink.RegistryConfiguration;
27 import com.google.crypto.tink.internal.LegacyKeyManagerImpl;
28 import com.google.crypto.tink.internal.MonitoringAnnotations;
29 import com.google.crypto.tink.internal.MutableKeyCreationRegistry;
30 import com.google.crypto.tink.internal.MutableMonitoringRegistry;
31 import com.google.crypto.tink.internal.MutablePrimitiveRegistry;
32 import com.google.crypto.tink.internal.PrimitiveConstructor;
33 import com.google.crypto.tink.internal.PrimitiveRegistry;
34 import com.google.crypto.tink.internal.testing.FakeMonitoringClient;
35 import com.google.crypto.tink.prf.HkdfPrfParameters.HashType;
36 import com.google.crypto.tink.prf.internal.HkdfPrfProtoSerialization;
37 import com.google.crypto.tink.proto.KeyData.KeyMaterialType;
38 import com.google.crypto.tink.subtle.Hex;
39 import com.google.crypto.tink.util.SecretBytes;
40 import com.google.errorprone.annotations.Immutable;
41 import java.security.GeneralSecurityException;
42 import java.util.List;
43 import org.junit.BeforeClass;
44 import org.junit.Test;
45 import org.junit.runner.RunWith;
46 import org.junit.runners.JUnit4;
47 
48 /** Tests for PrfSetWrapper. */
49 @RunWith(JUnit4.class)
50 public class PrfSetWrapperTest {
51   private static final int KEY_SIZE = 32;
52 
53   private static HkdfPrfKey hkdfPrfKey0;
54   private static HkdfPrfKey hkdfPrfKey1;
55   private static HkdfPrfKey hkdfPrfKeyFixed;
56 
57   @BeforeClass
setUp()58   public static void setUp() throws Exception {
59     createTestKeys();
60   }
61 
createTestKeys()62   private static void createTestKeys() throws GeneralSecurityException {
63     hkdfPrfKey0 =
64         HkdfPrfKey.builder()
65             .setParameters(
66                 HkdfPrfParameters.builder()
67                     .setKeySizeBytes(KEY_SIZE)
68                     .setHashType(HashType.SHA256)
69                     .build())
70             .setKeyBytes(SecretBytes.randomBytes(KEY_SIZE))
71             .build();
72     hkdfPrfKey1 =
73         HkdfPrfKey.builder()
74             .setParameters(
75                 HkdfPrfParameters.builder()
76                     .setKeySizeBytes(KEY_SIZE)
77                     .setHashType(HashType.SHA256)
78                     .build())
79             .setKeyBytes(SecretBytes.randomBytes(KEY_SIZE))
80             .build();
81     hkdfPrfKeyFixed =
82         HkdfPrfKey.builder()
83             .setParameters(
84                 HkdfPrfParameters.builder()
85                     .setKeySizeBytes(KEY_SIZE)
86                     .setHashType(HashType.SHA256)
87                     .build())
88             .setKeyBytes(
89                 SecretBytes.copyFrom(
90                     Hex.decode("0000000000000000000000000000000000000000000000000000000000000000"),
91                     InsecureSecretKeyAccess.get()))
92             .build();
93   }
94 
95   @Test
compute_works()96   public void compute_works() throws Exception {
97     MutablePrimitiveRegistry.resetGlobalInstanceTestOnly();
98     PrfConfig.register();
99 
100     KeysetHandle keysetHandle =
101         KeysetHandle.newBuilder()
102             .addEntry(KeysetHandle.importKey(hkdfPrfKeyFixed).withFixedId(42).makePrimary())
103             .build();
104     PrfSet prfSet = keysetHandle.getPrimitive(RegistryConfiguration.get(), PrfSet.class);
105     byte[] plaintext = "blah".getBytes(UTF_8);
106 
107     byte[] prs = prfSet.computePrimary(plaintext, 12);
108 
109     assertThat(prfSet.getPrfs()).hasSize(1);
110     assertThat(prs).isEqualTo(Hex.decode("04f108788845580686b70d61"));
111   }
112 
113   @Test
compute_usesPrimaryKey()114   public void compute_usesPrimaryKey() throws Exception {
115     MutablePrimitiveRegistry.resetGlobalInstanceTestOnly();
116     PrfConfig.register();
117 
118     KeysetHandle keysetHandle =
119         KeysetHandle.newBuilder()
120             .addEntry(KeysetHandle.importKey(hkdfPrfKey0).withFixedId(42).makePrimary())
121             .addEntry(KeysetHandle.importKey(hkdfPrfKey1).withFixedId(43))
122             .build();
123     PrfSet prfSet = keysetHandle.getPrimitive(RegistryConfiguration.get(), PrfSet.class);
124     byte[] plaintext = "blah".getBytes(UTF_8);
125 
126     byte[] prs = prfSet.computePrimary(plaintext, 12);
127     byte[] prsPrimary = prfSet.getPrfs().get(42).compute(plaintext, 12);
128 
129     assertThat(prfSet.getPrimaryId()).isEqualTo(42);
130     assertArrayEquals(prsPrimary, prs);
131   }
132 
133   @Test
prfsCorrespondToCorrectKeys()134   public void prfsCorrespondToCorrectKeys() throws Exception {
135     MutablePrimitiveRegistry.resetGlobalInstanceTestOnly();
136     PrfConfig.register();
137 
138     KeysetHandle keysetHandle =
139         KeysetHandle.newBuilder()
140             .addEntry(KeysetHandle.importKey(hkdfPrfKey0).withFixedId(42).makePrimary())
141             .addEntry(KeysetHandle.importKey(hkdfPrfKey1).withFixedId(43))
142             .build();
143     KeysetHandle singleKeyKeysetHandle =
144         KeysetHandle.newBuilder()
145             .addEntry(KeysetHandle.importKey(hkdfPrfKey1).withFixedId(43).makePrimary())
146             .build();
147     PrfSet prfSet = keysetHandle.getPrimitive(RegistryConfiguration.get(), PrfSet.class);
148     PrfSet singleKeyPrfSet =
149         singleKeyKeysetHandle.getPrimitive(RegistryConfiguration.get(), PrfSet.class);
150     byte[] plaintext = "blah".getBytes(UTF_8);
151 
152     byte[] prs = prfSet.getPrfs().get(43).compute(plaintext, 12);
153     byte[] singleKeyPrs = singleKeyPrfSet.computePrimary(plaintext, 12);
154 
155     assertArrayEquals(singleKeyPrs, prs);
156   }
157 
158   @Test
getPrfs_containsOnlyExistingKeys()159   public void getPrfs_containsOnlyExistingKeys() throws Exception {
160     MutablePrimitiveRegistry.resetGlobalInstanceTestOnly();
161     PrfConfig.register();
162 
163     KeysetHandle keysetHandle =
164         KeysetHandle.newBuilder()
165             .addEntry(KeysetHandle.importKey(hkdfPrfKey0).withFixedId(42).makePrimary())
166             .addEntry(KeysetHandle.importKey(hkdfPrfKey1).withFixedId(43))
167             .build();
168     PrfSet prfSet = keysetHandle.getPrimitive(RegistryConfiguration.get(), PrfSet.class);
169 
170     assertThat(prfSet.getPrfs().keySet()).containsExactly(42, 43);
171   }
172 
173   @Test
testWithEmptyAnnotations_noMonitoring()174   public void testWithEmptyAnnotations_noMonitoring() throws Exception {
175     MutablePrimitiveRegistry.resetGlobalInstanceTestOnly();
176     PrfConfig.register();
177     FakeMonitoringClient fakeMonitoringClient = new FakeMonitoringClient();
178     MutableMonitoringRegistry.globalInstance().clear();
179     MutableMonitoringRegistry.globalInstance().registerMonitoringClient(fakeMonitoringClient);
180 
181     KeysetHandle keysetHandle =
182         KeysetHandle.newBuilder()
183             .addEntry(KeysetHandle.importKey(hkdfPrfKey0).withFixedId(42).makePrimary())
184             .addEntry(KeysetHandle.importKey(hkdfPrfKey1).withFixedId(43))
185             .build();
186     PrfSet prfSet = keysetHandle.getPrimitive(RegistryConfiguration.get(), PrfSet.class);
187     byte[] plaintext = "blah".getBytes(UTF_8);
188 
189     byte[] unused = prfSet.computePrimary(plaintext, 12);
190     unused = prfSet.getPrfs().get(42).compute(plaintext, 12);
191     unused = prfSet.getPrfs().get(43).compute(plaintext, 12);
192 
193     // Without annotations, nothing gets logged.
194     assertThat(fakeMonitoringClient.getLogEntries()).isEmpty();
195     assertThat(fakeMonitoringClient.getLogFailureEntries()).isEmpty();
196   }
197 
198   @Test
testWithAnnotations_hasMonitoring()199   public void testWithAnnotations_hasMonitoring() throws Exception {
200     MutablePrimitiveRegistry.resetGlobalInstanceTestOnly();
201     PrfConfig.register();
202 
203     FakeMonitoringClient fakeMonitoringClient = new FakeMonitoringClient();
204     MutableMonitoringRegistry.globalInstance().clear();
205     MutableMonitoringRegistry.globalInstance().registerMonitoringClient(fakeMonitoringClient);
206 
207     MonitoringAnnotations annotations =
208         MonitoringAnnotations.newBuilder().add("annotation_name", "annotation_value").build();
209     KeysetHandle hkdfKeysetHandle =
210         KeysetHandle.newBuilder()
211             .addEntry(KeysetHandle.importKey(hkdfPrfKey0).withFixedId(5).makePrimary())
212             .addEntry(KeysetHandle.importKey(hkdfPrfKey1).withFixedId(6))
213             .setMonitoringAnnotations(annotations)
214             .build();
215     byte[] plaintext = "blah".getBytes(UTF_8);
216 
217     PrfSet prfSet = hkdfKeysetHandle.getPrimitive(RegistryConfiguration.get(), PrfSet.class);
218     byte[] prsPrimary = prfSet.computePrimary(plaintext, 12);
219     byte[] prs5 = prfSet.getPrfs().get(5).compute(plaintext, 12);
220     byte[] prs6 = prfSet.getPrfs().get(6).compute(plaintext, 12);
221 
222     assertThat(prfSet.getPrimaryId()).isEqualTo(5);
223 
224     assertThat(prfSet.getPrfs()).hasSize(2);
225     assertThat(prsPrimary).hasLength(12);
226     assertThat(prs5).isEqualTo(prsPrimary);
227     assertThat(prsPrimary).isNotEqualTo(prs6);
228 
229     assertThat(fakeMonitoringClient.getLogFailureEntries()).isEmpty();
230 
231     List<FakeMonitoringClient.LogEntry> logEntries = fakeMonitoringClient.getLogEntries();
232     assertThat(logEntries).hasSize(3);
233     FakeMonitoringClient.LogEntry entry0 = logEntries.get(0);
234     assertThat(entry0.getKeyId()).isEqualTo(5);
235     assertThat(entry0.getPrimitive()).isEqualTo("prf");
236     assertThat(entry0.getApi()).isEqualTo("compute");
237     assertThat(entry0.getKeysetInfo().getAnnotations()).isEqualTo(annotations);
238     FakeMonitoringClient.LogEntry entry1 = logEntries.get(1);
239     assertThat(entry1.getKeyId()).isEqualTo(5);
240     assertThat(entry1.getPrimitive()).isEqualTo("prf");
241     assertThat(entry1.getApi()).isEqualTo("compute");
242     assertThat(entry1.getKeysetInfo().getAnnotations()).isEqualTo(annotations);
243     FakeMonitoringClient.LogEntry entry2 = logEntries.get(2);
244     assertThat(entry2.getKeyId()).isEqualTo(6);
245     assertThat(entry2.getPrimitive()).isEqualTo("prf");
246     assertThat(entry2.getApi()).isEqualTo("compute");
247     assertThat(entry2.getKeysetInfo().getAnnotations()).isEqualTo(annotations);
248   }
249 
250   @Immutable
251   private static class AlwaysFailingPrf implements Prf {
252 
AlwaysFailingPrf(HkdfPrfKey key)253     AlwaysFailingPrf(HkdfPrfKey key) {}
254 
255     @Override
compute(byte[] input, int outputLength)256     public byte[] compute(byte[] input, int outputLength) throws GeneralSecurityException {
257       throw new GeneralSecurityException("fail");
258     }
259   }
260 
261   /** Perform registrations such as HkdfKeyManager.register, but with a failing PRF */
doHkdfKeyManagerRegistrationWithFailingPrf()262   private static void doHkdfKeyManagerRegistrationWithFailingPrf() throws Exception {
263     HkdfPrfProtoSerialization.register();
264     MutablePrimitiveRegistry.globalInstance()
265         .registerPrimitiveConstructor(
266             PrimitiveConstructor.create(AlwaysFailingPrf::new, HkdfPrfKey.class, Prf.class));
267     MutableKeyCreationRegistry.globalInstance()
268         .add(HkdfPrfKeyManager.KEY_CREATOR, HkdfPrfParameters.class);
269     Registry.registerKeyManager(
270         LegacyKeyManagerImpl.create(
271             HkdfPrfKeyManager.getKeyType(),
272             Prf.class,
273             KeyMaterialType.SYMMETRIC,
274             com.google.crypto.tink.proto.HkdfPrfKey.parser()),
275         true);
276   }
277 
278   @Test
testAlwaysFailingPrfWithAnnotations_hasMonitoring()279   public void testAlwaysFailingPrfWithAnnotations_hasMonitoring() throws Exception {
280     MutablePrimitiveRegistry.resetGlobalInstanceTestOnly();
281     PrfSetWrapper.register();
282     doHkdfKeyManagerRegistrationWithFailingPrf();
283 
284     FakeMonitoringClient fakeMonitoringClient = new FakeMonitoringClient();
285     MutableMonitoringRegistry.globalInstance().clear();
286     MutableMonitoringRegistry.globalInstance().registerMonitoringClient(fakeMonitoringClient);
287 
288     MonitoringAnnotations annotations =
289         MonitoringAnnotations.newBuilder().add("annotation_name", "annotation_value").build();
290     KeysetHandle hkdfKeysetHandle =
291         KeysetHandle.newBuilder()
292             .addEntry(KeysetHandle.importKey(hkdfPrfKey0).withFixedId(5).makePrimary())
293             .setMonitoringAnnotations(annotations)
294             .build();
295     PrfSet prfSet = hkdfKeysetHandle.getPrimitive(RegistryConfiguration.get(), PrfSet.class);
296     byte[] plaintext = "blah".getBytes(UTF_8);
297 
298     assertThrows(GeneralSecurityException.class, () -> prfSet.computePrimary(plaintext, 12));
299     assertThrows(
300         GeneralSecurityException.class, () -> prfSet.getPrfs().get(5).compute(plaintext, 12));
301 
302     assertThat(fakeMonitoringClient.getLogEntries()).isEmpty();
303 
304     List<FakeMonitoringClient.LogFailureEntry> failures =
305         fakeMonitoringClient.getLogFailureEntries();
306     assertThat(failures).hasSize(2);
307     FakeMonitoringClient.LogFailureEntry failure0 = failures.get(0);
308     assertThat(failure0.getPrimitive()).isEqualTo("prf");
309     assertThat(failure0.getApi()).isEqualTo("compute");
310     assertThat(failure0.getKeysetInfo().getPrimaryKeyId()).isEqualTo(5);
311     assertThat(failure0.getKeysetInfo().getAnnotations()).isEqualTo(annotations);
312     FakeMonitoringClient.LogFailureEntry failure1 = failures.get(1);
313     assertThat(failure1.getPrimitive()).isEqualTo("prf");
314     assertThat(failure1.getApi()).isEqualTo("compute");
315     assertThat(failure1.getKeysetInfo().getPrimaryKeyId()).isEqualTo(5);
316     assertThat(failure1.getKeysetInfo().getAnnotations()).isEqualTo(annotations);
317   }
318 
319   @Test
registerToInternalPrimitiveRegistry_works()320   public void registerToInternalPrimitiveRegistry_works() throws Exception {
321     PrimitiveRegistry.Builder initialBuilder = PrimitiveRegistry.builder();
322     PrimitiveRegistry initialRegistry = initialBuilder.build();
323     PrimitiveRegistry.Builder processedBuilder = PrimitiveRegistry.builder(initialRegistry);
324 
325     PrfSetWrapper.registerToInternalPrimitiveRegistry(processedBuilder);
326     PrimitiveRegistry processedRegistry = processedBuilder.build();
327 
328     assertThrows(
329         GeneralSecurityException.class, () -> initialRegistry.getInputPrimitiveClass(PrfSet.class));
330     assertThat(processedRegistry.getInputPrimitiveClass(PrfSet.class)).isEqualTo(Prf.class);
331   }
332 }
333