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
18package java.security;
19
20import java.nio.ByteOrder;
21import java.util.Random;
22import libcore.io.Memory;
23import libcore.io.SizeOf;
24import org.apache.harmony.security.fortress.Engine;
25import org.apache.harmony.security.fortress.Services;
26import 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 */
65public 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     */
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     */
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     */
124    protected SecureRandom(SecureRandomSpi secureRandomSpi,
125                           Provider provider) {
126        this(secureRandomSpi, provider, "unknown");
127    }
128
129    // Constructor
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     */
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     */
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     */
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     */
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     */
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     */
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
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
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
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     */
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     */
328    public byte[] generateSeed(int numBytes) {
329        return secureRandomSpi.engineGenerateSeed(numBytes);
330    }
331
332}
333