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 18package java.security; 19 20import java.nio.ByteOrder; 21import java.util.Random; 22import libcore.io.Memory; 23import libcore.io.SizeOf; 24import org.apache.harmony.security.fortress.Engine; 25import org.apache.harmony.security.fortress.Services; 26import org.apache.harmony.security.provider.crypto.SHA1PRNG_SecureRandomImpl; 27 28/** 29 * This class generates cryptographically secure pseudo-random numbers. 30 * 31 * It is best to invoke {@code SecureRandom} using the default constructor. 32 * This will provide an instance of the most cryptographically strong 33 * provider available: 34 * 35 * <pre>SecureRandom sr = new SecureRandom(); 36 * byte[] output = new byte[16]; 37 * sr.nextBytes(output);</pre> 38 * 39 * <p>The default algorithm is defined by the first {@code SecureRandomSpi} 40 * provider found in the installed security providers. Use {@link Security} 41 * to install custom {@link SecureRandomSpi} providers. 42 * 43 * <p>Note that the output of a {@code SecureRandom} instance should never 44 * be relied upon to be deterministic. For deterministic output from a given 45 * input, see {@link MessageDigest} which provides one-way hash functions. 46 * For deriving keys from passwords, see 47 * {@link javax.crypto.SecretKeyFactory}. 48 * 49 * <h3><a name="insecure_seed"></a>Seeding {@code SecureRandom} may be 50 * insecure</h3> 51 * A seed is an array of bytes used to bootstrap random number generation. 52 * To produce cryptographically secure random numbers, both the seed and the 53 * algorithm must be secure. 54 * 55 * <p>By default, instances of this class will generate an initial seed using 56 * an internal entropy source, such as {@code /dev/urandom}. This seed is 57 * unpredictable and appropriate for secure use. 58 * 59 * <p>Using the {@link #SecureRandom(byte[]) seeded constructor} or calling 60 * {@link #setSeed} may completely replace the cryptographically strong 61 * default seed causing the instance to return a predictable sequence of 62 * numbers unfit for secure use. Due to variations between implementations 63 * it is not recommended to use {@code setSeed} at all. 64 */ 65public class SecureRandom extends Random { 66 67 private static final long serialVersionUID = 4940670005562187L; 68 69 // The service name. 70 private static final String SERVICE = "SecureRandom"; 71 72 // Used to access common engine functionality 73 private static final Engine ENGINE = new Engine(SERVICE); 74 75 private final Provider provider; 76 77 private final SecureRandomSpi secureRandomSpi; 78 79 private final String algorithm; 80 81 // Internal SecureRandom used for getSeed(int) 82 private static volatile SecureRandom internalSecureRandom; 83 84 /** 85 * Constructs a new {@code SecureRandom} that uses the default algorithm. 86 */ 87 public SecureRandom() { 88 super(0); 89 Provider.Service service = Services.getSecureRandomService(); 90 if (service == null) { 91 this.provider = null; 92 this.secureRandomSpi = new SHA1PRNG_SecureRandomImpl(); 93 this.algorithm = "SHA1PRNG"; 94 } else { 95 try { 96 this.provider = service.getProvider(); 97 this.secureRandomSpi = (SecureRandomSpi)service.newInstance(null); 98 this.algorithm = service.getAlgorithm(); 99 } catch (Exception e) { 100 throw new RuntimeException(e); 101 } 102 } 103 } 104 105 /** 106 * Constructs a new seeded {@code SecureRandom} that uses the default 107 * algorithm. <a href="#insecure_seed">Seeding {@code SecureRandom} may be 108 * insecure</a>. 109 */ 110 public SecureRandom(byte[] seed) { 111 this(); 112 setSeed(seed); 113 } 114 115 /** 116 * Constructs a new instance of {@code SecureRandom} using the given 117 * implementation from the specified provider. 118 * 119 * @param secureRandomSpi 120 * the implementation. 121 * @param provider 122 * the security provider. 123 */ 124 protected SecureRandom(SecureRandomSpi secureRandomSpi, 125 Provider provider) { 126 this(secureRandomSpi, provider, "unknown"); 127 } 128 129 // Constructor 130 private SecureRandom(SecureRandomSpi secureRandomSpi, 131 Provider provider, 132 String algorithm) { 133 super(0); 134 this.provider = provider; 135 this.algorithm = algorithm; 136 this.secureRandomSpi = secureRandomSpi; 137 } 138 139 /** 140 * Returns a new instance of {@code SecureRandom} that utilizes the 141 * specified algorithm. 142 * 143 * @param algorithm 144 * the name of the algorithm to use. 145 * @return a new instance of {@code SecureRandom} that utilizes the 146 * specified algorithm. 147 * @throws NoSuchAlgorithmException 148 * if the specified algorithm is not available. 149 * @throws NullPointerException 150 * if {@code algorithm} is {@code null}. 151 */ 152 public static SecureRandom getInstance(String algorithm) throws NoSuchAlgorithmException { 153 if (algorithm == null) { 154 throw new NullPointerException("algorithm == null"); 155 } 156 Engine.SpiAndProvider sap = ENGINE.getInstance(algorithm, null); 157 return new SecureRandom((SecureRandomSpi) sap.spi, sap.provider, 158 algorithm); 159 } 160 161 /** 162 * Returns a new instance of {@code SecureRandom} that utilizes the 163 * specified algorithm from the specified provider. 164 * 165 * @param algorithm 166 * the name of the algorithm to use. 167 * @param provider 168 * the name of the provider. 169 * @return a new instance of {@code SecureRandom} that utilizes the 170 * specified algorithm from the specified provider. 171 * @throws NoSuchAlgorithmException 172 * if the specified algorithm is not available. 173 * @throws NoSuchProviderException 174 * if the specified provider is not available. 175 * @throws NullPointerException 176 * if {@code algorithm} is {@code null}. 177 * @throws IllegalArgumentException if {@code provider == null || provider.isEmpty()} 178 */ 179 public static SecureRandom getInstance(String algorithm, String provider) 180 throws NoSuchAlgorithmException, NoSuchProviderException { 181 if (provider == null || provider.isEmpty()) { 182 throw new IllegalArgumentException(); 183 } 184 Provider p = Security.getProvider(provider); 185 if (p == null) { 186 throw new NoSuchProviderException(provider); 187 } 188 return getInstance(algorithm, p); 189 } 190 191 /** 192 * Returns a new instance of {@code SecureRandom} that utilizes the 193 * specified algorithm from the specified provider. The 194 * {@code provider} supplied does not have to be registered. 195 * 196 * @param algorithm 197 * the name of the algorithm to use. 198 * @param provider 199 * the security provider. 200 * @return a new instance of {@code SecureRandom} that utilizes the 201 * specified algorithm from the specified provider. 202 * @throws NoSuchAlgorithmException 203 * if the specified algorithm is not available. 204 * @throws NullPointerException 205 * if {@code algorithm} is {@code null}. 206 * @throws IllegalArgumentException if {@code provider == null} 207 */ 208 public static SecureRandom getInstance(String algorithm, Provider provider) 209 throws NoSuchAlgorithmException { 210 if (provider == null) { 211 throw new IllegalArgumentException("provider == null"); 212 } 213 if (algorithm == null) { 214 throw new NullPointerException("algorithm == null"); 215 } 216 Object spi = ENGINE.getInstance(algorithm, provider, null); 217 return new SecureRandom((SecureRandomSpi) spi, provider, algorithm); 218 } 219 220 /** 221 * Returns the provider associated with this {@code SecureRandom}. 222 * 223 * @return the provider associated with this {@code SecureRandom}. 224 */ 225 public final Provider getProvider() { 226 return provider; 227 } 228 229 /** 230 * Returns the name of the algorithm of this {@code SecureRandom}. 231 * 232 * @return the name of the algorithm of this {@code SecureRandom}. 233 */ 234 public String getAlgorithm() { 235 return algorithm; 236 } 237 238 /** 239 * Seeds this {@code SecureRandom} instance with the specified {@code 240 * seed}. <a href="#insecure_seed">Seeding {@code SecureRandom} may be 241 * insecure</a>. 242 */ 243 public synchronized void setSeed(byte[] seed) { 244 secureRandomSpi.engineSetSeed(seed); 245 } 246 247 /** 248 * Seeds this {@code SecureRandom} instance with the specified eight-byte 249 * {@code seed}. <a href="#insecure_seed">Seeding {@code SecureRandom} may 250 * be insecure</a>. 251 */ 252 @Override 253 public void setSeed(long seed) { 254 if (seed == 0) { // skip call from Random 255 return; 256 } 257 byte[] byteSeed = new byte[SizeOf.LONG]; 258 Memory.pokeLong(byteSeed, 0, seed, ByteOrder.BIG_ENDIAN); 259 setSeed(byteSeed); 260 } 261 262 /** 263 * Generates and stores random bytes in the given {@code byte[]} for each 264 * array element. 265 * 266 * @param bytes 267 * the {@code byte[]} to be filled with random bytes. 268 */ 269 @Override 270 public synchronized void nextBytes(byte[] bytes) { 271 secureRandomSpi.engineNextBytes(bytes); 272 } 273 274 /** 275 * Generates and returns an {@code int} containing the specified number of 276 * random bits (right justified, with leading zeros). 277 * 278 * @param numBits 279 * number of bits to be generated. An input value should be in 280 * the range [0, 32]. 281 * @return an {@code int} containing the specified number of random bits. 282 */ 283 @Override 284 protected final int next(int numBits) { 285 if (numBits < 0) { 286 numBits = 0; 287 } else { 288 if (numBits > 32) { 289 numBits = 32; 290 } 291 } 292 int bytes = (numBits+7)/8; 293 byte[] next = new byte[bytes]; 294 int ret = 0; 295 296 nextBytes(next); 297 for (int i = 0; i < bytes; i++) { 298 ret = (next[i] & 0xFF) | (ret << 8); 299 } 300 ret = ret >>> (bytes*8 - numBits); 301 return ret; 302 } 303 304 /** 305 * Generates and returns the specified number of seed bytes, computed using 306 * the seed generation algorithm used by this {@code SecureRandom}. 307 * 308 * @param numBytes 309 * the number of seed bytes. 310 * @return the seed bytes 311 */ 312 public static byte[] getSeed(int numBytes) { 313 SecureRandom result = internalSecureRandom; 314 if (result == null) { 315 // single-check idiom 316 internalSecureRandom = result = new SecureRandom(); 317 } 318 return result.generateSeed(numBytes); 319 } 320 321 /** 322 * Generates and returns the specified number of seed bytes, computed using 323 * the seed generation algorithm used by this {@code SecureRandom}. 324 * 325 * @param numBytes 326 * the number of seed bytes. 327 * @return the seed bytes. 328 */ 329 public byte[] generateSeed(int numBytes) { 330 return secureRandomSpi.engineGenerateSeed(numBytes); 331 } 332 333} 334