• 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.tinkkey;
17 
18 import static com.google.common.truth.Truth.assertThat;
19 import static com.google.crypto.tink.internal.KeyTemplateProtoConverter.getOutputPrefixType;
20 import static org.junit.Assert.assertThrows;
21 
22 import com.google.common.truth.Expect;
23 import com.google.crypto.tink.KeyTemplate;
24 import com.google.crypto.tink.KeyTemplate.OutputPrefixType;
25 import com.google.crypto.tink.KeyTemplates;
26 import com.google.crypto.tink.Registry;
27 import com.google.crypto.tink.aead.AesEaxKeyManager;
28 import com.google.crypto.tink.aead.AesEaxParameters;
29 import com.google.crypto.tink.proto.AesEaxKey;
30 import com.google.crypto.tink.proto.KeyData;
31 import com.google.crypto.tink.signature.Ed25519PrivateKeyManager;
32 import com.google.crypto.tink.tinkkey.internal.ProtoKey;
33 import com.google.errorprone.annotations.Immutable;
34 import com.google.protobuf.ByteString;
35 import com.google.protobuf.ExtensionRegistryLite;
36 import java.security.GeneralSecurityException;
37 import java.util.Set;
38 import java.util.TreeSet;
39 import org.junit.Before;
40 import org.junit.Rule;
41 import org.junit.Test;
42 import org.junit.runner.RunWith;
43 import org.junit.runners.JUnit4;
44 
45 /** Tests for KeyHandle * */
46 @RunWith(JUnit4.class)
47 public final class KeyHandleTest {
48 
49   @Rule public final Expect expect = Expect.create();
50 
51   @Immutable
52   static final class DummyTinkKey implements TinkKey {
53     private final boolean hasSecret;
54     private final KeyTemplate template;
55 
DummyTinkKey(boolean hasSecret)56     public DummyTinkKey(boolean hasSecret) {
57       this.hasSecret = hasSecret;
58       this.template = null;
59     }
60 
DummyTinkKey(boolean hasSecret, KeyTemplate template)61     public DummyTinkKey(boolean hasSecret, KeyTemplate template) {
62       this.hasSecret = hasSecret;
63       this.template = template;
64     }
65 
66     @Override
hasSecret()67     public boolean hasSecret() {
68       return hasSecret;
69     }
70 
71     @Override
getKeyTemplate()72     public KeyTemplate getKeyTemplate() {
73       if (template == null) {
74         throw new UnsupportedOperationException();
75       }
76       return template;
77     }
78   }
79 
80   @Before
setUp()81   public void setUp() throws Exception {
82     AesEaxKeyManager.register(/* newKeyAllowed= */ true);
83     Ed25519PrivateKeyManager.registerPair(/* newKeyAllowed= */ true);
84   }
85 
86   @Test
createFromKey_tinkKeyWithSecret_noSecretKeyAccess_shouldThrowException()87   public void createFromKey_tinkKeyWithSecret_noSecretKeyAccess_shouldThrowException()
88       throws Exception {
89     TinkKey key = new DummyTinkKey(/* hasSecret= */ true);
90     KeyAccess access = KeyAccess.publicAccess();
91 
92     assertThrows(GeneralSecurityException.class, () -> KeyHandle.createFromKey(key, access));
93   }
94 
95   @Test
createFromKey_keyDataSymmetric_shouldHaveSecret()96   public void createFromKey_keyDataSymmetric_shouldHaveSecret() throws Exception {
97     KeyTemplate kt = KeyTemplates.get("AES128_EAX");
98     KeyData kd = Registry.newKeyData(kt);
99 
100     KeyHandle kh = KeyHandle.createFromKey(kd, getOutputPrefixType(kt));
101 
102     assertThat(kh.hasSecret()).isTrue();
103   }
104 
105   @Test
createFromKey_keyDataAsymmetricPrivate_shouldHaveSecret()106   public void createFromKey_keyDataAsymmetricPrivate_shouldHaveSecret() throws Exception {
107     KeyTemplate kt = KeyTemplates.get("ED25519");
108     KeyData kd = Registry.newKeyData(kt);
109 
110     KeyHandle kh = KeyHandle.createFromKey(kd, getOutputPrefixType(kt));
111 
112     assertThat(kh.hasSecret()).isTrue();
113   }
114 
115   @Test
createFromKey_keyDataUnknown_shouldHaveSecret()116   public void createFromKey_keyDataUnknown_shouldHaveSecret() throws Exception {
117     KeyTemplate kt = KeyTemplates.get("ED25519");
118     KeyData kd =
119         KeyData.newBuilder()
120             .mergeFrom(Registry.newKeyData(kt))
121             .setKeyMaterialType(KeyData.KeyMaterialType.UNKNOWN_KEYMATERIAL)
122             .build();
123 
124     KeyHandle kh = KeyHandle.createFromKey(kd, getOutputPrefixType(kt));
125 
126     assertThat(kh.hasSecret()).isTrue();
127   }
128 
129   @Test
createFromKey_keyDataAsymmetricPublic_shouldNotHaveSecret()130   public void createFromKey_keyDataAsymmetricPublic_shouldNotHaveSecret() throws Exception {
131     KeyTemplate kt = KeyTemplates.get("ED25519");
132     KeyData privateKeyData = Registry.newKeyData(kt);
133     KeyData kd = Registry.getPublicKeyData(privateKeyData.getTypeUrl(), privateKeyData.getValue());
134 
135     KeyHandle kh = KeyHandle.createFromKey(kd, getOutputPrefixType(kt));
136 
137     assertThat(kh.hasSecret()).isFalse();
138   }
139 
140   @Test
createFromKey_keyDataRemote_shouldNotHaveSecret()141   public void createFromKey_keyDataRemote_shouldNotHaveSecret() throws Exception {
142     KeyTemplate kt = KeyTemplates.get("ED25519");
143     KeyData kd =
144         KeyData.newBuilder()
145             .mergeFrom(Registry.newKeyData(kt))
146             .setKeyMaterialType(KeyData.KeyMaterialType.REMOTE)
147             .build();
148 
149     KeyHandle kh = KeyHandle.createFromKey(kd, getOutputPrefixType(kt));
150 
151     assertThat(kh.hasSecret()).isFalse();
152   }
153 
154   @Test
generateNew_shouldWork()155   public void generateNew_shouldWork() throws Exception {
156     KeyTemplate template = KeyTemplates.get("AES128_EAX");
157 
158     KeyHandle handle = KeyHandle.generateNew(template);
159 
160     ProtoKey protoKey = (ProtoKey) handle.getKey(SecretKeyAccess.insecureSecretAccess());
161     expect.that(protoKey.getOutputPrefixType()).isEqualTo(KeyTemplate.OutputPrefixType.TINK);
162     expect.that(protoKey.hasSecret()).isTrue();
163     KeyData keyData = protoKey.getProtoKey();
164     expect.that(keyData.getTypeUrl()).isEqualTo("type.googleapis.com/google.crypto.tink.AesEaxKey");
165 
166     AesEaxParameters parameters = (AesEaxParameters) template.toParameters();
167 
168     AesEaxKey aesEaxKey =
169         AesEaxKey.parseFrom(keyData.getValue(), ExtensionRegistryLite.getEmptyRegistry());
170     expect.that(aesEaxKey.getKeyValue().size()).isEqualTo(parameters.getKeySizeBytes());
171   }
172 
173   @Test
generateNew_compareWith_createFromKeyViaProtoKey_shouldBeEqual()174   public void generateNew_compareWith_createFromKeyViaProtoKey_shouldBeEqual() throws Exception {
175     KeyTemplate template = KeyTemplates.get("AES128_EAX");
176     KeyData keyData = Registry.newKeyData(template);
177     ProtoKey protoKey = new ProtoKey(keyData, KeyTemplate.OutputPrefixType.TINK);
178 
179     KeyHandle handle1 = KeyHandle.generateNew(template);
180     KeyHandle handle2 = KeyHandle.createFromKey(protoKey, SecretKeyAccess.insecureSecretAccess());
181 
182     expect.that(handle1.getStatus()).isEqualTo(handle2.getStatus());
183     ProtoKey outputProtoKey1 = (ProtoKey) handle1.getKey(SecretKeyAccess.insecureSecretAccess());
184     ProtoKey outputProtoKey2 = (ProtoKey) handle2.getKey(SecretKeyAccess.insecureSecretAccess());
185     expect
186         .that(outputProtoKey1.getOutputPrefixType())
187         .isEqualTo(outputProtoKey2.getOutputPrefixType());
188     expect.that(handle1.hasSecret()).isEqualTo(handle2.hasSecret());
189   }
190 
191   @Test
generateNew_generatesDifferentKeys()192   public void generateNew_generatesDifferentKeys() throws Exception {
193     KeyTemplate template = KeyTemplates.get("AES128_EAX");
194     Set<String> keys = new TreeSet<>();
195 
196     int numKeys = 2;
197     for (int j = 0; j < numKeys; j++) {
198       KeyHandle handle = KeyHandle.generateNew(template);
199       ProtoKey protoKey = (ProtoKey) handle.getKey(SecretKeyAccess.insecureSecretAccess());
200       KeyData keyData = protoKey.getProtoKey();
201       AesEaxKey aesEaxKey =
202           AesEaxKey.parseFrom(keyData.getValue(), ExtensionRegistryLite.getEmptyRegistry());
203       keys.add(aesEaxKey.getKeyValue().toStringUtf8());
204     }
205 
206     assertThat(keys).hasSize(numKeys);
207   }
208 
209   @Test
generateNew_unregisteredTypeUrl_shouldThrow()210   public void generateNew_unregisteredTypeUrl_shouldThrow() throws Exception {
211     String typeUrl = "testNewKeyDataTypeUrl";
212     ByteString keyformat = ByteString.copyFromUtf8("testNewKeyDataKeyFormat");
213     com.google.crypto.tink.KeyTemplate keyTemplate =
214         com.google.crypto.tink.KeyTemplate.create(
215             typeUrl, keyformat.toByteArray(), OutputPrefixType.TINK);
216 
217     assertThrows(GeneralSecurityException.class, () -> KeyHandle.generateNew(keyTemplate));
218   }
219 
220   @Test
hasSecret_tinkKeyWithSecret_shouldReturnTrue()221   public void hasSecret_tinkKeyWithSecret_shouldReturnTrue() throws Exception {
222     TinkKey key = new DummyTinkKey(/* hasSecret= */ true);
223     KeyHandle kh = KeyHandle.createFromKey(key, SecretKeyAccess.insecureSecretAccess());
224 
225     assertThat(kh.hasSecret()).isTrue();
226   }
227 
228   @Test
hasSecret_tinkKeyWithoutSecret_shouldReturnFalse()229   public void hasSecret_tinkKeyWithoutSecret_shouldReturnFalse() throws Exception {
230     TinkKey key = new DummyTinkKey(/* hasSecret= */ false);
231     KeyAccess access = KeyAccess.publicAccess();
232     KeyHandle kh = KeyHandle.createFromKey(key, access);
233 
234     assertThat(kh.hasSecret()).isFalse();
235   }
236 
237   @Test
getKey_tinkKeyWithoutSecret_noSecretKeyAccess_shouldWork()238   public void getKey_tinkKeyWithoutSecret_noSecretKeyAccess_shouldWork() throws Exception {
239     TinkKey key = new DummyTinkKey(/* hasSecret= */ false);
240     KeyAccess access = KeyAccess.publicAccess();
241     KeyHandle kh = KeyHandle.createFromKey(key, access);
242 
243     assertThat(kh.getKey(access)).isEqualTo(key);
244   }
245 
246   @Test
getKey_tinkKeyWithoutSecret_secretKeyAccess_shouldWork()247   public void getKey_tinkKeyWithoutSecret_secretKeyAccess_shouldWork() throws Exception {
248     TinkKey key = new DummyTinkKey(/* hasSecret= */ false);
249     KeyAccess access = SecretKeyAccess.insecureSecretAccess();
250     KeyHandle kh = KeyHandle.createFromKey(key, access);
251 
252     assertThat(kh.getKey(access)).isEqualTo(key);
253   }
254 
255   @Test
getKey_tinkKeyWithSecret_noSecretKeyAccess_shouldThrowException()256   public void getKey_tinkKeyWithSecret_noSecretKeyAccess_shouldThrowException() throws Exception {
257     TinkKey key = new DummyTinkKey(/* hasSecret= */ true);
258     KeyHandle kh = KeyHandle.createFromKey(key, SecretKeyAccess.insecureSecretAccess());
259     KeyAccess pubAccess = KeyAccess.publicAccess();
260 
261     assertThrows(GeneralSecurityException.class, () -> kh.getKey(pubAccess));
262   }
263 
264   @Test
getKey_tinkKeyWithSecret_secretKeyAccess_shouldWork()265   public void getKey_tinkKeyWithSecret_secretKeyAccess_shouldWork() throws Exception {
266     TinkKey key = new DummyTinkKey(/* hasSecret= */ true);
267     KeyAccess access = SecretKeyAccess.insecureSecretAccess();
268     KeyHandle kh = KeyHandle.createFromKey(key, access);
269 
270     assertThat(kh.getKey(access)).isEqualTo(key);
271   }
272 
273   @Test
getKeyTemplate()274   public void getKeyTemplate() throws Exception {
275     KeyTemplate keyTemplate = KeyTemplates.get("ED25519_RAW");
276     TinkKey key = new DummyTinkKey(/* hasSecret= */ false, keyTemplate);
277     KeyHandle keyHandle = KeyHandle.createFromKey(key, KeyAccess.publicAccess());
278 
279     KeyTemplate returnedKeyTemplate = keyHandle.getKeyTemplate();
280 
281     assertThat(returnedKeyTemplate.toParameters()).isEqualTo(keyTemplate.toParameters());
282   }
283 
284   @Test
getKeyTemplate_tinkKeyWithoutKeyTemplateSupport_shouldThrow()285   public void getKeyTemplate_tinkKeyWithoutKeyTemplateSupport_shouldThrow() throws Exception {
286     TinkKey key = new DummyTinkKey(/* hasSecret= */ false);
287     KeyHandle keyHandle = KeyHandle.createFromKey(key, KeyAccess.publicAccess());
288 
289     assertThrows(UnsupportedOperationException.class, keyHandle::getKeyTemplate);
290   }
291 }
292