📄 randomdataimpl.java
字号:
/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package org.apache.commons.math.random;import java.io.Serializable;import java.security.MessageDigest;import java.security.SecureRandom;import java.security.NoSuchAlgorithmException;import java.security.NoSuchProviderException;import java.util.Collection;/** * Implements the {@link RandomData} interface using a {@link RandomGenerator} * instance to generate non-secure data and a * {@link java.security.SecureRandom} instance to provide data for the * <code>nextSecureXxx</code> methods. If no <code>RandomGenerator</code> * is provided in the constructor, the default is to use a generator based on * {@link java.util.Random}. To plug in a different implementation, * either implement <code>RandomGenerator</code> directly or extend * {@link AbstractRandomGenerator}. * <p> * Supports reseeding the underlying pseudo-random number generator (PRNG). * The <code>SecurityProvider</code> and <code>Algorithm</code> * used by the <code>SecureRandom</code> instance can also be reset.</p> * <p> * For details on the default PRNGs, see {@link java.util.Random} and * {@link java.security.SecureRandom}.</p> * <p> * <strong>Usage Notes</strong>: <ul> * <li> * Instance variables are used to maintain <code>RandomGenerator</code> and * <code>SecureRandom</code> instances used in data generation. Therefore, * to generate a random sequence of values or strings, you should use just * <strong>one</strong> <code>RandomDataImpl</code> instance repeatedly.</li> * <li> * The "secure" methods are *much* slower. These should be used only when a * cryptographically secure random sequence is required. A secure random * sequence is a sequence of pseudo-random values which, in addition to being * well-dispersed (so no subsequence of values is an any more likely than other * subsequence of the the same length), also has the additional property that * knowledge of values generated up to any point in the sequence does not make * it any easier to predict subsequent values.</li> * <li> * When a new <code>RandomDataImpl</code> is created, the underlying random * number generators are <strong>not</strong> intialized. If you do not * explicitly seed the default non-secure generator, it is seeded with the current time * in milliseconds on first use. The same holds for the secure generator. * If you provide a <code>RandomGenerator</code> to the constructor, however, * this generator is not reseeded by the constructor nor is it reseeded on * first use. </li> * <li> * The <code>reSeed</code> and <code>reSeedSecure</code> methods delegate * to the corresponding methods on the underlying <code>RandomGenerator</code> * and<code>SecureRandom</code> instances. Therefore, * <code>reSeed(long)</code> fully resets the initial state of the non-secure * random number generator (so that reseeding with a specific value always * results in the same subsequent random sequence); whereas reSeedSecure(long) * does <strong>not</strong> reinitialize the secure random number generator * (so secure sequences started with calls to reseedSecure(long) won't be * identical).</li> * <li> * This implementation is not synchronized. * </ul></p> * * @version $Revision: 615734 $ $Date: 2008-01-27 23:10:03 -0700 (Sun, 27 Jan 2008) $ */public class RandomDataImpl implements RandomData, Serializable { /** Serializable version identifier */ private static final long serialVersionUID = -626730818244969716L; /** underlying random number generator */ private RandomGenerator rand = null; /** underlying secure random number generator */ private SecureRandom secRand = null; /** * Construct a RandomDataImpl. */ public RandomDataImpl() { } /** * Construct a RandomDataImpl using the supplied {@link RandomGenerator} * as the source of (non-secure) random data. * * @param rand the source of (non-secure) random data * @since 1.1 */ public RandomDataImpl(RandomGenerator rand) { super(); this.rand = rand; } /** * {@inheritDoc}<p> * <strong>Algorithm Description:</strong> hex strings are generated * using a 2-step process. <ol> * <li> * len/2+1 binary bytes are generated using the underlying Random</li> * <li> * Each binary byte is translated into 2 hex digits</li></ol></p> * * @param len the desired string length. * @return the random string. */ public String nextHexString(int len) { if (len <= 0) { throw new IllegalArgumentException("length must be positive"); } //Get a random number generator RandomGenerator ran = getRan(); //Initialize output buffer StringBuffer outBuffer = new StringBuffer(); //Get int(len/2)+1 random bytes byte[] randomBytes = new byte[(len / 2) + 1]; ran.nextBytes(randomBytes); //Convert each byte to 2 hex digits for (int i = 0; i < randomBytes.length; i++) { Integer c = new Integer(randomBytes[i]); /* Add 128 to byte value to make interval 0-255 before * doing hex conversion. * This guarantees <= 2 hex digits from toHexString() * toHexString would otherwise add 2^32 to negative arguments. */ String hex = Integer.toHexString(c.intValue() + 128); // Make sure we add 2 hex digits for each byte if (hex.length() == 1) { hex = "0" + hex; } outBuffer.append(hex); } return outBuffer.toString().substring(0, len); } /** * Generate a random int value uniformly distributed between * <code>lower</code> and <code>upper</code>, inclusive. * * @param lower the lower bound. * @param upper the upper bound. * @return the random integer. */ public int nextInt(int lower, int upper) { if (lower >= upper) { throw new IllegalArgumentException ("upper bound must be > lower bound"); } RandomGenerator rand = getRan(); double r = rand.nextDouble(); return (int)((r * upper) + ((1.0 - r) * lower) + r); } /** * Generate a random long value uniformly distributed between * <code>lower</code> and <code>upper</code>, inclusive. * * @param lower the lower bound. * @param upper the upper bound. * @return the random integer. */ public long nextLong(long lower, long upper) { if (lower >= upper) { throw new IllegalArgumentException ("upper bound must be > lower bound"); } RandomGenerator rand = getRan(); double r = rand.nextDouble(); return (long)((r * upper) + ((1.0 - r) * lower) + r); } /** * {@inheritDoc}<p> * <strong>Algorithm Description:</strong> hex strings are generated in * 40-byte segments using a 3-step process. <ol> * <li> * 20 random bytes are generated using the underlying * <code>SecureRandom</code>.</li> * <li> * SHA-1 hash is applied to yield a 20-byte binary digest.</li> * <li> * Each byte of the binary digest is converted to 2 hex digits.</li></ol> * </p> * * @param len the length of the generated string * @return the random string */ public String nextSecureHexString(int len) { if (len <= 0) { throw new IllegalArgumentException("length must be positive"); } // Get SecureRandom and setup Digest provider SecureRandom secRan = getSecRan(); MessageDigest alg = null; try { alg = MessageDigest.getInstance("SHA-1"); } catch (NoSuchAlgorithmException ex) { return null; // gulp FIXME? -- this *should* never fail. } alg.reset(); //Compute number of iterations required (40 bytes each) int numIter = (len / 40) + 1; StringBuffer outBuffer = new StringBuffer(); for (int iter = 1; iter < numIter + 1; iter++) { byte[] randomBytes = new byte[40]; secRan.nextBytes(randomBytes); alg.update(randomBytes); //Compute hash -- will create 20-byte binary hash byte hash[] = alg.digest(); //Loop over the hash, converting each byte to 2 hex digits for (int i = 0; i < hash.length; i++) { Integer c = new Integer(hash[i]); /* Add 128 to byte value to make interval 0-255 * This guarantees <= 2 hex digits from toHexString() * toHexString would otherwise add 2^32 to negative * arguments */ String hex = Integer.toHexString(c.intValue() + 128); //Keep strings uniform length -- guarantees 40 bytes if (hex.length() == 1) { hex = "0" + hex; } outBuffer.append(hex); } } return outBuffer.toString().substring(0, len); } /** * Generate a random int value uniformly distributed between * <code>lower</code> and <code>upper</code>, inclusive. This algorithm * uses a secure random number generator. * * @param lower the lower bound. * @param upper the upper bound. * @return the random integer. */ public int nextSecureInt(int lower, int upper) { if (lower >= upper) { throw new IllegalArgumentException ("lower bound must be < upper bound"); } SecureRandom sec = getSecRan(); return lower + (int) (sec.nextDouble() * (upper - lower + 1)); } /** * Generate a random long value uniformly distributed between * <code>lower</code> and <code>upper</code>, inclusive. This algorithm * uses a secure random number generator. * * @param lower the lower bound. * @param upper the upper bound. * @return the random integer. */ public long nextSecureLong(long lower, long upper) { if (lower >= upper) { throw new IllegalArgumentException ("lower bound must be < upper bound"); } SecureRandom sec = getSecRan(); return lower + (long) (sec.nextDouble() * (upper - lower + 1)); } /** * {@inheritDoc} * <p> * <strong>Algorithm Description</strong>: * Uses simulation of a Poisson process using Uniform deviates, as * described * <a href="http://irmi.epfl.ch/cmos/Pmmi/interactive/rng7.htm"> * here.</a></p> * <p> * The Poisson process (and hence value returned) is bounded by
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -