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.aead.internal.LegacyFullAead; 25 import com.google.crypto.tink.config.internal.TinkFipsUtil; 26 import com.google.crypto.tink.internal.KeyManagerRegistry; 27 import com.google.crypto.tink.internal.LegacyKeyManagerImpl; 28 import com.google.crypto.tink.internal.MutableKeyCreationRegistry; 29 import com.google.crypto.tink.internal.MutablePrimitiveRegistry; 30 import com.google.crypto.tink.internal.PrimitiveConstructor; 31 import com.google.crypto.tink.proto.KeyData.KeyMaterialType; 32 import com.google.crypto.tink.proto.KmsAeadKey; 33 import java.security.GeneralSecurityException; 34 import javax.annotation.Nullable; 35 36 /** 37 * This key manager produces new instances of {@code Aead} that forwards encrypt/decrypt requests to 38 * a key residing in a remote KMS. 39 */ 40 public final class KmsAeadKeyManager { create(LegacyKmsAeadKey key)41 private static Aead create(LegacyKmsAeadKey key) throws GeneralSecurityException { 42 43 Aead rawAead = 44 KmsClients.get(key.getParameters().keyUri()).getAead(key.getParameters().keyUri()); 45 return LegacyFullAead.create(rawAead, key.getOutputPrefix()); 46 } 47 48 private static final PrimitiveConstructor<LegacyKmsAeadKey, Aead> 49 LEGACY_KMS_AEAD_PRIMITIVE_CONSTRUCTOR = 50 PrimitiveConstructor.create( 51 KmsAeadKeyManager::create, LegacyKmsAeadKey.class, Aead.class); 52 53 private static final KeyManager<Aead> legacyKeyManager = 54 LegacyKeyManagerImpl.create( 55 getKeyType(), Aead.class, KeyMaterialType.REMOTE, KmsAeadKey.parser()); 56 57 /** 58 * Creates a "new" key from a parameters object. 59 * 60 * <p>While this creates a new Key object, it doesn't actually create a new key. It simply creates 61 * the key object corresponding to this parameters object. Creating a new key would require to 62 * call an API in the KMS, which this method does not do. 63 * 64 * <p>The reason this method exists is that in the past, Tink did not provide an API for the user 65 * to create a key object by themselves. Instead, users had to always create a Key from a key 66 * template (which is now a Parameters object) via {@code KeysetHandle.generateNew(template);}. To 67 * support old usages, we need to register this creator. 68 */ 69 @AccessesPartialKey newKey( LegacyKmsAeadParameters parameters, @Nullable Integer idRequirement)70 private static LegacyKmsAeadKey newKey( 71 LegacyKmsAeadParameters parameters, @Nullable Integer idRequirement) 72 throws GeneralSecurityException { 73 return LegacyKmsAeadKey.create(parameters, idRequirement); 74 } 75 76 @SuppressWarnings("InlineLambdaConstant") // We need a correct Object#equals in registration. 77 private static final MutableKeyCreationRegistry.KeyCreator<LegacyKmsAeadParameters> KEY_CREATOR = 78 KmsAeadKeyManager::newKey; 79 getKeyType()80 static String getKeyType() { 81 return "type.googleapis.com/google.crypto.tink.KmsAeadKey"; 82 } 83 register(boolean newKeyAllowed)84 public static void register(boolean newKeyAllowed) throws GeneralSecurityException { 85 if (!TinkFipsUtil.AlgorithmFipsCompatibility.ALGORITHM_NOT_FIPS.isCompatible()) { 86 throw new GeneralSecurityException("Registering KMS AEAD is not supported in FIPS mode"); 87 } 88 LegacyKmsAeadProtoSerialization.register(); 89 MutablePrimitiveRegistry.globalInstance() 90 .registerPrimitiveConstructor(LEGACY_KMS_AEAD_PRIMITIVE_CONSTRUCTOR); 91 MutableKeyCreationRegistry.globalInstance().add(KEY_CREATOR, LegacyKmsAeadParameters.class); 92 KeyManagerRegistry.globalInstance().registerKeyManager(legacyKeyManager, newKeyAllowed); 93 } 94 95 /** 96 * Returns a new {@link KeyTemplate} that can generate a {@link 97 * com.google.crypto.tink.proto.KmsAeadKey} whose key is pointing to {@code keyUri}. Keys 98 * generated by this key template use the RAW output prefix to make them compatible with the 99 * remote KMS' encrypt/decrypt operations. 100 * 101 * <p>It requires that a {@code KmsClient} that can handle {@code keyUri} is registered. Avoid 102 * registering it more than once. 103 * 104 * <p><b>Note: </b> Unlike other templates, when you call {@link KeysetHandle#generateNew} with 105 * this template, Tink does not generate new key material, but only creates a reference to the 106 * remote key. 107 * 108 * <p>It is often not necessary to use this function. Instead of registering a {@code KmsClient}, 109 * and creating an {@code Aead} using {@code 110 * KeysetHandle.generateNew(KmsAeadKeyManager.createKeyTemplate(keyUri)).getPrimitive(RegistryConfiguration.get(), 111 * Aead.class)}, you can create the {@code Aead} directly using {@code kmsClient.getAead(kekUri)}, 112 * without registering any {@code KmsClient}. 113 */ createKeyTemplate(String keyUri)114 public static KeyTemplate createKeyTemplate(String keyUri) { 115 try { 116 return KeyTemplate.createFrom(LegacyKmsAeadParameters.create(keyUri)); 117 } catch (GeneralSecurityException e) { 118 // This should never happen: LegacyKmsAeadParameters shouldn't throw. 119 throw new IllegalArgumentException(e); 120 } 121 } 122 KmsAeadKeyManager()123 private KmsAeadKeyManager() {} 124 } 125