Path: blob/master/src/java.base/share/classes/sun/security/provider/SecureRandom.java
41159 views
/*1* Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.security.provider;2627import java.io.IOException;28import java.security.MessageDigest;29import java.security.SecureRandomSpi;30import java.security.NoSuchAlgorithmException;31import java.security.NoSuchProviderException;3233/**34* <p>This class provides a crytpographically strong pseudo-random number35* generator based on the SHA-1 hash algorithm.36*37* <p>Note that if a seed is not provided, we attempt to provide sufficient38* seed bytes to completely randomize the internal state of the generator39* (20 bytes). However, our seed generation algorithm has not been thoroughly40* studied or widely deployed.41*42* <p>Also note that when a random object is deserialized,43* <a href="#engineNextBytes(byte[])">engineNextBytes</a> invoked on the44* restored random object will yield the exact same (random) bytes as the45* original object. If this behaviour is not desired, the restored random46* object should be seeded, using47* <a href="#engineSetSeed(byte[])">engineSetSeed</a>.48*49* @author Benjamin Renaud50* @author Josh Bloch51* @author Gadi Guy52*/5354public final class SecureRandom extends SecureRandomSpi55implements java.io.Serializable {5657@java.io.Serial58private static final long serialVersionUID = 3581829991155417889L;5960private static final int DIGEST_SIZE = 20;61private transient MessageDigest digest;62private byte[] state;63private byte[] remainder;64private int remCount;6566/**67* An empty constructor that creates an unseeded SecureRandom object.68* <p>69* Unless the user calls setSeed(), the first call to engineGetBytes()70* will have the SeedGenerator provide sufficient seed bytes to71* completely randomize the internal state of the generator (20 bytes).72* Note that the old threaded seed generation algorithm is provided73* only as a fallback, and has not been thoroughly studied or widely74* deployed.75* <p>76* The SeedGenerator relies on a VM-wide entropy pool to generate77* seed bytes for these objects. The first time the SeedGenerator is78* called, it may take several seconds of CPU time to initialize,79* depending on the underlying hardware. Successive calls run80* quickly because they rely on the same (internal) pseudo-random81* number generator for their seed bits.82*/83public SecureRandom() {84init(null);85}8687/**88* This constructor is used to instantiate the private seeder object89* with a given seed from the SeedGenerator.90*91* @param seed the seed.92*/93private SecureRandom(byte[] seed) {94init(seed);95}9697/**98* This call, used by the constructors, instantiates the SHA digest99* and sets the seed, if given.100*/101private void init(byte[] seed) {102try {103/*104* Use the local SUN implementation to avoid native105* performance overhead.106*/107digest = MessageDigest.getInstance("SHA", "SUN");108} catch (NoSuchProviderException | NoSuchAlgorithmException e) {109// Fallback to any available.110try {111digest = MessageDigest.getInstance("SHA");112} catch (NoSuchAlgorithmException exc) {113throw new InternalError(114"internal error: SHA-1 not available.", exc);115}116}117118if (seed != null) {119engineSetSeed(seed);120}121}122123/**124* Returns the given number of seed bytes, computed using the seed125* generation algorithm that this class uses to seed itself. This126* call may be used to seed other random number generators. While127* we attempt to return a "truly random" sequence of bytes, we do not128* know exactly how random the bytes returned by this call are. (See129* the empty constructor <a href = "#SecureRandom">SecureRandom</a>130* for a brief description of the underlying algorithm.)131* The prudent user will err on the side of caution and get extra132* seed bytes, although it should be noted that seed generation is133* somewhat costly.134*135* @param numBytes the number of seed bytes to generate.136*137* @return the seed bytes.138*/139@Override140public byte[] engineGenerateSeed(int numBytes) {141// Neither of the SeedGenerator implementations require142// locking, so no sync needed here.143byte[] b = new byte[numBytes];144SeedGenerator.generateSeed(b);145return b;146}147148/**149* Reseeds this random object. The given seed supplements, rather than150* replaces, the existing seed. Thus, repeated calls are guaranteed151* never to reduce randomness.152*153* @param seed the seed.154*/155@Override156public synchronized void engineSetSeed(byte[] seed) {157if (state != null) {158digest.update(state);159for (int i = 0; i < state.length; i++) {160state[i] = 0;161}162}163state = digest.digest(seed);164remCount = 0;165}166167private static void updateState(byte[] state, byte[] output) {168int last = 1;169int v;170byte t;171boolean zf = false;172173// state(n + 1) = (state(n) + output(n) + 1) % 2^160;174for (int i = 0; i < state.length; i++) {175// Add two bytes176v = (int)state[i] + (int)output[i] + last;177// Result is lower 8 bits178t = (byte)v;179// Store result. Check for state collision.180zf = zf | (state[i] != t);181state[i] = t;182// High 8 bits are carry. Store for next iteration.183last = v >> 8;184}185186// Make sure at least one bit changes!187if (!zf) {188state[0]++;189}190}191192/**193* This static object will be seeded by SeedGenerator, and used194* to seed future instances of SHA1PRNG SecureRandoms.195*196* Bloch, Effective Java Second Edition: Item 71197*/198private static class SeederHolder {199200private static final SecureRandom seeder;201202static {203/*204* Call to SeedGenerator.generateSeed() to add additional205* seed material (likely from the Native implementation).206*/207seeder = new SecureRandom(SeedGenerator.getSystemEntropy());208byte [] b = new byte[DIGEST_SIZE];209SeedGenerator.generateSeed(b);210seeder.engineSetSeed(b);211}212}213214/**215* Generates a user-specified number of random bytes.216*217* @param result the array to be filled in with random bytes.218*/219@Override220public synchronized void engineNextBytes(byte[] result) {221int index = 0;222int todo;223byte[] output = remainder;224225if (state == null) {226byte[] seed = new byte[DIGEST_SIZE];227SeederHolder.seeder.engineNextBytes(seed);228state = digest.digest(seed);229}230231// Use remainder from last time232int r = remCount;233if (r > 0) {234// How many bytes?235todo = (result.length - index) < (DIGEST_SIZE - r) ?236(result.length - index) : (DIGEST_SIZE - r);237// Copy the bytes, zero the buffer238for (int i = 0; i < todo; i++) {239result[i] = output[r];240output[r++] = 0;241}242remCount += todo;243index += todo;244}245246// If we need more bytes, make them.247while (index < result.length) {248// Step the state249digest.update(state);250output = digest.digest();251updateState(state, output);252253// How many bytes?254todo = (result.length - index) > DIGEST_SIZE ?255DIGEST_SIZE : result.length - index;256// Copy the bytes, zero the buffer257for (int i = 0; i < todo; i++) {258result[index++] = output[i];259output[i] = 0;260}261remCount += todo;262}263264// Store remainder for next time265remainder = output;266remCount %= DIGEST_SIZE;267}268269/*270* readObject is called to restore the state of the random object from271* a stream. We have to create a new instance of MessageDigest, because272* it is not included in the stream (it is marked "transient").273*274* Note that the engineNextBytes() method invoked on the restored random275* object will yield the exact same (random) bytes as the original.276* If you do not want this behaviour, you should re-seed the restored277* random object, using engineSetSeed().278*/279@java.io.Serial280private void readObject(java.io.ObjectInputStream s)281throws IOException, ClassNotFoundException {282283s.defaultReadObject ();284285try {286/*287* Use the local SUN implementation to avoid native288* performance overhead.289*/290digest = MessageDigest.getInstance("SHA", "SUN");291} catch (NoSuchProviderException | NoSuchAlgorithmException e) {292// Fallback to any available.293try {294digest = MessageDigest.getInstance("SHA");295} catch (NoSuchAlgorithmException exc) {296throw new InternalError(297"internal error: SHA-1 not available.", exc);298}299}300}301}302303304