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.crypto.tink.internal.TinkBugException.exceptionIsBug; 20 21 import com.google.crypto.tink.AccessesPartialKey; 22 import com.google.crypto.tink.KeyManager; 23 import com.google.crypto.tink.KeyTemplate; 24 import com.google.crypto.tink.Parameters; 25 import com.google.crypto.tink.SecretKeyAccess; 26 import com.google.crypto.tink.config.internal.TinkFipsUtil; 27 import com.google.crypto.tink.internal.KeyManagerRegistry; 28 import com.google.crypto.tink.internal.LegacyKeyManagerImpl; 29 import com.google.crypto.tink.internal.MutableKeyCreationRegistry; 30 import com.google.crypto.tink.internal.MutableKeyDerivationRegistry; 31 import com.google.crypto.tink.internal.MutableParametersRegistry; 32 import com.google.crypto.tink.internal.MutablePrimitiveRegistry; 33 import com.google.crypto.tink.internal.PrimitiveConstructor; 34 import com.google.crypto.tink.internal.Util; 35 import com.google.crypto.tink.prf.internal.HmacPrfProtoSerialization; 36 import com.google.crypto.tink.proto.KeyData.KeyMaterialType; 37 import com.google.crypto.tink.subtle.PrfHmacJce; 38 import com.google.crypto.tink.util.SecretBytes; 39 import java.io.InputStream; 40 import java.security.GeneralSecurityException; 41 import java.util.Collections; 42 import java.util.HashMap; 43 import java.util.Map; 44 import javax.annotation.Nullable; 45 46 /** 47 * This key manager generates new {@code HmacPrfKey} keys and produces new instances of {@code 48 * PrfHmacJce}. 49 */ 50 public final class HmacPrfKeyManager { 51 52 private static final PrimitiveConstructor<com.google.crypto.tink.prf.HmacPrfKey, Prf> 53 PRF_PRIMITIVE_CONSTRUCTOR = 54 PrimitiveConstructor.create( 55 PrfHmacJce::create, com.google.crypto.tink.prf.HmacPrfKey.class, Prf.class); 56 57 private static final KeyManager<Prf> legacyKeyManager = 58 LegacyKeyManagerImpl.create( 59 getKeyType(), 60 Prf.class, 61 KeyMaterialType.SYMMETRIC, 62 com.google.crypto.tink.proto.HmacPrfKey.parser()); 63 64 @AccessesPartialKey newKey(HmacPrfParameters parameters, @Nullable Integer idRequirement)65 private static HmacPrfKey newKey(HmacPrfParameters parameters, @Nullable Integer idRequirement) 66 throws GeneralSecurityException { 67 if (idRequirement != null) { 68 throw new GeneralSecurityException("Id Requirement is not supported for HMAC PRF keys"); 69 } 70 return HmacPrfKey.builder() 71 .setParameters(parameters) 72 .setKeyBytes(SecretBytes.randomBytes(parameters.getKeySizeBytes())) 73 .build(); 74 } 75 76 @SuppressWarnings("InlineLambdaConstant") // We need a correct Object#equals in registration. 77 private static final MutableKeyCreationRegistry.KeyCreator<HmacPrfParameters> KEY_CREATOR = 78 HmacPrfKeyManager::newKey; 79 getKeyType()80 static String getKeyType() { 81 return "type.googleapis.com/google.crypto.tink.HmacPrfKey"; 82 } 83 84 @SuppressWarnings("InlineLambdaConstant") // We need a correct Object#equals in registration. 85 private static final MutableKeyDerivationRegistry.InsecureKeyCreator<HmacPrfParameters> 86 KEY_DERIVER = HmacPrfKeyManager::createHmacKeyFromRandomness; 87 88 @AccessesPartialKey createHmacKeyFromRandomness( HmacPrfParameters parameters, InputStream stream, @Nullable Integer idRequirement, SecretKeyAccess access)89 static com.google.crypto.tink.prf.HmacPrfKey createHmacKeyFromRandomness( 90 HmacPrfParameters parameters, 91 InputStream stream, 92 @Nullable Integer idRequirement, 93 SecretKeyAccess access) 94 throws GeneralSecurityException { 95 return com.google.crypto.tink.prf.HmacPrfKey.builder() 96 .setParameters(parameters) 97 .setKeyBytes(Util.readIntoSecretBytes(stream, parameters.getKeySizeBytes(), access)) 98 .build(); 99 } 100 namedParameters()101 private static Map<String, Parameters> namedParameters() throws GeneralSecurityException { 102 Map<String, Parameters> result = new HashMap<>(); 103 result.put("HMAC_SHA256_PRF", PredefinedPrfParameters.HMAC_SHA256_PRF); 104 result.put("HMAC_SHA512_PRF", PredefinedPrfParameters.HMAC_SHA512_PRF); 105 return Collections.unmodifiableMap(result); 106 } 107 108 private static final TinkFipsUtil.AlgorithmFipsCompatibility FIPS = 109 TinkFipsUtil.AlgorithmFipsCompatibility.ALGORITHM_REQUIRES_BORINGCRYPTO; 110 register(boolean newKeyAllowed)111 public static void register(boolean newKeyAllowed) throws GeneralSecurityException { 112 if (!FIPS.isCompatible()) { 113 throw new GeneralSecurityException( 114 "Can not use HMAC in FIPS-mode, as BoringCrypto module is not available."); 115 } 116 HmacPrfProtoSerialization.register(); 117 MutablePrimitiveRegistry.globalInstance() 118 .registerPrimitiveConstructor(PRF_PRIMITIVE_CONSTRUCTOR); 119 MutableParametersRegistry.globalInstance().putAll(namedParameters()); 120 MutableKeyCreationRegistry.globalInstance().add(KEY_CREATOR, HmacPrfParameters.class); 121 MutableKeyDerivationRegistry.globalInstance().add(KEY_DERIVER, HmacPrfParameters.class); 122 KeyManagerRegistry.globalInstance() 123 .registerKeyManagerWithFipsCompatibility(legacyKeyManager, FIPS, newKeyAllowed); 124 } 125 126 /** 127 * Returns a {@link KeyTemplate} that generates new instances of HMAC keys with the following 128 * parameters: 129 * 130 * <ul> 131 * <li>Key size: 32 bytes 132 * <li>Hash function: SHA256 133 * <li>Prefix type: {@link KeyTemplate.OutputPrefixType#RAW} 134 * </ul> 135 */ hmacSha256Template()136 public static final KeyTemplate hmacSha256Template() { 137 return exceptionIsBug( 138 () -> 139 KeyTemplate.createFrom( 140 HmacPrfParameters.builder() 141 .setKeySizeBytes(32) 142 .setHashType(HmacPrfParameters.HashType.SHA256) 143 .build())); 144 } 145 146 /** 147 * Returns a {@link KeyTemplate} that generates new instances of HMAC keys with the following 148 * parameters: 149 * 150 * <ul> 151 * <li>Key size: 64 bytes 152 * <li>Hash function: SHA512 153 * <li>Prefix type: {@link KeyTemplate.OutputPrefixType#RAW} 154 * </ul> 155 */ hmacSha512Template()156 public static final KeyTemplate hmacSha512Template() { 157 return exceptionIsBug( 158 () -> 159 KeyTemplate.createFrom( 160 HmacPrfParameters.builder() 161 .setKeySizeBytes(64) 162 .setHashType(HmacPrfParameters.HashType.SHA512) 163 .build())); 164 } 165 HmacPrfKeyManager()166 private HmacPrfKeyManager() {} 167 } 168