/*
 * Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code 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 General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package sun.security.provider;

import java.io.IOException;
import java.security.MessageDigest;
import java.security.SecureRandomSpi;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;

This class provides a crytpographically strong pseudo-random number generator based on the SHA-1 hash algorithm.

Note that if a seed is not provided, we attempt to provide sufficient seed bytes to completely randomize the internal state of the generator (20 bytes). However, our seed generation algorithm has not been thoroughly studied or widely deployed.

Also note that when a random object is deserialized, engineNextBytes invoked on the restored random object will yield the exact same (random) bytes as the original object. If this behaviour is not desired, the restored random object should be seeded, using engineSetSeed.

Author:Benjamin Renaud, Josh Bloch, Gadi Guy
/** * <p>This class provides a crytpographically strong pseudo-random number * generator based on the SHA-1 hash algorithm. * * <p>Note that if a seed is not provided, we attempt to provide sufficient * seed bytes to completely randomize the internal state of the generator * (20 bytes). However, our seed generation algorithm has not been thoroughly * studied or widely deployed. * * <p>Also note that when a random object is deserialized, * <a href="#engineNextBytes(byte[])">engineNextBytes</a> invoked on the * restored random object will yield the exact same (random) bytes as the * original object. If this behaviour is not desired, the restored random * object should be seeded, using * <a href="#engineSetSeed(byte[])">engineSetSeed</a>. * * @author Benjamin Renaud * @author Josh Bloch * @author Gadi Guy */
public final class SecureRandom extends SecureRandomSpi implements java.io.Serializable { @java.io.Serial private static final long serialVersionUID = 3581829991155417889L; private static final int DIGEST_SIZE = 20; private transient MessageDigest digest; private byte[] state; private byte[] remainder; private int remCount;
An empty constructor that creates an unseeded SecureRandom object.

Unless the user calls setSeed(), the first call to engineGetBytes() will have the SeedGenerator provide sufficient seed bytes to completely randomize the internal state of the generator (20 bytes). Note that the old threaded seed generation algorithm is provided only as a fallback, and has not been thoroughly studied or widely deployed.

The SeedGenerator relies on a VM-wide entropy pool to generate seed bytes for these objects. The first time the SeedGenerator is called, it may take several seconds of CPU time to initialize, depending on the underlying hardware. Successive calls run quickly because they rely on the same (internal) pseudo-random number generator for their seed bits.

/** * An empty constructor that creates an unseeded SecureRandom object. * <p> * Unless the user calls setSeed(), the first call to engineGetBytes() * will have the SeedGenerator provide sufficient seed bytes to * completely randomize the internal state of the generator (20 bytes). * Note that the old threaded seed generation algorithm is provided * only as a fallback, and has not been thoroughly studied or widely * deployed. * <p> * The SeedGenerator relies on a VM-wide entropy pool to generate * seed bytes for these objects. The first time the SeedGenerator is * called, it may take several seconds of CPU time to initialize, * depending on the underlying hardware. Successive calls run * quickly because they rely on the same (internal) pseudo-random * number generator for their seed bits. */
public SecureRandom() { init(null); }
This constructor is used to instantiate the private seeder object with a given seed from the SeedGenerator.
Params:
  • seed – the seed.
/** * This constructor is used to instantiate the private seeder object * with a given seed from the SeedGenerator. * * @param seed the seed. */
private SecureRandom(byte[] seed) { init(seed); }
This call, used by the constructors, instantiates the SHA digest and sets the seed, if given.
/** * This call, used by the constructors, instantiates the SHA digest * and sets the seed, if given. */
private void init(byte[] seed) { try { /* * Use the local SUN implementation to avoid native * performance overhead. */ digest = MessageDigest.getInstance("SHA", "SUN"); } catch (NoSuchProviderException | NoSuchAlgorithmException e) { // Fallback to any available. try { digest = MessageDigest.getInstance("SHA"); } catch (NoSuchAlgorithmException exc) { throw new InternalError( "internal error: SHA-1 not available.", exc); } } if (seed != null) { engineSetSeed(seed); } }
Returns the given number of seed bytes, computed using the seed generation algorithm that this class uses to seed itself. This call may be used to seed other random number generators. While we attempt to return a "truly random" sequence of bytes, we do not know exactly how random the bytes returned by this call are. (See the empty constructor SecureRandom for a brief description of the underlying algorithm.) The prudent user will err on the side of caution and get extra seed bytes, although it should be noted that seed generation is somewhat costly.
Params:
  • numBytes – the number of seed bytes to generate.
Returns:the seed bytes.
/** * Returns the given number of seed bytes, computed using the seed * generation algorithm that this class uses to seed itself. This * call may be used to seed other random number generators. While * we attempt to return a "truly random" sequence of bytes, we do not * know exactly how random the bytes returned by this call are. (See * the empty constructor <a href = "#SecureRandom">SecureRandom</a> * for a brief description of the underlying algorithm.) * The prudent user will err on the side of caution and get extra * seed bytes, although it should be noted that seed generation is * somewhat costly. * * @param numBytes the number of seed bytes to generate. * * @return the seed bytes. */
@Override public byte[] engineGenerateSeed(int numBytes) { // Neither of the SeedGenerator implementations require // locking, so no sync needed here. byte[] b = new byte[numBytes]; SeedGenerator.generateSeed(b); return b; }
Reseeds this random object. The given seed supplements, rather than replaces, the existing seed. Thus, repeated calls are guaranteed never to reduce randomness.
Params:
  • seed – the seed.
/** * Reseeds this random object. The given seed supplements, rather than * replaces, the existing seed. Thus, repeated calls are guaranteed * never to reduce randomness. * * @param seed the seed. */
@Override public synchronized void engineSetSeed(byte[] seed) { if (state != null) { digest.update(state); for (int i = 0; i < state.length; i++) { state[i] = 0; } } state = digest.digest(seed); remCount = 0; } private static void updateState(byte[] state, byte[] output) { int last = 1; int v; byte t; boolean zf = false; // state(n + 1) = (state(n) + output(n) + 1) % 2^160; for (int i = 0; i < state.length; i++) { // Add two bytes v = (int)state[i] + (int)output[i] + last; // Result is lower 8 bits t = (byte)v; // Store result. Check for state collision. zf = zf | (state[i] != t); state[i] = t; // High 8 bits are carry. Store for next iteration. last = v >> 8; } // Make sure at least one bit changes! if (!zf) { state[0]++; } }
This static object will be seeded by SeedGenerator, and used to seed future instances of SHA1PRNG SecureRandoms. Bloch, Effective Java Second Edition: Item 71
/** * This static object will be seeded by SeedGenerator, and used * to seed future instances of SHA1PRNG SecureRandoms. * * Bloch, Effective Java Second Edition: Item 71 */
private static class SeederHolder { private static final SecureRandom seeder; static { /* * Call to SeedGenerator.generateSeed() to add additional * seed material (likely from the Native implementation). */ seeder = new SecureRandom(SeedGenerator.getSystemEntropy()); byte [] b = new byte[DIGEST_SIZE]; SeedGenerator.generateSeed(b); seeder.engineSetSeed(b); } }
Generates a user-specified number of random bytes.
Params:
  • result – the array to be filled in with random bytes.
/** * Generates a user-specified number of random bytes. * * @param result the array to be filled in with random bytes. */
@Override public synchronized void engineNextBytes(byte[] result) { int index = 0; int todo; byte[] output = remainder; if (state == null) { byte[] seed = new byte[DIGEST_SIZE]; SeederHolder.seeder.engineNextBytes(seed); state = digest.digest(seed); } // Use remainder from last time int r = remCount; if (r > 0) { // How many bytes? todo = (result.length - index) < (DIGEST_SIZE - r) ? (result.length - index) : (DIGEST_SIZE - r); // Copy the bytes, zero the buffer for (int i = 0; i < todo; i++) { result[i] = output[r]; output[r++] = 0; } remCount += todo; index += todo; } // If we need more bytes, make them. while (index < result.length) { // Step the state digest.update(state); output = digest.digest(); updateState(state, output); // How many bytes? todo = (result.length - index) > DIGEST_SIZE ? DIGEST_SIZE : result.length - index; // Copy the bytes, zero the buffer for (int i = 0; i < todo; i++) { result[index++] = output[i]; output[i] = 0; } remCount += todo; } // Store remainder for next time remainder = output; remCount %= DIGEST_SIZE; } /* * readObject is called to restore the state of the random object from * a stream. We have to create a new instance of MessageDigest, because * it is not included in the stream (it is marked "transient"). * * Note that the engineNextBytes() method invoked on the restored random * object will yield the exact same (random) bytes as the original. * If you do not want this behaviour, you should re-seed the restored * random object, using engineSetSeed(). */ @java.io.Serial private void readObject(java.io.ObjectInputStream s) throws IOException, ClassNotFoundException { s.defaultReadObject (); try { /* * Use the local SUN implementation to avoid native * performance overhead. */ digest = MessageDigest.getInstance("SHA", "SUN"); } catch (NoSuchProviderException | NoSuchAlgorithmException e) { // Fallback to any available. try { digest = MessageDigest.getInstance("SHA"); } catch (NoSuchAlgorithmException exc) { throw new InternalError( "internal error: SHA-1 not available.", exc); } } } }