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

package com.google.crypto.tink.hybrid.internal;

import java.util.Arrays;
import com.google.crypto.tink.internal.Util;
import com.google.crypto.tink.AccessesPartialKey;
import com.google.crypto.tink.InsecureSecretKeyAccess;
import com.google.crypto.tink.hybrid.HpkePrivateKey;
import java.security.GeneralSecurityException;
import com.google.crypto.tink.hybrid.HpkeParameters;
import com.google.crypto.tink.util.Bytes;
import com.google.errorprone.annotations.Immutable;
import com.google.crypto.tink.HybridDecrypt;

@Immutable
public final class HpkeDecrypt implements HybridDecrypt
{
    private static final byte[] EMPTY_ASSOCIATED_DATA;
    private final HpkeKemPrivateKey recipientPrivateKey;
    private final HpkeKem kem;
    private final HpkeKdf kdf;
    private final HpkeAead aead;
    private final int encapsulatedKeyLength;
    private final byte[] outputPrefix;
    
    private HpkeDecrypt(final HpkeKemPrivateKey recipientPrivateKey, final HpkeKem kem, final HpkeKdf kdf, final HpkeAead aead, final int encapsulatedKeyLength, final Bytes outputPrefix) {
        this.recipientPrivateKey = recipientPrivateKey;
        this.kem = kem;
        this.kdf = kdf;
        this.aead = aead;
        this.encapsulatedKeyLength = encapsulatedKeyLength;
        this.outputPrefix = outputPrefix.toByteArray();
    }
    
    private static int encodingSizeInBytes(final HpkeParameters.KemId kemId) throws GeneralSecurityException {
        if (kemId.equals(HpkeParameters.KemId.DHKEM_X25519_HKDF_SHA256)) {
            return 32;
        }
        if (kemId.equals(HpkeParameters.KemId.DHKEM_P256_HKDF_SHA256)) {
            return 65;
        }
        if (kemId.equals(HpkeParameters.KemId.DHKEM_P384_HKDF_SHA384)) {
            return 97;
        }
        if (kemId.equals(HpkeParameters.KemId.DHKEM_P521_HKDF_SHA512)) {
            return 133;
        }
        throw new GeneralSecurityException("Unrecognized HPKE KEM identifier");
    }
    
    @AccessesPartialKey
    private static HpkeKemPrivateKey createHpkeKemPrivateKey(final HpkePrivateKey privateKey) throws GeneralSecurityException {
        final HpkeParameters.KemId kemId = privateKey.getParameters().getKemId();
        if (kemId.equals(HpkeParameters.KemId.DHKEM_X25519_HKDF_SHA256) || kemId.equals(HpkeParameters.KemId.DHKEM_P256_HKDF_SHA256) || kemId.equals(HpkeParameters.KemId.DHKEM_P384_HKDF_SHA384) || kemId.equals(HpkeParameters.KemId.DHKEM_P521_HKDF_SHA512)) {
            final Bytes convertedPrivateKeyBytes = Bytes.copyFrom(privateKey.getPrivateKeyBytes().toByteArray(InsecureSecretKeyAccess.get()));
            return new HpkeKemPrivateKey(convertedPrivateKeyBytes, privateKey.getPublicKey().getPublicKeyBytes());
        }
        throw new GeneralSecurityException("Unrecognized HPKE KEM identifier");
    }
    
    public static HybridDecrypt create(final HpkePrivateKey privateKey) throws GeneralSecurityException {
        final HpkeParameters parameters = privateKey.getParameters();
        final HpkeKem kem = HpkePrimitiveFactory.createKem(parameters.getKemId());
        final HpkeKdf kdf = HpkePrimitiveFactory.createKdf(parameters.getKdfId());
        final HpkeAead aead = HpkePrimitiveFactory.createAead(parameters.getAeadId());
        final int encapsulatedKeyLength = encodingSizeInBytes(parameters.getKemId());
        final HpkeKemPrivateKey recipientKemPrivateKey = createHpkeKemPrivateKey(privateKey);
        return new HpkeDecrypt(recipientKemPrivateKey, kem, kdf, aead, encapsulatedKeyLength, privateKey.getOutputPrefix());
    }
    
    @Override
    public byte[] decrypt(final byte[] ciphertext, final byte[] contextInfo) throws GeneralSecurityException {
        final int prefixAndHeaderLength = this.outputPrefix.length + this.encapsulatedKeyLength;
        if (ciphertext.length < prefixAndHeaderLength) {
            throw new GeneralSecurityException("Ciphertext is too short.");
        }
        if (!Util.isPrefix(this.outputPrefix, ciphertext)) {
            throw new GeneralSecurityException("Invalid ciphertext (output prefix mismatch)");
        }
        byte[] info = contextInfo;
        if (info == null) {
            info = new byte[0];
        }
        final byte[] encapsulatedKey = Arrays.copyOfRange(ciphertext, this.outputPrefix.length, prefixAndHeaderLength);
        final HpkeContext context = HpkeContext.createRecipientContext(encapsulatedKey, this.recipientPrivateKey, this.kem, this.kdf, this.aead, info);
        return context.open(ciphertext, prefixAndHeaderLength, HpkeDecrypt.EMPTY_ASSOCIATED_DATA);
    }
    
    static {
        EMPTY_ASSOCIATED_DATA = new byte[0];
    }
}
