/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.generator.sp80038d; import org.bouncycastle.crypto.digests.SHA256Digest; import org.bouncycastle.crypto.prng.EntropySource; import org.bouncycastle.crypto.prng.drbg.HashSP800DRBG; import org.bouncycastle.crypto.prng.drbg.SP80090DRBG; import org.cryptacular.generator.LimitException; import org.cryptacular.generator.Nonce; import org.cryptacular.util.ByteUtil; import org.cryptacular.util.NonceUtil; /** * RBG-based nonce generation strategy that uses a RBG component to produce values for the invocation field as 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. * * <p><strong>NOTE:</strong> users of this class are responsible for counting number of invocations and enforcing the * constraints described in section 8.3; namely the following:</p> * * <blockquote>The total number of invocations of the authenticated encryption function shall not exceed 2<sup>32</sup>, * including all IV lengths and all instances of the authenticated encryption function with the given key.</blockquote> * * <p>Instances of this class are thread safe.</p> * * @author Middleware Services */ public class RBGNonce implements Nonce { /** Fixed field value. */ private final byte[] fixed; /** Number of bytes of random data in invocation field. */ private final int randomLength; /** Random bit generator. */ private final SP80090DRBG rbg; /** * Creates a new instance that produces 12-bytes (96-bits) of random data; that is, the fixed field of the nonce is * null. */ public RBGNonce() { this(12); } /** * Creates a new instance that produces length bytes of random data; that is, the fixed field of the nonce is null. * * @param randomLength Number of bytes in the random part of the nonce. MUST be at least 12. */ public RBGNonce(final int randomLength) { this(null, randomLength); } /** * Creates a new instance using the given fixed field value. * * @param fixed User-defined fixed field value. * @param randomLength Number of bytes in the random part of the nonce. MUST be at least 12. */ public RBGNonce(final String fixed, final int randomLength) { if (randomLength < 12) { throw new IllegalArgumentException("Must specify at least 12 bytes (96 bits) for random part."); } this.randomLength = randomLength; if (fixed != null) { this.fixed = ByteUtil.toBytes(fixed); } else { this.fixed = new byte[0]; } this.rbg = newRBG(this.randomLength, this.fixed); } @Override public byte[] generate() throws LimitException { final byte[] random = new byte[randomLength]; synchronized (rbg) { rbg.generate(random, null, false); } final byte[] value = new byte[getLength()]; System.arraycopy(fixed, 0, value, 0, fixed.length); System.arraycopy(random, 0, value, fixed.length, random.length); return value; } @Override public int getLength() { return fixed.length + randomLength; } /** * Creates a new DRBG instance. * * @param length Length in bits of values produced by DRBG. * @param domain Domain qualifier. * * @return New DRBG instance. */ private static SP80090DRBG newRBG(final int length, final byte[] domain) { return new HashSP800DRBG( new SHA256Digest(), length, new EntropySource() { @Override public boolean isPredictionResistant() { return false; } @Override public byte[] getEntropy() { return NonceUtil.timestampNonce(length); } @Override public int entropySize() { return length; } }, domain, NonceUtil.timestampNonce(8)); } }