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

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

import com.google.crypto.tink.subtle.Bytes;
import java.util.Arrays;
import java.nio.ByteBuffer;
import java.security.Key;
import com.google.crypto.tink.internal.Util;
import com.google.crypto.tink.mac.ChunkedMacVerification;
import com.google.crypto.tink.mac.ChunkedMacComputation;
import java.security.NoSuchAlgorithmException;
import javax.crypto.Mac;
import java.security.GeneralSecurityException;
import com.google.crypto.tink.AccessesPartialKey;
import com.google.crypto.tink.InsecureSecretKeyAccess;
import com.google.crypto.tink.mac.AesCmacKey;
import java.security.Provider;
import javax.crypto.spec.SecretKeySpec;
import com.google.crypto.tink.mac.AesCmacParameters;
import com.google.crypto.tink.config.internal.TinkFipsUtil;
import com.google.errorprone.annotations.Immutable;
import com.google.crypto.tink.mac.ChunkedMac;

@Immutable
public final class ChunkedAesCmacConscrypt implements ChunkedMac
{
    private static final TinkFipsUtil.AlgorithmFipsCompatibility FIPS;
    private final byte[] outputPrefix;
    private final AesCmacParameters parameters;
    private final SecretKeySpec secretKeySpec;
    private final Provider conscrypt;
    
    @AccessesPartialKey
    private static SecretKeySpec toSecretKeySpec(final AesCmacKey key) {
        return new SecretKeySpec(key.getAesKey().toByteArray(InsecureSecretKeyAccess.get()), "AES");
    }
    
    private ChunkedAesCmacConscrypt(final AesCmacKey key, final Provider conscrypt) throws GeneralSecurityException {
        if (conscrypt == null) {
            throw new IllegalArgumentException("conscrypt is null");
        }
        if (!ChunkedAesCmacConscrypt.FIPS.isCompatible()) {
            throw new GeneralSecurityException("Cannot use AES-CMAC in FIPS-mode.");
        }
        try {
            Mac.getInstance("AESCMAC", conscrypt);
        }
        catch (final NoSuchAlgorithmException e) {
            throw new GeneralSecurityException("AES-CMAC not available.", e);
        }
        this.conscrypt = conscrypt;
        this.outputPrefix = key.getOutputPrefix().toByteArray();
        this.parameters = key.getParameters();
        this.secretKeySpec = toSecretKeySpec(key);
    }
    
    @Override
    public ChunkedMacComputation createComputation() throws GeneralSecurityException {
        return new AesCmacComputation(this.secretKeySpec, this.parameters, this.outputPrefix, this.conscrypt);
    }
    
    @Override
    public ChunkedMacVerification createVerification(final byte[] tag) throws GeneralSecurityException {
        if (!Util.isPrefix(this.outputPrefix, tag)) {
            throw new GeneralSecurityException("Wrong tag prefix");
        }
        return ChunkedMacVerificationFromComputation.create(this.createComputation(), tag);
    }
    
    public static ChunkedMac create(final AesCmacKey key, final Provider conscrypt) throws GeneralSecurityException {
        return new ChunkedAesCmacConscrypt(key, conscrypt);
    }
    
    static {
        FIPS = TinkFipsUtil.AlgorithmFipsCompatibility.ALGORITHM_NOT_FIPS;
    }
    
    private static final class AesCmacComputation implements ChunkedMacComputation
    {
        private static final byte[] legacyFormatVersion;
        private final byte[] outputPrefix;
        private final AesCmacParameters parameters;
        private final Mac aesCmac;
        private boolean finalized;
        
        private AesCmacComputation(final SecretKeySpec secretKeySpec, final AesCmacParameters parameters, final byte[] outputPrefix, final Provider conscrypt) throws GeneralSecurityException {
            this.finalized = false;
            this.parameters = parameters;
            this.outputPrefix = outputPrefix;
            (this.aesCmac = Mac.getInstance("AESCMAC", conscrypt)).init(secretKeySpec);
        }
        
        @Override
        public void update(final ByteBuffer data) {
            if (this.finalized) {
                throw new IllegalStateException("Cannot update after computing the MAC tag. Please create a new object.");
            }
            this.aesCmac.update(data);
        }
        
        @Override
        public byte[] computeMac() throws GeneralSecurityException {
            if (this.finalized) {
                throw new IllegalStateException("Cannot compute after computing the MAC tag. Please create a new object.");
            }
            this.finalized = true;
            if (this.parameters.getVariant() == AesCmacParameters.Variant.LEGACY) {
                this.aesCmac.update(AesCmacComputation.legacyFormatVersion);
            }
            return Bytes.concat(new byte[][] { this.outputPrefix, Arrays.copyOf(this.aesCmac.doFinal(), this.parameters.getCryptographicTagSizeBytes()) });
        }
        
        static {
            legacyFormatVersion = new byte[] { 0 };
        }
    }
}
