• 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.aead;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 import static java.nio.charset.StandardCharsets.UTF_8;
21 import static org.junit.Assert.assertArrayEquals;
22 import static org.junit.Assert.assertThrows;
23 import static org.junit.Assert.assertTrue;
24 import static org.junit.Assert.fail;
25 
26 import com.google.crypto.tink.Aead;
27 import com.google.crypto.tink.InsecureSecretKeyAccess;
28 import com.google.crypto.tink.Key;
29 import com.google.crypto.tink.KeyTemplate;
30 import com.google.crypto.tink.KeyTemplates;
31 import com.google.crypto.tink.KeysetHandle;
32 import com.google.crypto.tink.Parameters;
33 import com.google.crypto.tink.RegistryConfiguration;
34 import com.google.crypto.tink.internal.KeyManagerRegistry;
35 import com.google.crypto.tink.internal.SlowInputStream;
36 import com.google.crypto.tink.subtle.AesGcmJce;
37 import com.google.crypto.tink.subtle.Bytes;
38 import com.google.crypto.tink.subtle.Hex;
39 import com.google.crypto.tink.util.SecretBytes;
40 import java.io.ByteArrayInputStream;
41 import java.security.GeneralSecurityException;
42 import java.util.Arrays;
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 /** Test for AesGcmJce and its key manager. */
52 @RunWith(Theories.class)
53 public class AesGcmKeyManagerTest {
54   @Before
register()55   public void register() throws Exception {
56     AeadConfig.register();
57   }
58 
59   private static class NistTestVector {
60     String name;
61     public byte[] keyValue;
62     public byte[] plaintext;
63     public byte[] aad;
64     public byte[] iv;
65     public byte[] ciphertext;
66     public byte[] tag;
67 
NistTestVector( String name, String keyValue, String plaintext, String aad, String iv, String ciphertext, String tag)68     public NistTestVector(
69         String name,
70         String keyValue,
71         String plaintext,
72         String aad,
73         String iv,
74         String ciphertext,
75         String tag) {
76       try {
77         this.name = name;
78         this.keyValue = Hex.decode(keyValue);
79         this.plaintext = Hex.decode(plaintext);
80         this.aad = Hex.decode(aad);
81         this.iv = Hex.decode(iv);
82         this.ciphertext = Hex.decode(ciphertext);
83         this.tag = Hex.decode(tag);
84       } catch (Exception ignored) {
85         // Ignored
86       }
87     }
88   }
89 
90   // Test vectors from
91   // http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-revised-spec.pdf.
92   NistTestVector[] nistTestVectors = {
93     new NistTestVector(
94         "Test Case 1",
95         "00000000000000000000000000000000",
96         "",
97         "",
98         "000000000000000000000000",
99         "",
100         "58e2fccefa7e3061367f1d57a4e7455a"),
101     new NistTestVector(
102         "Test Case 2",
103         "00000000000000000000000000000000",
104         "00000000000000000000000000000000",
105         "",
106         "000000000000000000000000",
107         "0388dace60b6a392f328c2b971b2fe78",
108         "ab6e47d42cec13bdf53a67b21257bddf"),
109     new NistTestVector(
110         "Test Case 3",
111         "feffe9928665731c6d6a8f9467308308",
112         "d9313225f88406e5a55909c5aff5269a"
113             + "86a7a9531534f7da2e4c303d8a318a72"
114             + "1c3c0c95956809532fcf0e2449a6b525"
115             + "b16aedf5aa0de657ba637b391aafd255",
116         "",
117         "cafebabefacedbaddecaf888",
118         "42831ec2217774244b7221b784d0d49c"
119             + "e3aa212f2c02a4e035c17e2329aca12e"
120             + "21d514b25466931c7d8f6a5aac84aa05"
121             + "1ba30b396a0aac973d58e091473f5985",
122         "4d5c2af327cd64a62cf35abd2ba6fab4"),
123     new NistTestVector(
124         "Test Case 4",
125         "feffe9928665731c6d6a8f9467308308",
126         "d9313225f88406e5a55909c5aff5269a"
127             + "86a7a9531534f7da2e4c303d8a318a72"
128             + "1c3c0c95956809532fcf0e2449a6b525"
129             + "b16aedf5aa0de657ba637b39",
130         "feedfacedeadbeeffeedfacedeadbeef" + "abaddad2",
131         "cafebabefacedbaddecaf888",
132         "42831ec2217774244b7221b784d0d49c"
133             + "e3aa212f2c02a4e035c17e2329aca12e"
134             + "21d514b25466931c7d8f6a5aac84aa05"
135             + "1ba30b396a0aac973d58e091",
136         "5bc94fbc3221a5db94fae95ae7121a47"),
137     new NistTestVector(
138         "Test Case 5",
139         "feffe9928665731c6d6a8f9467308308",
140         "d9313225f88406e5a55909c5aff5269a"
141             + "86a7a9531534f7da2e4c303d8a318a72"
142             + "1c3c0c95956809532fcf0e2449a6b525"
143             + "b16aedf5aa0de657ba637b39",
144         "feedfacedeadbeeffeedfacedeadbeef" + "abaddad2",
145         "cafebabefacedbad",
146         "61353b4c2806934a777ff51fa22a4755"
147             + "699b2a714fcdc6f83766e5f97b6c7423"
148             + "73806900e49f24b22b097544d4896b42"
149             + "4989b5e1ebac0f07c23f4598",
150         "3612d2e79e3b0785561be14aaca2fccb"),
151     new NistTestVector(
152         "Test Case 6",
153         "feffe9928665731c6d6a8f9467308308",
154         "d9313225f88406e5a55909c5aff5269a"
155             + "86a7a9531534f7da2e4c303d8a318a72"
156             + "1c3c0c95956809532fcf0e2449a6b525"
157             + "b16aedf5aa0de657ba637b39",
158         "feedfacedeadbeeffeedfacedeadbeef" + "abaddad2",
159         "9313225df88406e555909c5aff5269aa"
160             + "6a7a9538534f7da1e4c303d2a318a728"
161             + "c3c0c95156809539fcf0e2429a6b5254"
162             + "16aedbf5a0de6a57a637b39b",
163         "8ce24998625615b603a033aca13fb894"
164             + "be9112a5c3a211a8ba262a3cca7e2ca7"
165             + "01e4a9a4fba43c90ccdcb281d48c7c6f"
166             + "d62875d2aca417034c34aee5",
167         "619cc5aefffe0bfa462af43c1699d050"),
168     new NistTestVector(
169         "Test Case 13",
170         "00000000000000000000000000000000" + "00000000000000000000000000000000",
171         "",
172         "",
173         "000000000000000000000000",
174         "",
175         "530f8afbc74536b9a963b4f1c4cb738b"),
176     new NistTestVector(
177         "Test Case 14",
178         "00000000000000000000000000000000" + "00000000000000000000000000000000",
179         "00000000000000000000000000000000",
180         "",
181         "000000000000000000000000",
182         "cea7403d4d606b6e074ec5d3baf39d18",
183         "d0d1c8a799996bf0265b98b5d48ab919"),
184     new NistTestVector(
185         "Test Case 15",
186         "feffe9928665731c6d6a8f9467308308" + "feffe9928665731c6d6a8f9467308308",
187         "d9313225f88406e5a55909c5aff5269a"
188             + "86a7a9531534f7da2e4c303d8a318a72"
189             + "1c3c0c95956809532fcf0e2449a6b525"
190             + "b16aedf5aa0de657ba637b391aafd255",
191         "",
192         "cafebabefacedbaddecaf888",
193         "522dc1f099567d07f47f37a32a84427d"
194             + "643a8cdcbfe5c0c97598a2bd2555d1aa"
195             + "8cb08e48590dbb3da7b08b1056828838"
196             + "c5f61e6393ba7a0abcc9f662898015ad",
197         "b094dac5d93471bdec1a502270e3cc6c"),
198     new NistTestVector(
199         "Test Case 16",
200         "feffe9928665731c6d6a8f9467308308" + "feffe9928665731c6d6a8f9467308308",
201         "d9313225f88406e5a55909c5aff5269a"
202             + "86a7a9531534f7da2e4c303d8a318a72"
203             + "1c3c0c95956809532fcf0e2449a6b525"
204             + "b16aedf5aa0de657ba637b39",
205         "feedfacedeadbeeffeedfacedeadbeef" + "abaddad2",
206         "cafebabefacedbaddecaf888",
207         "522dc1f099567d07f47f37a32a84427d"
208             + "643a8cdcbfe5c0c97598a2bd2555d1aa"
209             + "8cb08e48590dbb3da7b08b1056828838"
210             + "c5f61e6393ba7a0abcc9f662",
211         "76fc6ece0f4e1768cddf8853bb2d551b"),
212     new NistTestVector(
213         "Test Case 17",
214         "feffe9928665731c6d6a8f9467308308" + "feffe9928665731c6d6a8f9467308308",
215         "d9313225f88406e5a55909c5aff5269a"
216             + "86a7a9531534f7da2e4c303d8a318a72"
217             + "1c3c0c95956809532fcf0e2449a6b525"
218             + "b16aedf5aa0de657ba637b39",
219         "feedfacedeadbeeffeedfacedeadbeef" + "abaddad2",
220         "cafebabefacedbad",
221         "c3762df1ca787d32ae47c13bf19844cb"
222             + "af1ae14d0b976afac52ff7d79bba9de0"
223             + "feb582d33934a4f0954cc2363bc73f78"
224             + "62ac430e64abe499f47c9b1f",
225         "3a337dbf46a792c45e454913fe2ea8f2"),
226     new NistTestVector(
227         "Test Case 18",
228         "feffe9928665731c6d6a8f9467308308" + "feffe9928665731c6d6a8f9467308308",
229         "d9313225f88406e5a55909c5aff5269a"
230             + "86a7a9531534f7da2e4c303d8a318a72"
231             + "1c3c0c95956809532fcf0e2449a6b525"
232             + "b16aedf5aa0de657ba637b39",
233         "feedfacedeadbeeffeedfacedeadbeef" + "abaddad2",
234         "9313225df88406e555909c5aff5269aa"
235             + "6a7a9538534f7da1e4c303d2a318a728"
236             + "c3c0c95156809539fcf0e2429a6b5254"
237             + "16aedbf5a0de6a57a637b39b",
238         "5a8def2f0c9e53f1f75d7853659e2a20"
239             + "eeb2b22aafde6419a058ab4f6f746bf4"
240             + "0fc0c3b780f244452da3ebf1c5d82cde"
241             + "a2418997200ef82e44ae7e3f",
242         "a44a8266ee1c8eb0c8b5d4cf5ae9f19a"),
243   };
244 
245   @Test
testNistVectors()246   public void testNistVectors() throws Exception {
247     for (NistTestVector t : nistTestVectors) {
248       if (t.iv.length != 12 || t.tag.length != 16) {
249         // We support only 12-byte IV and 16-byte tag.
250         continue;
251       }
252       AesGcmParameters parameters =
253           AesGcmParameters.builder()
254               .setIvSizeBytes(12)
255               .setKeySizeBytes(t.keyValue.length)
256               .setTagSizeBytes(16)
257               .setVariant(AesGcmParameters.Variant.NO_PREFIX)
258               .build();
259       AesGcmKey key =
260           AesGcmKey.builder()
261               .setParameters(parameters)
262               .setKeyBytes(SecretBytes.copyFrom(t.keyValue, InsecureSecretKeyAccess.get()))
263               .build();
264       Aead aead =
265           KeysetHandle.newBuilder()
266               .addEntry(KeysetHandle.importKey(key).makePrimary().withRandomId())
267               .build()
268               .getPrimitive(RegistryConfiguration.get(), Aead.class);
269       try {
270         byte[] ciphertext = Bytes.concat(t.iv, t.ciphertext, t.tag);
271         byte[] plaintext = aead.decrypt(ciphertext, t.aad);
272         assertArrayEquals(plaintext, t.plaintext);
273       } catch (GeneralSecurityException e) {
274         fail("Should not fail at " + t.name + ", but thrown exception " + e);
275       }
276     }
277   }
278 
279   @Test
testKeyManagerRegistered()280   public void testKeyManagerRegistered() throws Exception {
281     assertThat(
282             KeyManagerRegistry.globalInstance()
283                 .getKeyManager("type.googleapis.com/google.crypto.tink.AesGcmKey", Aead.class))
284         .isNotNull();
285   }
286 
287   @Test
testAes128GcmTemplate()288   public void testAes128GcmTemplate() throws Exception {
289     KeyTemplate template = AesGcmKeyManager.aes128GcmTemplate();
290     assertThat(template.toParameters())
291         .isEqualTo(
292             AesGcmParameters.builder()
293                 .setIvSizeBytes(12)
294                 .setTagSizeBytes(16)
295                 .setKeySizeBytes(16)
296                 .setVariant(AesGcmParameters.Variant.TINK)
297                 .build());
298   }
299 
300   @Test
testRawAes128GcmTemplate()301   public void testRawAes128GcmTemplate() throws Exception {
302     KeyTemplate template = AesGcmKeyManager.rawAes128GcmTemplate();
303     assertThat(template.toParameters())
304         .isEqualTo(
305             AesGcmParameters.builder()
306                 .setIvSizeBytes(12)
307                 .setTagSizeBytes(16)
308                 .setKeySizeBytes(16)
309                 .setVariant(AesGcmParameters.Variant.NO_PREFIX)
310                 .build());
311   }
312 
313   @Test
testAes256GcmTemplate()314   public void testAes256GcmTemplate() throws Exception {
315     KeyTemplate template = AesGcmKeyManager.aes256GcmTemplate();
316     assertThat(template.toParameters())
317         .isEqualTo(
318             AesGcmParameters.builder()
319                 .setIvSizeBytes(12)
320                 .setTagSizeBytes(16)
321                 .setKeySizeBytes(32)
322                 .setVariant(AesGcmParameters.Variant.TINK)
323                 .build());
324   }
325 
326   @Test
testRawAes256GcmTemplate()327   public void testRawAes256GcmTemplate() throws Exception {
328     KeyTemplate template = AesGcmKeyManager.rawAes256GcmTemplate();
329     assertThat(template.toParameters())
330         .isEqualTo(
331             AesGcmParameters.builder()
332                 .setIvSizeBytes(12)
333                 .setTagSizeBytes(16)
334                 .setKeySizeBytes(32)
335                 .setVariant(AesGcmParameters.Variant.NO_PREFIX)
336                 .build());
337   }
338 
339   @Test
testKeyTemplatesWork()340   public void testKeyTemplatesWork() throws Exception {
341     Parameters p = AesGcmKeyManager.aes128GcmTemplate().toParameters();
342     assertThat(KeysetHandle.generateNew(p).getAt(0).getKey().getParameters()).isEqualTo(p);
343 
344     p = AesGcmKeyManager.rawAes128GcmTemplate().toParameters();
345     assertThat(KeysetHandle.generateNew(p).getAt(0).getKey().getParameters()).isEqualTo(p);
346 
347     p = AesGcmKeyManager.aes256GcmTemplate().toParameters();
348     assertThat(KeysetHandle.generateNew(p).getAt(0).getKey().getParameters()).isEqualTo(p);
349 
350     p = AesGcmKeyManager.rawAes256GcmTemplate().toParameters();
351     assertThat(KeysetHandle.generateNew(p).getAt(0).getKey().getParameters()).isEqualTo(p);
352   }
353 
354   @DataPoints("templateNames")
355   public static final String[] KEY_TEMPLATES =
356       new String[] {
357         "AES128_GCM", "AES128_GCM_RAW", "AES256_GCM", "AES256_GCM_RAW",
358       };
359 
360   @Theory
testTemplates(@romDataPoints"templateNames") String templateName)361   public void testTemplates(@FromDataPoints("templateNames") String templateName) throws Exception {
362     KeysetHandle h = KeysetHandle.generateNew(KeyTemplates.get(templateName));
363     assertThat(h.size()).isEqualTo(1);
364     assertThat(h.getAt(0).getKey().getParameters())
365         .isEqualTo(KeyTemplates.get(templateName).toParameters());
366   }
367 
368   @Theory
testCreateKeyFromRandomness(@romDataPoints"templateNames") String templateName)369   public void testCreateKeyFromRandomness(@FromDataPoints("templateNames") String templateName)
370       throws Exception {
371     byte[] keyMaterial =
372         new byte[] {
373           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,
374           25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35
375         };
376     AesGcmParameters parameters = (AesGcmParameters) KeyTemplates.get(templateName).toParameters();
377     AesGcmKey key =
378         AesGcmKeyManager.createAesGcmKeyFromRandomness(
379             parameters,
380             new ByteArrayInputStream(keyMaterial),
381             parameters.hasIdRequirement() ? 123 : null,
382             InsecureSecretKeyAccess.get());
383     byte[] truncatedKeyMaterial = Arrays.copyOf(keyMaterial, parameters.getKeySizeBytes());
384     Key expectedKey =
385         AesGcmKey.builder()
386             .setParameters(parameters)
387             .setIdRequirement(parameters.hasIdRequirement() ? 123 : null)
388             .setKeyBytes(SecretBytes.copyFrom(truncatedKeyMaterial, InsecureSecretKeyAccess.get()))
389             .build();
390     assertTrue(key.equalsKey(expectedKey));
391   }
392 
393   @Test
callingCreateTwiceGivesDifferentKeys()394   public void callingCreateTwiceGivesDifferentKeys() throws Exception {
395     Parameters p = AesGcmKeyManager.aes128GcmTemplate().toParameters();
396     Key key = KeysetHandle.generateNew(p).getAt(0).getKey();
397     for (int i = 0; i < 1000; ++i) {
398       assertThat(KeysetHandle.generateNew(p).getAt(0).getKey().equalsKey(key)).isFalse();
399     }
400   }
401 
402   @Test
test_24byte_keyCreation_throws()403   public void test_24byte_keyCreation_throws() throws Exception {
404     // We currently disallow creation of AesGcmKeys with 24 bytes (Tink doesn't support using these
405     // for consistency among the languages, so we also disallow creation at the moment).
406     AesGcmParameters p =
407         AesGcmParameters.builder()
408             .setIvSizeBytes(12)
409             .setTagSizeBytes(16)
410             .setKeySizeBytes(24)
411             .build();
412     assertThrows(GeneralSecurityException.class, () -> KeysetHandle.generateNew(p));
413   }
414 
415   @Test
test_24byte_primitiveCreation_throws()416   public void test_24byte_primitiveCreation_throws() throws Exception {
417     // We currently disallow creation of AesGcmKeys with 24 bytes (Tink doesn't support using these
418     // for consistency among the languages, so we also disallow creation at the moment).
419     AesGcmParameters p =
420         AesGcmParameters.builder()
421             .setIvSizeBytes(12)
422             .setTagSizeBytes(16)
423             .setKeySizeBytes(24)
424             .build();
425     AesGcmKey key =
426         AesGcmKey.builder().setParameters(p).setKeyBytes(SecretBytes.randomBytes(24)).build();
427     KeysetHandle keysetHandle =
428         KeysetHandle.newBuilder()
429             .addEntry(KeysetHandle.importKey(key).makePrimary().withRandomId())
430             .build();
431     assertThrows(
432         GeneralSecurityException.class,
433         () -> keysetHandle.getPrimitive(RegistryConfiguration.get(), Aead.class));
434   }
435 
436   @Test
test_24byte_createKeyFromRandomness_throws()437   public void test_24byte_createKeyFromRandomness_throws() throws Exception {
438     // We currently disallow creation of AesGcmKeys with 24 bytes (Tink doesn't support using these
439     // for consistency among the languages, so we also disallow creation at the moment).
440     AesGcmParameters parameters =
441         AesGcmParameters.builder()
442             .setIvSizeBytes(12)
443             .setTagSizeBytes(16)
444             .setKeySizeBytes(24)
445             .build();
446     byte[] keyMaterial =
447         new byte[] {
448           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,
449           25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35
450         };
451     assertThrows(
452         GeneralSecurityException.class,
453         () ->
454             AesGcmKeyManager.createAesGcmKeyFromRandomness(
455                 parameters,
456                 SlowInputStream.copyFrom(keyMaterial),
457                 null,
458                 InsecureSecretKeyAccess.get()));
459   }
460 
461   @Test
testCreateKeyFromRandomness_slowInputStream_works()462   public void testCreateKeyFromRandomness_slowInputStream_works() throws Exception {
463     byte[] keyMaterial =
464         new byte[] {
465           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,
466           25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35
467         };
468     AesGcmParameters parameters =
469         AesGcmParameters.builder()
470             .setIvSizeBytes(12)
471             .setTagSizeBytes(16)
472             .setKeySizeBytes(32)
473             .setVariant(AesGcmParameters.Variant.NO_PREFIX)
474             .build();
475     AesGcmKey key =
476         AesGcmKeyManager.createAesGcmKeyFromRandomness(
477             parameters, SlowInputStream.copyFrom(keyMaterial), null, InsecureSecretKeyAccess.get());
478     byte[] truncatedKeyMaterial = Arrays.copyOf(keyMaterial, parameters.getKeySizeBytes());
479     Key expectedKey =
480         AesGcmKey.builder()
481             .setParameters(parameters)
482             .setIdRequirement(null)
483             .setKeyBytes(SecretBytes.copyFrom(truncatedKeyMaterial, InsecureSecretKeyAccess.get()))
484             .build();
485     assertTrue(key.equalsKey(expectedKey));
486   }
487 
488   @Test
getPrimitiveFromKeysetHandle()489   public void getPrimitiveFromKeysetHandle() throws Exception {
490     AesGcmParameters parameters =
491         AesGcmParameters.builder()
492             .setIvSizeBytes(12)
493             .setTagSizeBytes(16)
494             .setKeySizeBytes(16)
495             .setVariant(AesGcmParameters.Variant.TINK)
496             .build();
497     AesGcmKey key =
498         AesGcmKey.builder()
499             .setParameters(parameters)
500             .setKeyBytes(SecretBytes.randomBytes(16))
501             .setIdRequirement(31)
502             .build();
503     KeysetHandle keysetHandle =
504         KeysetHandle.newBuilder().addEntry(KeysetHandle.importKey(key).makePrimary()).build();
505     byte[] plaintext = "plaintext".getBytes(UTF_8);
506     byte[] aad = "aad".getBytes(UTF_8);
507 
508     Aead aead = keysetHandle.getPrimitive(RegistryConfiguration.get(), Aead.class);
509     Aead directAead = AesGcmJce.create(key);
510 
511     Object unused = directAead.decrypt(aead.encrypt(plaintext, aad), aad);
512     unused = aead.decrypt(directAead.encrypt(plaintext, aad), aad);
513   }
514 }
515