• 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         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