// 
// Decompiled by Procyon v0.6.0
// 

package com.google.crypto.tink.tinkkey;

import com.google.crypto.tink.internal.KeyTemplateProtoConverter;
import com.google.crypto.tink.internal.Util;
import com.google.crypto.tink.tinkkey.internal.ProtoKey;
import com.google.crypto.tink.KeyManager;
import com.google.protobuf.InvalidProtocolBufferException;
import java.security.GeneralSecurityException;
import com.google.crypto.tink.internal.KeyManagerRegistry;
import com.google.protobuf.ExtensionRegistryLite;
import com.google.crypto.tink.TinkProtoParametersFormat;
import com.google.crypto.tink.proto.KeyData;
import com.google.crypto.tink.KeyTemplate;
import com.google.errorprone.annotations.Immutable;

@Immutable
public class KeyHandle
{
    private final TinkKey key;
    private final KeyStatusType status;
    private final int id;
    
    private static KeyData newKeyData(final KeyTemplate keyTemplate) throws GeneralSecurityException {
        try {
            final byte[] serializedKeyTemplate = TinkProtoParametersFormat.serialize(keyTemplate.toParameters());
            final com.google.crypto.tink.proto.KeyTemplate protoTemplate = com.google.crypto.tink.proto.KeyTemplate.parseFrom(serializedKeyTemplate, ExtensionRegistryLite.getEmptyRegistry());
            final KeyManager<?> manager = KeyManagerRegistry.globalInstance().getUntypedKeyManager(protoTemplate.getTypeUrl());
            if (KeyManagerRegistry.globalInstance().isNewKeyAllowed(protoTemplate.getTypeUrl())) {
                return manager.newKeyData(protoTemplate.getValue());
            }
            throw new GeneralSecurityException("newKey-operation not permitted for key type " + protoTemplate.getTypeUrl());
        }
        catch (final InvalidProtocolBufferException e) {
            throw new GeneralSecurityException("Failed to parse serialized parameters", e);
        }
    }
    
    public static KeyHandle createFromKey(final TinkKey key, final KeyAccess access) throws GeneralSecurityException {
        final KeyHandle result = new KeyHandle(key);
        result.checkAccess(access);
        return result;
    }
    
    public static KeyHandle createFromKey(final KeyData keyData, final KeyTemplate.OutputPrefixType opt) {
        return new KeyHandle(new ProtoKey(keyData, opt));
    }
    
    private KeyHandle(final TinkKey key) {
        this.key = key;
        this.status = KeyStatusType.ENABLED;
        this.id = Util.randKeyId();
    }
    
    protected KeyHandle(final TinkKey key, final KeyStatusType status, final int keyId) {
        this.key = key;
        this.status = status;
        this.id = keyId;
    }
    
    public static KeyHandle generateNew(final KeyTemplate keyTemplate) throws GeneralSecurityException {
        final ProtoKey protoKey = new ProtoKey(newKeyData(keyTemplate), KeyTemplateProtoConverter.getOutputPrefixType(keyTemplate));
        return new KeyHandle(protoKey);
    }
    
    public boolean hasSecret() {
        return this.key.hasSecret();
    }
    
    public KeyStatusType getStatus() {
        return this.status;
    }
    
    public int getId() {
        return this.id;
    }
    
    public TinkKey getKey(final KeyAccess access) throws GeneralSecurityException {
        this.checkAccess(access);
        return this.key;
    }
    
    public KeyTemplate getKeyTemplate() {
        return this.key.getKeyTemplate();
    }
    
    private void checkAccess(final KeyAccess access) throws GeneralSecurityException {
        if (this.hasSecret() && !access.canAccessSecret()) {
            throw new GeneralSecurityException("No access");
        }
    }
    
    public enum KeyStatusType
    {
        ENABLED, 
        DISABLED, 
        DESTROYED;
    }
}
