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.prf; 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.TinkProtoKeysetFormat; 30 import com.google.crypto.tink.internal.KeyManagerRegistry; 31 import com.google.crypto.tink.internal.MutablePrimitiveRegistry; 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.subtle.Hex; 38 import com.google.crypto.tink.subtle.PrfHmacJce; 39 import com.google.crypto.tink.util.SecretBytes; 40 import java.io.ByteArrayInputStream; 41 import java.util.Arrays; 42 import java.util.Set; 43 import java.util.TreeSet; 44 import org.junit.Before; 45 import org.junit.Test; 46 import org.junit.experimental.theories.DataPoints; 47 import org.junit.experimental.theories.FromDataPoints; 48 import org.junit.experimental.theories.Theories; 49 import org.junit.experimental.theories.Theory; 50 import org.junit.runner.RunWith; 51 52 /** Unit tests for {@link HmacPrfKeyManager}. */ 53 @RunWith(Theories.class) 54 public class HmacPrfKeyManagerTest { 55 @Before register()56 public void register() throws Exception { 57 KeyDerivationConfig.register(); 58 PrfConfig.register(); 59 } 60 61 @Test testHmacSha256Template()62 public void testHmacSha256Template() throws Exception { 63 KeyTemplate template = HmacPrfKeyManager.hmacSha256Template(); 64 assertThat(template.toParameters()) 65 .isEqualTo( 66 HmacPrfParameters.builder() 67 .setKeySizeBytes(32) 68 .setHashType(HmacPrfParameters.HashType.SHA256) 69 .build()); 70 } 71 72 @Test testHmacSha512Template()73 public void testHmacSha512Template() throws Exception { 74 KeyTemplate template = HmacPrfKeyManager.hmacSha512Template(); 75 assertThat(template.toParameters()) 76 .isEqualTo( 77 HmacPrfParameters.builder() 78 .setKeySizeBytes(64) 79 .setHashType(HmacPrfParameters.HashType.SHA512) 80 .build()); 81 } 82 83 @Test testKeyTemplateAndManagerCompatibility()84 public void testKeyTemplateAndManagerCompatibility() throws Exception { 85 Parameters p = HmacPrfKeyManager.hmacSha256Template().toParameters(); 86 assertThat(KeysetHandle.generateNew(p).getAt(0).getKey().getParameters()).isEqualTo(p); 87 88 p = HmacPrfKeyManager.hmacSha256Template().toParameters(); 89 assertThat(KeysetHandle.generateNew(p).getAt(0).getKey().getParameters()).isEqualTo(p); 90 } 91 92 @DataPoints("templateNames") 93 public static final String[] KEY_TEMPLATES = new String[] {"HMAC_SHA256_PRF", "HMAC_SHA512_PRF"}; 94 95 @Theory testTemplates(@romDataPoints"templateNames") String templateName)96 public void testTemplates(@FromDataPoints("templateNames") String templateName) throws Exception { 97 KeysetHandle h = KeysetHandle.generateNew(KeyTemplates.get(templateName)); 98 assertThat(h.size()).isEqualTo(1); 99 assertThat(h.getAt(0).getKey().getParameters()) 100 .isEqualTo(KeyTemplates.get(templateName).toParameters()); 101 } 102 103 @Test registersPrfPrimitiveConstructor()104 public void registersPrfPrimitiveConstructor() throws Exception { 105 Prf prf = 106 MutablePrimitiveRegistry.globalInstance() 107 .getPrimitive( 108 com.google.crypto.tink.prf.HmacPrfKey.builder() 109 .setParameters( 110 HmacPrfParameters.builder() 111 .setHashType(HmacPrfParameters.HashType.SHA256) 112 .setKeySizeBytes(32) 113 .build()) 114 .setKeyBytes(SecretBytes.randomBytes(32)) 115 .build(), 116 Prf.class); 117 118 assertThat(prf).isInstanceOf(PrfHmacJce.class); 119 } 120 121 @Theory testCreateKeyFromRandomness(@romDataPoints"templateNames") String templateName)122 public void testCreateKeyFromRandomness(@FromDataPoints("templateNames") String templateName) 123 throws Exception { 124 byte[] keyMaterial = 125 new byte[] { 126 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, 127 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 128 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 129 }; 130 HmacPrfParameters parameters = 131 (HmacPrfParameters) KeyTemplates.get(templateName).toParameters(); 132 com.google.crypto.tink.prf.HmacPrfKey key = 133 HmacPrfKeyManager.createHmacKeyFromRandomness( 134 parameters, new ByteArrayInputStream(keyMaterial), null, InsecureSecretKeyAccess.get()); 135 byte[] expectedKeyBytes = Arrays.copyOf(keyMaterial, parameters.getKeySizeBytes()); 136 Key expectedKey = 137 com.google.crypto.tink.prf.HmacPrfKey.builder() 138 .setParameters(parameters) 139 .setKeyBytes(SecretBytes.copyFrom(expectedKeyBytes, InsecureSecretKeyAccess.get())) 140 .build(); 141 assertTrue(key.equalsKey(expectedKey)); 142 } 143 144 @Test testCreateKeyFromRandomness_slowInputStream_works()145 public void testCreateKeyFromRandomness_slowInputStream_works() throws Exception { 146 byte[] keyMaterial = 147 new byte[] { 148 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, 149 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 150 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 151 }; 152 HmacPrfParameters parameters = 153 HmacPrfParameters.builder() 154 .setKeySizeBytes(64) 155 .setHashType(HmacPrfParameters.HashType.SHA512) 156 .build(); 157 com.google.crypto.tink.prf.HmacPrfKey key = 158 HmacPrfKeyManager.createHmacKeyFromRandomness( 159 parameters, SlowInputStream.copyFrom(keyMaterial), null, InsecureSecretKeyAccess.get()); 160 byte[] expectedKeyBytes = Arrays.copyOf(keyMaterial, parameters.getKeySizeBytes()); 161 Key expectedKey = 162 com.google.crypto.tink.prf.HmacPrfKey.builder() 163 .setParameters(parameters) 164 .setKeyBytes(SecretBytes.copyFrom(expectedKeyBytes, InsecureSecretKeyAccess.get())) 165 .build(); 166 assertTrue(key.equalsKey(expectedKey)); 167 } 168 169 @Test testKeyManagerRegistered()170 public void testKeyManagerRegistered() throws Exception { 171 assertThat( 172 KeyManagerRegistry.globalInstance() 173 .getKeyManager("type.googleapis.com/google.crypto.tink.HmacPrfKey", Prf.class)) 174 .isNotNull(); 175 } 176 177 @Test createKey_works()178 public void createKey_works() throws Exception { 179 HmacPrfParameters params = 180 HmacPrfParameters.builder() 181 .setHashType(HmacPrfParameters.HashType.SHA256) 182 .setKeySizeBytes(32) 183 .build(); 184 KeysetHandle handle = KeysetHandle.generateNew(params); 185 assertThat(handle.size()).isEqualTo(1); 186 com.google.crypto.tink.prf.HmacPrfKey key = 187 (com.google.crypto.tink.prf.HmacPrfKey) handle.getAt(0).getKey(); 188 assertThat(key.getParameters()).isEqualTo(params); 189 } 190 191 @Test createKey_otherParams_works()192 public void createKey_otherParams_works() throws Exception { 193 HmacPrfParameters params = 194 HmacPrfParameters.builder() 195 .setHashType(HmacPrfParameters.HashType.SHA512) 196 .setKeySizeBytes(32) 197 .build(); 198 KeysetHandle handle = KeysetHandle.generateNew(params); 199 assertThat(handle.size()).isEqualTo(1); 200 com.google.crypto.tink.prf.HmacPrfKey key = 201 (com.google.crypto.tink.prf.HmacPrfKey) handle.getAt(0).getKey(); 202 assertThat(key.getParameters()).isEqualTo(params); 203 } 204 205 @Test createKey_differentKeyValues_alwaysDifferent()206 public void createKey_differentKeyValues_alwaysDifferent() throws Exception { 207 HmacPrfParameters params = 208 HmacPrfParameters.builder() 209 .setHashType(HmacPrfParameters.HashType.SHA512) 210 .setKeySizeBytes(32) 211 .build(); 212 213 int numKeys = 100; 214 Set<String> keys = new TreeSet<>(); 215 for (int i = 0; i < numKeys; i++) { 216 KeysetHandle handle = KeysetHandle.generateNew(params); 217 assertThat(handle.size()).isEqualTo(1); 218 com.google.crypto.tink.prf.HmacPrfKey key = 219 (com.google.crypto.tink.prf.HmacPrfKey) handle.getAt(0).getKey(); 220 keys.add(Hex.encode(key.getKeyBytes().toByteArray(InsecureSecretKeyAccess.get()))); 221 } 222 assertThat(keys).hasSize(numKeys); 223 } 224 225 @Test createPrimitiveAndUseIt_works()226 public void createPrimitiveAndUseIt_works() throws Exception { 227 HmacPrfParameters params = 228 HmacPrfParameters.builder() 229 .setHashType(HmacPrfParameters.HashType.SHA512) 230 .setKeySizeBytes(32) 231 .build(); 232 KeysetHandle handle = KeysetHandle.generateNew(params); 233 assertThat(handle.size()).isEqualTo(1); 234 PrfSet prfSet = handle.getPrimitive(RegistryConfiguration.get(), PrfSet.class); 235 Prf directPrf = 236 PrfHmacJce.create((com.google.crypto.tink.prf.HmacPrfKey) handle.getAt(0).getKey()); 237 assertThat(prfSet.computePrimary(new byte[0], 16)) 238 .isEqualTo(directPrf.compute(new byte[0], 16)); 239 } 240 241 @Test serializeAndDeserializeKeysets()242 public void serializeAndDeserializeKeysets() throws Exception { 243 HmacPrfParameters params = 244 HmacPrfParameters.builder() 245 .setHashType(HmacPrfParameters.HashType.SHA512) 246 .setKeySizeBytes(32) 247 .build(); 248 KeysetHandle handle = KeysetHandle.generateNew(params); 249 250 byte[] serializedKeyset = 251 TinkProtoKeysetFormat.serializeKeyset(handle, InsecureSecretKeyAccess.get()); 252 KeysetHandle parsed = 253 TinkProtoKeysetFormat.parseKeyset(serializedKeyset, InsecureSecretKeyAccess.get()); 254 assertTrue(parsed.equalsKeyset(handle)); 255 } 256 257 @Test deriveHmacPrfKey_works()258 public void deriveHmacPrfKey_works() throws Exception { 259 PrfKey prfKeyForDeriver = 260 HkdfPrfKey.builder() 261 .setParameters( 262 HkdfPrfParameters.builder() 263 .setKeySizeBytes(32) 264 .setHashType(HkdfPrfParameters.HashType.SHA256) 265 .build()) 266 .setKeyBytes( 267 SecretBytes.copyFrom( 268 Hex.decode("0102030405060708091011121314151617181920212123242526272829303132"), 269 InsecureSecretKeyAccess.get())) 270 .build(); 271 PrfBasedKeyDerivationParameters derivationParameters = 272 PrfBasedKeyDerivationParameters.builder() 273 .setDerivedKeyParameters(PredefinedPrfParameters.HMAC_SHA256_PRF) 274 .setPrfParameters(prfKeyForDeriver.getParameters()) 275 .build(); 276 PrfBasedKeyDerivationKey key = 277 PrfBasedKeyDerivationKey.create( 278 derivationParameters, prfKeyForDeriver, /* idRequirement= */ null); 279 280 KeysetHandle keyset = 281 KeysetHandle.newBuilder() 282 .addEntry(KeysetHandle.importKey(key).withFixedId(112233).makePrimary()) 283 .build(); 284 KeysetDeriver deriver = keyset.getPrimitive(RegistryConfiguration.get(), KeysetDeriver.class); 285 286 KeysetHandle derivedKeyset = deriver.deriveKeyset(Hex.decode("000102")); 287 288 assertThat(derivedKeyset.size()).isEqualTo(1); 289 assertThat( 290 derivedKeyset 291 .getAt(0) 292 .getKey() 293 .equalsKey( 294 com.google.crypto.tink.prf.HmacPrfKey.builder() 295 .setParameters(PredefinedPrfParameters.HMAC_SHA256_PRF) 296 .setKeyBytes( 297 SecretBytes.copyFrom( 298 Hex.decode( 299 "94e397d674deda6e965295698491a3feb69838a35f1d48143f3c4cbad9" 300 + "0eeb24"), 301 InsecureSecretKeyAccess.get())) 302 .build())) 303 .isTrue(); 304 } 305 } 306