• 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.streamingaead;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 
21 import com.google.crypto.tink.InsecureSecretKeyAccess;
22 import com.google.crypto.tink.KeyTemplate;
23 import com.google.crypto.tink.KeyTemplates;
24 import com.google.crypto.tink.KeysetHandle;
25 import com.google.crypto.tink.Parameters;
26 import com.google.crypto.tink.RegistryConfiguration;
27 import com.google.crypto.tink.StreamingAead;
28 import com.google.crypto.tink.TinkProtoKeysetFormat;
29 import com.google.crypto.tink.internal.KeyManagerRegistry;
30 import com.google.crypto.tink.streamingaead.internal.testing.AesCtrHmacStreamingTestUtil;
31 import com.google.crypto.tink.streamingaead.internal.testing.StreamingAeadTestVector;
32 import com.google.crypto.tink.subtle.AesCtrHmacStreaming;
33 import com.google.crypto.tink.subtle.Hex;
34 import com.google.crypto.tink.testing.StreamingTestUtil;
35 import com.google.crypto.tink.testing.StreamingTestUtil.ByteBufferChannel;
36 import java.io.ByteArrayInputStream;
37 import java.io.InputStream;
38 import java.nio.ByteBuffer;
39 import java.nio.channels.ReadableByteChannel;
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 /** Test for AesCtrHmacStreamingKeyManager. */
52 @RunWith(Theories.class)
53 public class AesCtrHmacStreamingKeyManagerTest {
54   @Before
register()55   public void register() throws Exception {
56     StreamingAeadConfig.register();
57   }
58 
59   @Test
testKeyManagerRegistered()60   public void testKeyManagerRegistered() throws Exception {
61     assertThat(
62             KeyManagerRegistry.globalInstance()
63                 .getKeyManager(
64                     "type.googleapis.com/google.crypto.tink.AesCtrHmacStreamingKey",
65                     StreamingAead.class))
66         .isNotNull();
67   }
68 
69   @Test
testSkip()70   public void testSkip() throws Exception {
71     Parameters parameters =
72         AesCtrHmacStreamingKeyManager.aes128CtrHmacSha2564KBTemplate().toParameters();
73     KeysetHandle handle = KeysetHandle.generateNew(parameters);
74     StreamingAead streamingAead =
75         handle.getPrimitive(RegistryConfiguration.get(), StreamingAead.class);
76 
77     int offset = 0;
78     int plaintextSize = 1 << 16;
79     // Runs the test with different sizes for the chunks to skip.
80     StreamingTestUtil.testSkipWithStream(streamingAead, offset, plaintextSize, 1);
81     StreamingTestUtil.testSkipWithStream(streamingAead, offset, plaintextSize, 64);
82     StreamingTestUtil.testSkipWithStream(streamingAead, offset, plaintextSize, 300);
83   }
84 
85   @Test
createKey_multipleTimes_differentValues()86   public void createKey_multipleTimes_differentValues() throws Exception {
87     Parameters parameters =
88         AesCtrHmacStreamingKeyManager.aes128CtrHmacSha2564KBTemplate().toParameters();
89     Set<String> keys = new TreeSet<>();
90     // Calls newKey multiple times and make sure that they generate different keys.
91     int numTests = 100;
92     for (int i = 0; i < numTests; i++) {
93       KeysetHandle handle = KeysetHandle.generateNew(parameters);
94       com.google.crypto.tink.streamingaead.AesCtrHmacStreamingKey key =
95           (com.google.crypto.tink.streamingaead.AesCtrHmacStreamingKey) handle.getAt(0).getKey();
96       keys.add(Hex.encode(key.getInitialKeyMaterial().toByteArray(InsecureSecretKeyAccess.get())));
97     }
98     assertThat(keys).hasSize(numTests);
99   }
100 
101   @Test
getPrimitive_works()102   public void getPrimitive_works() throws Exception {
103     Parameters parameters =
104         AesCtrHmacStreamingKeyManager.aes128CtrHmacSha2564KBTemplate().toParameters();
105     KeysetHandle handle = KeysetHandle.generateNew(parameters);
106     StreamingAead streamingAead =
107         handle.getPrimitive(RegistryConfiguration.get(), StreamingAead.class);
108     StreamingAead directAead =
109         AesCtrHmacStreaming.create(
110             (com.google.crypto.tink.streamingaead.AesCtrHmacStreamingKey) handle.getAt(0).getKey());
111 
112     StreamingTestUtil.testEncryptDecryptDifferentInstances(
113         streamingAead, directAead, 0, 2049, 1000);
114   }
115 
116   @Test
testAes128CtrHmacSha2564KBTemplate()117   public void testAes128CtrHmacSha2564KBTemplate() throws Exception {
118     KeyTemplate template = AesCtrHmacStreamingKeyManager.aes128CtrHmacSha2564KBTemplate();
119     assertThat(template.toParameters())
120         .isEqualTo(
121             AesCtrHmacStreamingParameters.builder()
122                 .setKeySizeBytes(16)
123                 .setDerivedKeySizeBytes(16)
124                 .setHkdfHashType(AesCtrHmacStreamingParameters.HashType.SHA256)
125                 .setHmacHashType(AesCtrHmacStreamingParameters.HashType.SHA256)
126                 .setHmacTagSizeBytes(32)
127                 .setCiphertextSegmentSizeBytes(4 * 1024)
128                 .build());
129   }
130 
131   @Test
testAes128CtrHmacSha2561MBTemplate()132   public void testAes128CtrHmacSha2561MBTemplate() throws Exception {
133     KeyTemplate template = AesCtrHmacStreamingKeyManager.aes128CtrHmacSha2561MBTemplate();
134     assertThat(template.toParameters())
135         .isEqualTo(
136             AesCtrHmacStreamingParameters.builder()
137                 .setKeySizeBytes(16)
138                 .setDerivedKeySizeBytes(16)
139                 .setHkdfHashType(AesCtrHmacStreamingParameters.HashType.SHA256)
140                 .setHmacHashType(AesCtrHmacStreamingParameters.HashType.SHA256)
141                 .setHmacTagSizeBytes(32)
142                 .setCiphertextSegmentSizeBytes(1024 * 1024)
143                 .build());
144   }
145 
146   @Test
testAes256CtrHmacSha2564KBTemplate()147   public void testAes256CtrHmacSha2564KBTemplate() throws Exception {
148     KeyTemplate template = AesCtrHmacStreamingKeyManager.aes256CtrHmacSha2564KBTemplate();
149     assertThat(template.toParameters())
150         .isEqualTo(
151             AesCtrHmacStreamingParameters.builder()
152                 .setKeySizeBytes(32)
153                 .setDerivedKeySizeBytes(32)
154                 .setHkdfHashType(AesCtrHmacStreamingParameters.HashType.SHA256)
155                 .setHmacHashType(AesCtrHmacStreamingParameters.HashType.SHA256)
156                 .setHmacTagSizeBytes(32)
157                 .setCiphertextSegmentSizeBytes(4 * 1024)
158                 .build());
159   }
160 
161   @Test
testAes256CtrHmacSha2561MBTemplate()162   public void testAes256CtrHmacSha2561MBTemplate() throws Exception {
163     KeyTemplate template = AesCtrHmacStreamingKeyManager.aes256CtrHmacSha2561MBTemplate();
164     assertThat(template.toParameters())
165         .isEqualTo(
166             AesCtrHmacStreamingParameters.builder()
167                 .setKeySizeBytes(32)
168                 .setDerivedKeySizeBytes(32)
169                 .setHkdfHashType(AesCtrHmacStreamingParameters.HashType.SHA256)
170                 .setHmacHashType(AesCtrHmacStreamingParameters.HashType.SHA256)
171                 .setHmacTagSizeBytes(32)
172                 .setCiphertextSegmentSizeBytes(1024 * 1024)
173                 .build());
174   }
175 
176   @DataPoints("templateNames")
177   public static final String[] KEY_TEMPLATES =
178       new String[] {
179         "AES128_CTR_HMAC_SHA256_4KB",
180         "AES128_CTR_HMAC_SHA256_1MB",
181         "AES256_CTR_HMAC_SHA256_4KB",
182         "AES256_CTR_HMAC_SHA256_1MB"
183       };
184 
185   @Theory
testTemplates(@romDataPoints"templateNames") String templateName)186   public void testTemplates(@FromDataPoints("templateNames") String templateName) throws Exception {
187     KeysetHandle h = KeysetHandle.generateNew(KeyTemplates.get(templateName));
188     assertThat(h.size()).isEqualTo(1);
189     assertThat(h.getAt(0).getKey().getParameters())
190         .isEqualTo(KeyTemplates.get(templateName).toParameters());
191   }
192 
193   @Test
serializeAndParse_works()194   public void serializeAndParse_works() throws Exception {
195     Parameters parameters =
196         AesCtrHmacStreamingKeyManager.aes128CtrHmacSha2561MBTemplate().toParameters();
197     KeysetHandle handle = KeysetHandle.generateNew(parameters);
198     byte[] serializedHandle =
199         TinkProtoKeysetFormat.serializeKeyset(handle, InsecureSecretKeyAccess.get());
200     KeysetHandle parsedHandle =
201         TinkProtoKeysetFormat.parseKeyset(serializedHandle, InsecureSecretKeyAccess.get());
202     assertThat(parsedHandle.equalsKeyset(handle)).isTrue();
203   }
204 
205   @DataPoints("testVectors")
206   public static final StreamingAeadTestVector[] streamingTestVector =
207       AesCtrHmacStreamingTestUtil.createAesCtrHmacTestVectors();
208 
209   @Theory
decryptCiphertextInputStream_works( @romDataPoints"testVectors") StreamingAeadTestVector v)210   public void decryptCiphertextInputStream_works(
211       @FromDataPoints("testVectors") StreamingAeadTestVector v) throws Exception {
212     KeysetHandle.Builder.Entry entry = KeysetHandle.importKey(v.getKey()).makePrimary();
213     @Nullable Integer id = v.getKey().getIdRequirementOrNull();
214     if (id == null) {
215       entry.withRandomId();
216     } else {
217       entry.withFixedId(id);
218     }
219     KeysetHandle handle = KeysetHandle.newBuilder().addEntry(entry).build();
220     StreamingAead streamingAead =
221         handle.getPrimitive(RegistryConfiguration.get(), StreamingAead.class);
222     InputStream plaintextStream =
223         streamingAead.newDecryptingStream(
224             new ByteArrayInputStream(v.getCiphertext()), v.getAssociatedData());
225     byte[] decryption = new byte[v.getPlaintext().length];
226     plaintextStream.read(decryption);
227     assertThat(decryption).isEqualTo(v.getPlaintext());
228   }
229 
230   @Theory
decryptCiphertextChannel_works( @romDataPoints"testVectors") StreamingAeadTestVector v)231   public void decryptCiphertextChannel_works(
232       @FromDataPoints("testVectors") StreamingAeadTestVector v) throws Exception {
233     KeysetHandle.Builder.Entry entry = KeysetHandle.importKey(v.getKey()).makePrimary();
234     @Nullable Integer id = v.getKey().getIdRequirementOrNull();
235     if (id == null) {
236       entry.withRandomId();
237     } else {
238       entry.withFixedId(id);
239     }
240     KeysetHandle handle = KeysetHandle.newBuilder().addEntry(entry).build();
241     StreamingAead streamingAead =
242         handle.getPrimitive(RegistryConfiguration.get(), StreamingAead.class);
243     ReadableByteChannel plaintextChannel =
244         streamingAead.newDecryptingChannel(
245             new ByteBufferChannel(v.getCiphertext()), v.getAssociatedData());
246     ByteBuffer decryption = ByteBuffer.allocate(v.getPlaintext().length);
247     plaintextChannel.read(decryption);
248     assertThat(decryption.array()).isEqualTo(v.getPlaintext());
249   }
250 }
251