/* * $Id$ * * Copyright (C) 2003-2015 JNode.org * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; If not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ package java.security; /** * VM-specific methods for generating real (or almost real) random * seeds. VM implementors should write a version of this class that * reads random bytes from some system source. * * <p>The default implementation of this class runs eight threads that * increment counters in a tight loop, and XORs each counter to * produce one byte of seed data. This is not very efficient, and is * not guaranteed to be random (the thread scheduler is probably * deterministic, after all). If possible, VM implementors should * reimplement this class so it obtains a random seed from a system * facility, such as a system entropy gathering device or hardware * random number generator. */ final class VMSecureRandom { /** * Generate a random seed. Implementations are free to generate * fewer random bytes than are requested, and leave the remaining * bytes of the destination buffer as zeros. Implementations SHOULD, * however, make a best-effort attempt to satisfy the request. * * @param buffer The destination buffer. * @param offset The offset in the buffer to start putting bytes. * @param length The number of random bytes to generate. */ static int generateSeed(byte[] buffer, int offset, int length) { if (length < 0) throw new IllegalArgumentException("length must be nonnegative"); if (offset < 0 || offset + length > buffer.length) throw new IndexOutOfBoundsException(); Spinner[] spinners = new Spinner[8]; int n = 0x1; for (int i = 0; i < spinners.length; i++) { spinners[i] = new Spinner((byte) n); Thread t = new Thread(spinners[i]); t.start(); n <<= 1; } // Wait until at least one spinner has started. while (!(spinners[0].running || spinners[1].running || spinners[2].running || spinners[3].running || spinners[4].running || spinners[5].running || spinners[6].running || spinners[7].running)) { Thread.yield(); } for (int i = offset; i < length; i++) { buffer[i] = (byte) (spinners[0].value ^ spinners[1].value ^ spinners[2].value ^ spinners[3].value ^ spinners[4].value ^ spinners[5].value ^ spinners[6].value ^ spinners[7].value); Thread.yield(); } for (int i = 0; i < spinners.length; i++) spinners[i].stop(); return length; } static class Spinner implements Runnable { volatile byte value; volatile boolean running; Spinner(final byte initial) { value = initial; } public void run() { running = true; while (running) value++; } private void stop() { running = false; } } }