• 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.prf;
17 
18 import static com.google.crypto.tink.internal.TinkBugException.exceptionIsBug;
19 
20 import com.google.crypto.tink.AccessesPartialKey;
21 import com.google.crypto.tink.KeyManager;
22 import com.google.crypto.tink.KeyTemplate;
23 import com.google.crypto.tink.Parameters;
24 import com.google.crypto.tink.config.internal.TinkFipsUtil;
25 import com.google.crypto.tink.internal.KeyManagerRegistry;
26 import com.google.crypto.tink.internal.LegacyKeyManagerImpl;
27 import com.google.crypto.tink.internal.MutableKeyCreationRegistry;
28 import com.google.crypto.tink.internal.MutableParametersRegistry;
29 import com.google.crypto.tink.internal.MutablePrimitiveRegistry;
30 import com.google.crypto.tink.internal.PrimitiveConstructor;
31 import com.google.crypto.tink.prf.internal.HkdfPrfProtoSerialization;
32 import com.google.crypto.tink.proto.KeyData.KeyMaterialType;
33 import com.google.crypto.tink.subtle.prf.HkdfStreamingPrf;
34 import com.google.crypto.tink.subtle.prf.PrfImpl;
35 import com.google.crypto.tink.subtle.prf.StreamingPrf;
36 import com.google.crypto.tink.util.SecretBytes;
37 import java.security.GeneralSecurityException;
38 import java.util.Collections;
39 import java.util.HashMap;
40 import java.util.Map;
41 import javax.annotation.Nullable;
42 
43 /**
44  * This key manager generates new {@code HkdfPrfKey} keys and produces new instances of {@code
45  * HkdfStreamingPrf} and {@code HkdfPrf}.
46  */
47 public class HkdfPrfKeyManager {
validate(HkdfPrfParameters parameters)48   private static void validate(HkdfPrfParameters parameters) throws GeneralSecurityException {
49     if (parameters.getKeySizeBytes() < MIN_KEY_SIZE) {
50       throw new GeneralSecurityException("Key size must be at least " + MIN_KEY_SIZE);
51     }
52     if (parameters.getHashType() != HkdfPrfParameters.HashType.SHA256
53         && parameters.getHashType() != HkdfPrfParameters.HashType.SHA512) {
54       throw new GeneralSecurityException("Hash type must be SHA256 or SHA512");
55     }
56   }
57 
createStreamingPrf(HkdfPrfKey key)58   private static StreamingPrf createStreamingPrf(HkdfPrfKey key) throws GeneralSecurityException {
59     validate(key.getParameters());
60     return HkdfStreamingPrf.create(key);
61   }
62 
createPrf(HkdfPrfKey key)63   private static Prf createPrf(HkdfPrfKey key) throws GeneralSecurityException {
64     return PrfImpl.wrap(createStreamingPrf(key));
65   }
66 
67   private static final PrimitiveConstructor<HkdfPrfKey, StreamingPrf>
68       STREAMING_HKDF_PRF_CONSTRUCTOR =
69           PrimitiveConstructor.create(
70               HkdfPrfKeyManager::createStreamingPrf, HkdfPrfKey.class, StreamingPrf.class);
71   private static final PrimitiveConstructor<HkdfPrfKey, Prf> HKDF_PRF_CONSTRUCTOR =
72       PrimitiveConstructor.create(HkdfPrfKeyManager::createPrf, HkdfPrfKey.class, Prf.class);
73 
74   private static final KeyManager<Prf> legacyKeyManager =
75       LegacyKeyManagerImpl.create(
76           getKeyType(),
77           Prf.class,
78           KeyMaterialType.SYMMETRIC,
79           com.google.crypto.tink.proto.HkdfPrfKey.parser());
80 
81   @AccessesPartialKey
newKey(HkdfPrfParameters parameters, @Nullable Integer idRequirement)82   private static HkdfPrfKey newKey(HkdfPrfParameters parameters, @Nullable Integer idRequirement)
83       throws GeneralSecurityException {
84     if (idRequirement != null) {
85       throw new GeneralSecurityException("Id Requirement is not supported for HKDF PRF keys");
86     }
87     validate(parameters);
88     return HkdfPrfKey.builder()
89         .setParameters(parameters)
90         .setKeyBytes(SecretBytes.randomBytes(parameters.getKeySizeBytes()))
91         .build();
92   }
93 
94   @SuppressWarnings("InlineLambdaConstant") // We need a correct Object#equals in registration.
95   static final MutableKeyCreationRegistry.KeyCreator<HkdfPrfParameters> KEY_CREATOR =
96       HkdfPrfKeyManager::newKey;
97 
getKeyType()98   static String getKeyType() {
99     return "type.googleapis.com/google.crypto.tink.HkdfPrfKey";
100   }
101 
namedParameters()102   private static Map<String, Parameters> namedParameters() throws GeneralSecurityException {
103     Map<String, Parameters> result = new HashMap<>();
104     result.put("HKDF_SHA256", PredefinedPrfParameters.HKDF_SHA256);
105     return Collections.unmodifiableMap(result);
106   }
107 
108   // We use a somewhat larger minimum key size than usual, because PRFs might be used by many users,
109   // in which case the security can degrade by a factor depending on the number of users. (Discussed
110   // for example in https://eprint.iacr.org/2012/159)
111   private static final int MIN_KEY_SIZE = 32;
112 
register(boolean newKeyAllowed)113   public static void register(boolean newKeyAllowed) throws GeneralSecurityException {
114     if (!TinkFipsUtil.AlgorithmFipsCompatibility.ALGORITHM_NOT_FIPS.isCompatible()) {
115       throw new GeneralSecurityException("Registering HKDF PRF is not supported in FIPS mode");
116     }
117     HkdfPrfProtoSerialization.register();
118     MutablePrimitiveRegistry.globalInstance().registerPrimitiveConstructor(HKDF_PRF_CONSTRUCTOR);
119     MutablePrimitiveRegistry.globalInstance()
120         .registerPrimitiveConstructor(STREAMING_HKDF_PRF_CONSTRUCTOR);
121     MutableKeyCreationRegistry.globalInstance().add(KEY_CREATOR, HkdfPrfParameters.class);
122     MutableParametersRegistry.globalInstance().putAll(namedParameters());
123     KeyManagerRegistry.globalInstance().registerKeyManager(legacyKeyManager, newKeyAllowed);
124   }
125 
staticKeyType()126   public static String staticKeyType() {
127     return HkdfPrfKeyManager.getKeyType();
128   }
129 
130   /**
131    * Generates a {@link KeyTemplate} for HKDF-PRF keys with the following parameters.
132    *
133    * <ul>
134    *   <li>Hash function: SHA256
135    *   <li>HMAC key size: 32 bytes
136    *   <li>Salt: empty
137    * </ul>
138    */
hkdfSha256Template()139   public static final KeyTemplate hkdfSha256Template() {
140     return exceptionIsBug(
141         () ->
142             KeyTemplate.createFrom(
143                 HkdfPrfParameters.builder()
144                     .setKeySizeBytes(32)
145                     .setHashType(HkdfPrfParameters.HashType.SHA256)
146                     .build()));
147   }
148 
HkdfPrfKeyManager()149   private HkdfPrfKeyManager() {}
150 }
151