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.AesGcmSivProtoSerialization; 28 import com.google.crypto.tink.aead.subtle.AesGcmSiv; 29 import com.google.crypto.tink.config.internal.TinkFipsUtil; 30 import com.google.crypto.tink.internal.KeyManagerRegistry; 31 import com.google.crypto.tink.internal.LegacyKeyManagerImpl; 32 import com.google.crypto.tink.internal.MutableKeyCreationRegistry; 33 import com.google.crypto.tink.internal.MutableKeyDerivationRegistry; 34 import com.google.crypto.tink.internal.MutableParametersRegistry; 35 import com.google.crypto.tink.internal.MutablePrimitiveRegistry; 36 import com.google.crypto.tink.internal.PrimitiveConstructor; 37 import com.google.crypto.tink.internal.Util; 38 import com.google.crypto.tink.proto.KeyData.KeyMaterialType; 39 import com.google.crypto.tink.util.SecretBytes; 40 import java.io.InputStream; 41 import java.security.GeneralSecurityException; 42 import java.security.NoSuchAlgorithmException; 43 import java.util.Collections; 44 import java.util.HashMap; 45 import java.util.Map; 46 import javax.annotation.Nullable; 47 import javax.crypto.Cipher; 48 import javax.crypto.NoSuchPaddingException; 49 50 /** 51 * This key manager generates new {@code AesGcmSivKey} keys and produces new instances of {@code 52 * AesGcmSiv}. 53 */ 54 public final class AesGcmSivKeyManager { 55 private static final PrimitiveConstructor<com.google.crypto.tink.aead.AesGcmSivKey, Aead> 56 AES_GCM_SIV_PRIMITIVE_CONSTRUCTOR = 57 PrimitiveConstructor.create( 58 AesGcmSiv::create, com.google.crypto.tink.aead.AesGcmSivKey.class, Aead.class); 59 60 @SuppressWarnings("InlineLambdaConstant") // We need a correct Object#equals in registration. 61 private static final MutableKeyCreationRegistry.KeyCreator<AesGcmSivParameters> KEY_CREATOR = 62 AesGcmSivKeyManager::createAesGcmSivKey; 63 64 @SuppressWarnings("InlineLambdaConstant") // We need a correct Object#equals in registration. 65 private static final MutableKeyDerivationRegistry.InsecureKeyCreator<AesGcmSivParameters> 66 KEY_DERIVER = AesGcmSivKeyManager::createAesGcmSivKeyFromRandomness; 67 68 private static final KeyManager<Aead> legacyKeyManager = 69 LegacyKeyManagerImpl.create( 70 "type.googleapis.com/google.crypto.tink.AesGcmSivKey", 71 Aead.class, 72 KeyMaterialType.SYMMETRIC, 73 com.google.crypto.tink.proto.AesGcmSivKey.parser()); 74 75 @AccessesPartialKey createAesGcmSivKeyFromRandomness( AesGcmSivParameters parameters, InputStream stream, @Nullable Integer idRequirement, SecretKeyAccess access)76 static com.google.crypto.tink.aead.AesGcmSivKey createAesGcmSivKeyFromRandomness( 77 AesGcmSivParameters parameters, 78 InputStream stream, 79 @Nullable Integer idRequirement, 80 SecretKeyAccess access) 81 throws GeneralSecurityException { 82 return com.google.crypto.tink.aead.AesGcmSivKey.builder() 83 .setParameters(parameters) 84 .setIdRequirement(idRequirement) 85 .setKeyBytes(Util.readIntoSecretBytes(stream, parameters.getKeySizeBytes(), access)) 86 .build(); 87 } 88 89 @AccessesPartialKey createAesGcmSivKey( AesGcmSivParameters parameters, @Nullable Integer idRequirement)90 private static com.google.crypto.tink.aead.AesGcmSivKey createAesGcmSivKey( 91 AesGcmSivParameters parameters, @Nullable Integer idRequirement) 92 throws GeneralSecurityException { 93 return com.google.crypto.tink.aead.AesGcmSivKey.builder() 94 .setParameters(parameters) 95 .setIdRequirement(idRequirement) 96 .setKeyBytes(SecretBytes.randomBytes(parameters.getKeySizeBytes())) 97 .build(); 98 } 99 namedParameters()100 private static Map<String, Parameters> namedParameters() throws GeneralSecurityException { 101 Map<String, Parameters> result = new HashMap<>(); 102 103 result.put( 104 "AES128_GCM_SIV", 105 AesGcmSivParameters.builder() 106 .setKeySizeBytes(16) 107 .setVariant(AesGcmSivParameters.Variant.TINK) 108 .build()); 109 result.put( 110 "AES128_GCM_SIV_RAW", 111 AesGcmSivParameters.builder() 112 .setKeySizeBytes(16) 113 .setVariant(AesGcmSivParameters.Variant.NO_PREFIX) 114 .build()); 115 result.put( 116 "AES256_GCM_SIV", 117 AesGcmSivParameters.builder() 118 .setKeySizeBytes(32) 119 .setVariant(AesGcmSivParameters.Variant.TINK) 120 .build()); 121 result.put( 122 "AES256_GCM_SIV_RAW", 123 AesGcmSivParameters.builder() 124 .setKeySizeBytes(32) 125 .setVariant(AesGcmSivParameters.Variant.NO_PREFIX) 126 .build()); 127 128 return Collections.unmodifiableMap(result); 129 } 130 canUseAesGcmSive()131 private static boolean canUseAesGcmSive() { 132 try { 133 Cipher.getInstance("AES/GCM-SIV/NoPadding"); 134 return true; 135 } catch (NoSuchAlgorithmException | NoSuchPaddingException ex) { 136 return false; 137 } 138 } 139 register(boolean newKeyAllowed)140 public static void register(boolean newKeyAllowed) throws GeneralSecurityException { 141 if (!TinkFipsUtil.AlgorithmFipsCompatibility.ALGORITHM_NOT_FIPS.isCompatible()) { 142 throw new GeneralSecurityException("Registering AES GCM SIV is not supported in FIPS mode"); 143 } 144 // We want to register key proto serialization even when AES-GCM-SIV is unavailable via the 145 // Java Cryptographic Extension framework (and thus via Tink) to enable operations that don't 146 // depend on the actual cryptographic primitive - for example, exporting keys to key management 147 // systems. 148 AesGcmSivProtoSerialization.register(); 149 if (canUseAesGcmSive()) { 150 MutablePrimitiveRegistry.globalInstance() 151 .registerPrimitiveConstructor(AES_GCM_SIV_PRIMITIVE_CONSTRUCTOR); 152 MutableParametersRegistry.globalInstance().putAll(namedParameters()); 153 MutableKeyDerivationRegistry.globalInstance().add(KEY_DERIVER, AesGcmSivParameters.class); 154 MutableKeyCreationRegistry.globalInstance().add(KEY_CREATOR, AesGcmSivParameters.class); 155 KeyManagerRegistry.globalInstance().registerKeyManager(legacyKeyManager, newKeyAllowed); 156 } 157 } 158 159 /** 160 * Creates and returns a {@link KeyTemplate} that generates new instances of AES-GCM-SIV with the 161 * following parameters: 162 * 163 * <ul> 164 * <li>Key size: 16 bytes 165 * <li>Prefix type: {@link KeyTemplate.OutputPrefixType#TINK} 166 * </ul> 167 */ aes128GcmSivTemplate()168 public static final KeyTemplate aes128GcmSivTemplate() { 169 return exceptionIsBug( 170 () -> 171 KeyTemplate.createFrom( 172 AesGcmSivParameters.builder() 173 .setKeySizeBytes(16) 174 .setVariant(AesGcmSivParameters.Variant.TINK) 175 .build())); 176 } 177 178 /** 179 * Creates and returns a {@link KeyTemplate} that generates new instances of AES-GCM with the 180 * following parameters: 181 * 182 * <ul> 183 * <li>Key size: 16 bytes 184 * <li>Prefix type: {@link KeyTemplate.OutputPrefixType#RAW} (no prefix) 185 * </ul> 186 * 187 * <p>Keys generated from this template should create ciphertexts compatible with other libraries. 188 */ rawAes128GcmSivTemplate()189 public static final KeyTemplate rawAes128GcmSivTemplate() { 190 return exceptionIsBug( 191 () -> 192 KeyTemplate.createFrom( 193 AesGcmSivParameters.builder() 194 .setKeySizeBytes(16) 195 .setVariant(AesGcmSivParameters.Variant.NO_PREFIX) 196 .build())); 197 } 198 199 /** 200 * Creates and returns a {@link KeyTemplate} that generates new instances of AES-GCM-SIV with the 201 * following parameters: 202 * 203 * <ul> 204 * <li>Key size: 32 bytes 205 * <li>Prefix type: {@link KeyTemplate.OutputPrefixType#TINK} 206 * </ul> 207 */ aes256GcmSivTemplate()208 public static final KeyTemplate aes256GcmSivTemplate() { 209 return exceptionIsBug( 210 () -> 211 KeyTemplate.createFrom( 212 AesGcmSivParameters.builder() 213 .setKeySizeBytes(32) 214 .setVariant(AesGcmSivParameters.Variant.TINK) 215 .build())); 216 } 217 218 /** 219 * Creates and returns a {@link KeyTemplate} that generates new instances of AES-GCM-SIV with the 220 * following parameters: 221 * 222 * <ul> 223 * <li>Key size: 32 bytes 224 * <li>Prefix type: {@link KeyTemplate.OutputPrefixType#RAW} (no prefix) 225 * </ul> 226 * 227 * <p>Keys generated from this template should create ciphertexts compatible with other libraries. 228 */ rawAes256GcmSivTemplate()229 public static final KeyTemplate rawAes256GcmSivTemplate() { 230 return exceptionIsBug( 231 () -> 232 KeyTemplate.createFrom( 233 AesGcmSivParameters.builder() 234 .setKeySizeBytes(32) 235 .setVariant(AesGcmSivParameters.Variant.NO_PREFIX) 236 .build())); 237 } 238 AesGcmSivKeyManager()239 private AesGcmSivKeyManager() {} 240 } 241