SecureRandom.java revision f6c387128427e121477c1b32ad35cdcaa5101ba3
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/** 19* @author Boris V. Kuznetsov 20* @version $Revision$ 21*/ 22 23package java.security; 24 25import java.util.Iterator; 26import java.util.Random; 27import java.util.Set; 28 29import org.apache.harmony.security.fortress.Engine; 30import org.apache.harmony.security.fortress.Services; 31import org.apache.harmony.security.internal.nls.Messages; 32 33import org.apache.harmony.security.provider.crypto.SHA1PRNG_SecureRandomImpl; 34 35/** 36 * {@code SecureRandom} is an engine class which is capable of generating 37 * cryptographically secure pseudo-random numbers. 38 * 39 * @since Android 1.0 40 */ 41public class SecureRandom extends Random { 42 43 private static final long serialVersionUID = 4940670005562187L; 44 45 // The service name. 46 private static final transient String SERVICE = "SecureRandom"; //$NON-NLS-1$ 47 48 // Used to access common engine functionality 49 private static transient Engine engine = new Engine(SERVICE); 50 51 private Provider provider; 52 53 private SecureRandomSpi secureRandomSpi; 54 55 private String algorithm; 56 57 private byte[] state; 58 59 private byte[] randomBytes; 60 61 private int randomBytesUsed; 62 63 private long counter; 64 65 // Internal SecureRandom used for getSeed(int) 66 private static transient SecureRandom internalSecureRandom; 67 68 /** 69 * Constructs a new instance of {@code SecureRandom}. An implementation for 70 * the highest-priority provider is returned. The constructed instance will 71 * not have been seeded. 72 * 73 * @since Android 1.0 74 */ 75 public SecureRandom() { 76 super(0); 77 Provider.Service service = findService(); 78 if (service == null) { 79 this.provider = null; 80 this.secureRandomSpi = new SHA1PRNG_SecureRandomImpl(); 81 this.algorithm = "SHA1PRNG"; //$NON-NLS-1$ 82 } else { 83 try { 84 this.provider = service.getProvider(); 85 this.secureRandomSpi = (SecureRandomSpi)service.newInstance(null); 86 this.algorithm = service.getAlgorithm(); 87 } catch (Exception e) { 88 throw new RuntimeException(e); 89 } 90 } 91 } 92 93 /** 94 * Constructs a new instance of {@code SecureRandom}. An implementation for 95 * the highest-priority provider is returned. The constructed instance will 96 * be seeded with the parameter. 97 * 98 * @param seed 99 * the seed for this generator. 100 * @since Android 1.0 101 */ 102 public SecureRandom(byte[] seed) { 103 this(); 104 setSeed(seed); 105 } 106 107 //Find SecureRandom service. 108 private Provider.Service findService() { 109 Set s; 110 Provider.Service service; 111 for (Iterator it1 = Services.getProvidersList().iterator(); it1.hasNext();) { 112 service = ((Provider)it1.next()).getService("SecureRandom"); //$NON-NLS-1$ 113 if (service != null) { 114 return service; 115 } 116 } 117 return null; 118 } 119 120 /** 121 * Constructs a new instance of {@code SecureRandom} using the given 122 * implementation from the specified provider. 123 * 124 * @param secureRandomSpi 125 * the implementation. 126 * @param provider 127 * the security provider. 128 * @since Android 1.0 129 */ 130 protected SecureRandom(SecureRandomSpi secureRandomSpi, 131 Provider provider) { 132 this(secureRandomSpi, provider, "unknown"); //$NON-NLS-1$ 133 } 134 135 // Constructor 136 private SecureRandom(SecureRandomSpi secureRandomSpi, 137 Provider provider, 138 String algorithm) { 139 super(0); 140 this.provider = provider; 141 this.algorithm = algorithm; 142 this.secureRandomSpi = secureRandomSpi; 143 } 144 145 /** 146 * Returns a new instance of {@code SecureRandom} that utilizes the 147 * specified algorithm. 148 * 149 * @param algorithm 150 * the name of the algorithm to use. 151 * @return a new instance of {@code SecureRandom} that utilizes the 152 * specified algorithm. 153 * @throws NoSuchAlgorithmException 154 * if the specified algorithm is not available. 155 * @throws NullPointerException 156 * if {@code algorithm} is {@code null}. 157 * @since Android 1.0 158 */ 159 public static SecureRandom getInstance(String algorithm) 160 throws NoSuchAlgorithmException { 161 if (algorithm == null) { 162 throw new NullPointerException(Messages.getString("security.01")); //$NON-NLS-1$ 163 } 164 synchronized (engine) { 165 engine.getInstance(algorithm, null); 166 return new SecureRandom((SecureRandomSpi)engine.spi, engine.provider, algorithm); 167 } 168 } 169 170 /** 171 * Returns a new instance of {@code SecureRandom} that utilizes the 172 * specified algorithm from the specified provider. 173 * 174 * @param algorithm 175 * the name of the algorithm to use. 176 * @param provider 177 * the name of the provider. 178 * @return a new instance of {@code SecureRandom} that utilizes the 179 * specified algorithm from the specified provider. 180 * @throws NoSuchAlgorithmException 181 * if the specified algorithm is not available. 182 * @throws NoSuchProviderException 183 * if the specified provider is not available. 184 * @throws NullPointerException 185 * if {@code algorithm} is {@code null}. 186 * @since Android 1.0 187 */ 188 public static SecureRandom getInstance(String algorithm, String provider) 189 throws NoSuchAlgorithmException, NoSuchProviderException { 190 if ((provider == null) || (provider.length() == 0)) { 191 throw new IllegalArgumentException( 192 Messages.getString("security.02")); //$NON-NLS-1$ 193 } 194 Provider p = Security.getProvider(provider); 195 if (p == null) { 196 throw new NoSuchProviderException(Messages.getString("security.03", provider)); //$NON-NLS-1$ 197 } 198 return getInstance(algorithm, p); 199 } 200 201 /** 202 * Returns a new instance of {@code SecureRandom} that utilizes the 203 * specified algorithm from the specified provider. 204 * 205 * @param algorithm 206 * the name of the algorithm to use. 207 * @param provider 208 * the security provider. 209 * @return a new instance of {@code SecureRandom} that utilizes the 210 * specified algorithm from the specified provider. 211 * @throws NoSuchAlgorithmException 212 * if the specified algorithm is not available. 213 * @throws NullPointerException 214 * if {@code algorithm} is {@code null}. 215 * @since Android 1.0 216 */ 217 public static SecureRandom getInstance(String algorithm, Provider provider) 218 throws NoSuchAlgorithmException { 219 if (provider == null) { 220 throw new IllegalArgumentException(Messages.getString("security.04")); //$NON-NLS-1$ 221 } 222 if (algorithm == null) { 223 throw new NullPointerException(Messages.getString("security.01")); //$NON-NLS-1$ 224 } 225 synchronized (engine) { 226 engine.getInstance(algorithm, provider, null); 227 return new SecureRandom((SecureRandomSpi)engine.spi, provider, algorithm); 228 } 229 } 230 231 /** 232 * Returns the provider associated with this {@code SecureRandom}. 233 * 234 * @return the provider associated with this {@code SecureRandom}. 235 * @since Android 1.0 236 */ 237 public final Provider getProvider() { 238 return provider; 239 } 240 241 /** 242 * Returns the name of the algorithm of this {@code SecureRandom}. 243 * 244 * @return the name of the algorithm of this {@code SecureRandom}. 245 * @since Android 1.0 246 */ 247 public String getAlgorithm() { 248 return algorithm; 249 } 250 251 /** 252 * Reseeds this {@code SecureRandom} instance with the specified {@code 253 * seed}. The seed of this {@code SecureRandom} instance is supplemented, 254 * not replaced. 255 * 256 * @param seed 257 * the new seed. 258 * @since Android 1.0 259 */ 260 public synchronized void setSeed(byte[] seed) { 261 secureRandomSpi.engineSetSeed(seed); 262 } 263 264 /** 265 * Reseeds this this {@code SecureRandom} instance with the eight bytes 266 * described by the representation of the given {@code long seed}. The seed 267 * of this {@code SecureRandom} instance is supplemented, not replaced. 268 * 269 * @param seed 270 * the new seed. 271 * @since Android 1.0 272 */ 273 public void setSeed(long seed) { 274 if (seed == 0) { // skip call from Random 275 return; 276 } 277 byte[] byteSeed = { 278 (byte)((seed >> 56) & 0xFF), 279 (byte)((seed >> 48) & 0xFF), 280 (byte)((seed >> 40) & 0xFF), 281 (byte)((seed >> 32) & 0xFF), 282 (byte)((seed >> 24) & 0xFF), 283 (byte)((seed >> 16) & 0xFF), 284 (byte)((seed >> 8) & 0xFF), 285 (byte)((seed) & 0xFF) 286 }; 287 setSeed(byteSeed); 288 } 289 290 /** 291 * Generates and stores random bytes in the given {@code byte[]} for each 292 * array element. 293 * 294 * @param bytes 295 * the {@code byte[]} to be filled with random bytes. 296 * @since Android 1.0 297 */ 298 public synchronized void nextBytes(byte[] bytes) { 299 secureRandomSpi.engineNextBytes(bytes); 300 } 301 302 /** 303 * Generates and returns an {@code int} containing the specified number of 304 * random bits (right justified, with leading zeros). 305 * 306 * @param numBits 307 * number of bits to be generated. An input value should be in 308 * the range [0, 32]. 309 * @return an {@code int} containing the specified number of random bits. 310 * @since Android 1.0 311 */ 312 protected final int next(int numBits) { 313 if (numBits < 0) { 314 numBits = 0; 315 } else { 316 if (numBits > 32) { 317 numBits = 32; 318 } 319 } 320 int bytes = (numBits+7)/8; 321 byte[] next = new byte[bytes]; 322 int ret = 0; 323 324 nextBytes(next); 325 for (int i = 0; i < bytes; i++) { 326 ret = (next[i] & 0xFF) | (ret << 8); 327 } 328 ret = ret >>> (bytes*8 - numBits); 329 return ret; 330 } 331 332 /** 333 * Generates and returns the specified number of seed bytes, computed using 334 * the seed generation algorithm used by this {@code SecureRandom}. 335 * 336 * @param numBytes 337 * the number of seed bytes. 338 * @return the seed bytes 339 * @since Android 1.0 340 */ 341 public static byte[] getSeed(int numBytes) { 342 if (internalSecureRandom == null) { 343 internalSecureRandom = new SecureRandom(); 344 } 345 return internalSecureRandom.generateSeed(numBytes); 346 } 347 348 /** 349 * Generates and returns the specified number of seed bytes, computed using 350 * the seed generation algorithm used by this {@code SecureRandom}. 351 * 352 * @param numBytes 353 * the number of seed bytes. 354 * @return the seed bytes. 355 * @since Android 1.0 356 */ 357 public byte[] generateSeed(int numBytes) { 358 return secureRandomSpi.engineGenerateSeed(numBytes); 359 } 360 361} 362