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 com.google.crypto.tink.AccessesPartialKey; 20 import com.google.crypto.tink.Aead; 21 import com.google.crypto.tink.KeyManager; 22 import com.google.crypto.tink.KeyTemplate; 23 import com.google.crypto.tink.KmsClients; 24 import com.google.crypto.tink.Parameters; 25 import com.google.crypto.tink.aead.internal.LegacyFullAead; 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.MutablePrimitiveRegistry; 31 import com.google.crypto.tink.internal.PrimitiveConstructor; 32 import com.google.crypto.tink.proto.KeyData.KeyMaterialType; 33 import java.security.GeneralSecurityException; 34 import javax.annotation.Nullable; 35 36 /** 37 * This key manager generates new {@code KmsEnvelopeAeadKey} keys and produces new instances of 38 * {@code KmsEnvelopeAead}. 39 */ 40 public class KmsEnvelopeAeadKeyManager { 41 private static final String TYPE_URL = 42 "type.googleapis.com/google.crypto.tink.KmsEnvelopeAeadKey"; 43 44 private static final KeyManager<Aead> legacyKeyManager = 45 LegacyKeyManagerImpl.create( 46 getKeyType(), 47 Aead.class, 48 KeyMaterialType.SYMMETRIC, 49 com.google.crypto.tink.proto.KmsEnvelopeAeadKey.parser()); 50 51 /** 52 * Creates a "new" key from a parameters. 53 * 54 * <p>While this creates a new Key object, it doesn't actually create a new key. It simply creates 55 * the key object corresponding to this parameters object. Creating a new key would require to 56 * call an API in the KMS, which this method does not do. 57 * 58 * <p>The reason this method exists is that in the past, Tink did not provide an API for the user 59 * to create a key object by themselves. Instead, users had to always create a Key from a key 60 * template (which is now a Parameters object) via {@code KeysetHandle.generateNew(template);}. To 61 * support old usages, we need to register this creator. 62 */ 63 @AccessesPartialKey newKey( LegacyKmsEnvelopeAeadParameters parameters, @Nullable Integer idRequirement)64 private static LegacyKmsEnvelopeAeadKey newKey( 65 LegacyKmsEnvelopeAeadParameters parameters, @Nullable Integer idRequirement) 66 throws GeneralSecurityException { 67 return LegacyKmsEnvelopeAeadKey.create(parameters, idRequirement); 68 } 69 70 @SuppressWarnings("InlineLambdaConstant") // We need a correct Object#equals in registration. 71 private static final MutableKeyCreationRegistry.KeyCreator<LegacyKmsEnvelopeAeadParameters> 72 KEY_CREATOR = KmsEnvelopeAeadKeyManager::newKey; 73 74 @AccessesPartialKey create(LegacyKmsEnvelopeAeadKey key)75 private static Aead create(LegacyKmsEnvelopeAeadKey key) throws GeneralSecurityException { 76 String kekUri = key.getParameters().getKekUri(); 77 Aead rawAead = 78 KmsEnvelopeAead.create( 79 key.getParameters().getDekParametersForNewKeys(), 80 KmsClients.get(kekUri).getAead(kekUri)); 81 return LegacyFullAead.create(rawAead, key.getOutputPrefix()); 82 } 83 84 private static final PrimitiveConstructor<LegacyKmsEnvelopeAeadKey, Aead> 85 LEGACY_KMS_ENVELOPE_AEAD_PRIMITIVE_CONSTRUCTOR = 86 PrimitiveConstructor.create( 87 KmsEnvelopeAeadKeyManager::create, LegacyKmsEnvelopeAeadKey.class, Aead.class); 88 getKeyType()89 static String getKeyType() { 90 return TYPE_URL; 91 } 92 makeRawAesGcm(AesGcmParameters parameters)93 private static AeadParameters makeRawAesGcm(AesGcmParameters parameters) 94 throws GeneralSecurityException { 95 return AesGcmParameters.builder() 96 .setIvSizeBytes(parameters.getIvSizeBytes()) 97 .setKeySizeBytes(parameters.getKeySizeBytes()) 98 .setTagSizeBytes(parameters.getTagSizeBytes()) 99 .setVariant(AesGcmParameters.Variant.NO_PREFIX) 100 .build(); 101 } 102 makeRawChaCha20Poly1305()103 private static AeadParameters makeRawChaCha20Poly1305() { 104 return ChaCha20Poly1305Parameters.create(ChaCha20Poly1305Parameters.Variant.NO_PREFIX); 105 } 106 makeRawXChaCha20Poly1305()107 private static AeadParameters makeRawXChaCha20Poly1305() { 108 return XChaCha20Poly1305Parameters.create(XChaCha20Poly1305Parameters.Variant.NO_PREFIX); 109 } 110 makeRawAesCtrHmacAead(AesCtrHmacAeadParameters parameters)111 private static AeadParameters makeRawAesCtrHmacAead(AesCtrHmacAeadParameters parameters) 112 throws GeneralSecurityException { 113 return AesCtrHmacAeadParameters.builder() 114 .setAesKeySizeBytes(parameters.getAesKeySizeBytes()) 115 .setHmacKeySizeBytes(parameters.getHmacKeySizeBytes()) 116 .setTagSizeBytes(parameters.getTagSizeBytes()) 117 .setIvSizeBytes(parameters.getIvSizeBytes()) 118 .setHashType(parameters.getHashType()) 119 .setVariant(AesCtrHmacAeadParameters.Variant.NO_PREFIX) 120 .build(); 121 } 122 makeRawAesEax(AesEaxParameters parameters)123 private static AeadParameters makeRawAesEax(AesEaxParameters parameters) 124 throws GeneralSecurityException { 125 return AesEaxParameters.builder() 126 .setIvSizeBytes(parameters.getIvSizeBytes()) 127 .setKeySizeBytes(parameters.getKeySizeBytes()) 128 .setTagSizeBytes(parameters.getTagSizeBytes()) 129 .setVariant(AesEaxParameters.Variant.NO_PREFIX) 130 .build(); 131 } 132 makeRawAesGcmSiv(AesGcmSivParameters parameters)133 private static AeadParameters makeRawAesGcmSiv(AesGcmSivParameters parameters) 134 throws GeneralSecurityException { 135 return AesGcmSivParameters.builder() 136 .setKeySizeBytes(parameters.getKeySizeBytes()) 137 .setVariant(AesGcmSivParameters.Variant.NO_PREFIX) 138 .build(); 139 } 140 makeRaw(Parameters parameters)141 private static AeadParameters makeRaw(Parameters parameters) throws GeneralSecurityException { 142 if (parameters instanceof AesGcmParameters) { 143 return makeRawAesGcm((AesGcmParameters) parameters); 144 } 145 if (parameters instanceof ChaCha20Poly1305Parameters) { 146 return makeRawChaCha20Poly1305(); 147 } 148 if (parameters instanceof XChaCha20Poly1305Parameters) { 149 return makeRawXChaCha20Poly1305(); 150 } 151 if (parameters instanceof AesCtrHmacAeadParameters) { 152 return makeRawAesCtrHmacAead((AesCtrHmacAeadParameters) parameters); 153 } 154 if (parameters instanceof AesEaxParameters) { 155 return makeRawAesEax((AesEaxParameters) parameters); 156 } 157 if (parameters instanceof AesGcmSivParameters) { 158 return makeRawAesGcmSiv((AesGcmSivParameters) parameters); 159 } 160 throw new IllegalArgumentException("Illegal parameters" + parameters); 161 } 162 getRequiredParsingStrategy( AeadParameters parameters)163 private static LegacyKmsEnvelopeAeadParameters.DekParsingStrategy getRequiredParsingStrategy( 164 AeadParameters parameters) { 165 if (parameters instanceof AesGcmParameters) { 166 return LegacyKmsEnvelopeAeadParameters.DekParsingStrategy.ASSUME_AES_GCM; 167 } 168 if (parameters instanceof ChaCha20Poly1305Parameters) { 169 return LegacyKmsEnvelopeAeadParameters.DekParsingStrategy.ASSUME_CHACHA20POLY1305; 170 } 171 if (parameters instanceof XChaCha20Poly1305Parameters) { 172 return LegacyKmsEnvelopeAeadParameters.DekParsingStrategy.ASSUME_XCHACHA20POLY1305; 173 } 174 if (parameters instanceof AesCtrHmacAeadParameters) { 175 return LegacyKmsEnvelopeAeadParameters.DekParsingStrategy.ASSUME_AES_CTR_HMAC; 176 } 177 if (parameters instanceof AesEaxParameters) { 178 return LegacyKmsEnvelopeAeadParameters.DekParsingStrategy.ASSUME_AES_EAX; 179 } 180 if (parameters instanceof AesGcmSivParameters) { 181 return LegacyKmsEnvelopeAeadParameters.DekParsingStrategy.ASSUME_AES_GCM_SIV; 182 } 183 throw new IllegalArgumentException("Illegal parameters" + parameters); 184 } 185 186 /** 187 * Returns a new {@link KeyTemplate} that can generate a {@link LegacyKmsEnvelopeAeadKey} whose 188 * key encrypting key (KEK) is pointing to {@code kekUri} and DEK template is {@code dekTemplate} 189 * (or a derived version of it). 190 * 191 * <p>It requires that a {@code KmsClient} that can handle {@code kekUri} is registered. Avoid 192 * registering it more than once. 193 * 194 * <p><b>Note: </b> Unlike other templates, when you call {@link KeysetHandle#generateNew} with 195 * this template Tink does not generate new key material, but instead creates a reference to the 196 * remote KEK. 197 * 198 * <p>The second argument of the passed in template is ignoring the Variant, and assuming 199 * NO_PREFIX instead. 200 * 201 * <p>It is often not necessary to use this function. Instead of registering a {@code KmsClient}, 202 * and creating an {@code Aead} using {@code 203 * KeysetHandle.generateNew(KmsEnvelopeAeadKeyManager.createKeyTemplate(keyUri, 204 * KeyTemplates.get("AES128_GCM"))).getPrimitive(RegistryConfiguration.get(), Aead.class)}, create 205 * the {@code Aead} directly using {@code 206 * KmsEnvelopeAead.create(PredefinedAeadParameters.AES256_GCM, kmsClient.getAead(keyUri))}, 207 * without registering any {@code KmsClient}. 208 */ 209 @AccessesPartialKey createKeyTemplate(String kekUri, KeyTemplate dekTemplate)210 public static KeyTemplate createKeyTemplate(String kekUri, KeyTemplate dekTemplate) { 211 try { 212 Parameters parameters = dekTemplate.toParameters(); 213 AeadParameters outputPrefixRawParameters = makeRaw(parameters); 214 LegacyKmsEnvelopeAeadParameters legacyKmsEnvelopeAeadParameters = 215 LegacyKmsEnvelopeAeadParameters.builder() 216 .setKekUri(kekUri) 217 .setDekParsingStrategy(getRequiredParsingStrategy(outputPrefixRawParameters)) 218 .setDekParametersForNewKeys(outputPrefixRawParameters) 219 .build(); 220 return KeyTemplate.createFrom(legacyKmsEnvelopeAeadParameters); 221 } catch (GeneralSecurityException e) { 222 throw new IllegalArgumentException( 223 "Cannot create LegacyKmsEnvelopeAeadParameters for template: " + dekTemplate, e); 224 } 225 } 226 register(boolean newKeyAllowed)227 public static void register(boolean newKeyAllowed) throws GeneralSecurityException { 228 if (!TinkFipsUtil.AlgorithmFipsCompatibility.ALGORITHM_NOT_FIPS.isCompatible()) { 229 throw new GeneralSecurityException( 230 "Registering KMS Envelope AEAD is not supported in FIPS mode"); 231 } 232 LegacyKmsEnvelopeAeadProtoSerialization.register(); 233 MutableKeyCreationRegistry.globalInstance() 234 .add(KEY_CREATOR, LegacyKmsEnvelopeAeadParameters.class); 235 MutablePrimitiveRegistry.globalInstance() 236 .registerPrimitiveConstructor(LEGACY_KMS_ENVELOPE_AEAD_PRIMITIVE_CONSTRUCTOR); 237 KeyManagerRegistry.globalInstance().registerKeyManager(legacyKeyManager, newKeyAllowed); 238 } 239 KmsEnvelopeAeadKeyManager()240 private KmsEnvelopeAeadKeyManager() {} 241 } 242