com.google.crypto.tink.internal.MutableKeyCreationRegistry Maven / Gradle / Ivy
Show all versions of tink-android Show documentation
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////
package com.google.crypto.tink.internal;
import com.google.crypto.tink.InsecureSecretKeyAccess;
import com.google.crypto.tink.Key;
import com.google.crypto.tink.KeyManager;
import com.google.crypto.tink.Parameters;
import com.google.crypto.tink.proto.KeyData;
import com.google.crypto.tink.proto.KeyTemplate;
import java.security.GeneralSecurityException;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.Nullable;
/** Stores methods to create {@link Key} objects from {@link Parameters} with new randomness. */
public final class MutableKeyCreationRegistry {
private final Map, KeyCreator extends Parameters>> creators =
new HashMap<>();
/** A class to create key objects from parameters with given randomness. */
public static interface KeyCreator {
public Key createKey(ParametersT parameters, @Nullable Integer idRequirement)
throws GeneralSecurityException;
}
private static LegacyProtoKey createProtoKeyFromProtoParameters(
LegacyProtoParameters parameters, @Nullable Integer idRequirement)
throws GeneralSecurityException {
KeyTemplate keyTemplate = parameters.getSerialization().getKeyTemplate();
KeyManager> manager =
KeyManagerRegistry.globalInstance().getUntypedKeyManager(keyTemplate.getTypeUrl());
if (!KeyManagerRegistry.globalInstance().isNewKeyAllowed(keyTemplate.getTypeUrl())) {
throw new GeneralSecurityException("Creating new keys is not allowed.");
}
KeyData keyData = manager.newKeyData(keyTemplate.getValue());
ProtoKeySerialization protoSerialization =
ProtoKeySerialization.create(
keyData.getTypeUrl(),
keyData.getValue(),
keyData.getKeyMaterialType(),
keyTemplate.getOutputPrefixType(),
idRequirement);
return new LegacyProtoKey(protoSerialization, InsecureSecretKeyAccess.get());
}
@SuppressWarnings("InlineLambdaConstant") // We need a correct Object#equals in registration.
private static final MutableKeyCreationRegistry.KeyCreator
LEGACY_PROTO_KEY_CREATOR = MutableKeyCreationRegistry::createProtoKeyFromProtoParameters;
private static MutableKeyCreationRegistry newRegistryWithLegacyFallback() {
MutableKeyCreationRegistry registry = new MutableKeyCreationRegistry();
try {
registry.add(LEGACY_PROTO_KEY_CREATOR, LegacyProtoParameters.class);
} catch (GeneralSecurityException e) {
throw new IllegalStateException("unexpected error.", e);
}
return registry;
}
private static final MutableKeyCreationRegistry globalInstance = newRegistryWithLegacyFallback();
public static MutableKeyCreationRegistry globalInstance() {
return globalInstance;
}
/**
* Adds a new "InsecureKeyCreator" to the instance.
*
* If a creator for this class has been added previously, the two instances have to be equal.
* Otherwise, this method throws a {@code GeneralSecurityException}.
*/
public synchronized void add(
KeyCreator creator, Class parametersClass)
throws GeneralSecurityException {
KeyCreator> existingCreator = creators.get(parametersClass);
if (existingCreator != null) {
if (!existingCreator.equals(creator)) {
throw new GeneralSecurityException(
"Different key creator for parameters class " + parametersClass + " already inserted");
}
}
creators.put(parametersClass, creator);
}
/**
* Creates a {@link Key} from a given {@link Parameters} object.
*
* Finds the previously added creator (with {@link #add}) for the class given by {@code
* parameters.getClass()} and uses it.
*/
public Key createKey(Parameters parameters, @Nullable Integer idRequirement)
throws GeneralSecurityException {
return createKeyTyped(parameters, idRequirement);
}
// Separate function to hide use of generics in the above public function.
private synchronized Key createKeyTyped(
ParametersT parameters, @Nullable Integer idRequirement) throws GeneralSecurityException {
Class> parametersClass = parameters.getClass();
KeyCreator> creator = creators.get(parametersClass);
if (creator == null) {
throw new GeneralSecurityException(
"Cannot create a new key for parameters "
+ parameters
+ ": no key creator for this class was registered.");
}
@SuppressWarnings("unchecked") // We know we only insert like this.
KeyCreator castCreator = (KeyCreator) creator;
return castCreator.createKey(parameters, idRequirement);
}
}