• 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  * <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         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      */
SecureRandom(byte[] seed)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      */
SecureRandom(SecureRandomSpi secureRandomSpi, Provider provider)126     protected SecureRandom(SecureRandomSpi secureRandomSpi,
127                            Provider provider) {
128         this(secureRandomSpi, provider, "unknown");
129     }
130 
131     // Constructor
SecureRandom(SecureRandomSpi secureRandomSpi, Provider provider, String algorithm)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      */
getInstance(String algorithm)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      */
getInstance(String algorithm, String provider)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      */
getInstance(String algorithm, Provider provider)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      */
getProvider()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      */
getAlgorithm()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      */
setSeed(byte[] seed)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
setSeed(long seed)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
nextBytes(byte[] bytes)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
next(int numBits)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      */
getSeed(int numBytes)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      */
generateSeed(int numBytes)330     public byte[] generateSeed(int numBytes) {
331         return secureRandomSpi.engineGenerateSeed(numBytes);
332     }
333 
334 }
335