diff options
Diffstat (limited to 'libraries/spongycastle/core/src/main/java/org/spongycastle/crypto/prng/DigestRandomGenerator.java')
-rw-r--r-- | libraries/spongycastle/core/src/main/java/org/spongycastle/crypto/prng/DigestRandomGenerator.java | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/libraries/spongycastle/core/src/main/java/org/spongycastle/crypto/prng/DigestRandomGenerator.java b/libraries/spongycastle/core/src/main/java/org/spongycastle/crypto/prng/DigestRandomGenerator.java new file mode 100644 index 000000000..5505338ad --- /dev/null +++ b/libraries/spongycastle/core/src/main/java/org/spongycastle/crypto/prng/DigestRandomGenerator.java @@ -0,0 +1,123 @@ +package org.spongycastle.crypto.prng; + +import org.spongycastle.crypto.Digest; + +/** + * Random generation based on the digest with counter. Calling addSeedMaterial will + * always increase the entropy of the hash. + * <p> + * Internal access to the digest is synchronized so a single one of these can be shared. + * </p> + */ +public class DigestRandomGenerator + implements RandomGenerator +{ + private static long CYCLE_COUNT = 10; + + private long stateCounter; + private long seedCounter; + private Digest digest; + private byte[] state; + private byte[] seed; + + // public constructors + public DigestRandomGenerator( + Digest digest) + { + this.digest = digest; + + this.seed = new byte[digest.getDigestSize()]; + this.seedCounter = 1; + + this.state = new byte[digest.getDigestSize()]; + this.stateCounter = 1; + } + + public void addSeedMaterial(byte[] inSeed) + { + synchronized (this) + { + digestUpdate(inSeed); + digestUpdate(seed); + digestDoFinal(seed); + } + } + + public void addSeedMaterial(long rSeed) + { + synchronized (this) + { + digestAddCounter(rSeed); + digestUpdate(seed); + + digestDoFinal(seed); + } + } + + public void nextBytes(byte[] bytes) + { + nextBytes(bytes, 0, bytes.length); + } + + public void nextBytes(byte[] bytes, int start, int len) + { + synchronized (this) + { + int stateOff = 0; + + generateState(); + + int end = start + len; + for (int i = start; i != end; i++) + { + if (stateOff == state.length) + { + generateState(); + stateOff = 0; + } + bytes[i] = state[stateOff++]; + } + } + } + + private void cycleSeed() + { + digestUpdate(seed); + digestAddCounter(seedCounter++); + + digestDoFinal(seed); + } + + private void generateState() + { + digestAddCounter(stateCounter++); + digestUpdate(state); + digestUpdate(seed); + + digestDoFinal(state); + + if ((stateCounter % CYCLE_COUNT) == 0) + { + cycleSeed(); + } + } + + private void digestAddCounter(long seed) + { + for (int i = 0; i != 8; i++) + { + digest.update((byte)seed); + seed >>>= 8; + } + } + + private void digestUpdate(byte[] inSeed) + { + digest.update(inSeed, 0, inSeed.length); + } + + private void digestDoFinal(byte[] result) + { + digest.doFinal(result, 0); + } +} |