com.google.crypto.tink.internal.SerializationRegistry Maven / Gradle / Ivy
// Copyright 2022 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.Key;
import com.google.crypto.tink.Parameters;
import com.google.crypto.tink.SecretKeyAccess;
import com.google.crypto.tink.util.Bytes;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import java.security.GeneralSecurityException;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import javax.annotation.Nullable;
/**
* Allows registering {@code KeySerializer}, {@code KeyParser}, {@code ParametersSerializer}, and
* {@link ParametersParser} objects, and parsing/serializing keys and key formats with such objects.
*/
public final class SerializationRegistry {
private final Map> keySerializerMap;
private final Map> keyParserMap;
private final Map> parametersSerializerMap;
private final Map> parametersParserMap;
/** Allows building SerializationRegistry objects. */
public static final class Builder {
private final Map> keySerializerMap;
private final Map> keyParserMap;
private final Map> parametersSerializerMap;
private final Map> parametersParserMap;
public Builder() {
keySerializerMap = new HashMap<>();
keyParserMap = new HashMap<>();
parametersSerializerMap = new HashMap<>();
parametersParserMap = new HashMap<>();
}
public Builder(SerializationRegistry registry) {
keySerializerMap = new HashMap<>(registry.keySerializerMap);
keyParserMap = new HashMap<>(registry.keyParserMap);
parametersSerializerMap = new HashMap<>(registry.parametersSerializerMap);
parametersParserMap = new HashMap<>(registry.parametersParserMap);
}
/**
* Registers a key serializer for later use in {@link #serializeKey}.
*
* This registers a key serializer which can later be used to serialize a key by calling
* {@link #serializeKey}. If a serializer for the pair {@code (KeyT, SerializationT)} has
* already been registered, this checks if they are the same. If they are, the call is ignored,
* otherwise an exception is thrown.
*/
@CanIgnoreReturnValue
public Builder registerKeySerializer(
KeySerializer serializer) throws GeneralSecurityException {
SerializerIndex index =
new SerializerIndex(serializer.getKeyClass(), serializer.getSerializationClass());
if (keySerializerMap.containsKey(index)) {
KeySerializer existingSerializer = keySerializerMap.get(index);
if (!existingSerializer.equals(serializer) || !serializer.equals(existingSerializer)) {
throw new GeneralSecurityException(
"Attempt to register non-equal serializer for already existing object of type: "
+ index);
}
} else {
keySerializerMap.put(index, serializer);
}
return this;
}
/**
* Registers a key parser for later use in {@link #parseKey}.
*
* This registers a key serializer which can later be used to serialize a key by calling
* {@link #parseKey}. If a parser for the pair {@code (SerializationT,
* parser.getObjectIdentifier())} has already been registered, this checks if they are the same.
* If they are, the call is ignored, otherwise an exception is thrown.
*/
@CanIgnoreReturnValue
public Builder registerKeyParser(
KeyParser parser) throws GeneralSecurityException {
ParserIndex index =
new ParserIndex(parser.getSerializationClass(), parser.getObjectIdentifier());
if (keyParserMap.containsKey(index)) {
KeyParser existingParser = keyParserMap.get(index);
if (!existingParser.equals(parser) || !parser.equals(existingParser)) {
throw new GeneralSecurityException(
"Attempt to register non-equal parser for already existing object of type: " + index);
}
} else {
keyParserMap.put(index, parser);
}
return this;
}
/**
* Registers a key serializer for later use in {@link #serializeKey}.
*
* This registers a key serializer which can later be used to serialize a key by calling
* {@link #serializeKey}. If a serializer for the pair {@code (KeyT, SerializationT)} has
* already been registered, this checks if they are the same. If they are, the call is ignored,
* otherwise an exception is thrown.
*/
@CanIgnoreReturnValue
public
Builder registerParametersSerializer(
ParametersSerializer serializer)
throws GeneralSecurityException {
SerializerIndex index =
new SerializerIndex(serializer.getParametersClass(), serializer.getSerializationClass());
if (parametersSerializerMap.containsKey(index)) {
ParametersSerializer existingSerializer = parametersSerializerMap.get(index);
if (!existingSerializer.equals(serializer) || !serializer.equals(existingSerializer)) {
throw new GeneralSecurityException(
"Attempt to register non-equal serializer for already existing object of type: "
+ index);
}
} else {
parametersSerializerMap.put(index, serializer);
}
return this;
}
/**
* Registers a key parser for later use in {@link #parseKey}.
*
* This registers a key serializer which can later be used to serialize a key by calling
* {@link #parseKey}. If a parser for the pair {@code (SerializationT,
* parser.getObjectIdentifier())} has already been registered, this checks if they are the same.
* If they are, the call is ignored, otherwise an exception is thrown.
*/
@CanIgnoreReturnValue
public Builder registerParametersParser(
ParametersParser parser) throws GeneralSecurityException {
ParserIndex index =
new ParserIndex(parser.getSerializationClass(), parser.getObjectIdentifier());
if (parametersParserMap.containsKey(index)) {
ParametersParser existingParser = parametersParserMap.get(index);
if (!existingParser.equals(parser) || !parser.equals(existingParser)) {
throw new GeneralSecurityException(
"Attempt to register non-equal parser for already existing object of type: " + index);
}
} else {
parametersParserMap.put(index, parser);
}
return this;
}
SerializationRegistry build() {
return new SerializationRegistry(this);
}
}
private SerializationRegistry(Builder builder) {
keySerializerMap = new HashMap<>(builder.keySerializerMap);
keyParserMap = new HashMap<>(builder.keyParserMap);
parametersSerializerMap = new HashMap<>(builder.parametersSerializerMap);
parametersParserMap = new HashMap<>(builder.parametersParserMap);
}
private static class SerializerIndex {
private final Class keyClass;
private final Class keySerializationClass;
private SerializerIndex(
Class keyClass, Class keySerializationClass) {
this.keyClass = keyClass;
this.keySerializationClass = keySerializationClass;
}
@Override
public boolean equals(Object o) {
if (!(o instanceof SerializerIndex)) {
return false;
}
SerializerIndex other = (SerializerIndex) o;
return other.keyClass.equals(keyClass)
&& other.keySerializationClass.equals(keySerializationClass);
}
@Override
public int hashCode() {
return Objects.hash(keyClass, keySerializationClass);
}
@Override
public String toString() {
return keyClass.getSimpleName()
+ " with serialization type: "
+ keySerializationClass.getSimpleName();
}
}
private static class ParserIndex {
private final Class keySerializationClass;
private final Bytes serializationIdentifier;
private ParserIndex(
Class keySerializationClass, Bytes serializationIdentifier) {
this.keySerializationClass = keySerializationClass;
this.serializationIdentifier = serializationIdentifier;
}
@Override
public boolean equals(Object o) {
if (!(o instanceof ParserIndex)) {
return false;
}
ParserIndex other = (ParserIndex) o;
return other.keySerializationClass.equals(keySerializationClass)
&& other.serializationIdentifier.equals(serializationIdentifier);
}
@Override
public int hashCode() {
return Objects.hash(keySerializationClass, serializationIdentifier);
}
@Override
public String toString() {
return keySerializationClass.getSimpleName()
+ ", object identifier: "
+ serializationIdentifier;
}
}
/** Returns true if a parser for this {@code serializedKey} has been registered. */
public boolean hasParserForKey(
SerializationT serializedKey) {
ParserIndex index =
new ParserIndex(serializedKey.getClass(), serializedKey.getObjectIdentifier());
return keyParserMap.containsKey(index);
}
/**
* Parses the given serialization into a Key.
*
* This will look up a previously registered parser for the passed in {@code SerializationT}
* class, and the used object identifier (as indicated by {@code
* serializedKey.getObjectIdentifier()}), and then parse the object with this parsers.
*/
public Key parseKey(
SerializationT serializedKey, @Nullable SecretKeyAccess access)
throws GeneralSecurityException {
ParserIndex index =
new ParserIndex(serializedKey.getClass(), serializedKey.getObjectIdentifier());
if (!keyParserMap.containsKey(index)) {
throw new GeneralSecurityException(
"No Key Parser for requested key type " + index + " available");
}
@SuppressWarnings("unchecked") // We know we only insert like this.
KeyParser parser = (KeyParser) keyParserMap.get(index);
return parser.parseKey(serializedKey, access);
}
/** Returns true if a parser for this {@code serializedKey} has been registered. */
public boolean hasSerializerForKey(
KeyT key, Class serializationClass) {
SerializerIndex index = new SerializerIndex(key.getClass(), serializationClass);
return keySerializerMap.containsKey(index);
}
/**
* Serializes a given Key into a "SerializationT" object.
*
* This will look up a previously registered serializer for the requested {@code
* SerializationT} class and the passed in key type, and then call serializeKey on the result.
*/
public SerializationT serializeKey(
KeyT key, Class serializationClass, @Nullable SecretKeyAccess access)
throws GeneralSecurityException {
SerializerIndex index = new SerializerIndex(key.getClass(), serializationClass);
if (!keySerializerMap.containsKey(index)) {
throw new GeneralSecurityException("No Key serializer for " + index + " available");
}
@SuppressWarnings("unchecked") // We know we only insert like this.
KeySerializer serializer =
(KeySerializer) keySerializerMap.get(index);
return serializer.serializeKey(key, access);
}
/** Returns true if a parser for this {@code serializedKey} has been registered. */
public boolean hasParserForParameters(
SerializationT serializedParameters) {
ParserIndex index =
new ParserIndex(
serializedParameters.getClass(), serializedParameters.getObjectIdentifier());
return parametersParserMap.containsKey(index);
}
/**
* Parses the given serialization into a Parameters.
*
* This will look up a previously registered parser for the passed in {@code SerializationT}
* class, and the used object identifier (as indicated by {@code
* serializedKey.getObjectIdentifier()}), and then parse the object with this parsers.
*/
public Parameters parseParameters(
SerializationT serializedParameters) throws GeneralSecurityException {
ParserIndex index =
new ParserIndex(
serializedParameters.getClass(), serializedParameters.getObjectIdentifier());
if (!parametersParserMap.containsKey(index)) {
throw new GeneralSecurityException(
"No Parameters Parser for requested key type " + index + " available");
}
@SuppressWarnings("unchecked") // We know we only insert like this.
ParametersParser parser =
(ParametersParser) parametersParserMap.get(index);
return parser.parseParameters(serializedParameters);
}
/** Returns true if a parser for this {@code serializedKey} has been registered. */
public
boolean hasSerializerForParameters(
ParametersT parameters, Class serializationClass) {
SerializerIndex index = new SerializerIndex(parameters.getClass(), serializationClass);
return parametersSerializerMap.containsKey(index);
}
/**
* Serializes a given Parameters object into a "SerializationT" object.
*
* This will look up a previously registered serializer for the requested {@code
* SerializationT} class and the passed in key type, and then call serializeKey on the result.
*/
public
SerializationT serializeParameters(
ParametersT parameters, Class serializationClass)
throws GeneralSecurityException {
SerializerIndex index = new SerializerIndex(parameters.getClass(), serializationClass);
if (!parametersSerializerMap.containsKey(index)) {
throw new GeneralSecurityException("No Key Format serializer for " + index + " available");
}
@SuppressWarnings("unchecked") // We know we only insert like this.
ParametersSerializer serializer =
(ParametersSerializer) parametersSerializerMap.get(index);
return serializer.serializeParameters(parameters);
}
}