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.aead; 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.Aead; 23 import com.google.crypto.tink.KeyManager; 24 import com.google.crypto.tink.KeyTemplate; 25 import com.google.crypto.tink.Parameters; 26 import com.google.crypto.tink.SecretKeyAccess; 27 import com.google.crypto.tink.aead.internal.AesCtrHmacAeadProtoSerialization; 28 import com.google.crypto.tink.config.internal.TinkFipsUtil; 29 import com.google.crypto.tink.internal.KeyManagerRegistry; 30 import com.google.crypto.tink.internal.LegacyKeyManagerImpl; 31 import com.google.crypto.tink.internal.MutableKeyCreationRegistry; 32 import com.google.crypto.tink.internal.MutableKeyDerivationRegistry; 33 import com.google.crypto.tink.internal.MutableParametersRegistry; 34 import com.google.crypto.tink.internal.MutablePrimitiveRegistry; 35 import com.google.crypto.tink.internal.PrimitiveConstructor; 36 import com.google.crypto.tink.internal.Util; 37 import com.google.crypto.tink.proto.KeyData.KeyMaterialType; 38 import com.google.crypto.tink.subtle.EncryptThenAuthenticate; 39 import com.google.crypto.tink.util.SecretBytes; 40 import java.io.InputStream; 41 import java.security.GeneralSecurityException; 42 import java.util.Collections; 43 import java.util.HashMap; 44 import java.util.Map; 45 import javax.annotation.Nullable; 46 47 /** 48 * This key manager generates new {@link AesCtrHmacAeadKey} keys and produces new instances of 49 * {@link EncryptThenAuthenticate}. 50 */ 51 public final class AesCtrHmacAeadKeyManager { validate(AesCtrHmacAeadParameters parameters)52 private static void validate(AesCtrHmacAeadParameters parameters) 53 throws GeneralSecurityException { 54 if (parameters.getAesKeySizeBytes() != 16 && parameters.getAesKeySizeBytes() != 32) { 55 throw new GeneralSecurityException("AES key size must be 16 or 32 bytes"); 56 } 57 } 58 59 private static final PrimitiveConstructor<com.google.crypto.tink.aead.AesCtrHmacAeadKey, Aead> 60 AES_CTR_HMAC_AEAD_PRIMITIVE_CONSTRUCTOR = 61 PrimitiveConstructor.create( 62 EncryptThenAuthenticate::create, 63 com.google.crypto.tink.aead.AesCtrHmacAeadKey.class, 64 Aead.class); 65 66 private static final KeyManager<Aead> legacyKeyManager = 67 LegacyKeyManagerImpl.create( 68 getKeyType(), 69 Aead.class, 70 KeyMaterialType.SYMMETRIC, 71 com.google.crypto.tink.proto.AesCtrHmacAeadKey.parser()); 72 getKeyType()73 static String getKeyType() { 74 return "type.googleapis.com/google.crypto.tink.AesCtrHmacAeadKey"; 75 } 76 77 @SuppressWarnings("InlineLambdaConstant") // We need a correct Object#equals in registration. 78 private static final MutableKeyDerivationRegistry.InsecureKeyCreator<AesCtrHmacAeadParameters> 79 KEY_DERIVER = AesCtrHmacAeadKeyManager::createAesCtrHmacAeadKeyFromRandomness; 80 81 // To ensure that the derived key can provide key commitment, the AES-CTR key must be derived 82 // before the HMAC key. 83 // Consider the following malicious scenario using a brute-forced key InputStream with a 0 as 84 // its 32nd byte: 85 // 31 bytes || 1 byte of 0s || 16 bytes 86 // We give this stream to party A, saying that it is 32-byte HMAC key || 16-byte AES key. We 87 // also give this stream to party B, saying that it is 31-byte HMAC key || 16-byte AES key. 88 // Since HMAC pads the key with zeroes, this same stream will lead to both parties using the 89 // same HMAC key but different AES keys. 90 @AccessesPartialKey createAesCtrHmacAeadKeyFromRandomness( AesCtrHmacAeadParameters parameters, InputStream stream, @Nullable Integer idRequirement, SecretKeyAccess access)91 static com.google.crypto.tink.aead.AesCtrHmacAeadKey createAesCtrHmacAeadKeyFromRandomness( 92 AesCtrHmacAeadParameters parameters, 93 InputStream stream, 94 @Nullable Integer idRequirement, 95 SecretKeyAccess access) 96 throws GeneralSecurityException { 97 return com.google.crypto.tink.aead.AesCtrHmacAeadKey.builder() 98 .setParameters(parameters) 99 .setIdRequirement(idRequirement) 100 .setAesKeyBytes(Util.readIntoSecretBytes(stream, parameters.getAesKeySizeBytes(), access)) 101 .setHmacKeyBytes(Util.readIntoSecretBytes(stream, parameters.getHmacKeySizeBytes(), access)) 102 .build(); 103 } 104 105 @SuppressWarnings("InlineLambdaConstant") // We need a correct Object#equals in registration. 106 private static final MutableKeyCreationRegistry.KeyCreator<AesCtrHmacAeadParameters> KEY_CREATOR = 107 AesCtrHmacAeadKeyManager::createAesCtrHmacAeadKey; 108 109 @AccessesPartialKey createAesCtrHmacAeadKey( AesCtrHmacAeadParameters parameters, @Nullable Integer idRequirement)110 static com.google.crypto.tink.aead.AesCtrHmacAeadKey createAesCtrHmacAeadKey( 111 AesCtrHmacAeadParameters parameters, @Nullable Integer idRequirement) 112 throws GeneralSecurityException { 113 validate(parameters); 114 return com.google.crypto.tink.aead.AesCtrHmacAeadKey.builder() 115 .setParameters(parameters) 116 .setIdRequirement(idRequirement) 117 .setAesKeyBytes(SecretBytes.randomBytes(parameters.getAesKeySizeBytes())) 118 .setHmacKeyBytes(SecretBytes.randomBytes(parameters.getHmacKeySizeBytes())) 119 .build(); 120 } 121 namedParameters()122 private static Map<String, Parameters> namedParameters() throws GeneralSecurityException { 123 Map<String, Parameters> result = new HashMap<>(); 124 125 result.put("AES128_CTR_HMAC_SHA256", PredefinedAeadParameters.AES128_CTR_HMAC_SHA256); 126 result.put( 127 "AES128_CTR_HMAC_SHA256_RAW", 128 AesCtrHmacAeadParameters.builder() 129 .setAesKeySizeBytes(16) 130 .setHmacKeySizeBytes(32) 131 .setTagSizeBytes(16) 132 .setIvSizeBytes(16) 133 .setHashType(AesCtrHmacAeadParameters.HashType.SHA256) 134 .setVariant(AesCtrHmacAeadParameters.Variant.NO_PREFIX) 135 .build()); 136 137 result.put("AES256_CTR_HMAC_SHA256", PredefinedAeadParameters.AES256_CTR_HMAC_SHA256); 138 result.put( 139 "AES256_CTR_HMAC_SHA256_RAW", 140 AesCtrHmacAeadParameters.builder() 141 .setAesKeySizeBytes(32) 142 .setHmacKeySizeBytes(32) 143 .setTagSizeBytes(32) 144 .setIvSizeBytes(16) 145 .setHashType(AesCtrHmacAeadParameters.HashType.SHA256) 146 .setVariant(AesCtrHmacAeadParameters.Variant.NO_PREFIX) 147 .build()); 148 149 return Collections.unmodifiableMap(result); 150 } 151 152 private static final TinkFipsUtil.AlgorithmFipsCompatibility FIPS = 153 TinkFipsUtil.AlgorithmFipsCompatibility.ALGORITHM_REQUIRES_BORINGCRYPTO; 154 register(boolean newKeyAllowed)155 public static void register(boolean newKeyAllowed) throws GeneralSecurityException { 156 if (!FIPS.isCompatible()) { 157 throw new GeneralSecurityException( 158 "Can not use AES-CTR-HMAC in FIPS-mode, as BoringCrypto module is not available."); 159 } 160 AesCtrHmacAeadProtoSerialization.register(); 161 MutablePrimitiveRegistry.globalInstance() 162 .registerPrimitiveConstructor(AES_CTR_HMAC_AEAD_PRIMITIVE_CONSTRUCTOR); 163 MutableParametersRegistry.globalInstance().putAll(namedParameters()); 164 MutableKeyDerivationRegistry.globalInstance().add(KEY_DERIVER, AesCtrHmacAeadParameters.class); 165 MutableKeyCreationRegistry.globalInstance().add(KEY_CREATOR, AesCtrHmacAeadParameters.class); 166 KeyManagerRegistry.globalInstance() 167 .registerKeyManagerWithFipsCompatibility(legacyKeyManager, FIPS, newKeyAllowed); 168 } 169 170 /** 171 * @return a {@link KeyTemplate} that generates new instances of AES-CTR-HMAC-AEAD keys with the 172 * following parameters: 173 * <ul> 174 * <li>AES key size: 16 bytes 175 * <li>AES CTR IV size: 16 byte 176 * <li>HMAC key size: 32 bytes 177 * <li>HMAC tag size: 16 bytes 178 * <li>HMAC hash function: SHA256 179 * </ul> 180 */ aes128CtrHmacSha256Template()181 public static final KeyTemplate aes128CtrHmacSha256Template() { 182 return exceptionIsBug( 183 () -> 184 KeyTemplate.createFrom( 185 AesCtrHmacAeadParameters.builder() 186 .setAesKeySizeBytes(16) 187 .setHmacKeySizeBytes(32) 188 .setIvSizeBytes(16) 189 .setTagSizeBytes(16) 190 .setHashType(AesCtrHmacAeadParameters.HashType.SHA256) 191 .setVariant(AesCtrHmacAeadParameters.Variant.TINK) 192 .build())); 193 } 194 195 /** 196 * @return a {@link KeyTemplate} that generates new instances of AES-CTR-HMAC-AEAD keys with the 197 * following parameters: 198 * <ul> 199 * <li>AES key size: 32 bytes 200 * <li>AES CTR IV size: 16 byte 201 * <li>HMAC key size: 32 bytes 202 * <li>HMAC tag size: 32 bytes 203 * <li>HMAC hash function: SHA256 204 * </ul> 205 */ aes256CtrHmacSha256Template()206 public static final KeyTemplate aes256CtrHmacSha256Template() { 207 return exceptionIsBug( 208 () -> 209 KeyTemplate.createFrom( 210 AesCtrHmacAeadParameters.builder() 211 .setAesKeySizeBytes(32) 212 .setHmacKeySizeBytes(32) 213 .setIvSizeBytes(16) 214 .setTagSizeBytes(32) 215 .setHashType(AesCtrHmacAeadParameters.HashType.SHA256) 216 .setVariant(AesCtrHmacAeadParameters.Variant.TINK) 217 .build())); 218 } 219 AesCtrHmacAeadKeyManager()220 private AesCtrHmacAeadKeyManager() {} 221 } 222