Class CipherCounterRandom
- java.lang.Object
-
- java.util.Random
-
- io.github.pr0methean.betterrandom.prng.BaseRandom
-
- io.github.pr0methean.betterrandom.prng.CipherCounterRandom
-
- All Implemented Interfaces:
ByteArrayReseedableRandom,EntropyCountingRandom,Java8CompatRandom,RepeatableRandom,SeekableRandom,Dumpable,Serializable
- Direct Known Subclasses:
AesCounterRandom
public abstract class CipherCounterRandom extends BaseRandom implements SeekableRandom
Non-linear random number generator based on a cipher that encrypts an incrementing counter. fed. Subclasses must specify the key length for a given total seed length; When reseeded with a seed of less than the maximum key length, the new seed is combined with the existing key using a hash algorithm specified by the subclass.
All interaction with the cipher is through abstract methods, so that both JCE and other cipher APIs such as Bouncy Castle can be used. If using a JCE cipher, extending
AesCounterRandommay be simpler than extending this class directly.When used with a fixed seed, the maintainer believes this implementation conforms to NIST SP 800-90A Rev. 1 section 10.2.1. However, the reseeding process differs from section 10.2.1.4.
- Author:
- Daniel Dyer, Chris Hennick
- See Also:
- Serialized Form
-
-
Field Summary
Fields Modifier and Type Field Description protected byte[]counterThe counter.protected byte[]currentBlockAn array holding generated, encrypted bytes.protected intindexThe offset incurrentBlockto draw output from.-
Fields inherited from class io.github.pr0methean.betterrandom.prng.BaseRandom
ENTROPY_OF_DOUBLE, ENTROPY_OF_FLOAT, entropyBits, lock, randomSeeder, seed, superConstructorFinished
-
-
Constructor Summary
Constructors Constructor Description CipherCounterRandom(byte[] seed)Creates an instance.
-
Method Summary
All Methods Instance Methods Abstract Methods Concrete Methods Modifier and Type Method Description voidadvance(long delta)Advances the generator forwarddeltasteps, but does so in logarithmic time.protected abstract voidcreateCipher()Creates the cipher thatdoCipher(byte[], byte[])will invoke.protected abstract MessageDigestcreateHash()Returns the hash that will be used to combine seeds.protected abstract voiddoCipher(byte[] input, byte[] output)Executes the cipher.abstract intgetBlocksAtOnce()Returns how many consecutive values of the counter are encrypted at once, in order to reduce the number of calls to Cipher methods.protected intgetBytesAtOnce()Returns the number of random bytes that can be precalculated at once, which is normallygetCounterSizeBytes() * getBlocksAtOnce().intgetCounterSizeBytes()Returns the length of the counter, which should equal the cipher's block size.protected abstract intgetKeyLength(int inputLength)Returns the length of the key that should be extracted from a seed of a given length.abstract intgetMaxKeyLengthBytes()Returns the maximum length in bytes of a key for this PRNG's cipher.intgetMaxTotalSeedLengthBytes()Returns the maximum seed length, including both the cipher key and a new counter value.protected abstract intgetMinSeedLength()Returns the minimum seed length.intgetNewSeedLength()Returns the preferred length of a new byte-array seed.protected voidinitTransientFields()Called in constructor and readObject to initialize transient fields.protected intnext(int bits)Generates the next pseudorandom number.protected voidnextBlock()Generates BLOCKS_AT_ONCE 128-bit (16-byte) blocks.protected abstract voidsetKey(byte[] key)Sets the key on the cipher.voidsetSeed(byte[] seed)Reseed this PRNG.voidsetSeed(long seed)Combines the given seed with the existing seed using the hash algorithm.protected voidsetSeedInternal(byte[] seed)Sets the seed, and should be overridden to set other state that derives from the seed.protected booleansupportsMultipleSeedLengths()Returns true, because the seed can either be a counter IV plus a key, or just a key.-
Methods inherited from class io.github.pr0methean.betterrandom.prng.BaseRandom
addSubclassFields, checkLength, creditEntropyForNewSeed, debitEntropy, doubles, doubles, doubles, doubles, dump, entropyOfInt, entropyOfLong, fallbackSetSeedIfInitialized, gaussians, gaussians, getEntropyBits, getRandomSeeder, getSeed, internalNextGaussian, ints, ints, ints, ints, lockForNextGaussian, longs, longs, longs, longs, needsReseedingEarly, nextBoolean, nextBytes, nextDouble, nextDouble, nextDouble, nextDoubleNoEntropyDebit, nextElement, nextElement, nextEnum, nextFloat, nextGaussian, nextInt, nextInt, nextInt, nextLong, nextLong, nextLong, nextLongNoEntropyDebit, preferSeedWithLong, setRandomSeeder, unlockForNextGaussian, usesParallelStreams, withProbability, withProbabilityInternal
-
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
-
Methods inherited from interface io.github.pr0methean.betterrandom.RepeatableRandom
getSeed
-
-
-
-
Field Detail
-
currentBlock
protected final byte[] currentBlock
An array holding generated, encrypted bytes.
-
counter
protected volatile byte[] counter
The counter. Successive values are encrypted to generate pseudorandom numbers.
-
index
protected volatile int index
The offset incurrentBlockto draw output from.
-
-
Method Detail
-
getCounterSizeBytes
public int getCounterSizeBytes()
Returns the length of the counter, which should equal the cipher's block size.- Returns:
- the length of the counter
-
getNewSeedLength
public int getNewSeedLength()
Description copied from interface:ByteArrayReseedableRandomReturns the preferred length of a new byte-array seed. "Preferred" is implementation-defined when multiple seed lengths are supported, but should probably usually mean the longest one, since the longer the seed, the more random the output.- Specified by:
getNewSeedLengthin interfaceByteArrayReseedableRandom- Specified by:
getNewSeedLengthin classBaseRandom- Returns:
- The desired length of a new byte-array seed.
-
getMaxKeyLengthBytes
public abstract int getMaxKeyLengthBytes()
Returns the maximum length in bytes of a key for this PRNG's cipher. If the seed is longer than this, part of it becomes the counter's initial value. Otherwise, the full seed becomes the key and the counter is initially zero.- Returns:
- the maximum length in bytes of a key.
-
advance
public void advance(long delta)
Description copied from interface:SeekableRandomAdvances the generator forwarddeltasteps, but does so in logarithmic time.- Specified by:
advancein interfaceSeekableRandom- Parameters:
delta- the number of steps to advance; can be negative
-
getKeyLength
protected abstract int getKeyLength(int inputLength)
Returns the length of the key that should be extracted from a seed of a given length. During the initial seeding, whatever part of the seed does not become the key, becomes the counter's initial value.- Parameters:
inputLength- the length of the whole seed- Returns:
- the length of the key
-
getBlocksAtOnce
public abstract int getBlocksAtOnce()
Returns how many consecutive values of the counter are encrypted at once, in order to reduce the number of calls to Cipher methods. Each counter value encrypts to yield a "block" of pseudorandom data. Changing this value won't change the output if the cipher is running in block mode, but it may impact performance.- Returns:
- the number of blocks (counter values) to encrypt at once
-
getBytesAtOnce
protected int getBytesAtOnce()
Returns the number of random bytes that can be precalculated at once, which is normallygetCounterSizeBytes() * getBlocksAtOnce().- Returns:
- the number of random bytes that can be precalculated at once
-
getMaxTotalSeedLengthBytes
public int getMaxTotalSeedLengthBytes()
Returns the maximum seed length, including both the cipher key and a new counter value.- Returns:
- the maximum seed length
-
initTransientFields
protected void initTransientFields()
Description copied from class:BaseRandomCalled in constructor and readObject to initialize transient fields.- Overrides:
initTransientFieldsin classBaseRandom
-
supportsMultipleSeedLengths
protected boolean supportsMultipleSeedLengths()
Returns true, because the seed can either be a counter IV plus a key, or just a key.- Overrides:
supportsMultipleSeedLengthsin classBaseRandom- Returns:
- true
-
createHash
protected abstract MessageDigest createHash()
Returns the hash that will be used to combine seeds. Only called on construction and deserialization.- Returns:
- a resettable
MessageDigest
-
createCipher
protected abstract void createCipher()
Creates the cipher thatdoCipher(byte[], byte[])will invoke.setKey(byte[])will be called before the cipher is used.
-
nextBlock
protected void nextBlock()
Generates BLOCKS_AT_ONCE 128-bit (16-byte) blocks. Copies them to currentBlock.- Throws:
IllegalStateException- If there is a problem with the cipher that generates the random data.
-
doCipher
protected abstract void doCipher(byte[] input, byte[] output) throws GeneralSecurityExceptionExecutes the cipher.- Parameters:
input- an array of input whose length is equal togetBytesAtOnce()output- an array of output whose length is equal togetBytesAtOnce()- Throws:
GeneralSecurityException- if an internal error occurs in the cipher
-
next
protected final int next(int bits)
Description copied from class:BaseRandomGenerates the next pseudorandom number. Called by all other random-number-generating methods. Should not debit the entropy count, since that's done by the calling methods according to the amount they actually output (see for exampleBaseRandom.withProbability(double), which uses 53 random bits but outputs only one, and thus debits only 1 bit of entropy).- Specified by:
nextin classBaseRandom
-
setSeed
public void setSeed(byte[] seed)
Reseed this PRNG.Most subclasses should override
If the seed is not of the maximum length, it is combined with the existing seed using the hash algorithm.BaseRandom.setSeedInternal(byte[])instead of this method, so that they will deserialize properly.- Specified by:
setSeedin interfaceByteArrayReseedableRandom- Overrides:
setSeedin classBaseRandom- Parameters:
seed- The PRNG's new seed.
-
setSeed
public void setSeed(long seed)
Combines the given seed with the existing seed using the hash algorithm.- Specified by:
setSeedin interfaceJava8CompatRandom- Overrides:
setSeedin classBaseRandom
-
setSeedInternal
protected void setSeedInternal(byte[] seed)
Description copied from class:BaseRandomSets the seed, and should be overridden to set other state that derives from the seed. Called byBaseRandom.setSeed(byte[]), constructors, andreadObject(ObjectInputStream). When called after initialization, theBaseRandom.lockis always held.- Overrides:
setSeedInternalin classBaseRandom- Parameters:
seed- The new seed.
-
getMinSeedLength
protected abstract int getMinSeedLength()
Returns the minimum seed length.- Returns:
- the minimum seed length
-
setKey
protected abstract void setKey(byte[] key) throws InvalidKeyExceptionSets the key on the cipher. Always called withlockheld.- Parameters:
key- the new key- Throws:
InvalidKeyException- if the cipher rejects the key
-
-