org.cryptacular.util.NonceUtil.java Source code

Java tutorial

Introduction

Here is the source code for org.cryptacular.util.NonceUtil.java

Source

/* See LICENSE for licensing and NOTICE for copyright. */
package org.cryptacular.util;

import java.lang.reflect.Method;
import javax.crypto.SecretKey;
import org.bouncycastle.crypto.BlockCipher;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.digests.SHA256Digest;
import org.bouncycastle.crypto.prng.EntropySource;
import org.bouncycastle.crypto.prng.SP800SecureRandom;
import org.bouncycastle.crypto.prng.drbg.HashSP800DRBG;
import org.bouncycastle.crypto.prng.drbg.SP80090DRBG;
import org.cryptacular.generator.sp80038a.EncryptedNonce;
import org.cryptacular.generator.sp80038d.RBGNonce;

/**
 * Utility class for generating secure nonce and initialization vectors.
 *
 * @author  Middleware Services
 */
public final class NonceUtil {

    /** Private constructor of utility class. */
    private NonceUtil() {
    }

    /**
     * Generates a nonce of the given size by repetitively concatenating system
     * timestamps (i.e. {@link System#nanoTime()}) up to the required size.
     *
     * @param  length  Positive number of bytes in nonce.
     *
     * @return  Nonce bytes.
     */
    public static byte[] timestampNonce(final int length) {
        if (length <= 0) {
            throw new IllegalArgumentException(length + " is invalid. Length must be positive.");
        }

        final byte[] nonce = new byte[length];
        int count = 0;
        long timestamp;
        while (count < length) {
            timestamp = System.nanoTime();
            for (int i = 0; i < 8 && count < length; i++) {
                nonce[count++] = (byte) (timestamp & 0xFF);
                timestamp >>= 8;
            }
        }
        return nonce;
    }

    /**
     * Generates a nonce/IV using the strategy described in NIST <a
     * href="http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf">
     * SP-800-38d</a>, section 8.2.2, "RBG-based Construction". The implementation
     * uses a hash-based DRBG based on a SHA-256 digest, and uses random data for
     * all bits of the nonce; that is, the fixed field is null.
     *
     * <p>This nonce generation strategy is suitable for GCM ciphers.</p>
     *
     * @param  length  Number of bytes in nonce; MUST be 12 or more.
     *
     * @return  Nonce bytes.
     */
    public static byte[] nist80038d(final int length) {
        return new RBGNonce(length).generate();
    }

    /**
     * Generates a random IV according to NIST <a href="http://goo.gl/S9z8qF">
     * SP-800-63a</a>, appendix C, method 1 (encrypted nonce), suitable for use
     * with any block cipher mode described in that standard. This method uses an
     * instance of {@link EncryptedNonce} for the implementation.
     *
     * @param  cipher  Block cipher.
     * @param  key  Encryption key intended for use with IV.
     *
     * @return  Cipher block size number of random bytes.
     *
     * @see  EncryptedNonce
     */
    public static byte[] nist80063a(final BlockCipher cipher, final SecretKey key) {
        BlockCipher raw = cipher;
        // Get the underlying cipher if there is one
        final Method method = ReflectUtil.getMethod(cipher.getClass(), "getUnderlyingCipher");
        if (method != null) {
            raw = (BlockCipher) ReflectUtil.invoke(cipher, method);
        }
        return new EncryptedNonce(raw, key).generate();
    }

    /**
     * Generates a random IV according to NIST <a href="http://goo.gl/S9z8qF">
     * SP-800-63a</a>, appendix C, method 2 (pseudorandom), suitable for use with
     * any block cipher mode described in that standard.
     *
     * @param  prng  NIST SP800-63a approved pseudorandom number generator.
     * @param  blockSize  Cipher block size in bytes.
     *
     * @return  Cipher block size number of random bytes.
     */
    public static byte[] nist80063a(final SP800SecureRandom prng, final int blockSize) {
        prng.setSeed(System.nanoTime());

        final byte[] iv = new byte[blockSize];
        prng.nextBytes(iv);
        return iv;
    }

    /**
     * Generates a random IV according to NIST <a href="http://goo.gl/S9z8qF">
     * SP-800-63a</a>, appendix C, method 2 (pseudorandom), suitable for use with
     * any block cipher mode described in that standard. Uses an instance of
     * {@link RBGNonce} internally with length equal to block size of given
     * cipher.
     *
     * @param  cipher  Block cipher.
     *
     * @return  Cipher block size number of random bytes.
     *
     * @see  RBGNonce
     */
    public static byte[] nist80063a(final BlockCipher cipher) {
        return new RBGNonce(cipher.getBlockSize()).generate();
    }

    /**
     * Creates a new DRBG instance based on a SHA-256 digest.
     *
     * @param  length  Length in bits of values to be produced by DRBG instance.
     *
     * @return  New DRGB instance.
     */
    public static SP80090DRBG newRBG(final int length) {
        return newRBG(new SHA256Digest(), length);
    }

    /**
     * Creates a new hash-based DRBG instance that uses the given digest as the
     * pseudorandom source.
     *
     * @param  digest  Digest algorithm.
     * @param  length  Length in bits of values to be produced by DRBG instance.
     *
     * @return  New DRGB instance.
     */
    public static SP80090DRBG newRBG(final Digest digest, final int length) {
        return new HashSP800DRBG(digest, length, new EntropySource() {
            @Override
            public boolean isPredictionResistant() {
                return false;
            }

            @Override
            public byte[] getEntropy() {
                return NonceUtil.timestampNonce(length);
            }

            @Override
            public int entropySize() {
                return length;
            }
        }, null, NonceUtil.timestampNonce(8));
    }
}