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.daead; 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.DeterministicAead; 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.config.internal.TinkFipsUtil; 28 import com.google.crypto.tink.daead.internal.AesSivProtoSerialization; 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.AesSiv; 39 import com.google.crypto.tink.util.SecretBytes; 40 import java.io.InputStream; 41 import java.security.GeneralSecurityException; 42 import java.security.InvalidAlgorithmParameterException; 43 import java.util.Collections; 44 import java.util.HashMap; 45 import java.util.Map; 46 import javax.annotation.Nullable; 47 48 /** 49 * This key manager generates new {@code AesSivKey} keys and produces new instances of {@code 50 * AesSiv}. 51 */ 52 public final class AesSivKeyManager { createDeterministicAead(AesSivKey key)53 private static DeterministicAead createDeterministicAead(AesSivKey key) 54 throws GeneralSecurityException { 55 validateParameters(key.getParameters()); 56 return AesSiv.create(key); 57 } 58 59 private static final PrimitiveConstructor<AesSivKey, DeterministicAead> 60 AES_SIV_PRIMITIVE_CONSTRUCTOR = 61 PrimitiveConstructor.create( 62 AesSivKeyManager::createDeterministicAead, AesSivKey.class, DeterministicAead.class); 63 64 private static final int KEY_SIZE_IN_BYTES = 64; 65 getKeyType()66 static String getKeyType() { 67 return "type.googleapis.com/google.crypto.tink.AesSivKey"; 68 } 69 70 private static final KeyManager<DeterministicAead> legacyKeyManager = 71 LegacyKeyManagerImpl.create( 72 getKeyType(), 73 DeterministicAead.class, 74 KeyMaterialType.SYMMETRIC, 75 com.google.crypto.tink.proto.AesSivKey.parser()); 76 validateParameters(AesSivParameters parameters)77 private static void validateParameters(AesSivParameters parameters) 78 throws GeneralSecurityException { 79 if (parameters.getKeySizeBytes() != KEY_SIZE_IN_BYTES) { 80 throw new InvalidAlgorithmParameterException( 81 "invalid key size: " 82 + parameters.getKeySizeBytes() 83 + ". Valid keys must have " 84 + KEY_SIZE_IN_BYTES 85 + " bytes."); 86 } 87 } 88 89 @SuppressWarnings("InlineLambdaConstant") // We need a correct Object#equals in registration. 90 private static final MutableKeyDerivationRegistry.InsecureKeyCreator<AesSivParameters> 91 KEY_DERIVER = AesSivKeyManager::createAesSivKeyFromRandomness; 92 93 @AccessesPartialKey createAesSivKeyFromRandomness( AesSivParameters parameters, InputStream stream, @Nullable Integer idRequirement, SecretKeyAccess access)94 static AesSivKey createAesSivKeyFromRandomness( 95 AesSivParameters parameters, 96 InputStream stream, 97 @Nullable Integer idRequirement, 98 SecretKeyAccess access) 99 throws GeneralSecurityException { 100 validateParameters(parameters); 101 return AesSivKey.builder() 102 .setParameters(parameters) 103 .setIdRequirement(idRequirement) 104 .setKeyBytes(Util.readIntoSecretBytes(stream, parameters.getKeySizeBytes(), access)) 105 .build(); 106 } 107 108 @SuppressWarnings("InlineLambdaConstant") // We need a correct Object#equals in registration. 109 private static final MutableKeyCreationRegistry.KeyCreator<AesSivParameters> KEY_CREATOR = 110 AesSivKeyManager::newKey; 111 112 @AccessesPartialKey newKey(AesSivParameters parameters, @Nullable Integer idRequirement)113 static AesSivKey newKey(AesSivParameters parameters, @Nullable Integer idRequirement) 114 throws GeneralSecurityException { 115 validateParameters(parameters); 116 return AesSivKey.builder() 117 .setParameters(parameters) 118 .setIdRequirement(idRequirement) 119 .setKeyBytes(SecretBytes.randomBytes(parameters.getKeySizeBytes())) 120 .build(); 121 } 122 namedParameters()123 private static Map<String, Parameters> namedParameters() throws GeneralSecurityException { 124 Map<String, Parameters> result = new HashMap<>(); 125 result.put("AES256_SIV", PredefinedDeterministicAeadParameters.AES256_SIV); 126 result.put( 127 "AES256_SIV_RAW", 128 AesSivParameters.builder() 129 .setKeySizeBytes(64) 130 .setVariant(AesSivParameters.Variant.NO_PREFIX) 131 .build()); 132 return Collections.unmodifiableMap(result); 133 } 134 register(boolean newKeyAllowed)135 public static void register(boolean newKeyAllowed) throws GeneralSecurityException { 136 if (!TinkFipsUtil.AlgorithmFipsCompatibility.ALGORITHM_NOT_FIPS.isCompatible()) { 137 throw new GeneralSecurityException("Registering AES SIV is not supported in FIPS mode"); 138 } 139 AesSivProtoSerialization.register(); 140 MutablePrimitiveRegistry.globalInstance() 141 .registerPrimitiveConstructor(AES_SIV_PRIMITIVE_CONSTRUCTOR); 142 MutableParametersRegistry.globalInstance().putAll(namedParameters()); 143 MutableKeyDerivationRegistry.globalInstance().add(KEY_DERIVER, AesSivParameters.class); 144 MutableKeyCreationRegistry.globalInstance().add(KEY_CREATOR, AesSivParameters.class); 145 KeyManagerRegistry.globalInstance().registerKeyManager(legacyKeyManager, newKeyAllowed); 146 } 147 148 /** 149 * @return a {@code KeyTemplate} that generates new instances of AES-SIV-CMAC keys. 150 */ aes256SivTemplate()151 public static final KeyTemplate aes256SivTemplate() { 152 return exceptionIsBug( 153 () -> 154 KeyTemplate.createFrom( 155 AesSivParameters.builder() 156 .setKeySizeBytes(KEY_SIZE_IN_BYTES) 157 .setVariant(AesSivParameters.Variant.TINK) 158 .build())); 159 } 160 161 /** 162 * @return A {@code KeyTemplate} that generates new instances of AES-SIV-CMAC keys. Keys generated 163 * from this template create ciphertexts compatible with other libraries. 164 */ rawAes256SivTemplate()165 public static final KeyTemplate rawAes256SivTemplate() { 166 return exceptionIsBug( 167 () -> 168 KeyTemplate.createFrom( 169 AesSivParameters.builder() 170 .setKeySizeBytes(KEY_SIZE_IN_BYTES) 171 .setVariant(AesSivParameters.Variant.NO_PREFIX) 172 .build())); 173 } 174 AesSivKeyManager()175 private AesSivKeyManager() {} 176 } 177