Package se.grunka.fortuna

Source Code of se.grunka.fortuna.Fortuna

package se.grunka.fortuna;

import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Random;
import java.util.concurrent.locks.ReentrantLock;

import se.grunka.fortuna.accumulator.Accumulator;
import se.grunka.fortuna.entropy.FreeMemoryEntropySource;
import se.grunka.fortuna.entropy.GarbageCollectorEntropySource;
import se.grunka.fortuna.entropy.LoadAverageEntropySource;
import se.grunka.fortuna.entropy.SchedulingEntropySource;
import se.grunka.fortuna.entropy.ThreadTimeEntropySource;
import se.grunka.fortuna.entropy.URandomEntropySource;
import se.grunka.fortuna.entropy.UptimeEntropySource;

public class Fortuna extends Random {
    private static final int MIN_POOL_SIZE = 64;
    private static final int[] POWERS_OF_TWO = initializePowersOfTwo();

    private static int[] initializePowersOfTwo() {
        int[] result = new int[32];
        for (int power = 0; power < result.length; power++) {
            result[power] = (int) Math.pow(2, power);
        }
        return result;
    }

    private long lastReseedTime = 0;
    private long reseedCount = 0;
    private final Generator generator;
    private final Pool[] pools;
    private final ReentrantLock lock = new ReentrantLock();

    public static Fortuna createInstance() {
        Pool[] pools = new Pool[32];
        for (int pool = 0; pool < pools.length; pool++) {
            pools[pool] = new Pool();
        }
        Accumulator accumulator = new Accumulator(pools);
        accumulator.addSource(new SchedulingEntropySource());
        accumulator.addSource(new GarbageCollectorEntropySource());
        accumulator.addSource(new LoadAverageEntropySource());
        accumulator.addSource(new FreeMemoryEntropySource());
        accumulator.addSource(new ThreadTimeEntropySource());
        accumulator.addSource(new UptimeEntropySource());
        if (Files.exists(Paths.get("/dev/urandom"))) {
            accumulator.addSource(new URandomEntropySource());
        }
        while (pools[0].size() < MIN_POOL_SIZE) {
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                throw new Error("Interrupted while waiting for initialization", e);
            }
        }
        return new Fortuna(new Generator(), pools);
    }

    private Fortuna(Generator generator, Pool[] pools) {
        this.generator = generator;
        this.pools = pools;
    }

    private byte[] randomData(int bytes) {
        lock.lock();
        try {
            long now = System.currentTimeMillis();
            if (pools[0].size() >= MIN_POOL_SIZE && now - lastReseedTime > 100) {
                lastReseedTime = now;
                reseedCount++;
                byte[] seed = new byte[pools.length * 32]; // Maximum potential length
                int seedLength = 0;
                for (int pool = 0; pool < pools.length; pool++) {
                    if (reseedCount % POWERS_OF_TWO[pool] == 0) {
                        System.arraycopy(pools[pool].getAndClear(), 0, seed, seedLength, 32);
                        seedLength += 32;
                    }
                }
                generator.reseed(Arrays.copyOf(seed, seedLength));
            }
            if (reseedCount == 0) {
                throw new IllegalStateException("Generator not reseeded yet");
            } else {
                return generator.pseudoRandomData(bytes);
            }
        } finally {
            lock.unlock();
        }
    }

    @Override
    protected int next(int bits) {
        byte[] bytes = randomData(Util.ceil(bits, 8));
        int result = 0;
        for (int i = 0; i < bytes.length; i++) {
            int shift = 8 * i;
            result |= (bytes[i] << shift) & (0xff << shift);
        }
        return result >>> (bytes.length * 8 - bits);
    }

    @Override
    public synchronized void setSeed(long seed) {
        // Does not do anything
    }

}
TOP

Related Classes of se.grunka.fortuna.Fortuna

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.