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