tech.ydb.shaded.bouncycastle.crypto.generators.KDFFeedbackBytesGenerator Maven / Gradle / Ivy
package org.bouncycastle.crypto.generators;
import java.math.BigInteger;
import org.bouncycastle.crypto.DataLengthException;
import org.bouncycastle.crypto.DerivationParameters;
import org.bouncycastle.crypto.Mac;
import org.bouncycastle.crypto.MacDerivationFunction;
import org.bouncycastle.crypto.params.KDFFeedbackParameters;
import org.bouncycastle.crypto.params.KeyParameter;
/**
 * This KDF has been defined by the publicly available NIST SP 800-108 specification.
 */
public class KDFFeedbackBytesGenerator
    implements MacDerivationFunction
{
    private static final BigInteger INTEGER_MAX = BigInteger.valueOf(Integer.MAX_VALUE);
    private static final BigInteger TWO = BigInteger.valueOf(2);
    // please refer to the standard for the meaning of the variable names
    // all field lengths are in bytes, not in bits as specified by the standard
    // fields set by the constructor
    private final Mac prf;
    private final int h;
    // fields set by init
    private byte[] fixedInputData;
    private int maxSizeExcl;
    // ios is i defined as an octet string (the binary representation)
    private byte[] ios;
    private byte[] iv;
    private boolean useCounter;
    // operational
    private int generatedBytes;
    // k is used as buffer for all K(i) values
    private byte[] k;
    public KDFFeedbackBytesGenerator(Mac prf)
    {
        this.prf = prf;
        this.h = prf.getMacSize();
        this.k = new byte[h];
    }
    public void init(DerivationParameters params)
    {
        if (!(params instanceof KDFFeedbackParameters))
        {
            throw new IllegalArgumentException("Wrong type of arguments given");
        }
        KDFFeedbackParameters feedbackParams = (KDFFeedbackParameters)params;
        // --- init mac based PRF ---
        this.prf.init(new KeyParameter(feedbackParams.getKI()));
        // --- set arguments ---
        this.fixedInputData = feedbackParams.getFixedInputData();
        int r = feedbackParams.getR();
        this.ios = new byte[r / 8];
        if (feedbackParams.useCounter())
        {
            // this is more conservative than the spec
            BigInteger maxSize = TWO.pow(r).multiply(BigInteger.valueOf(h));
            this.maxSizeExcl = maxSize.compareTo(INTEGER_MAX) == 1 ?
                Integer.MAX_VALUE : maxSize.intValue();
        }
        else
        {
            this.maxSizeExcl = Integer.MAX_VALUE;
        }
        this.iv = feedbackParams.getIV();
        this.useCounter = feedbackParams.useCounter();
        // --- set operational state ---
        generatedBytes = 0;
    }
    public Mac getMac()
    {
        return prf;
    }
    public int generateBytes(byte[] out, int outOff, int len)
        throws DataLengthException, IllegalArgumentException
    {
        int generatedBytesAfter = generatedBytes + len;
        if (generatedBytesAfter < 0 || generatedBytesAfter >= maxSizeExcl)
        {
            throw new DataLengthException(
                "Current KDFCTR may only be used for " + maxSizeExcl + " bytes");
        }
        if (generatedBytes % h == 0)
        {
            generateNext();
        }
        // copy what is left in the currentT (1..hash
        int toGenerate = len;
        int posInK = generatedBytes % h;
        int leftInK = h - generatedBytes % h;
        int toCopy = Math.min(leftInK, toGenerate);
        System.arraycopy(k, posInK, out, outOff, toCopy);
        generatedBytes += toCopy;
        toGenerate -= toCopy;
        outOff += toCopy;
        while (toGenerate > 0)
        {
            generateNext();
            toCopy = Math.min(h, toGenerate);
            System.arraycopy(k, 0, out, outOff, toCopy);
            generatedBytes += toCopy;
            toGenerate -= toCopy;
            outOff += toCopy;
        }
        return len;
    }
    private void generateNext()
    {
        // TODO enable IV
        if (generatedBytes == 0)
        {
            prf.update(iv, 0, iv.length);
        }
        else
        {
            prf.update(k, 0, k.length);
        }
        if (useCounter)
        {
            int i = generatedBytes / h + 1;
            // encode i into counter buffer
            switch (ios.length)
            {
            case 4:
                ios[0] = (byte)(i >>> 24);
                // fall through
            case 3:
                ios[ios.length - 3] = (byte)(i >>> 16);
                // fall through
            case 2:
                ios[ios.length - 2] = (byte)(i >>> 8);
                // fall through
            case 1:
                ios[ios.length - 1] = (byte)i;
                break;
            default:
                throw new IllegalStateException("Unsupported size of counter i");
            }
            prf.update(ios, 0, ios.length);
        }
        prf.update(fixedInputData, 0, fixedInputData.length);
        prf.doFinal(k, 0);
    }
}
    © 2015 - 2025 Weber Informatics LLC | Privacy Policy