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"></a>Seeding {@code SecureRandom} may be
50 * insecure</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. 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     */
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     */
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     */
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     */
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
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
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
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     */
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     */
329    public byte[] generateSeed(int numBytes) {
330        return secureRandomSpi.engineGenerateSeed(numBytes);
331    }
332
333}
334