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