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

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

Go to download

The Long Term Stable (LTS) Bouncy Castle Crypto package is a Java implementation of cryptographic algorithms. This jar contains the JCA/JCE provider and low-level API for the BC LTS version 2.73.6 for Java 8 and later.

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

import java.io.ByteArrayOutputStream;

import org.bouncycastle.crypto.BlockCipher;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.DataLengthException;
import org.bouncycastle.crypto.ExceptionMessages;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.modes.GCMSIVModeCipher;
import org.bouncycastle.crypto.params.AEADParameters;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.params.ParametersWithIV;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.dispose.NativeDisposer;
import org.bouncycastle.util.dispose.NativeReference;

public class AESNativeGCMSIV
        implements GCMSIVModeCipher
{
    private GCMSIVRefWrapper refWrapper;
    private byte[] keptMac;

    /**
     * The encryptedDataStream
     */
    private GCMSIVCache theEncData = new GCMSIVCache();

    /**
     * Are we encrypting?
     */
    private boolean forEncryption;

    /**
     * The initialAEAD.
     */
    private byte[] theInitialAEAD;


    /**
     * The nonce.
     */
    private byte[] theNonce;
    private byte[] lastKey;

    @Override
    public BlockCipher getUnderlyingCipher()
    {
        BlockCipher engine = AESEngine.newInstance();
        if (lastKey != null)
        {
            engine.init(true, new KeyParameter(lastKey));
        }
        return engine;
    }

    @Override
    public void init(boolean forEncryption, CipherParameters cipherParameters)
            throws IllegalArgumentException
    {
        this.forEncryption = forEncryption;
        keptMac = null;
        theEncData.reset();

        /* Set defaults */
        byte[] myInitialAEAD = null;
        byte[] myNonce;
        KeyParameter myKey;

        /* Access parameters */
        if (cipherParameters instanceof AEADParameters)
        {
            final AEADParameters myAEAD = (AEADParameters) cipherParameters;
            myInitialAEAD = myAEAD.getAssociatedText();
            myNonce = myAEAD.getNonce();
            myKey = myAEAD.getKey();
        }
        else if (cipherParameters instanceof ParametersWithIV)
        {
            final ParametersWithIV myParms = (ParametersWithIV) cipherParameters;
            myNonce = myParms.getIV();
            myKey = (KeyParameter) myParms.getParameters();
        }
        else
        {
            throw new IllegalArgumentException("invalid parameters passed to GCM-SIV");
        }

        /* Reset details */
        theInitialAEAD = myInitialAEAD;
        theNonce = myNonce;
        lastKey = myKey.getKey();
        switch (lastKey.length)
        {
            case 16:
            case 24:
            case 32:
                break;
            default:
                throw new IllegalStateException(ExceptionMessages.AES_KEY_LENGTH);
        }

        initRef();


        initNative(
                refWrapper.getReference(),
                forEncryption, lastKey,
                theNonce, theInitialAEAD);

    }

    private void initRef()
    {
        refWrapper = new GCMSIVRefWrapper(makeInstance());
    }

    @Override
    public String getAlgorithmName()
    {
        return "AES/GCM-SIV";
    }

    @Override
    public void processAADByte(byte in)
    {
        if (refWrapper == null)
        {
            throw new IllegalStateException(ExceptionMessages.GCM_SIV_UNINITIALIZED);
        }
        processAADByte(refWrapper.getReference(), in);
    }

    @Override
    public void processAADBytes(byte[] in, int inOff, int len)
    {
        if (refWrapper == null)
        {
            throw new IllegalStateException(ExceptionMessages.GCM_SIV_UNINITIALIZED);
        }
        processAADBytes(refWrapper.getReference(), in, inOff, len);
    }

    @Override
    public int processByte(byte in, byte[] out, int outOff)
            throws DataLengthException
    {
        if (refWrapper == null)
        {
            throw new IllegalStateException(ExceptionMessages.GCM_SIV_UNINITIALIZED);
        }
        theEncData.write(in);
        return 0;
    }

    @Override
    public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff)
            throws DataLengthException
    {
        if (refWrapper == null)
        {
            throw new IllegalStateException(ExceptionMessages.GCM_SIV_UNINITIALIZED);
        }
        theEncData.write(in, inOff, len);
        return 0;
    }

    @Override
    public int doFinal(byte[] out, int outOff)
            throws IllegalStateException, InvalidCipherTextException
    {

        int len = doFinal(refWrapper.getReference(), theEncData.getBuffer(), theEncData.size(), out, outOff);
        //resetKeepMac
        keptMac = getMac();
        reset();
        return len;
    }

    @Override
    public byte[] getMac()
    {
        if (refWrapper == null)
        {
            throw new IllegalStateException(ExceptionMessages.GCM_SIV_UNINITIALIZED);
        }

        if (keptMac != null)
        {
            return Arrays.clone(keptMac);
        }
        return getMac(refWrapper.getReference());
    }

    @Override
    public int getUpdateOutputSize(int len)
    {
        if (refWrapper == null)
        {
            throw new IllegalStateException(ExceptionMessages.GCM_SIV_UNINITIALIZED);
        }
        return getUpdateOutputSize(refWrapper.getReference(), len, theEncData.size());
    }

    @Override
    public int getOutputSize(int len)
    {
        if (refWrapper == null)
        {
            throw new IllegalStateException(ExceptionMessages.GCM_SIV_UNINITIALIZED);
        }
        return getOutputSize(refWrapper.getReference(), len);
    }


    @Override
    public void reset()
    {

        theEncData.clearBuffer();
        if (refWrapper == null)
        {
            // deal with reset being called before init.
            return;
        }
        reset(refWrapper.getReference());
    }

    public String toString()
    {
        if (lastKey != null)
        {
            return "GCMSIV[Native](AES[Native](" + (lastKey.length * 8) + "))";
        }
        return "GCMSIV[Native](AES[Native](not initialized))";
    }

    private static class GCMSIVRefWrapper
            extends NativeReference
    {
        public GCMSIVRefWrapper(long reference)
        {
            super(reference, "GCM-SIV");
        }

        @Override
        public Runnable createAction()
        {
            return new Disposer(reference);
        }

    }

    private static class Disposer
            extends NativeDisposer
    {
        Disposer(long ref)
        {
            super(ref);
        }

        @Override
        protected void dispose(long reference)
        {
            AESNativeGCMSIV.dispose(reference);
        }
    }

    private native void reset(long ref);

    static native void initNative(
            long reference,
            boolean forEncryption,
            byte[] keyParam,
            byte[] nonce,
            byte[] initialAssociatedText);

    static native long makeInstance();

    static native void dispose(long nativeRef);

    static native void processAADByte(long ref, byte in);

    static native void processAADBytes(long ref, byte[] in, int inOff, int len);

    static native int doFinal(long ref, byte[] input, int inputLen, byte[] out, int outOff);

    static native int getUpdateOutputSize(long ref, int len, int streamLen);

    static native int getOutputSize(long ref, int len);

    static native byte[] getMac(long ref);

    /**
     * Test method, you have ABSOLUTELY no reason to call this in normal use.
     * max_dl is the maximum amount of data the implementation will process.
     */
    static native void test_set_max_dl(long ref, long value);


    /**
     * GCMSIVCache.
     */
    private static class GCMSIVCache
            extends ByteArrayOutputStream
    {
        /**
         * Constructor.
         */
        GCMSIVCache()
        {
        }

        /**
         * Obtain the buffer.
         *
         * @return the buffer
         */
        byte[] getBuffer()
        {
            return this.buf;
        }

        /**
         * Clear the buffer.
         */
        void clearBuffer()
        {
            Arrays.fill(getBuffer(), (byte) 0);
            reset();
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy