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 * http://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()} <b>which is not cryptographically secure</b>. 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 RandomUtils INSECURE = new RandomUtils(ThreadLocalRandom::current); 74 75 private static 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 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>; use {@link #secure()} to use an algorithms/providers specified in the 92 * {@code securerandom.strongAlgorithms} {@link Security} property. 93 * <p> 94 * The method {@link ThreadLocalRandom#current()} is called on-demand. 95 * </p> 96 * 97 * @return the singleton instance based on {@link ThreadLocalRandom#current()}. 98 * @see ThreadLocalRandom#current() 99 * @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 150 * negative 151 * @return the random double 152 * @deprecated Use {@link #secure()}, {@link #secureStrong()},or {@link #insecure()}. 153 */ 154 @Deprecated 155 public static double nextDouble(final double startInclusive, final double endExclusive) { 156 return secure().randomDouble(startInclusive, endExclusive); 157 } 158 159 /** 160 * Generates a random float between 0 (inclusive) and Float.MAX_VALUE (exclusive). 161 * 162 * @return the random float 163 * @see #nextFloat(float, float) 164 * @since 3.5 165 * @deprecated Use {@link #secure()}, {@link #secureStrong()},or {@link #insecure()}. 166 */ 167 @Deprecated 168 public static float nextFloat() { 169 return secure().randomFloat(); 170 } 171 172 /** 173 * Generates a random float within the specified range. 174 * 175 * @param startInclusive the smallest value that can be returned, must be non-negative 176 * @param endExclusive the upper bound (not included) 177 * @throws IllegalArgumentException if {@code startInclusive > endExclusive} or if {@code startInclusive} is 178 * negative 179 * @return the random float 180 * @deprecated Use {@link #secure()}, {@link #secureStrong()},or {@link #insecure()}. 181 */ 182 @Deprecated 183 public static float nextFloat(final float startInclusive, final float endExclusive) { 184 return secure().randomFloat(startInclusive, endExclusive); 185 } 186 187 /** 188 * Generates a random int between 0 (inclusive) and Integer.MAX_VALUE (exclusive). 189 * 190 * @return the random integer 191 * @see #nextInt(int, int) 192 * @since 3.5 193 * @deprecated Use {@link #secure()}, {@link #secureStrong()},or {@link #insecure()}. 194 */ 195 @Deprecated 196 public static int nextInt() { 197 return secure().randomInt(); 198 } 199 200 /** 201 * Generates a random integer within the specified range. 202 * 203 * @param startInclusive the smallest value that can be returned, must be non-negative 204 * @param endExclusive the upper bound (not included) 205 * @throws IllegalArgumentException if {@code startInclusive > endExclusive} or if {@code startInclusive} is 206 * negative 207 * @return the random integer 208 * @deprecated Use {@link #secure()}, {@link #secureStrong()},or {@link #insecure()}. 209 */ 210 @Deprecated 211 public static int nextInt(final int startInclusive, final int endExclusive) { 212 return secure().randomInt(startInclusive, endExclusive); 213 } 214 215 /** 216 * Generates a random long between 0 (inclusive) and Long.MAX_VALUE (exclusive). 217 * 218 * @return the random long 219 * @see #nextLong(long, long) 220 * @since 3.5 221 * @deprecated Use {@link #secure()}, {@link #secureStrong()},or {@link #insecure()}. 222 */ 223 @Deprecated 224 public static long nextLong() { 225 return secure().randomLong(); 226 } 227 228 /** 229 * Generates a random long within the specified range. 230 * 231 * @param startInclusive the smallest value that can be returned, must be non-negative 232 * @param endExclusive the upper bound (not included) 233 * @throws IllegalArgumentException if {@code startInclusive > endExclusive} or if {@code startInclusive} is 234 * negative 235 * @return the random long 236 * @deprecated Use {@link #secure()}, {@link #secureStrong()},or {@link #insecure()}. 237 */ 238 @Deprecated 239 public static long nextLong(final long startInclusive, final long endExclusive) { 240 return secure().randomLong(startInclusive, endExclusive); 241 } 242 243 /** 244 * Gets the singleton instance based on {@link SecureRandom#SecureRandom()} which uses an algorithms/providers 245 * specified in the {@code securerandom.strongAlgorithms} {@link Security} property. 246 * <p> 247 * The method {@link SecureRandom#SecureRandom()} is called on-demand. 248 * </p> 249 * 250 * @return the singleton instance based on {@link SecureRandom#SecureRandom()}. 251 * @see SecureRandom#SecureRandom() 252 * @since 3.16.0 253 */ 254 public static RandomUtils secure() { 255 return SECURE; 256 } 257 258 static SecureRandom secureRandom() { 259 return SECURE_RANDOM_STRONG.get(); 260 } 261 262 /** 263 * Gets the singleton instance based on {@link SecureRandom#getInstanceStrong()} which uses an algorithms/providers 264 * specified in the {@code securerandom.strongAlgorithms} {@link Security} property. 265 * <p> 266 * The method {@link SecureRandom#getInstanceStrong()} is called on-demand. 267 * </p> 268 * 269 * @return the singleton instance based on {@link SecureRandom#getInstanceStrong()}. 270 * @see SecureRandom#getInstanceStrong() 271 * @since 3.17.0 272 */ 273 public static RandomUtils secureStrong() { 274 return SECURE_STRONG; 275 } 276 277 private final Supplier<Random> random; 278 279 /** 280 * {@link RandomUtils} instances should NOT be constructed in standard programming. Instead, the class should be 281 * used as {@code RandomUtils.nextBytes(5);}. 282 * <p> 283 * This constructor is public to permit tools that require a JavaBean instance to operate. 284 * </p> 285 * 286 * @deprecated TODO Make private in 4.0. 287 */ 288 @Deprecated 289 public RandomUtils() { 290 this(SECURE_STRONG_SUPPLIER); 291 } 292 293 private RandomUtils(final Supplier<Random> random) { 294 this.random = random; 295 } 296 297 Random random() { 298 return random.get(); 299 } 300 301 /** 302 * Generates a random boolean value. 303 * 304 * @return the random boolean 305 * @since 3.16.0 306 */ 307 public boolean randomBoolean() { 308 return random().nextBoolean(); 309 } 310 311 /** 312 * Generates an array of random bytes. 313 * 314 * @param count the size of the returned array 315 * @return the random byte array 316 * @throws IllegalArgumentException if {@code count} is negative 317 * @since 3.16.0 318 */ 319 public byte[] randomBytes(final int count) { 320 Validate.isTrue(count >= 0, "Count cannot be negative."); 321 final byte[] result = new byte[count]; 322 random().nextBytes(result); 323 return result; 324 } 325 326 /** 327 * Generates a random double between 0 (inclusive) and Double.MAX_VALUE (exclusive). 328 * 329 * @return the random double 330 * @see #randomDouble(double, double) 331 * @since 3.16.0 332 */ 333 public double randomDouble() { 334 return randomDouble(0, Double.MAX_VALUE); 335 } 336 337 /** 338 * Generates a random double within the specified range. 339 * 340 * @param startInclusive the smallest value that can be returned, must be non-negative 341 * @param endExclusive the upper bound (not included) 342 * @throws IllegalArgumentException if {@code startInclusive > endExclusive} or if {@code startInclusive} is 343 * negative 344 * @return the random double 345 * @since 3.16.0 346 */ 347 public double randomDouble(final double startInclusive, final double endExclusive) { 348 Validate.isTrue(endExclusive >= startInclusive, "Start value must be smaller or equal to end value."); 349 Validate.isTrue(startInclusive >= 0, "Both range values must be non-negative."); 350 if (startInclusive == endExclusive) { 351 return startInclusive; 352 } 353 return startInclusive + (endExclusive - startInclusive) * random().nextDouble(); 354 } 355 356 /** 357 * Generates a random float between 0 (inclusive) and Float.MAX_VALUE (exclusive). 358 * 359 * @return the random float 360 * @see #randomFloat(float, float) 361 * @since 3.16.0 362 */ 363 public float randomFloat() { 364 return randomFloat(0, Float.MAX_VALUE); 365 } 366 367 /** 368 * Generates a random float within the specified range. 369 * 370 * @param startInclusive the smallest value that can be returned, must be non-negative 371 * @param endExclusive the upper bound (not included) 372 * @throws IllegalArgumentException if {@code startInclusive > endExclusive} or if {@code startInclusive} is 373 * negative 374 * @return the random float 375 */ 376 public float randomFloat(final float startInclusive, final float endExclusive) { 377 Validate.isTrue(endExclusive >= startInclusive, "Start value must be smaller or equal to end value."); 378 Validate.isTrue(startInclusive >= 0, "Both range values must be non-negative."); 379 if (startInclusive == endExclusive) { 380 return startInclusive; 381 } 382 return startInclusive + (endExclusive - startInclusive) * random().nextFloat(); 383 } 384 385 /** 386 * Generates a random int between 0 (inclusive) and Integer.MAX_VALUE (exclusive). 387 * 388 * @return the random integer 389 * @see #randomInt(int, int) 390 * @since 3.16.0 391 */ 392 public int randomInt() { 393 return randomInt(0, Integer.MAX_VALUE); 394 } 395 396 /** 397 * Generates a random integer within the specified range. 398 * 399 * @param startInclusive the smallest value that can be returned, must be non-negative 400 * @param endExclusive the upper bound (not included) 401 * @throws IllegalArgumentException if {@code startInclusive > endExclusive} or if {@code startInclusive} is 402 * negative 403 * @return the random integer 404 * @since 3.16.0 405 */ 406 public int randomInt(final int startInclusive, final int endExclusive) { 407 Validate.isTrue(endExclusive >= startInclusive, "Start value must be smaller or equal to end value."); 408 Validate.isTrue(startInclusive >= 0, "Both range values must be non-negative."); 409 if (startInclusive == endExclusive) { 410 return startInclusive; 411 } 412 return startInclusive + random().nextInt(endExclusive - startInclusive); 413 } 414 415 /** 416 * Generates a random long between 0 (inclusive) and Long.MAX_VALUE (exclusive). 417 * 418 * @return the random long 419 * @see #randomLong(long, long) 420 * @since 3.16.0 421 */ 422 public long randomLong() { 423 return randomLong(Long.MAX_VALUE); 424 } 425 426 /** 427 * Generates a {@code long} value between 0 (inclusive) and the specified value (exclusive). 428 * 429 * @param n Bound on the random number to be returned. Must be positive. 430 * @return a random {@code long} value between 0 (inclusive) and {@code n} (exclusive). 431 */ 432 private long randomLong(final long n) { 433 // Extracted from o.a.c.rng.core.BaseProvider.nextLong(long) 434 long bits; 435 long val; 436 do { 437 bits = random().nextLong() >>> 1; 438 val = bits % n; 439 } while (bits - val + n - 1 < 0); 440 return val; 441 } 442 443 /** 444 * Generates a random long within the specified range. 445 * 446 * @param startInclusive the smallest value that can be returned, must be non-negative 447 * @param endExclusive the upper bound (not included) 448 * @throws IllegalArgumentException if {@code startInclusive > endExclusive} or if {@code startInclusive} is 449 * negative 450 * @return the random long 451 * @since 3.16.0 452 */ 453 public long randomLong(final long startInclusive, final long endExclusive) { 454 Validate.isTrue(endExclusive >= startInclusive, "Start value must be smaller or equal to end value."); 455 Validate.isTrue(startInclusive >= 0, "Both range values must be non-negative."); 456 if (startInclusive == endExclusive) { 457 return startInclusive; 458 } 459 return startInclusive + randomLong(endExclusive - startInclusive); 460 } 461 462 @Override 463 public String toString() { 464 return "RandomUtils [random=" + random() + "]"; 465 } 466 467 }