    001/*
    002 * Licensed to the Apache Software Foundation (ASF) under one or more
    003 * contributor license agreements.  See the NOTICE file distributed with
    004 * this work for additional information regarding copyright ownership.
    005 * The ASF licenses this file to You under the Apache License, Version 2.0
    006 * (the "License"); you may not use this file except in compliance with
    007 * the License.  You may obtain a copy of the License at
    008 *
    009 *     https://www.apache.org/licenses/LICENSE-2.0
    010 *
    011 * Unless required by applicable law or agreed to in writing, software
    012 * distributed under the License is distributed on an "AS IS" BASIS,
    013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014 * See the License for the specific language governing permissions and
    015 * limitations under the License.
    016 */
    017package org.apache.commons.lang3;
    018
    019import java.security.NoSuchAlgorithmException;
    020import java.security.SecureRandom;
    021import java.security.Security;
    022import java.util.Random;
    023import java.util.concurrent.ThreadLocalRandom;
    024import java.util.function.Supplier;
    025
    026import org.apache.commons.lang3.exception.UncheckedException;
    027
    028/**
    029 * Supplements the standard {@link Random} class.
    030 * <p>
    031 * Use {@link #secure()} to get the singleton instance based on {@link SecureRandom#SecureRandom()} which uses a secure random number generator implementing the
    032 * default random number algorithm.
    033 * </p>
    034 * <p>
    035 * Use {@link #secureStrong()} to get the singleton instance based on {@link SecureRandom#getInstanceStrong()} which uses an instance that was selected by using
    036 * the algorithms/providers specified in the {@code securerandom.strongAlgorithms} {@link Security} property.
    037 * </p>
    038 * <p>
    039 * Use {@link #insecure()} to get the singleton instance based on {@link ThreadLocalRandom#current()} <strong>which is not cryptographically secure</strong>. In addition,
    040 * instances do not use a cryptographically random seed unless the {@linkplain System#getProperty system property} {@code java.util.secureRandomSeed} is set to
    041 * {@code true}.
    042 * </p>
    043 * <p>
    044 * Starting in version 3.17.0, the method {@link #secure()} uses {@link SecureRandom#SecureRandom()} instead of {@link SecureRandom#getInstanceStrong()}, and
    045 * adds {@link #secureStrong()}.
    046 * </p>
    047 * <p>
    048 * Starting in version 3.16.0, this class uses {@link #secure()} for static methods and adds {@link #insecure()}.
    049 * </p>
    050 * <p>
    051 * Starting in version 3.15.0, this class uses {@link SecureRandom#getInstanceStrong()} for static methods.
    052 * </p>
    053 * <p>
    054 * Before version 3.15.0, this class used {@link ThreadLocalRandom#current()} for static methods, which is not cryptographically secure.
    055 * </p>
    056 * <p>
    057 * Please note that the Apache Commons project provides a component dedicated to pseudo-random number generation, namely
    058 * <a href="https://commons.apache.org/proper/commons-rng/">Commons RNG</a>, that may be a better choice for applications with more stringent requirements
    059 * (performance and/or correctness).
    060 * </p>
    061 *
    062 * @see #secure()
    063 * @see #secureStrong()
    064 * @see #insecure()
    065 * @see SecureRandom#SecureRandom()
    066 * @see SecureRandom#getInstanceStrong()
    067 * @see ThreadLocalRandom#current()
    068 * @see RandomStringUtils
    069 * @since 3.3
    070 */
    071public class RandomUtils {
    072
    073    private static RandomUtils INSECURE = new RandomUtils(ThreadLocalRandom::current);
    074
    075    private static RandomUtils SECURE = new RandomUtils(SecureRandom::new);
    076
    077    private static final Supplier<Random> SECURE_STRONG_SUPPLIER = () -> RandomUtils.SECURE_RANDOM_STRONG.get();
    078
    079    private static RandomUtils SECURE_STRONG = new RandomUtils(SECURE_STRONG_SUPPLIER);
    080
    081    private static final ThreadLocal<SecureRandom> SECURE_RANDOM_STRONG = ThreadLocal.withInitial(() -> {
    082        try {
    083            return SecureRandom.getInstanceStrong();
    084        } catch (final NoSuchAlgorithmException e) {
    085            throw new UncheckedException(e);
    086        }
    087    });
    088
    089    /**
    090     * Gets the singleton instance based on {@link ThreadLocalRandom#current()}; <b>which is not cryptographically
    091     * secure</b>; use {@link #secure()} to use an algorithms/providers specified in the
    092     * {@code securerandom.strongAlgorithms} {@link Security} property.
    093     * <p>
    094     * The method {@link ThreadLocalRandom#current()} is called on-demand.
    095     * </p>
    096     *
    097     * @return the singleton instance based on {@link ThreadLocalRandom#current()}.
    098     * @see ThreadLocalRandom#current()
    099     * @see #secure()
    100     * @since 3.17.0
    101     */
    102    public static RandomUtils insecure() {
    103        return INSECURE;
    104    }
    105
    106    /**
    107     * Generates a random boolean value.
    108     *
    109     * @return the random boolean.
    110     * @since 3.5
    111     * @deprecated Use {@link #secure()}, {@link #secureStrong()}, or {@link #insecure()}.
    112     */
    113    @Deprecated
    114    public static boolean nextBoolean() {
    115        return secure().randomBoolean();
    116    }
    117
    118    /**
    119     * Generates an array of random bytes.
    120     *
    121     * @param count the size of the returned array.
    122     * @return the random byte array.
    123     * @throws IllegalArgumentException if {@code count} is negative.
    124     * @deprecated Use {@link #secure()}, {@link #secureStrong()}, or {@link #insecure()}.
    125     */
    126    @Deprecated
    127    public static byte[] nextBytes(final int count) {
    128        return secure().randomBytes(count);
    129    }
    130
    131    /**
    132     * Generates a random double between 0 (inclusive) and Double.MAX_VALUE (exclusive).
    133     *
    134     * @return the random double.
    135     * @see #nextDouble(double, double)
    136     * @since 3.5
    137     * @deprecated Use {@link #secure()}, {@link #secureStrong()}, or {@link #insecure()}.
    138     */
    139    @Deprecated
    140    public static double nextDouble() {
    141        return secure().randomDouble();
    142    }
    143
    144    /**
    145     * Generates a random double within the specified range.
    146     *
    147     * @param startInclusive the smallest value that can be returned, must be non-negative.
    148     * @param endExclusive   the upper bound (not included).
    149     * @throws IllegalArgumentException if {@code startInclusive > endExclusive} or if {@code startInclusive} is negative.
    150     * @return the random double.
    151     * @deprecated Use {@link #secure()}, {@link #secureStrong()}, or {@link #insecure()}.
    152     */
    153    @Deprecated
    154    public static double nextDouble(final double startInclusive, final double endExclusive) {
    155        return secure().randomDouble(startInclusive, endExclusive);
    156    }
    157
    158    /**
    159     * Generates a random float between 0 (inclusive) and Float.MAX_VALUE (exclusive).
    160     *
    161     * @return the random float.
    162     * @see #nextFloat(float, float)
    163     * @since 3.5
    164     * @deprecated Use {@link #secure()}, {@link #secureStrong()}, or {@link #insecure()}.
    165     */
    166    @Deprecated
    167    public static float nextFloat() {
    168        return secure().randomFloat();
    169    }
    170
    171    /**
    172     * Generates a random float within the specified range.
    173     *
    174     * @param startInclusive the smallest value that can be returned, must be non-negative.
    175     * @param endExclusive   the upper bound (not included).
    176     * @throws IllegalArgumentException if {@code startInclusive > endExclusive} or if {@code startInclusive} is negative.
    177     * @return the random float
    178     * @deprecated Use {@link #secure()}, {@link #secureStrong()}, or {@link #insecure()}.
    179     */
    180    @Deprecated
    181    public static float nextFloat(final float startInclusive, final float endExclusive) {
    182        return secure().randomFloat(startInclusive, endExclusive);
    183    }
    184
    185    /**
    186     * Generates a random int between 0 (inclusive) and Integer.MAX_VALUE (exclusive).
    187     *
    188     * @return the random integer.
    189     * @see #nextInt(int, int)
    190     * @since 3.5
    191     * @deprecated Use {@link #secure()}, {@link #secureStrong()}, or {@link #insecure()}.
    192     */
    193    @Deprecated
    194    public static int nextInt() {
    195        return secure().randomInt();
    196    }
    197
    198    /**
    199     * Generates a random integer within the specified range.
    200     *
    201     * @param startInclusive the smallest value that can be returned, must be non-negative.
    202     * @param endExclusive   the upper bound (not included).
    203     * @throws IllegalArgumentException if {@code startInclusive > endExclusive} or if {@code startInclusive} is negative.
    204     * @return the random integer.
    205     * @deprecated Use {@link #secure()}, {@link #secureStrong()}, or {@link #insecure()}.
    206     */
    207    @Deprecated
    208    public static int nextInt(final int startInclusive, final int endExclusive) {
    209        return secure().randomInt(startInclusive, endExclusive);
    210    }
    211
    212    /**
    213     * Generates a random long between 0 (inclusive) and Long.MAX_VALUE (exclusive).
    214     *
    215     * @return the random long.
    216     * @see #nextLong(long, long)
    217     * @since 3.5
    218     * @deprecated Use {@link #secure()}, {@link #secureStrong()}, or {@link #insecure()}.
    219     */
    220    @Deprecated
    221    public static long nextLong() {
    222        return secure().randomLong();
    223    }
    224
    225    /**
    226     * Generates a random long within the specified range.
    227     *
    228     * @param startInclusive the smallest value that can be returned, must be non-negative.
    229     * @param endExclusive   the upper bound (not included).
    230     * @throws IllegalArgumentException if {@code startInclusive > endExclusive} or if {@code startInclusive} is negative.
    231     * @return the random long.
    232     * @deprecated Use {@link #secure()}, {@link #secureStrong()}, or {@link #insecure()}.
    233     */
    234    @Deprecated
    235    public static long nextLong(final long startInclusive, final long endExclusive) {
    236        return secure().randomLong(startInclusive, endExclusive);
    237    }
    238
    239    /**
    240     * Gets the singleton instance based on {@link SecureRandom#SecureRandom()} which uses an algorithms/providers
    241     * specified in the {@code securerandom.strongAlgorithms} {@link Security} property.
    242     * <p>
    243     * The method {@link SecureRandom#SecureRandom()} is called on-demand.
    244     * </p>
    245     *
    246     * @return the singleton instance based on {@link SecureRandom#SecureRandom()}.
    247     * @see SecureRandom#SecureRandom()
    248     * @since 3.16.0
    249     */
    250    public static RandomUtils secure() {
    251        return SECURE;
    252    }
    253
    254    static SecureRandom secureRandom() {
    255        return SECURE_RANDOM_STRONG.get();
    256    }
    257
    258    /**
    259     * Gets the singleton instance based on {@link SecureRandom#getInstanceStrong()} which uses an algorithms/providers
    260     * specified in the {@code securerandom.strongAlgorithms} {@link Security} property.
    261     * <p>
    262     * The method {@link SecureRandom#getInstanceStrong()} is called on-demand.
    263     * </p>
    264     *
    265     * @return the singleton instance based on {@link SecureRandom#getInstanceStrong()}.
    266     * @see SecureRandom#getInstanceStrong()
    267     * @since 3.17.0
    268     */
    269    public static RandomUtils secureStrong() {
    270        return SECURE_STRONG;
    271    }
    272
    273    private final Supplier<Random> random;
    274
    275    /**
    276     * {@link RandomUtils} instances should NOT be constructed in standard programming. Instead, the class should be
    277     * used as {@code RandomUtils.nextBytes(5);}.
    278     * <p>
    279     * This constructor is public to permit tools that require a JavaBean instance to operate.
    280     * </p>
    281     *
    282     * @deprecated TODO Make private in 4.0.
    283     */
    284    @Deprecated
    285    public RandomUtils() {
    286        this(SECURE_STRONG_SUPPLIER);
    287    }
    288
    289    private RandomUtils(final Supplier<Random> random) {
    290        this.random = random;
    291    }
    292
    293    Random random() {
    294        return random.get();
    295    }
    296
    297    /**
    298     * Generates a random boolean value.
    299     *
    300     * @return the random boolean.
    301     * @since 3.16.0
    302     */
    303    public boolean randomBoolean() {
    304        return random().nextBoolean();
    305    }
    306
    307    /**
    308     * Generates an array of random bytes.
    309     *
    310     * @param count the size of the returned array.
    311     * @return the random byte array.
    312     * @throws IllegalArgumentException if {@code count} is negative
    313     * @since 3.16.0
    314     */
    315    public byte[] randomBytes(final int count) {
    316        Validate.isTrue(count >= 0, "Count cannot be negative.");
    317        final byte[] result = new byte[count];
    318        random().nextBytes(result);
    319        return result;
    320    }
    321
    322    /**
    323     * Generates a random double between 0 (inclusive) and Double.MAX_VALUE (exclusive).
    324     *
    325     * @return the random double.
    326     * @see #randomDouble(double, double)
    327     * @since 3.16.0
    328     */
    329    public double randomDouble() {
    330        return randomDouble(0, Double.MAX_VALUE);
    331    }
    332
    333    /**
    334     * Generates a random double within the specified range.
    335     *
    336     * @param startInclusive the smallest value that can be returned, must be non-negative.
    337     * @param endExclusive   the upper bound (not included).
    338     * @throws IllegalArgumentException if {@code startInclusive > endExclusive} or if {@code startInclusive} is negative.
    339     * @return the random double
    340     * @since 3.16.0
    341     */
    342    public double randomDouble(final double startInclusive, final double endExclusive) {
    343        Validate.isTrue(endExclusive >= startInclusive, "Start value must be smaller or equal to end value.");
    344        Validate.isTrue(startInclusive >= 0, "Both range values must be non-negative.");
    345        if (startInclusive == endExclusive) {
    346            return startInclusive;
    347        }
    348        return startInclusive + (endExclusive - startInclusive) * random().nextDouble();
    349    }
    350
    351    /**
    352     * Generates a random float between 0 (inclusive) and Float.MAX_VALUE (exclusive).
    353     *
    354     * @return the random float.
    355     * @see #randomFloat(float, float)
    356     * @since 3.16.0
    357     */
    358    public float randomFloat() {
    359        return randomFloat(0, Float.MAX_VALUE);
    360    }
    361
    362    /**
    363     * Generates a random float within the specified range.
    364     *
    365     * @param startInclusive the smallest value that can be returned, must be non-negative.
    366     * @param endExclusive   the upper bound (not included).
    367     * @throws IllegalArgumentException if {@code startInclusive > endExclusive} or if {@code startInclusive} is negative.
    368     * @return the random float.
    369     */
    370    public float randomFloat(final float startInclusive, final float endExclusive) {
    371        Validate.isTrue(endExclusive >= startInclusive, "Start value must be smaller or equal to end value.");
    372        Validate.isTrue(startInclusive >= 0, "Both range values must be non-negative.");
    373        if (startInclusive == endExclusive) {
    374            return startInclusive;
    375        }
    376        return startInclusive + (endExclusive - startInclusive) * random().nextFloat();
    377    }
    378
    379    /**
    380     * Generates a random int between 0 (inclusive) and Integer.MAX_VALUE (exclusive).
    381     *
    382     * @return the random integer.
    383     * @see #randomInt(int, int)
    384     * @since 3.16.0
    385     */
    386    public int randomInt() {
    387        return randomInt(0, Integer.MAX_VALUE);
    388    }
    389
    390    /**
    391     * Generates a random integer within the specified range.
    392     *
    393     * @param startInclusive the smallest value that can be returned, must be non-negative.
    394     * @param endExclusive   the upper bound (not included).
    395     * @throws IllegalArgumentException if {@code startInclusive > endExclusive} or if {@code startInclusive} is negative.
    396     * @return the random integer.
    397     * @since 3.16.0
    398     */
    399    public int randomInt(final int startInclusive, final int endExclusive) {
    400        Validate.isTrue(endExclusive >= startInclusive, "Start value must be smaller or equal to end value.");
    401        Validate.isTrue(startInclusive >= 0, "Both range values must be non-negative.");
    402        if (startInclusive == endExclusive) {
    403            return startInclusive;
    404        }
    405        return startInclusive + random().nextInt(endExclusive - startInclusive);
    406    }
    407
    408    /**
    409     * Generates a random long between 0 (inclusive) and Long.MAX_VALUE (exclusive).
    410     *
    411     * @return the random long.
    412     * @see #randomLong(long, long)
    413     * @since 3.16.0
    414     */
    415    public long randomLong() {
    416        return randomLong(Long.MAX_VALUE);
    417    }
    418
    419    /**
    420     * Generates a {@code long} value between 0 (inclusive) and the specified value (exclusive).
    421     *
    422     * @param n Bound on the random number to be returned. Must be positive.
    423     * @return a random {@code long} value between 0 (inclusive) and {@code n} (exclusive).
    424     */
    425    private long randomLong(final long n) {
    426        // Extracted from o.a.c.rng.core.BaseProvider.nextLong(long)
    427        long bits;
    428        long val;
    429        do {
    430            bits = random().nextLong() >>> 1;
    431            val = bits % n;
    432        } while (bits - val + n - 1 < 0);
    433        return val;
    434    }
    435
    436    /**
    437     * Generates a random long within the specified range.
    438     *
    439     * @param startInclusive the smallest value that can be returned, must be non-negative.
    440     * @param endExclusive   the upper bound (not included).
    441     * @throws IllegalArgumentException if {@code startInclusive > endExclusive} or if {@code startInclusive} is negative.
    442     * @return the random long.
    443     * @since 3.16.0
    444     */
    445    public long randomLong(final long startInclusive, final long endExclusive) {
    446        Validate.isTrue(endExclusive >= startInclusive, "Start value must be smaller or equal to end value.");
    447        Validate.isTrue(startInclusive >= 0, "Both range values must be non-negative.");
    448        if (startInclusive == endExclusive) {
    449            return startInclusive;
    450        }
    451        return startInclusive + randomLong(endExclusive - startInclusive);
    452    }
    453
    454    @Override
    455    public String toString() {
    456        return "RandomUtils [random=" + random() + "]";
    457    }
    458
    459}