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

org.cryptacular.util.NonceUtil Maven / Gradle / Ivy

There is a newer version: 6.2.20
Show newest version
/* See LICENSE for licensing and NOTICE for copyright. */
package org.cryptacular.util;

import java.lang.reflect.Method;
import java.security.SecureRandom;
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
{
  /** Class-wide random source. */
  private static final SecureRandom SECURE_RANDOM = new SecureRandom();

  /** Seed random source. */
  static
  {
    // Call nextBytes to force seeding via default process
    SECURE_RANDOM.nextBytes(new byte[1]);
  }

  /** 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 random nonce of the given length in bytes.
   *
   * @param  length  Positive number of bytes in nonce.
   *
   * @return  Nonce bytes.
   */
  public static byte[] randomNonce(final int length)
  {
    if (length <= 0) {
      throw new IllegalArgumentException(length + " is invalid. Length must be positive.");
    }
    final byte[] nonce = new byte[length];
    SECURE_RANDOM.nextBytes(nonce);
    return nonce;
  }


  /**
   * Creates a new entropy source that wraps a {@link SecureRandom} to produce random bytes.
   *
   * @param length Size of entropy blocks.
   *
   * @return New random entropy source.
   */
  public static EntropySource randomEntropySource(final int length)
  {
    return new EntropySource() {
      @Override
      public boolean isPredictionResistant()
      {
        return true;
      }

      @Override
      public byte[] getEntropy()
      {
        final byte[] bytes = new byte[length];
        SECURE_RANDOM.nextBytes(bytes);
        return bytes;
      }

      @Override
      public int entropySize()
      {
        return length;
      }
    };
  }


  /**
   * Generates a nonce/IV using the strategy described in NIST SP-800-38d, 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.
   *
   * 

This nonce generation strategy is suitable for GCM ciphers.

* * @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 SP-800-63a, 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 SP-800-63a, 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(randomNonce(blockSize)); final byte[] iv = new byte[blockSize]; prng.nextBytes(iv); return iv; } /** * Generates a random IV according to NIST SP-800-63a, 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 newRBG(digest, length, randomEntropySource(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. * @param es Entropy source. * * @return New DRGB instance. */ public static SP80090DRBG newRBG(final Digest digest, final int length, final EntropySource es) { return new HashSP800DRBG( digest, length, es, Thread.currentThread().getName().getBytes(), NonceUtil.timestampNonce(8)); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy