All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.bouncycastle.crypto.fips.ConcatenationKDFGenerator Maven / Gradle / Ivy

Go to download

The FIPS 140-2 Bouncy Castle Crypto package is a Java implementation of cryptographic algorithms certified to FIPS 140-2 level 1. This jar contains the debug version JCE provider and low-level API for the BC-FJA version 1.0.2.3, FIPS Certificate #3514. Please note the debug jar is not certified.

There is a newer version: 2.0.0
Show newest version
package org.bouncycastle.crypto.fips;

import org.bouncycastle.crypto.internal.DataLengthException;
import org.bouncycastle.crypto.internal.DerivationFunction;
import org.bouncycastle.crypto.internal.DerivationParameters;
import org.bouncycastle.crypto.internal.Digest;
import org.bouncycastle.crypto.internal.Mac;
import org.bouncycastle.crypto.internal.macs.HMac;
import org.bouncycastle.crypto.internal.params.KDFParameters;
import org.bouncycastle.crypto.internal.params.KeyParameterImpl;

/**
 * Generator for Concatenation Key Derivation Function defined in NIST SP 800-56A, Sect 5.8.1
 */
class ConcatenationKDFGenerator
    implements DerivationFunction
{
    private final Mac mac;
    private Digest digest;
    private byte[] shared;
    private byte[] otherInfo;
    private int hLen;

    /**
     * @param digest the digest to be used as the source of generated bytes
     */
    public ConcatenationKDFGenerator(
        Digest digest)
    {
        this.digest = digest;
        this.mac = null;
        this.hLen = digest.getDigestSize();
    }

    public ConcatenationKDFGenerator(
        Mac mac)
    {
        this.mac = mac;
        this.digest = null;
        this.hLen = mac.getMacSize();
    }

    public void init(
        DerivationParameters param)
    {
        if (param instanceof KDFParameters)
        {
            KDFParameters p = (KDFParameters)param;

            shared = p.getSharedSecret();
            otherInfo = p.getIV();
            if (mac != null)
            {
                byte[] salt = p.getSalt();
                if (p.getSalt() == null)
                {
                    if (mac instanceof HMac)
                    {
                        salt = new byte[((HMac)mac).getUnderlyingDigest().getByteLength()];
                    }
                    else if (mac instanceof KMAC)
                    {
                        salt = new byte[(((KMAC)mac).getByteLength()) - 4];
                    }
                    else
                    {
                        throw new IllegalArgumentException("cannot recognise MAC");
                    }
                }
                mac.init(new KeyParameterImpl(salt));
            }
        }
        else
        {
            throw new IllegalArgumentException("KDF parameters required for KDF generator");
        }
    }

    /**
     * return the underlying digest.
     */
    public Digest getDigest()
    {
        return digest;
    }

    /**
     * int to octet string.
     */
    private void ItoOSP(
        int i,
        byte[] sp)
    {
        sp[0] = (byte)(i >>> 24);
        sp[1] = (byte)(i >>> 16);
        sp[2] = (byte)(i >>> 8);
        sp[3] = (byte)(i >>> 0);
    }

    /**
     * fill len bytes of the output buffer with bytes generated from
     * the derivation function.
     *
     * @throws DataLengthException if the out buffer is too small.
     */
    public int generateBytes(
        byte[] out,
        int outOff,
        int len)
        throws DataLengthException, IllegalArgumentException
    {
        if (digest != null)
        {
            return digestGenerateBytes(out, outOff, len);
        }
        else
        {
            return macGenerateBytes(out, outOff, len);
        }
    }

    /**
     * fill len bytes of the output buffer with bytes generated from
     * the derivation function.
     *
     * @throws DataLengthException if the out buffer is too small.
     */
    public int digestGenerateBytes(
        byte[] out,
        int outOff,
        int len)
        throws DataLengthException, IllegalArgumentException
    {
        if ((out.length - len) < outOff)
        {
            throw new DataLengthException("output buffer too small");
        }

        byte[] hashBuf = new byte[hLen];
        byte[] C = new byte[4];
        int counter = 1;
        int outputLen = 0;

        digest.reset();

        if (len > hLen)
        {
            do
            {
                ItoOSP(counter, C);

                digest.update(C, 0, C.length);
                digest.update(shared, 0, shared.length);
                if (otherInfo != null)
                {
                    digest.update(otherInfo, 0, otherInfo.length);
                }

                digest.doFinal(hashBuf, 0);

                System.arraycopy(hashBuf, 0, out, outOff + outputLen, hLen);
                outputLen += hLen;
            }
            while ((counter++) < (len / hLen));
        }

        if (outputLen < len)
        {
            ItoOSP(counter, C);

            digest.update(C, 0, C.length);
            digest.update(shared, 0, shared.length);

            if (otherInfo != null)
            {
                digest.update(otherInfo, 0, otherInfo.length);
            }

            digest.doFinal(hashBuf, 0);

            System.arraycopy(hashBuf, 0, out, outOff + outputLen, len - outputLen);
        }

        return len;
    }

    /**
     * fill len bytes of the output buffer with bytes generated from
     * the derivation function.
     *
     * @throws DataLengthException if the out buffer is too small.
     */
    private int macGenerateBytes(
        byte[] out,
        int outOff,
        int len)
        throws DataLengthException, IllegalArgumentException
    {
        if ((out.length - len) < outOff)
        {
            throw new DataLengthException("output buffer too small");
        }

        byte[] hashBuf = new byte[hLen];
        byte[] C = new byte[4];
        int counter = 1;
        int outputLen = 0;

        mac.reset();

        if (mac instanceof KMAC)
        {
            ItoOSP(counter, C);

            mac.update(C, 0, C.length);
            mac.update(shared, 0, shared.length);
            if (otherInfo != null)
            {
                mac.update(otherInfo, 0, otherInfo.length);
            }

            return ((KMAC)mac).doFinal(out, outOff, len);
        }

        if (len > hLen)
        {
            do
            {
                ItoOSP(counter, C);

                mac.update(C, 0, C.length);
                mac.update(shared, 0, shared.length);
                if (otherInfo != null)
                {
                    mac.update(otherInfo, 0, otherInfo.length);
                }

                mac.doFinal(hashBuf, 0);

                System.arraycopy(hashBuf, 0, out, outOff + outputLen, hLen);
                outputLen += hLen;
            }
            while ((counter++) < (len / hLen));
        }

        if (outputLen < len)
        {
            ItoOSP(counter, C);

            mac.update(C, 0, C.length);
            mac.update(shared, 0, shared.length);

            if (otherInfo != null)
            {
                mac.update(otherInfo, 0, otherInfo.length);
            }

            mac.doFinal(hashBuf, 0);

            System.arraycopy(hashBuf, 0, out, outOff + outputLen, len - outputLen);
        }

        return len;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy