1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * https://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.commons.lang3;
18
19 import java.security.NoSuchAlgorithmException;
20 import java.security.SecureRandom;
21 import java.security.Security;
22 import java.util.Random;
23 import java.util.concurrent.ThreadLocalRandom;
24 import java.util.function.Supplier;
25
26 import org.apache.commons.lang3.exception.UncheckedException;
27
28 /**
29 * Supplements the standard {@link Random} class.
30 * <p>
31 * Use {@link #secure()} to get the singleton instance based on {@link SecureRandom#SecureRandom()} which uses a secure random number generator implementing the
32 * default random number algorithm.
33 * </p>
34 * <p>
35 * Use {@link #secureStrong()} to get the singleton instance based on {@link SecureRandom#getInstanceStrong()} which uses an instance that was selected by using
36 * the algorithms/providers specified in the {@code securerandom.strongAlgorithms} {@link Security} property.
37 * </p>
38 * <p>
39 * Use {@link #insecure()} to get the singleton instance based on {@link ThreadLocalRandom#current()} <strong>which is not cryptographically secure</strong>. In addition,
40 * instances do not use a cryptographically random seed unless the {@linkplain System#getProperty system property} {@code java.util.secureRandomSeed} is set to
41 * {@code true}.
42 * </p>
43 * <p>
44 * Starting in version 3.17.0, the method {@link #secure()} uses {@link SecureRandom#SecureRandom()} instead of {@link SecureRandom#getInstanceStrong()}, and
45 * adds {@link #secureStrong()}.
46 * </p>
47 * <p>
48 * Starting in version 3.16.0, this class uses {@link #secure()} for static methods and adds {@link #insecure()}.
49 * </p>
50 * <p>
51 * Starting in version 3.15.0, this class uses {@link SecureRandom#getInstanceStrong()} for static methods.
52 * </p>
53 * <p>
54 * Before version 3.15.0, this class used {@link ThreadLocalRandom#current()} for static methods, which is not cryptographically secure.
55 * </p>
56 * <p>
57 * Please note that the Apache Commons project provides a component dedicated to pseudo-random number generation, namely
58 * <a href="https://commons.apache.org/proper/commons-rng/">Commons RNG</a>, that may be a better choice for applications with more stringent requirements
59 * (performance and/or correctness).
60 * </p>
61 *
62 * @see #secure()
63 * @see #secureStrong()
64 * @see #insecure()
65 * @see SecureRandom#SecureRandom()
66 * @see SecureRandom#getInstanceStrong()
67 * @see ThreadLocalRandom#current()
68 * @see RandomStringUtils
69 * @since 3.3
70 */
71 public class RandomUtils {
72
73 private static final RandomUtils INSECURE = new RandomUtils(ThreadLocalRandom::current);
74
75 private static final RandomUtils SECURE = new RandomUtils(SecureRandom::new);
76
77 private static final Supplier<Random> SECURE_STRONG_SUPPLIER = () -> RandomUtils.SECURE_RANDOM_STRONG.get();
78
79 private static final RandomUtils SECURE_STRONG = new RandomUtils(SECURE_STRONG_SUPPLIER);
80
81 private static final ThreadLocal<SecureRandom> SECURE_RANDOM_STRONG = ThreadLocal.withInitial(() -> {
82 try {
83 return SecureRandom.getInstanceStrong();
84 } catch (final NoSuchAlgorithmException e) {
85 throw new UncheckedException(e);
86 }
87 });
88
89 /**
90 * Gets the singleton instance based on {@link ThreadLocalRandom#current()}; <b>which is not cryptographically
91 * secure</b>; for more secure processing use {@link #secure()} or {@link #secureStrong()}.
92 * <p>
93 * The method {@link ThreadLocalRandom#current()} is called on-demand.
94 * </p>
95 *
96 * @return the singleton instance based on {@link ThreadLocalRandom#current()}.
97 * @see ThreadLocalRandom#current()
98 * @see #secure()
99 * @see #secureStrong()
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 the default algorithm
241 * and provider of {@link SecureRandom}.
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 * @since 3.16.0
370 */
371 public float randomFloat(final float startInclusive, final float endExclusive) {
372 Validate.isTrue(endExclusive >= startInclusive, "Start value must be smaller or equal to end value.");
373 Validate.isTrue(startInclusive >= 0, "Both range values must be non-negative.");
374 if (startInclusive == endExclusive) {
375 return startInclusive;
376 }
377 return startInclusive + (endExclusive - startInclusive) * random().nextFloat();
378 }
379
380 /**
381 * Generates a random int between 0 (inclusive) and Integer.MAX_VALUE (exclusive).
382 *
383 * @return the random integer.
384 * @see #randomInt(int, int)
385 * @since 3.16.0
386 */
387 public int randomInt() {
388 return randomInt(0, Integer.MAX_VALUE);
389 }
390
391 /**
392 * Generates a random integer within the specified range.
393 *
394 * @param startInclusive the smallest value that can be returned, must be non-negative.
395 * @param endExclusive the upper bound (not included).
396 * @throws IllegalArgumentException if {@code startInclusive > endExclusive} or if {@code startInclusive} is negative.
397 * @return the random integer.
398 * @since 3.16.0
399 */
400 public int randomInt(final int startInclusive, final int endExclusive) {
401 Validate.isTrue(endExclusive >= startInclusive, "Start value must be smaller or equal to end value.");
402 Validate.isTrue(startInclusive >= 0, "Both range values must be non-negative.");
403 if (startInclusive == endExclusive) {
404 return startInclusive;
405 }
406 return startInclusive + random().nextInt(endExclusive - startInclusive);
407 }
408
409 /**
410 * Generates a random long between 0 (inclusive) and Long.MAX_VALUE (exclusive).
411 *
412 * @return the random long.
413 * @see #randomLong(long, long)
414 * @since 3.16.0
415 */
416 public long randomLong() {
417 return randomLong(Long.MAX_VALUE);
418 }
419
420 /**
421 * Generates a {@code long} value between 0 (inclusive) and the specified value (exclusive).
422 *
423 * @param n Bound on the random number to be returned. Must be positive.
424 * @return a random {@code long} value between 0 (inclusive) and {@code n} (exclusive).
425 */
426 private long randomLong(final long n) {
427 // Extracted from o.a.c.rng.core.BaseProvider.nextLong(long)
428 long bits;
429 long val;
430 do {
431 bits = random().nextLong() >>> 1;
432 val = bits % n;
433 } while (bits - val + n - 1 < 0);
434 return val;
435 }
436
437 /**
438 * Generates a random long within the specified range.
439 *
440 * @param startInclusive the smallest value that can be returned, must be non-negative.
441 * @param endExclusive the upper bound (not included).
442 * @throws IllegalArgumentException if {@code startInclusive > endExclusive} or if {@code startInclusive} is negative.
443 * @return the random long.
444 * @since 3.16.0
445 */
446 public long randomLong(final long startInclusive, final long endExclusive) {
447 Validate.isTrue(endExclusive >= startInclusive, "Start value must be smaller or equal to end value.");
448 Validate.isTrue(startInclusive >= 0, "Both range values must be non-negative.");
449 if (startInclusive == endExclusive) {
450 return startInclusive;
451 }
452 return startInclusive + randomLong(endExclusive - startInclusive);
453 }
454
455 @Override
456 public String toString() {
457 return "RandomUtils [random=" + random() + "]";
458 }
459
460 }