• 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. 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      */
getInstance(String algorithm, Provider provider)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      */
getProvider()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      */
getAlgorithm()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      */
setSeed(byte[] seed)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
setSeed(long seed)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
nextBytes(byte[] bytes)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
next(int numBits)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      */
getSeed(int numBytes)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      */
generateSeed(int numBytes)329     public byte[] generateSeed(int numBytes) {
330         return secureRandomSpi.engineGenerateSeed(numBytes);
331     }
332 
333 }
334