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 18 package java.security; 19 20 import java.nio.ByteOrder; 21 import java.util.Random; 22 import libcore.io.Memory; 23 import libcore.io.SizeOf; 24 import org.apache.harmony.security.fortress.Engine; 25 import org.apache.harmony.security.fortress.Services; 26 import 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 */ 67 public 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 */ SecureRandom()89 public SecureRandom() { 90 super(0); 91 Services.refresh(); 92 Provider.Service service = Services.getSecureRandomService(); 93 if (service == null) { 94 this.provider = null; 95 this.secureRandomSpi = new SHA1PRNG_SecureRandomImpl(); 96 this.algorithm = "SHA1PRNG"; 97 } else { 98 try { 99 this.provider = service.getProvider(); 100 this.secureRandomSpi = (SecureRandomSpi)service.newInstance(null); 101 this.algorithm = service.getAlgorithm(); 102 } catch (Exception e) { 103 throw new RuntimeException(e); 104 } 105 } 106 } 107 108 /** 109 * Constructs a new seeded {@code SecureRandom} that uses the default 110 * algorithm. <a href="#insecure_seed">Seeding {@code SecureRandom} may be 111 * insecure</a>. 112 */ SecureRandom(byte[] seed)113 public SecureRandom(byte[] seed) { 114 this(); 115 setSeed(seed); 116 } 117 118 /** 119 * Constructs a new instance of {@code SecureRandom} using the given 120 * implementation from the specified provider. 121 * 122 * @param secureRandomSpi 123 * the implementation. 124 * @param provider 125 * the security provider. 126 */ SecureRandom(SecureRandomSpi secureRandomSpi, Provider provider)127 protected SecureRandom(SecureRandomSpi secureRandomSpi, 128 Provider provider) { 129 this(secureRandomSpi, provider, "unknown"); 130 } 131 132 // Constructor SecureRandom(SecureRandomSpi secureRandomSpi, Provider provider, String algorithm)133 private SecureRandom(SecureRandomSpi secureRandomSpi, 134 Provider provider, 135 String algorithm) { 136 super(0); 137 this.provider = provider; 138 this.algorithm = algorithm; 139 this.secureRandomSpi = secureRandomSpi; 140 } 141 142 /** 143 * Returns a new instance of {@code SecureRandom} that utilizes the 144 * specified algorithm. 145 * 146 * @param algorithm 147 * the name of the algorithm to use. 148 * @return a new instance of {@code SecureRandom} that utilizes the 149 * specified algorithm. 150 * @throws NoSuchAlgorithmException 151 * if the specified algorithm is not available. 152 * @throws NullPointerException 153 * if {@code algorithm} is {@code null}. 154 */ getInstance(String algorithm)155 public static SecureRandom getInstance(String algorithm) throws NoSuchAlgorithmException { 156 if (algorithm == null) { 157 throw new NullPointerException(); 158 } 159 Engine.SpiAndProvider sap = ENGINE.getInstance(algorithm, null); 160 return new SecureRandom((SecureRandomSpi) sap.spi, sap.provider, 161 algorithm); 162 } 163 164 /** 165 * Returns a new instance of {@code SecureRandom} that utilizes the 166 * specified algorithm from the specified provider. 167 * 168 * @param algorithm 169 * the name of the algorithm to use. 170 * @param provider 171 * the name of the provider. 172 * @return a new instance of {@code SecureRandom} that utilizes the 173 * specified algorithm from the specified provider. 174 * @throws NoSuchAlgorithmException 175 * if the specified algorithm is not available. 176 * @throws NoSuchProviderException 177 * if the specified provider is not available. 178 * @throws NullPointerException 179 * if {@code algorithm} is {@code null}. 180 * @throws IllegalArgumentException if {@code provider == null || provider.isEmpty()} 181 */ getInstance(String algorithm, String provider)182 public static SecureRandom getInstance(String algorithm, String provider) 183 throws NoSuchAlgorithmException, NoSuchProviderException { 184 if (provider == null || provider.isEmpty()) { 185 throw new IllegalArgumentException(); 186 } 187 Provider p = Security.getProvider(provider); 188 if (p == null) { 189 throw new NoSuchProviderException(provider); 190 } 191 return getInstance(algorithm, p); 192 } 193 194 /** 195 * Returns a new instance of {@code SecureRandom} that utilizes the 196 * specified algorithm from the specified provider. 197 * 198 * @param algorithm 199 * the name of the algorithm to use. 200 * @param provider 201 * the security provider. 202 * @return a new instance of {@code SecureRandom} that utilizes the 203 * specified algorithm from the specified provider. 204 * @throws NoSuchAlgorithmException 205 * if the specified algorithm is not available. 206 * @throws NullPointerException 207 * if {@code algorithm} is {@code null}. 208 * @throws IllegalArgumentException if {@code provider == null} 209 */ getInstance(String algorithm, Provider provider)210 public static SecureRandom getInstance(String algorithm, Provider provider) 211 throws NoSuchAlgorithmException { 212 if (provider == null) { 213 throw new IllegalArgumentException(); 214 } 215 if (algorithm == null) { 216 throw new NullPointerException(); 217 } 218 Object spi = ENGINE.getInstance(algorithm, provider, null); 219 return new SecureRandom((SecureRandomSpi) spi, provider, algorithm); 220 } 221 222 /** 223 * Returns the provider associated with this {@code SecureRandom}. 224 * 225 * @return the provider associated with this {@code SecureRandom}. 226 */ getProvider()227 public final Provider getProvider() { 228 return provider; 229 } 230 231 /** 232 * Returns the name of the algorithm of this {@code SecureRandom}. 233 * 234 * @return the name of the algorithm of this {@code SecureRandom}. 235 */ getAlgorithm()236 public String getAlgorithm() { 237 return algorithm; 238 } 239 240 /** 241 * Seeds this {@code SecureRandom} instance with the specified {@code 242 * seed}. <a href="#insecure_seed">Seeding {@code SecureRandom} may be 243 * insecure</a>. 244 */ setSeed(byte[] seed)245 public synchronized void setSeed(byte[] seed) { 246 secureRandomSpi.engineSetSeed(seed); 247 } 248 249 /** 250 * Seeds this {@code SecureRandom} instance with the specified eight-byte 251 * {@code seed}. <a href="#insecure_seed">Seeding {@code SecureRandom} may 252 * be insecure</a>. 253 */ 254 @Override setSeed(long seed)255 public void setSeed(long seed) { 256 if (seed == 0) { // skip call from Random 257 return; 258 } 259 byte[] byteSeed = new byte[SizeOf.LONG]; 260 Memory.pokeLong(byteSeed, 0, seed, ByteOrder.BIG_ENDIAN); 261 setSeed(byteSeed); 262 } 263 264 /** 265 * Generates and stores random bytes in the given {@code byte[]} for each 266 * array element. 267 * 268 * @param bytes 269 * the {@code byte[]} to be filled with random bytes. 270 */ 271 @Override nextBytes(byte[] bytes)272 public synchronized void nextBytes(byte[] bytes) { 273 secureRandomSpi.engineNextBytes(bytes); 274 } 275 276 /** 277 * Generates and returns an {@code int} containing the specified number of 278 * random bits (right justified, with leading zeros). 279 * 280 * @param numBits 281 * number of bits to be generated. An input value should be in 282 * the range [0, 32]. 283 * @return an {@code int} containing the specified number of random bits. 284 */ 285 @Override next(int numBits)286 protected final int next(int numBits) { 287 if (numBits < 0) { 288 numBits = 0; 289 } else { 290 if (numBits > 32) { 291 numBits = 32; 292 } 293 } 294 int bytes = (numBits+7)/8; 295 byte[] next = new byte[bytes]; 296 int ret = 0; 297 298 nextBytes(next); 299 for (int i = 0; i < bytes; i++) { 300 ret = (next[i] & 0xFF) | (ret << 8); 301 } 302 ret = ret >>> (bytes*8 - numBits); 303 return ret; 304 } 305 306 /** 307 * Generates and returns the specified number of seed bytes, computed using 308 * the seed generation algorithm used by this {@code SecureRandom}. 309 * 310 * @param numBytes 311 * the number of seed bytes. 312 * @return the seed bytes 313 */ getSeed(int numBytes)314 public static byte[] getSeed(int numBytes) { 315 SecureRandom result = internalSecureRandom; 316 if (result == null) { 317 // single-check idiom 318 internalSecureRandom = result = new SecureRandom(); 319 } 320 return result.generateSeed(numBytes); 321 } 322 323 /** 324 * Generates and returns the specified number of seed bytes, computed using 325 * the seed generation algorithm used by this {@code SecureRandom}. 326 * 327 * @param numBytes 328 * the number of seed bytes. 329 * @return the seed bytes. 330 */ generateSeed(int numBytes)331 public byte[] generateSeed(int numBytes) { 332 return secureRandomSpi.engineGenerateSeed(numBytes); 333 } 334 335 } 336