package org.bouncycastle.crypto.prng; /** * Takes bytes generated by an underling RandomGenerator and reverses the order in * each small window (of configurable size). * <p> * Access to internals is synchronized so a single one of these can be shared. * </p> */ public class ReversedWindowGenerator implements RandomGenerator { private final RandomGenerator generator; private byte[] window; private int windowCount; public ReversedWindowGenerator( RandomGenerator generator, int windowSize) { if (generator == null) { throw new IllegalArgumentException("generator cannot be null"); } if (windowSize < 2) { throw new IllegalArgumentException("windowSize must be at least 2"); } this.generator = generator; this.window = new byte[windowSize]; } /** * Add more seed material to the generator. * * @param seed a byte array to be mixed into the generator's state. */ public void addSeedMaterial( byte[] seed) { synchronized (this) { windowCount = 0; generator.addSeedMaterial(seed); } } /** * Add more seed material to the generator. * * @param seed a long value to be mixed into the generator's state. */ public void addSeedMaterial( long seed) { synchronized (this) { windowCount = 0; generator.addSeedMaterial(seed); } } /** * Fill bytes with random values. * * @param bytes byte array to be filled. */ public void nextBytes( byte[] bytes) { doNextBytes(bytes, 0, bytes.length); } /** * Fill part of bytes with random values. * * @param bytes byte array to be filled. * @param start index to start filling at. * @param len length of segment to fill. */ public void nextBytes( byte[] bytes, int start, int len) { doNextBytes(bytes, start, len); } private void doNextBytes( byte[] bytes, int start, int len) { synchronized (this) { int done = 0; while (done < len) { if (windowCount < 1) { generator.nextBytes(window, 0, window.length); windowCount = window.length; } bytes[start + done++] = window[--windowCount]; } } } }