• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 Google Inc.
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.streamingaead;
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.Parameters;
28 import com.google.crypto.tink.RegistryConfiguration;
29 import com.google.crypto.tink.StreamingAead;
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.keyderivation.KeyDerivationConfig;
34 import com.google.crypto.tink.keyderivation.KeysetDeriver;
35 import com.google.crypto.tink.keyderivation.PrfBasedKeyDerivationKey;
36 import com.google.crypto.tink.keyderivation.PrfBasedKeyDerivationParameters;
37 import com.google.crypto.tink.prf.HkdfPrfKey;
38 import com.google.crypto.tink.prf.HkdfPrfParameters;
39 import com.google.crypto.tink.subtle.AesGcmHkdfStreaming;
40 import com.google.crypto.tink.subtle.Hex;
41 import com.google.crypto.tink.testing.StreamingTestUtil;
42 import com.google.crypto.tink.util.SecretBytes;
43 import java.io.ByteArrayInputStream;
44 import java.util.Arrays;
45 import java.util.Set;
46 import java.util.TreeSet;
47 import org.junit.Before;
48 import org.junit.Test;
49 import org.junit.experimental.theories.DataPoints;
50 import org.junit.experimental.theories.FromDataPoints;
51 import org.junit.experimental.theories.Theories;
52 import org.junit.experimental.theories.Theory;
53 import org.junit.runner.RunWith;
54 
55 /** Test for AesGcmHkdfStreamingKeyManager. */
56 @RunWith(Theories.class)
57 public class AesGcmHkdfStreamingKeyManagerTest {
58 
59   @Before
register()60   public void register() throws Exception {
61     StreamingAeadConfig.register();
62     KeyDerivationConfig.register();
63   }
64 
65   @Test
testKeyManagerRegistered()66   public void testKeyManagerRegistered() throws Exception {
67     assertThat(
68             KeyManagerRegistry.globalInstance()
69                 .getKeyManager(
70                     "type.googleapis.com/google.crypto.tink.AesGcmHkdfStreamingKey",
71                     StreamingAead.class))
72         .isNotNull();
73   }
74 
75   @Test
getPrimitive_works()76   public void getPrimitive_works() throws Exception {
77     Parameters parameters = AesGcmHkdfStreamingKeyManager.aes128GcmHkdf4KBTemplate().toParameters();
78     KeysetHandle handle = KeysetHandle.generateNew(parameters);
79     StreamingAead streamingAead =
80         handle.getPrimitive(RegistryConfiguration.get(), StreamingAead.class);
81     StreamingAead directAead =
82         AesGcmHkdfStreaming.create(
83             (com.google.crypto.tink.streamingaead.AesGcmHkdfStreamingKey) handle.getAt(0).getKey());
84 
85     StreamingTestUtil.testEncryptDecryptDifferentInstances(
86         streamingAead, directAead, 0, 2049, 1000);
87   }
88 
89   @Test
testSkip()90   public void testSkip() throws Exception {
91     KeysetHandle handle =
92         KeysetHandle.generateNew(
93             AesGcmHkdfStreamingKeyManager.aes128GcmHkdf4KBTemplate().toParameters());
94     StreamingAead streamingAead =
95         handle.getPrimitive(RegistryConfiguration.get(), StreamingAead.class);
96     int offset = 0;
97     int plaintextSize = 1 << 16;
98     // Runs the test with different sizes for the chunks to skip.
99     StreamingTestUtil.testSkipWithStream(streamingAead, offset, plaintextSize, 1);
100     StreamingTestUtil.testSkipWithStream(streamingAead, offset, plaintextSize, 64);
101     StreamingTestUtil.testSkipWithStream(streamingAead, offset, plaintextSize, 300);
102   }
103 
104   @Test
testNewKeyMultipleTimes()105   public void testNewKeyMultipleTimes() throws Exception {
106     Parameters parameters = AesGcmHkdfStreamingKeyManager.aes128GcmHkdf4KBTemplate().toParameters();
107     Set<String> keys = new TreeSet<>();
108     // Calls newKey multiple times and make sure that they generate different keys.
109     int numTests = 100;
110     for (int i = 0; i < numTests; i++) {
111       KeysetHandle handle = KeysetHandle.generateNew(parameters);
112       com.google.crypto.tink.streamingaead.AesGcmHkdfStreamingKey key =
113           (com.google.crypto.tink.streamingaead.AesGcmHkdfStreamingKey) handle.getAt(0).getKey();
114       keys.add(Hex.encode(key.getInitialKeyMaterial().toByteArray(InsecureSecretKeyAccess.get())));
115     }
116     assertThat(keys).hasSize(numTests);
117   }
118 
119   @Test
testAes128GcmHkdf4KBTemplate()120   public void testAes128GcmHkdf4KBTemplate() throws Exception {
121     KeyTemplate template = AesGcmHkdfStreamingKeyManager.aes128GcmHkdf4KBTemplate();
122     assertThat(template.toParameters())
123         .isEqualTo(
124             AesGcmHkdfStreamingParameters.builder()
125                 .setKeySizeBytes(16)
126                 .setDerivedAesGcmKeySizeBytes(16)
127                 .setCiphertextSegmentSizeBytes(4 * 1024)
128                 .setHkdfHashType(AesGcmHkdfStreamingParameters.HashType.SHA256)
129                 .build());
130   }
131 
132   @Test
testAes256GcmHkdf4KBTemplate()133   public void testAes256GcmHkdf4KBTemplate() throws Exception {
134     KeyTemplate template = AesGcmHkdfStreamingKeyManager.aes256GcmHkdf4KBTemplate();
135     assertThat(template.toParameters())
136         .isEqualTo(
137             AesGcmHkdfStreamingParameters.builder()
138                 .setKeySizeBytes(32)
139                 .setDerivedAesGcmKeySizeBytes(32)
140                 .setCiphertextSegmentSizeBytes(4 * 1024)
141                 .setHkdfHashType(AesGcmHkdfStreamingParameters.HashType.SHA256)
142                 .build());
143   }
144 
145   @Test
testAes128GcmHkdf1MBTemplate()146   public void testAes128GcmHkdf1MBTemplate() throws Exception {
147     KeyTemplate template = AesGcmHkdfStreamingKeyManager.aes128GcmHkdf1MBTemplate();
148     assertThat(template.toParameters())
149         .isEqualTo(
150             AesGcmHkdfStreamingParameters.builder()
151                 .setKeySizeBytes(16)
152                 .setDerivedAesGcmKeySizeBytes(16)
153                 .setCiphertextSegmentSizeBytes(1024 * 1024)
154                 .setHkdfHashType(AesGcmHkdfStreamingParameters.HashType.SHA256)
155                 .build());
156   }
157 
158   @Test
testAes256GcmHkdf1MBTemplate()159   public void testAes256GcmHkdf1MBTemplate() throws Exception {
160     KeyTemplate template = AesGcmHkdfStreamingKeyManager.aes256GcmHkdf1MBTemplate();
161     assertThat(template.toParameters())
162         .isEqualTo(
163             AesGcmHkdfStreamingParameters.builder()
164                 .setKeySizeBytes(32)
165                 .setDerivedAesGcmKeySizeBytes(32)
166                 .setCiphertextSegmentSizeBytes(1024 * 1024)
167                 .setHkdfHashType(AesGcmHkdfStreamingParameters.HashType.SHA256)
168                 .build());
169   }
170 
171   @DataPoints("templateNames")
172   public static final String[] KEY_TEMPLATES =
173       new String[] {
174         "AES128_GCM_HKDF_4KB", "AES128_GCM_HKDF_1MB", "AES256_GCM_HKDF_4KB", "AES256_GCM_HKDF_1MB",
175       };
176 
177   @Theory
testTemplates(@romDataPoints"templateNames") String templateName)178   public void testTemplates(@FromDataPoints("templateNames") String templateName) throws Exception {
179     KeysetHandle h = KeysetHandle.generateNew(KeyTemplates.get(templateName));
180     assertThat(h.size()).isEqualTo(1);
181     assertThat(h.getAt(0).getKey().getParameters())
182         .isEqualTo(KeyTemplates.get(templateName).toParameters());
183   }
184 
185   @Theory
testCreateKeyFromRandomness(@romDataPoints"templateNames") String templateName)186   public void testCreateKeyFromRandomness(@FromDataPoints("templateNames") String templateName)
187       throws Exception {
188     byte[] keyMaterial =
189         new byte[] {
190           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,
191           25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46,
192           47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68,
193         };
194     AesGcmHkdfStreamingParameters parameters =
195         (AesGcmHkdfStreamingParameters) KeyTemplates.get(templateName).toParameters();
196     com.google.crypto.tink.streamingaead.AesGcmHkdfStreamingKey key =
197         AesGcmHkdfStreamingKeyManager.createAesGcmHkdfStreamingKeyFromRandomness(
198             parameters, new ByteArrayInputStream(keyMaterial), null, InsecureSecretKeyAccess.get());
199     byte[] expectedKeyBytes = Arrays.copyOf(keyMaterial, parameters.getKeySizeBytes());
200     Key expectedKey =
201         com.google.crypto.tink.streamingaead.AesGcmHkdfStreamingKey.create(
202             parameters, SecretBytes.copyFrom(expectedKeyBytes, InsecureSecretKeyAccess.get()));
203     assertTrue(key.equalsKey(expectedKey));
204   }
205 
206   @Test
testCreateKeyFromRandomness_slowInputStream_works()207   public void testCreateKeyFromRandomness_slowInputStream_works() throws Exception {
208     AesGcmHkdfStreamingParameters parameters =
209         AesGcmHkdfStreamingParameters.builder()
210             .setKeySizeBytes(16)
211             .setDerivedAesGcmKeySizeBytes(16)
212             .setCiphertextSegmentSizeBytes(1024 * 1024)
213             .setHkdfHashType(AesGcmHkdfStreamingParameters.HashType.SHA256)
214             .build();
215 
216     byte[] keyMaterial =
217         new byte[] {
218           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,
219           25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46,
220           47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68,
221         };
222     com.google.crypto.tink.streamingaead.AesGcmHkdfStreamingKey key =
223         AesGcmHkdfStreamingKeyManager.createAesGcmHkdfStreamingKeyFromRandomness(
224             parameters, SlowInputStream.copyFrom(keyMaterial), null, InsecureSecretKeyAccess.get());
225     byte[] expectedKeyBytes = Arrays.copyOf(keyMaterial, parameters.getKeySizeBytes());
226     Key expectedKey =
227         com.google.crypto.tink.streamingaead.AesGcmHkdfStreamingKey.create(
228             parameters, SecretBytes.copyFrom(expectedKeyBytes, InsecureSecretKeyAccess.get()));
229     assertTrue(key.equalsKey(expectedKey));
230   }
231 
232   @Test
deriveKeyset_isAsExpected()233   public void deriveKeyset_isAsExpected() throws Exception {
234     HkdfPrfKey prfKey =
235         HkdfPrfKey.builder()
236             .setParameters(
237                 HkdfPrfParameters.builder()
238                     .setKeySizeBytes(32)
239                     .setHashType(HkdfPrfParameters.HashType.SHA256)
240                     .build())
241             .setKeyBytes(
242                 SecretBytes.copyFrom(
243                     Hex.decode("0102030405060708091011121314151617181920212123242526272829303132"),
244                     InsecureSecretKeyAccess.get()))
245             .build();
246 
247     PrfBasedKeyDerivationParameters derivationParameters =
248         PrfBasedKeyDerivationParameters.builder()
249             .setDerivedKeyParameters(PredefinedStreamingAeadParameters.AES256_GCM_HKDF_1MB)
250             .setPrfParameters(prfKey.getParameters())
251             .build();
252 
253     PrfBasedKeyDerivationKey keyDerivationKey =
254         PrfBasedKeyDerivationKey.create(derivationParameters, prfKey, /* idRequirement= */ null);
255     KeysetHandle keyset =
256         KeysetHandle.newBuilder()
257             .addEntry(KeysetHandle.importKey(keyDerivationKey).withFixedId(789789).makePrimary())
258             .build();
259     KeysetDeriver deriver = keyset.getPrimitive(RegistryConfiguration.get(), KeysetDeriver.class);
260 
261     KeysetHandle derivedKeyset = deriver.deriveKeyset(Hex.decode("000102"));
262 
263     assertThat(derivedKeyset.size()).isEqualTo(1);
264     // The only thing which we need to test is equalsKey(), but we first test other things to make
265     // test failures have nicer messages.
266     assertThat(derivedKeyset.getAt(0).getKey().getParameters())
267         .isEqualTo(derivationParameters.getDerivedKeyParameters());
268     assertTrue(
269         derivedKeyset
270             .getAt(0)
271             .getKey()
272             .equalsKey(
273                 com.google.crypto.tink.streamingaead.AesGcmHkdfStreamingKey.create(
274                     PredefinedStreamingAeadParameters.AES256_GCM_HKDF_1MB,
275                     SecretBytes.copyFrom(
276                         Hex.decode(
277                             "94e397d674deda6e965295698491a3feb69838a35f1d48143f3c4cbad90eeb24"),
278                         InsecureSecretKeyAccess.get()))));
279   }
280 
281   @Test
serializeAndParse_works()282   public void serializeAndParse_works() throws Exception {
283     Parameters parameters = AesGcmHkdfStreamingKeyManager.aes128GcmHkdf4KBTemplate().toParameters();
284     KeysetHandle handle = KeysetHandle.generateNew(parameters);
285     byte[] serializedHandle =
286         TinkProtoKeysetFormat.serializeKeyset(handle, InsecureSecretKeyAccess.get());
287     KeysetHandle parsedHandle =
288         TinkProtoKeysetFormat.parseKeyset(serializedHandle, InsecureSecretKeyAccess.get());
289     assertThat(parsedHandle.equalsKeyset(handle)).isTrue();
290   }
291 }
292