GordianDSTU7624Mac.java

package org.bouncycastle.crypto.patch.macs;

import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.DataLengthException;
import org.bouncycastle.crypto.Mac;
import org.bouncycastle.crypto.OutputLengthException;
import org.bouncycastle.crypto.engines.DSTU7624Engine;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.util.Arrays;

/**
 * Implementation of DSTU7624 MAC mode
 */
public class GordianDSTU7624Mac
        implements Mac {
    private final static int BITS_IN_BYTE = 8;

    private byte[] buf;
    private int bufOff;

    private int macSize;
    private int blockSize;
    private DSTU7624Engine engine;

    private byte[] c, cTemp, kDelta;

    public GordianDSTU7624Mac(int blockBitLength,
                              int q) {
        this.engine = new DSTU7624Engine(blockBitLength);
        this.blockSize = blockBitLength / BITS_IN_BYTE;
        this.macSize = q / BITS_IN_BYTE;
        this.c = new byte[blockSize];
        this.kDelta = new byte[blockSize];
        this.cTemp = new byte[blockSize];
        this.buf = new byte[blockSize];
    }

    public void init(CipherParameters params)
            throws IllegalArgumentException {
        if (params instanceof KeyParameter) {
            engine.init(true, params);
            reset();
        } else {
            throw new IllegalArgumentException("Invalid parameter passed to DSTU7624Mac");
        }
    }

    public String getAlgorithmName() {
        return "DSTU7624Mac";
    }

    public int getMacSize() {
        return macSize;
    }

    public void update(byte in) {
        if (bufOff == buf.length) {
            processBlock(buf, 0);
            bufOff = 0;
        }

        buf[bufOff++] = in;
    }

    public void update(byte[] in, int inOff, int len) {
        if (len < 0) {
            throw new IllegalArgumentException(
                    "can't have a negative input length!");
        }

        int blockSize = engine.getBlockSize();
        int gapLen = blockSize - bufOff;

        if (len > gapLen) {
            System.arraycopy(in, inOff, buf, bufOff, gapLen);

            processBlock(buf, 0);

            bufOff = 0;
            len -= gapLen;
            inOff += gapLen;

            while (len > blockSize) {
                processBlock(in, inOff);

                len -= blockSize;
                inOff += blockSize;
            }
        }

        System.arraycopy(in, inOff, buf, bufOff, len);

        bufOff += len;
    }

    private void processBlock(byte[] in, int inOff) {
        xor(c, 0, in, inOff, cTemp);

        engine.processBlock(cTemp, 0, c, 0);
    }

    public int doFinal(byte[] out, int outOff)
            throws DataLengthException, IllegalStateException {
        if (bufOff % buf.length != 0) {
            /* Pad using Poly1305 style padding */
            buf[bufOff] = 1;
            for (int i = bufOff + 1; i < buf.length; i++) {
                buf[i] = 0;
            }
        }

        // Last block
        xor(c, 0, buf, 0, cTemp);
        xor(cTemp, 0, kDelta, 0, c);
        engine.processBlock(c, 0, c, 0);

        if (macSize + outOff > out.length) {
            throw new OutputLengthException("output buffer too short");
        }

        System.arraycopy(c, 0, out, outOff, macSize);
        reset();

        return macSize;
    }

    public void reset() {
        Arrays.fill(c, (byte) 0x00);
        Arrays.fill(cTemp, (byte) 0x00);
        Arrays.fill(kDelta, (byte) 0x00);
        Arrays.fill(buf, (byte) 0x00);
        engine.reset();
        engine.processBlock(kDelta, 0, kDelta, 0);
        bufOff = 0;
    }

    private void xor(byte[] x, int xOff, byte[] y, int yOff, byte[] x_xor_y) {

        if (x.length - xOff < blockSize || y.length - yOff < blockSize || x_xor_y.length < blockSize) {
            throw new IllegalArgumentException("some of input buffers too short");
        }
        for (int byteIndex = 0; byteIndex < blockSize; byteIndex++) {
            x_xor_y[byteIndex] = (byte) (x[byteIndex + xOff] ^ y[byteIndex + yOff]);
        }
    }
}