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

nl.open.jwtdependency.org.bouncycastle.crypto.prng.X931RNG Maven / Gradle / Ivy

Go to download

This is a drop in replacement for the auth0 java-jwt library (see https://github.com/auth0/java-jwt). This jar makes sure there are no external dependencies (e.g. fasterXml, Apacha Commons) needed. This is useful when deploying to an application server (e.g. tomcat with Alfreso or Pega).

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

import org.bouncycastle.crypto.BlockCipher;

public class X931RNG
{
    private static final long       BLOCK64_RESEED_MAX = 1L << (16 - 1);
    private static final long       BLOCK128_RESEED_MAX = 1L << (24 - 1);
    private static final int        BLOCK64_MAX_BITS_REQUEST = 1 << (13 - 1);
    private static final int        BLOCK128_MAX_BITS_REQUEST = 1 << (19 - 1);
    
    private final BlockCipher engine;
    private final EntropySource entropySource;

    private final byte[] DT;
    private final byte[] I;
    private final byte[] R;;

    private byte[] V;

    private long reseedCounter = 1;

    /**
     *
     * @param engine
     * @param entropySource
     */
    public X931RNG(BlockCipher engine, byte[] dateTimeVector, EntropySource entropySource)
    {
        this.engine = engine;
        this.entropySource = entropySource;

        this.DT = new byte[engine.getBlockSize()];

        System.arraycopy(dateTimeVector, 0, DT, 0, DT.length);

        this.I = new byte[engine.getBlockSize()];
        this.R = new byte[engine.getBlockSize()];
    }

    /**
     * Populate a passed in array with random data.
     *
     * @param output output array for generated bits.
     * @param predictionResistant true if a reseed should be forced, false otherwise.
     *
     * @return number of bits generated, -1 if a reseed required.
     */
    int generate(byte[] output, boolean predictionResistant)
    {
        if (R.length == 8) // 64 bit block size
        {
            if (reseedCounter > BLOCK64_RESEED_MAX)
            {
                return -1;
            }

            if (isTooLarge(output, BLOCK64_MAX_BITS_REQUEST / 8))
            {
                throw new IllegalArgumentException("Number of bits per request limited to " + BLOCK64_MAX_BITS_REQUEST);
            }
        }
        else
        {
            if (reseedCounter > BLOCK128_RESEED_MAX)
            {
                return -1;
            }

            if (isTooLarge(output, BLOCK128_MAX_BITS_REQUEST / 8))
            {
                throw new IllegalArgumentException("Number of bits per request limited to " + BLOCK128_MAX_BITS_REQUEST);
            }
        }
        
        if (predictionResistant || V == null)
        {
            V = entropySource.getEntropy();
            if (V.length != engine.getBlockSize())
            {
                throw new IllegalStateException("Insufficient entropy returned");
            }
        }

        int m = output.length / R.length;

        for (int i = 0; i < m; i++)
        {
            engine.processBlock(DT, 0, I, 0);
            process(R, I, V);
            process(V, R, I);

            System.arraycopy(R, 0, output, i * R.length, R.length);

            increment(DT);
        }

        int bytesToCopy = (output.length - m * R.length);

        if (bytesToCopy > 0)
        {
            engine.processBlock(DT, 0, I, 0);
            process(R, I, V);
            process(V, R, I);

            System.arraycopy(R, 0, output, m * R.length, bytesToCopy);

            increment(DT);
        }

        reseedCounter++;

        return output.length;
    }

    /**
     * Reseed the RNG.
     */
    void reseed()
    {
        V = entropySource.getEntropy();
        if (V.length != engine.getBlockSize())
        {
            throw new IllegalStateException("Insufficient entropy returned");
        }
        reseedCounter = 1;
    }

    EntropySource getEntropySource()
    {
        return entropySource;
    }

    private void process(byte[] res, byte[] a, byte[] b)
    {
        for (int i = 0; i != res.length; i++)
        {
            res[i] = (byte)(a[i] ^ b[i]);
        }

        engine.processBlock(res, 0, res, 0);
    }

    private void increment(byte[] val)
    {
        for (int i = val.length - 1; i >= 0; i--)
        {
            if (++val[i] != 0)
            {
                break;
            }
        }
    }
    
    private static boolean isTooLarge(byte[] bytes, int maxBytes)
    {
        return bytes != null && bytes.length > maxBytes;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy