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
AesCounterRandom
may 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[]
counter
The counter.protected byte[]
currentBlock
An array holding generated, encrypted bytes.protected int
index
The offset incurrentBlock
to 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 void
advance(long delta)
Advances the generator forwarddelta
steps, but does so in logarithmic time.protected abstract void
createCipher()
Creates the cipher thatdoCipher(byte[], byte[])
will invoke.protected abstract MessageDigest
createHash()
Returns the hash that will be used to combine seeds.protected abstract void
doCipher(byte[] input, byte[] output)
Executes the cipher.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.protected int
getBytesAtOnce()
Returns the number of random bytes that can be precalculated at once, which is normallygetCounterSizeBytes() * getBlocksAtOnce()
.int
getCounterSizeBytes()
Returns the length of the counter, which should equal the cipher's block size.protected abstract int
getKeyLength(int inputLength)
Returns the length of the key that should be extracted from a seed of a given length.abstract int
getMaxKeyLengthBytes()
Returns the maximum length in bytes of a key for this PRNG's cipher.int
getMaxTotalSeedLengthBytes()
Returns the maximum seed length, including both the cipher key and a new counter value.protected abstract int
getMinSeedLength()
Returns the minimum seed length.int
getNewSeedLength()
Returns the preferred length of a new byte-array seed.protected void
initTransientFields()
Called in constructor and readObject to initialize transient fields.protected int
next(int bits)
Generates the next pseudorandom number.protected void
nextBlock()
Generates BLOCKS_AT_ONCE 128-bit (16-byte) blocks.protected abstract void
setKey(byte[] key)
Sets the key on the cipher.void
setSeed(byte[] seed)
Reseed this PRNG.void
setSeed(long seed)
Combines the given seed with the existing seed using the hash algorithm.protected void
setSeedInternal(byte[] seed)
Sets the seed, and should be overridden to set other state that derives from the seed.protected boolean
supportsMultipleSeedLengths()
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 incurrentBlock
to 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:ByteArrayReseedableRandom
Returns 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:
getNewSeedLength
in interfaceByteArrayReseedableRandom
- Specified by:
getNewSeedLength
in 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:SeekableRandom
Advances the generator forwarddelta
steps, but does so in logarithmic time.- Specified by:
advance
in 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:BaseRandom
Called in constructor and readObject to initialize transient fields.- Overrides:
initTransientFields
in classBaseRandom
-
supportsMultipleSeedLengths
protected boolean supportsMultipleSeedLengths()
Returns true, because the seed can either be a counter IV plus a key, or just a key.- Overrides:
supportsMultipleSeedLengths
in 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 GeneralSecurityException
Executes 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:BaseRandom
Generates 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:
next
in 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:
setSeed
in interfaceByteArrayReseedableRandom
- Overrides:
setSeed
in 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:
setSeed
in interfaceJava8CompatRandom
- Overrides:
setSeed
in classBaseRandom
-
setSeedInternal
protected void setSeedInternal(byte[] seed)
Description copied from class:BaseRandom
Sets 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.lock
is always held.- Overrides:
setSeedInternal
in 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 InvalidKeyException
Sets the key on the cipher. Always called withlock
held.- Parameters:
key
- the new key- Throws:
InvalidKeyException
- if the cipher rejects the key
-
-