• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  * 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">Seeding {@code SecureRandom} may be
50  * insecure</a></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  */
65 public 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      */
SecureRandom()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      */
SecureRandom(byte[] seed)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      */
SecureRandom(SecureRandomSpi secureRandomSpi, Provider provider)124     protected SecureRandom(SecureRandomSpi secureRandomSpi,
125                            Provider provider) {
126         this(secureRandomSpi, provider, "unknown");
127     }
128 
129     // Constructor
SecureRandom(SecureRandomSpi secureRandomSpi, Provider provider, String algorithm)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      */
getInstance(String algorithm)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      */
getInstance(String algorithm, String provider)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.
194      *
195      * @param algorithm
196      *            the name of the algorithm to use.
197      * @param provider
198      *            the security provider.
199      * @return a new instance of {@code SecureRandom} that utilizes the
200      *         specified algorithm from the specified provider.
201      * @throws NoSuchAlgorithmException
202      *             if the specified algorithm is not available.
203      * @throws NullPointerException
204      *             if {@code algorithm} is {@code null}.
205      * @throws IllegalArgumentException if {@code provider == null}
206      */
getInstance(String algorithm, Provider provider)207     public static SecureRandom getInstance(String algorithm, Provider provider)
208             throws NoSuchAlgorithmException {
209         if (provider == null) {
210             throw new IllegalArgumentException("provider == null");
211         }
212         if (algorithm == null) {
213             throw new NullPointerException("algorithm == null");
214         }
215         Object spi = ENGINE.getInstance(algorithm, provider, null);
216         return new SecureRandom((SecureRandomSpi) spi, provider, algorithm);
217     }
218 
219     /**
220      * Returns the provider associated with this {@code SecureRandom}.
221      *
222      * @return the provider associated with this {@code SecureRandom}.
223      */
getProvider()224     public final Provider getProvider() {
225         return provider;
226     }
227 
228     /**
229      * Returns the name of the algorithm of this {@code SecureRandom}.
230      *
231      * @return the name of the algorithm of this {@code SecureRandom}.
232      */
getAlgorithm()233     public String getAlgorithm() {
234         return algorithm;
235     }
236 
237     /**
238      * Seeds this {@code SecureRandom} instance with the specified {@code
239      * seed}. <a href="#insecure_seed">Seeding {@code SecureRandom} may be
240      * insecure</a>.
241      */
setSeed(byte[] seed)242     public synchronized void setSeed(byte[] seed) {
243         secureRandomSpi.engineSetSeed(seed);
244     }
245 
246     /**
247      * Seeds this {@code SecureRandom} instance with the specified eight-byte
248      * {@code seed}. <a href="#insecure_seed">Seeding {@code SecureRandom} may
249      * be insecure</a>.
250      */
251     @Override
setSeed(long seed)252     public void setSeed(long seed) {
253         if (seed == 0) {    // skip call from Random
254             return;
255         }
256         byte[] byteSeed = new byte[SizeOf.LONG];
257         Memory.pokeLong(byteSeed, 0, seed, ByteOrder.BIG_ENDIAN);
258         setSeed(byteSeed);
259     }
260 
261     /**
262      * Generates and stores random bytes in the given {@code byte[]} for each
263      * array element.
264      *
265      * @param bytes
266      *            the {@code byte[]} to be filled with random bytes.
267      */
268     @Override
nextBytes(byte[] bytes)269     public synchronized void nextBytes(byte[] bytes) {
270         secureRandomSpi.engineNextBytes(bytes);
271     }
272 
273     /**
274      * Generates and returns an {@code int} containing the specified number of
275      * random bits (right justified, with leading zeros).
276      *
277      * @param numBits
278      *            number of bits to be generated. An input value should be in
279      *            the range [0, 32].
280      * @return an {@code int} containing the specified number of random bits.
281      */
282     @Override
next(int numBits)283     protected final int next(int numBits) {
284         if (numBits < 0) {
285             numBits = 0;
286         } else {
287             if (numBits > 32) {
288                 numBits = 32;
289             }
290         }
291         int bytes = (numBits+7)/8;
292         byte[] next = new byte[bytes];
293         int ret = 0;
294 
295         nextBytes(next);
296         for (int i = 0; i < bytes; i++) {
297             ret = (next[i] & 0xFF) | (ret << 8);
298         }
299         ret = ret >>> (bytes*8 - numBits);
300         return ret;
301     }
302 
303     /**
304      * Generates and returns the specified number of seed bytes, computed using
305      * the seed generation algorithm used by this {@code SecureRandom}.
306      *
307      * @param numBytes
308      *            the number of seed bytes.
309      * @return the seed bytes
310      */
getSeed(int numBytes)311     public static byte[] getSeed(int numBytes) {
312         SecureRandom result = internalSecureRandom;
313         if (result == null) {
314             // single-check idiom
315             internalSecureRandom = result = new SecureRandom();
316         }
317         return result.generateSeed(numBytes);
318     }
319 
320     /**
321      * Generates and returns the specified number of seed bytes, computed using
322      * the seed generation algorithm used by this {@code SecureRandom}.
323      *
324      * @param numBytes
325      *            the number of seed bytes.
326      * @return the seed bytes.
327      */
generateSeed(int numBytes)328     public byte[] generateSeed(int numBytes) {
329         return secureRandomSpi.engineGenerateSeed(numBytes);
330     }
331 
332 }
333