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

org.bouncycastle.crypto.engines.NoekeonEngine Maven / Gradle / Ivy

Go to download

The Bouncy Castle Crypto package is a Java implementation of cryptographic algorithms. This jar contains JCE provider and lightweight API for the Bouncy Castle Cryptography APIs for Java 1.8 and later with debug enabled.

The newest version!
package org.bouncycastle.crypto.engines;

import org.bouncycastle.crypto.BlockCipher;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.CryptoServicesRegistrar;
import org.bouncycastle.crypto.DataLengthException;
import org.bouncycastle.crypto.OutputLengthException;
import org.bouncycastle.crypto.constraints.DefaultServiceProperties;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.util.Integers;
import org.bouncycastle.util.Pack;

/**
 * A Noekeon engine, using direct-key mode.
 */
public class NoekeonEngine
    implements BlockCipher
{
    // Block and key size, as well as the amount of rounds.
    private static final int SIZE = 16;

    // Used in decryption
    private static final byte[] roundConstants = { (byte)0x80, 0x1b, 0x36, 0x6c, (byte)0xd8, (byte)0xab, 0x4d,
        (byte)0x9a, 0x2f, 0x5e, (byte)0xbc, 0x63, (byte)0xc6, (byte)0x97, 0x35, 0x6a, (byte)0xd4 };

    private final int[] k = new int[4];

    private boolean _initialised, _forEncryption;

    /**
     * Create an instance of the Noekeon encryption algorithm and set some defaults
     */
    public NoekeonEngine()
    {
        _initialised = false;
    }

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

    public int getBlockSize()
    {
        return SIZE;
    }

    /**
     * initialise
     *
     * @param forEncryption
     *            whether or not we are for encryption.
     * @param params
     *            the parameters required to set up the cipher.
     * @exception IllegalArgumentException
     *                if the params argument is inappropriate.
     */
    public void init(boolean forEncryption, CipherParameters params)
    {
        if (!(params instanceof KeyParameter))
        {
            throw new IllegalArgumentException(
                "invalid parameter passed to Noekeon init - " + params.getClass().getName());
        }

        KeyParameter p = (KeyParameter)params;
        byte[] key = p.getKey();
        if (key.length != 16)
        {
            throw new IllegalArgumentException("Key length not 128 bits.");
        }

        Pack.bigEndianToInt(key, 0, k, 0, 4);

        if (!forEncryption)
        {
            // theta(k, new int[]{ 0x00, 0x00, 0x00, 0x00 });
            {
                int a0 = k[0], a1 = k[1], a2 = k[2], a3 = k[3];

                int t02 = a0 ^ a2;
                t02 ^= Integers.rotateLeft(t02, 8) ^ Integers.rotateLeft(t02, 24);

                int t13 = a1 ^ a3;
                t13 ^= Integers.rotateLeft(t13, 8) ^ Integers.rotateLeft(t13, 24);

                a0 ^= t13;
                a1 ^= t02;
                a2 ^= t13;
                a3 ^= t02;

                k[0] = a0; k[1] = a1; k[2] = a2; k[3] = a3;
            }
        }

        this._forEncryption = forEncryption;
        this._initialised = true;

        CryptoServicesRegistrar.checkConstraints(new DefaultServiceProperties(
                this.getAlgorithmName(), 128, params, Utils.getPurpose(forEncryption)));
    }

    public int processBlock(byte[] in, int inOff, byte[] out, int outOff)
    {
        if (!_initialised)
        {
            throw new IllegalStateException(getAlgorithmName() + " not initialised");
        }
        if (inOff > in.length - SIZE)
        {
            throw new DataLengthException("input buffer too short");
        }
        if (outOff > out.length - SIZE)
        {
            throw new OutputLengthException("output buffer too short");
        }

        return _forEncryption ? encryptBlock(in, inOff, out, outOff) : decryptBlock(in, inOff, out, outOff);
    }

    public void reset()
    {
    }

    private int encryptBlock(byte[] in, int inOff, byte[] out, int outOff)
    {
        int a0 = Pack.bigEndianToInt(in, inOff);
        int a1 = Pack.bigEndianToInt(in, inOff + 4);
        int a2 = Pack.bigEndianToInt(in, inOff + 8);
        int a3 = Pack.bigEndianToInt(in, inOff + 12);

        int k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];

        int round = 0;
        for (;;)
        {
            a0 ^= roundConstants[round] & 0xFF;

            // theta(a, k);
            {
                int t02 = a0 ^ a2;
                t02 ^= Integers.rotateLeft(t02, 8) ^ Integers.rotateLeft(t02, 24);

                a0 ^= k0;
                a1 ^= k1;
                a2 ^= k2;
                a3 ^= k3;

                int t13 = a1 ^ a3;
                t13 ^= Integers.rotateLeft(t13, 8) ^ Integers.rotateLeft(t13, 24);

                a0 ^= t13;
                a1 ^= t02;
                a2 ^= t13;
                a3 ^= t02;
            }

            if (++round > SIZE)
            {
                break;
            }

            // pi1(a);
            {
                a1 = Integers.rotateLeft(a1, 1);
                a2 = Integers.rotateLeft(a2, 5);
                a3 = Integers.rotateLeft(a3, 2);
            }

            // gamma(a);
            {
                int t = a3;
                a1 ^= a3 | a2;
                a3 = a0 ^ (a2 & ~a1);

                a2 = t ^ ~a1 ^ a2 ^ a3;

                a1 ^= a3 | a2;
                a0 = t ^ (a2 & a1);
            }

            // pi2(a);
            {
                a1 = Integers.rotateLeft(a1, 31);
                a2 = Integers.rotateLeft(a2, 27);
                a3 = Integers.rotateLeft(a3, 30);
            }
        }

        Pack.intToBigEndian(a0, out, outOff);
        Pack.intToBigEndian(a1, out, outOff + 4);
        Pack.intToBigEndian(a2, out, outOff + 8);
        Pack.intToBigEndian(a3, out, outOff + 12);

        return SIZE;
    }

    private int decryptBlock(byte[] in, int inOff, byte[] out, int outOff)
    {
        int a0 = Pack.bigEndianToInt(in, inOff);
        int a1 = Pack.bigEndianToInt(in, inOff + 4);
        int a2 = Pack.bigEndianToInt(in, inOff + 8);
        int a3 = Pack.bigEndianToInt(in, inOff + 12);

        int k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];

        int round = SIZE;
        for (;;)
        {
            // theta(a, k);
            {
                int t02 = a0 ^ a2;
                t02 ^= Integers.rotateLeft(t02, 8) ^ Integers.rotateLeft(t02, 24);

                a0 ^= k0;
                a1 ^= k1;
                a2 ^= k2;
                a3 ^= k3;

                int t13 = a1 ^ a3;
                t13 ^= Integers.rotateLeft(t13, 8) ^ Integers.rotateLeft(t13, 24);

                a0 ^= t13;
                a1 ^= t02;
                a2 ^= t13;
                a3 ^= t02;
            }

            a0 ^= roundConstants[round] & 0xFF;

            if (--round < 0)
            {
                break;
            }

            // pi1(a);
            {
                a1 = Integers.rotateLeft(a1, 1);
                a2 = Integers.rotateLeft(a2, 5);
                a3 = Integers.rotateLeft(a3, 2);
            }

            // gamma(a);
            {
                int t = a3;
                a1 ^= a3 | a2;
                a3 = a0 ^ (a2 & ~a1);

                a2 = t ^ ~a1 ^ a2 ^ a3;

                a1 ^= a3 | a2;
                a0 = t ^ (a2 & a1);
            }

            // pi2(a);
            {
                a1 = Integers.rotateLeft(a1, 31);
                a2 = Integers.rotateLeft(a2, 27);
                a3 = Integers.rotateLeft(a3, 30);
            }
        }

        Pack.intToBigEndian(a0, out, outOff);
        Pack.intToBigEndian(a1, out, outOff + 4);
        Pack.intToBigEndian(a2, out, outOff + 8);
        Pack.intToBigEndian(a3, out, outOff + 12);

        return SIZE;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy