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

package org.bouncycastle.crypto.generators;

import org.bouncycastle.crypto.DataLengthException;
import org.bouncycastle.util.Integers;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.params.KDFCounterParameters;
import org.bouncycastle.crypto.DerivationParameters;
import org.bouncycastle.crypto.Mac;
import org.bouncycastle.crypto.MacDerivationFunction;

public class KDFCounterBytesGenerator implements MacDerivationFunction
{
    private final Mac prf;
    private final int h;
    private byte[] fixedInputDataCtrPrefix;
    private byte[] fixedInputData_afterCtr;
    private int maxSizeExcl;
    private byte[] ios;
    private int generatedBytes;
    private byte[] k;
    
    public KDFCounterBytesGenerator(final Mac prf) {
        this.prf = prf;
        this.h = prf.getMacSize();
        this.k = new byte[this.h];
    }
    
    @Override
    public void init(final DerivationParameters derivationParameters) {
        if (!(derivationParameters instanceof KDFCounterParameters)) {
            throw new IllegalArgumentException("Wrong type of arguments given");
        }
        final KDFCounterParameters kdfCounterParameters = (KDFCounterParameters)derivationParameters;
        this.prf.init(new KeyParameter(kdfCounterParameters.getKI()));
        this.fixedInputDataCtrPrefix = kdfCounterParameters.getFixedInputDataCounterPrefix();
        this.fixedInputData_afterCtr = kdfCounterParameters.getFixedInputDataCounterSuffix();
        final int r = kdfCounterParameters.getR();
        this.ios = new byte[r / 8];
        this.maxSizeExcl = ((r >= Integers.numberOfLeadingZeros(this.h)) ? Integer.MAX_VALUE : (this.h << r));
        this.generatedBytes = 0;
    }
    
    @Override
    public Mac getMac() {
        return this.prf;
    }
    
    @Override
    public int generateBytes(final byte[] array, int n, final int b) throws DataLengthException, IllegalArgumentException {
        final int n2 = this.generatedBytes + b;
        if (n2 < 0 || n2 >= this.maxSizeExcl) {
            throw new DataLengthException("Current KDFCTR may only be used for " + this.maxSizeExcl + " bytes");
        }
        if (this.generatedBytes % this.h == 0) {
            this.generateNext();
        }
        final int n3 = this.generatedBytes % this.h;
        final int min = Math.min(this.h - this.generatedBytes % this.h, b);
        System.arraycopy(this.k, n3, array, n, min);
        this.generatedBytes += min;
        int i;
        int min2;
        for (i = b - min, n += min; i > 0; i -= min2, n += min2) {
            this.generateNext();
            min2 = Math.min(this.h, i);
            System.arraycopy(this.k, 0, array, n, min2);
            this.generatedBytes += min2;
        }
        return b;
    }
    
    private void generateNext() {
        final int n = this.generatedBytes / this.h + 1;
        switch (this.ios.length) {
            case 4: {
                this.ios[0] = (byte)(n >>> 24);
            }
            case 3: {
                this.ios[this.ios.length - 3] = (byte)(n >>> 16);
            }
            case 2: {
                this.ios[this.ios.length - 2] = (byte)(n >>> 8);
            }
            case 1: {
                this.ios[this.ios.length - 1] = (byte)n;
                this.prf.update(this.fixedInputDataCtrPrefix, 0, this.fixedInputDataCtrPrefix.length);
                this.prf.update(this.ios, 0, this.ios.length);
                this.prf.update(this.fixedInputData_afterCtr, 0, this.fixedInputData_afterCtr.length);
                this.prf.doFinal(this.k, 0);
                return;
            }
            default: {
                throw new IllegalStateException("Unsupported size of counter i");
            }
        }
    }
}
