• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2022 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.prf;
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.assertThrows;
22 
23 import com.google.crypto.tink.DeterministicAead;
24 import com.google.crypto.tink.InsecureSecretKeyAccess;
25 import com.google.crypto.tink.KeyTemplates;
26 import com.google.crypto.tink.KeysetHandle;
27 import com.google.crypto.tink.Mac;
28 import com.google.crypto.tink.RegistryConfiguration;
29 import com.google.crypto.tink.TinkJsonProtoKeysetFormat;
30 import com.google.crypto.tink.daead.DeterministicAeadConfig;
31 import java.security.GeneralSecurityException;
32 import org.junit.BeforeClass;
33 import org.junit.experimental.theories.DataPoints;
34 import org.junit.experimental.theories.FromDataPoints;
35 import org.junit.experimental.theories.Theories;
36 import org.junit.experimental.theories.Theory;
37 import org.junit.runner.RunWith;
38 
39 /** Unit tests for the Prf package. Uses only the public API. */
40 @RunWith(Theories.class)
41 public final class PrfTest {
42 
43   @BeforeClass
setUp()44   public static void setUp() throws Exception {
45     PrfConfig.register();
46     DeterministicAeadConfig.register(); // Needed for getPrimitiveFromNonMacKeyset_throws.
47   }
48 
49   @DataPoints("templates")
50   public static final String[] TEMPLATES =
51       new String[] {
52         "AES_CMAC_PRF",
53         "HMAC_SHA256_PRF",
54         "HMAC_SHA512_PRF",
55         "HKDF_SHA256",
56       };
57 
58   @Theory
create_computeVerify(@romDataPoints"templates") String templateName)59   public void create_computeVerify(@FromDataPoints("templates") String templateName)
60       throws Exception {
61     KeysetHandle handle = KeysetHandle.generateNew(KeyTemplates.get(templateName));
62     int primaryId = handle.getPrimary().getId();
63     PrfSet prfSet = handle.getPrimitive(RegistryConfiguration.get(), PrfSet.class);
64 
65     byte[] data = "data".getBytes(UTF_8);
66     byte[] outputPrimary = prfSet.computePrimary(data, 12);
67     byte[] output = prfSet.getPrfs().get(primaryId).compute(data, 12);
68     assertThat(output).isEqualTo(outputPrimary);
69 
70     int invalidId = primaryId + 1;
71     assertThat(prfSet.getPrfs().get(invalidId)).isNull();
72   }
73 
74   // A keyset with one MAC key, serialized in Tink's JSON format.
75   private static final String JSON_PRF_KEYSET =
76       ""
77           + "{"
78           + "  \"primaryKeyId\": 166506972,"
79           + "  \"key\": ["
80           + "    {"
81           + "      \"keyData\": {"
82           + "        \"typeUrl\": \"type.googleapis.com/google.crypto.tink.HmacPrfKey\","
83           + "        \"value\": \"GkAlMHOHF4em1ax2/xzlhOX9696c6OIuSuYJ//DmzMshOjeGDjVazNZZKXo"
84           + "yo+USpExayMyab+GtjOfCCVjsECxnEgIIBA==\","
85           + "        \"keyMaterialType\": \"SYMMETRIC\""
86           + "      },"
87           + "      \"status\": \"ENABLED\","
88           + "      \"keyId\": 166506972,"
89           + "      \"outputPrefixType\": \"RAW\""
90           + "    }"
91           + "  ]"
92           + "}";
93 
94   @Theory
readKeysetEncryptDecrypt()95   public void readKeysetEncryptDecrypt()
96       throws Exception {
97     KeysetHandle handle =
98         TinkJsonProtoKeysetFormat.parseKeyset(JSON_PRF_KEYSET, InsecureSecretKeyAccess.get());
99     PrfSet prfSet = handle.getPrimitive(RegistryConfiguration.get(), PrfSet.class);
100 
101     byte[] data = "data".getBytes(UTF_8);
102     byte[] output1 = prfSet.computePrimary(data, 12);
103     byte[] output2 = prfSet.getPrfs().get(166506972).compute(data, 12);
104     assertThat(output2).isEqualTo(output1);
105   }
106 
107   // A keyset with multiple keys. The first key is the same as in JSON_AEAD_KEYSET.
108   private static final String JSON_PRF_KEYSET_WITH_MULTIPLE_KEYS =
109       ""
110           + "{"
111           + "  \"primaryKeyId\": 1781110497,"
112           + "  \"key\": ["
113           + "    {"
114           + "      \"keyData\": {"
115           + "        \"typeUrl\": \"type.googleapis.com/google.crypto.tink.HmacPrfKey\","
116           + "        \"value\": \"GkAlMHOHF4em1ax2/xzlhOX9696c6OIuSuYJ//DmzMshOjeGDjVazNZZKXo"
117           + "yo+USpExayMyab+GtjOfCCVjsECxnEgIIBA==\","
118           + "        \"keyMaterialType\": \"SYMMETRIC\""
119           + "      },"
120           + "      \"status\": \"ENABLED\","
121           + "      \"keyId\": 166506972,"
122           + "      \"outputPrefixType\": \"RAW\""
123           + "    }, {"
124           + "      \"keyData\": {"
125           + "        \"typeUrl\": \"type.googleapis.com/google.crypto.tink.HkdfPrfKey\","
126           + "        \"value\": \"GiC+cZnHCSh8CGzIoe9/jYhJeyk+vNdVSH+77Rc+BaGNvxICCAM=\","
127           + "        \"keyMaterialType\": \"SYMMETRIC\""
128           + "      },"
129           + "      \"status\": \"ENABLED\","
130           + "      \"keyId\": 1781110497,"
131           + "      \"outputPrefixType\": \"RAW\""
132           + "    },"
133           + "    {"
134           + "      \"keyData\": {"
135           + "        \"typeUrl\": \"type.googleapis.com/google.crypto.tink.HmacPrfKey\","
136           + "        \"value\": \"GkBO8P7LMfUeCuqUZUY0xiAOi3q7lABfCA81kHv0qowLsjwmYwAa3leo9tD"
137           + "ez28gJtnWtghWQ3fVfWsZstNIOw0lEgIIBA==\","
138           + "        \"keyMaterialType\": \"SYMMETRIC\""
139           + "      },"
140           + "      \"status\": \"ENABLED\","
141           + "      \"keyId\": 1593211602,"
142           + "      \"outputPrefixType\": \"RAW\""
143           + "    }"
144           + "  ]"
145           + "}";
146 
147   @Theory
multipleKeysReadKeysetWithEncryptDecrypt()148   public void multipleKeysReadKeysetWithEncryptDecrypt()
149       throws Exception {
150     KeysetHandle handle =
151         TinkJsonProtoKeysetFormat.parseKeyset(
152             JSON_PRF_KEYSET_WITH_MULTIPLE_KEYS, InsecureSecretKeyAccess.get());
153 
154     PrfSet prfSet = handle.getPrimitive(RegistryConfiguration.get(), PrfSet.class);
155 
156     byte[] data = "data".getBytes(UTF_8);
157     byte[] outputPrimary = prfSet.computePrimary(data, 12);
158 
159     byte[] output1 = prfSet.getPrfs().get(166506972).compute(data, 12);
160     assertThat(output1).isNotEqualTo(outputPrimary);
161     byte[] output2 = prfSet.getPrfs().get(1781110497).compute(data, 12);
162     assertThat(output2).isEqualTo(outputPrimary);
163     byte[] output3 = prfSet.getPrfs().get(1593211602).compute(data, 12);
164     assertThat(output3).isNotEqualTo(outputPrimary);
165 
166   }
167 
168   // A keyset with a valid DeterministicAead key. This keyset can't be used with the Mac primitive.
169   private static final String JSON_DAEAD_KEYSET =
170       ""
171           + "{"
172           + "  \"primaryKeyId\": 961932622,"
173           + "  \"key\": ["
174           + "    {"
175           + "      \"keyData\": {"
176           + "        \"typeUrl\": \"type.googleapis.com/google.crypto.tink.AesSivKey\","
177           + "        \"keyMaterialType\": \"SYMMETRIC\","
178           + "        \"value\": \"EkCJ9r5iwc5uxq5ugFyrHXh5dijTa7qalWUgZ8Gf08RxNd545FjtLMYL7ObcaFtCS"
179           + "kvV2+7u6F2DN+kqUjAfkf2W\""
180           + "      },"
181           + "      \"outputPrefixType\": \"TINK\","
182           + "      \"keyId\": 961932622,"
183           + "      \"status\": \"ENABLED\""
184           + "    }"
185           + "  ]"
186           + "}";
187 
188   @Theory
getPrimitiveFromNonMacKeyset_throws()189   public void getPrimitiveFromNonMacKeyset_throws() throws Exception {
190     KeysetHandle handle =
191         TinkJsonProtoKeysetFormat.parseKeyset(JSON_DAEAD_KEYSET, InsecureSecretKeyAccess.get());
192     // Test that the keyset can create a DeterministicAead primitive, but not a Mac.
193     Object unused = handle.getPrimitive(RegistryConfiguration.get(), DeterministicAead.class);
194     assertThrows(
195         GeneralSecurityException.class,
196         () -> handle.getPrimitive(RegistryConfiguration.get(), Mac.class));
197   }
198 }
199