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

package com.google.crypto.tink.subtle;

import java.util.Arrays;
import javax.crypto.spec.SecretKeySpec;
import com.google.crypto.tink.InsecureSecretKeyAccess;
import com.google.crypto.tink.prf.HmacPrfKey;
import java.security.NoSuchAlgorithmException;
import java.security.InvalidAlgorithmParameterException;
import java.security.GeneralSecurityException;
import java.security.Key;
import javax.crypto.Mac;
import com.google.crypto.tink.config.internal.TinkFipsUtil;
import com.google.crypto.tink.AccessesPartialKey;
import com.google.errorprone.annotations.Immutable;
import com.google.crypto.tink.prf.Prf;

@Immutable
@AccessesPartialKey
public final class PrfHmacJce implements Prf
{
    public static final TinkFipsUtil.AlgorithmFipsCompatibility FIPS;
    static final int MIN_KEY_SIZE_IN_BYTES = 16;
    private final ThreadLocal<Mac> localMac;
    private final String algorithm;
    private final Key key;
    private final int maxOutputLength;
    
    public PrfHmacJce(final String algorithm, final Key key) throws GeneralSecurityException {
        this.localMac = new ThreadLocal<Mac>() {
            @Override
            protected Mac initialValue() {
                try {
                    final Mac mac = EngineFactory.MAC.getInstance(PrfHmacJce.this.algorithm);
                    mac.init(PrfHmacJce.this.key);
                    return mac;
                }
                catch (final GeneralSecurityException ex) {
                    throw new IllegalStateException(ex);
                }
            }
        };
        if (!PrfHmacJce.FIPS.isCompatible()) {
            throw new GeneralSecurityException("Can not use HMAC in FIPS-mode, as BoringCrypto module is not available.");
        }
        this.algorithm = algorithm;
        this.key = key;
        if (key.getEncoded().length < 16) {
            throw new InvalidAlgorithmParameterException("key size too small, need at least 16 bytes");
        }
        switch (algorithm) {
            case "HMACSHA1": {
                this.maxOutputLength = 20;
                break;
            }
            case "HMACSHA224": {
                this.maxOutputLength = 28;
                break;
            }
            case "HMACSHA256": {
                this.maxOutputLength = 32;
                break;
            }
            case "HMACSHA384": {
                this.maxOutputLength = 48;
                break;
            }
            case "HMACSHA512": {
                this.maxOutputLength = 64;
                break;
            }
            default: {
                throw new NoSuchAlgorithmException("unknown Hmac algorithm: " + algorithm);
            }
        }
        this.localMac.get();
    }
    
    public static Prf create(final HmacPrfKey key) throws GeneralSecurityException {
        return new PrfHmacJce("HMAC" + key.getParameters().getHashType(), new SecretKeySpec(key.getKeyBytes().toByteArray(InsecureSecretKeyAccess.get()), "HMAC"));
    }
    
    @Override
    public byte[] compute(final byte[] data, final int outputLength) throws GeneralSecurityException {
        if (outputLength > this.maxOutputLength) {
            throw new InvalidAlgorithmParameterException("tag size too big");
        }
        this.localMac.get().update(data);
        return Arrays.copyOf(this.localMac.get().doFinal(), outputLength);
    }
    
    public int getMaxOutputLength() {
        return this.maxOutputLength;
    }
    
    static {
        FIPS = TinkFipsUtil.AlgorithmFipsCompatibility.ALGORITHM_REQUIRES_BORINGCRYPTO;
    }
}
