blob: ce03d6943e73b12adbcc8d3536f8a26e6a3f0676 [file] [log] [blame]
// Copyright 2020 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.tinkkey;
import com.google.crypto.tink.KeyTemplate;
import com.google.crypto.tink.KeyTemplate.OutputPrefixType;
import com.google.crypto.tink.Registry;
import com.google.crypto.tink.internal.Util;
import com.google.crypto.tink.proto.KeyData;
import com.google.crypto.tink.tinkkey.internal.ProtoKey;
import com.google.errorprone.annotations.Immutable;
import java.security.GeneralSecurityException;
/**
* Wraps a {@link TinkKey} and enforces access to the underlying {@link TinkKey} with {@link
* KeyAccess}. Specifically, if the underlying {@link TinkKey} has a secret, then one can only get
* it with a {@link SecretKeyAccess} instance.
*/
@Immutable
public class KeyHandle {
/**
* KeyStatusType is metadata associated to a key which is only meaningful when the key is part of
* a {@link Keyset}. A key's status in the Keyset is either ENABLED (able to perform cryptographic
* operations), DISABLED (unable to perform operations, but could be re-enabled), or DESTROYED
* (the key's data is no longer present in the keyset).
*/
public enum KeyStatusType {
ENABLED,
DISABLED,
DESTROYED;
}
/**
* Returns a {@link KeyHandle} instance with {@code key} as the underlying {@link TinkKey} if the
* caller provides the correct {@link KeyAccess} instance.
*
* @throws GeneralSecurityException if {@code access} does not grant access to {@code key}
*/
public static KeyHandle createFromKey(TinkKey key, KeyAccess access)
throws GeneralSecurityException {
KeyHandle result = new KeyHandle(key);
result.checkAccess(access);
return result;
}
/**
* Returns a {@link KeyHandle} instance where the underlying {@link TinkKey} wraps the input
* {@code keyData}. The returned KeyHandle has a secret if keyData has key material of type
* UNKNOWN_KEYMATERIAL, SYMMETRIC, or ASYMMETRIC_PRIVATE.
*
* @deprecated Use the KeyHandle(TinkKey, KeyAccess) constructor instead.
*/
@Deprecated
public static KeyHandle createFromKey(KeyData keyData, OutputPrefixType opt) {
return new KeyHandle(new ProtoKey(keyData, opt));
}
private final TinkKey key;
private final KeyStatusType status;
private final int id;
/**
* Constructs a KeyHandle wrapping the input TinkKey. The KeyStatusType is set to ENABLED and an
* arbitrary key ID is assigned.
*/
private KeyHandle(TinkKey key) {
this.key = key;
this.status = KeyStatusType.ENABLED;
this.id = Util.randKeyId();
}
/**
* Constructor intended for Tink internal purposes; allows one to set all the member variables of
* a {@link KeyHandle}.
*/
protected KeyHandle(TinkKey key, KeyStatusType status, int keyId) {
this.key = key;
this.status = status;
this.id = keyId;
}
/**
* Generates a new {@link KeyHandle} that contains a fresh key generated according to {@code
* keyTemplate}.
*
* @throws GeneralSecurityException if the key template's type URL has not been registered with
* the {@link Registry}.
*/
public static KeyHandle generateNew(KeyTemplate keyTemplate) throws GeneralSecurityException {
ProtoKey protoKey =
new ProtoKey(Registry.newKeyData(keyTemplate), keyTemplate.getOutputPrefixType());
return new KeyHandle(protoKey);
}
/** Returns {@code true} if the underlying {@link TinkKey} has a secret. */
public boolean hasSecret() {
return key.hasSecret();
}
/** Returns the status of the key. See {@link KeyStatusType}. */
public KeyStatusType getStatus() {
return this.status;
}
/**
* Returns the key ID of this key. The key ID is not guaranteed to be unique among all KeyHandles.
*/
public int getId() {
return id;
}
/**
* Returns the underlying {@link TinkKey} key if {@code access} is a {@link SecretKeyAccess} and
* the key has a secret, or if the key does not have a secret, otherwise throws a {@link
* GeneralSecurityException}.
*/
public TinkKey getKey(KeyAccess access) throws GeneralSecurityException {
checkAccess(access);
return key;
}
/**
* Returns the {@link KeyTemplate} of the underlying {@link TinkKey}.
*
* @throws UnsupportedOperationException if the underlying {@link TinkKey} has not implemented
* getKeyTemplate().
*/
public KeyTemplate getKeyTemplate() {
return key.getKeyTemplate();
}
private void checkAccess(KeyAccess access) throws GeneralSecurityException {
if (hasSecret() && !access.canAccessSecret()) {
throw new GeneralSecurityException("No access");
}
}
}