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

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

import java.security.GeneralSecurityException;
import java.security.Key;
import javax.crypto.spec.SecretKeySpec;
import com.google.crypto.tink.subtle.EngineFactory;
import javax.crypto.Mac;
import com.google.errorprone.annotations.Immutable;

@Immutable
final class HkdfHpkeKdf implements HpkeKdf
{
    private final String macAlgorithm;
    
    HkdfHpkeKdf(final String macAlgorithm) {
        this.macAlgorithm = macAlgorithm;
    }
    
    private byte[] extract(final byte[] ikm, final byte[] salt) throws GeneralSecurityException {
        final Mac mac = EngineFactory.MAC.getInstance(this.macAlgorithm);
        if (salt == null || salt.length == 0) {
            mac.init(new SecretKeySpec(new byte[mac.getMacLength()], this.macAlgorithm));
        }
        else {
            mac.init(new SecretKeySpec(salt, this.macAlgorithm));
        }
        return mac.doFinal(ikm);
    }
    
    private byte[] expand(final byte[] prk, final byte[] info, final int length) throws GeneralSecurityException {
        final Mac mac = EngineFactory.MAC.getInstance(this.macAlgorithm);
        if (length > 255 * mac.getMacLength()) {
            throw new GeneralSecurityException("size too large");
        }
        final byte[] result = new byte[length];
        int ctr = 1;
        int pos = 0;
        mac.init(new SecretKeySpec(prk, this.macAlgorithm));
        byte[] digest = new byte[0];
        while (true) {
            mac.update(digest);
            mac.update(info);
            mac.update((byte)ctr);
            digest = mac.doFinal();
            if (pos + digest.length >= length) {
                break;
            }
            System.arraycopy(digest, 0, result, pos, digest.length);
            pos += digest.length;
            ++ctr;
        }
        System.arraycopy(digest, 0, result, pos, length - pos);
        return result;
    }
    
    @Override
    public byte[] labeledExtract(final byte[] salt, final byte[] ikm, final String ikmLabel, final byte[] suiteId) throws GeneralSecurityException {
        return this.extract(HpkeUtil.labelIkm(ikmLabel, ikm, suiteId), salt);
    }
    
    @Override
    public byte[] labeledExpand(final byte[] prk, final byte[] info, final String infoLabel, final byte[] suiteId, final int length) throws GeneralSecurityException {
        return this.expand(prk, HpkeUtil.labelInfo(infoLabel, info, suiteId, length), length);
    }
    
    @Override
    public byte[] extractAndExpand(final byte[] salt, final byte[] ikm, final String ikmLabel, final byte[] info, final String infoLabel, final byte[] suiteId, final int length) throws GeneralSecurityException {
        final byte[] prk = this.extract(HpkeUtil.labelIkm(ikmLabel, ikm, suiteId), salt);
        return this.expand(prk, HpkeUtil.labelInfo(infoLabel, info, suiteId, length), length);
    }
    
    @Override
    public byte[] getKdfId() throws GeneralSecurityException {
        final String macAlgorithm = this.macAlgorithm;
        switch (macAlgorithm) {
            case "HmacSha256": {
                return HpkeUtil.HKDF_SHA256_KDF_ID;
            }
            case "HmacSha384": {
                return HpkeUtil.HKDF_SHA384_KDF_ID;
            }
            case "HmacSha512": {
                return HpkeUtil.HKDF_SHA512_KDF_ID;
            }
            default: {
                throw new GeneralSecurityException("Could not determine HPKE KDF ID");
            }
        }
    }
    
    int getMacLength() throws GeneralSecurityException {
        return Mac.getInstance(this.macAlgorithm).getMacLength();
    }
}
