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

package com.google.crypto.tink.subtle;

import com.google.crypto.tink.prf.AesCmacPrfKey;
import com.google.crypto.tink.prf.AesCmacPrfParameters;
import com.google.crypto.tink.mac.HmacParameters;
import java.security.Key;
import javax.crypto.spec.SecretKeySpec;
import com.google.crypto.tink.InsecureSecretKeyAccess;
import com.google.crypto.tink.mac.HmacKey;
import java.util.Arrays;
import com.google.crypto.tink.mac.AesCmacParameters;
import com.google.crypto.tink.mac.AesCmacKey;
import java.security.GeneralSecurityException;
import java.security.InvalidAlgorithmParameterException;
import com.google.crypto.tink.prf.Prf;
import com.google.crypto.tink.AccessesPartialKey;
import com.google.errorprone.annotations.Immutable;
import com.google.crypto.tink.Mac;

@Immutable
@AccessesPartialKey
public class PrfMac implements Mac
{
    private static final byte[] formatVersion;
    static final int MIN_TAG_SIZE_IN_BYTES = 10;
    private final Prf wrappedPrf;
    private final int tagSize;
    private final byte[] outputPrefix;
    private final byte[] plaintextLegacySuffix;
    
    public PrfMac(final Prf wrappedPrf, final int tagSize) throws GeneralSecurityException {
        this.wrappedPrf = wrappedPrf;
        this.tagSize = tagSize;
        this.outputPrefix = new byte[0];
        this.plaintextLegacySuffix = new byte[0];
        if (tagSize < 10) {
            throw new InvalidAlgorithmParameterException("tag size too small, need at least 10 bytes");
        }
        final Object unused = wrappedPrf.compute(new byte[0], tagSize);
    }
    
    private PrfMac(final AesCmacKey key) throws GeneralSecurityException {
        this.wrappedPrf = createPrf(key);
        this.tagSize = key.getParameters().getCryptographicTagSizeBytes();
        this.outputPrefix = key.getOutputPrefix().toByteArray();
        if (key.getParameters().getVariant().equals(AesCmacParameters.Variant.LEGACY)) {
            this.plaintextLegacySuffix = Arrays.copyOf(PrfMac.formatVersion, PrfMac.formatVersion.length);
        }
        else {
            this.plaintextLegacySuffix = new byte[0];
        }
    }
    
    private PrfMac(final HmacKey key) throws GeneralSecurityException {
        this.wrappedPrf = new PrfHmacJce("HMAC" + key.getParameters().getHashType(), new SecretKeySpec(key.getKeyBytes().toByteArray(InsecureSecretKeyAccess.get()), "HMAC"));
        this.tagSize = key.getParameters().getCryptographicTagSizeBytes();
        this.outputPrefix = key.getOutputPrefix().toByteArray();
        if (key.getParameters().getVariant().equals(HmacParameters.Variant.LEGACY)) {
            this.plaintextLegacySuffix = Arrays.copyOf(PrfMac.formatVersion, PrfMac.formatVersion.length);
        }
        else {
            this.plaintextLegacySuffix = new byte[0];
        }
    }
    
    public static Mac create(final AesCmacKey key) throws GeneralSecurityException {
        return new PrfMac(key);
    }
    
    public static Mac create(final HmacKey key) throws GeneralSecurityException {
        return new PrfMac(key);
    }
    
    @Override
    public byte[] computeMac(final byte[] data) throws GeneralSecurityException {
        if (this.plaintextLegacySuffix.length > 0) {
            return Bytes.concat(new byte[][] { this.outputPrefix, this.wrappedPrf.compute(Bytes.concat(new byte[][] { data, this.plaintextLegacySuffix }), this.tagSize) });
        }
        return Bytes.concat(new byte[][] { this.outputPrefix, this.wrappedPrf.compute(data, this.tagSize) });
    }
    
    @Override
    public void verifyMac(final byte[] mac, final byte[] data) throws GeneralSecurityException {
        if (!Bytes.equal(this.computeMac(data), mac)) {
            throw new GeneralSecurityException("invalid MAC");
        }
    }
    
    @AccessesPartialKey
    private static Prf createPrf(final AesCmacKey key) throws GeneralSecurityException {
        return PrfAesCmac.create(AesCmacPrfKey.create(AesCmacPrfParameters.create(key.getParameters().getKeySizeBytes()), key.getAesKey()));
    }
    
    static {
        formatVersion = new byte[] { 0 };
    }
}
