SecureRandom.java revision f6c387128427e121477c1b32ad35cdcaa5101ba3
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/**
19* @author Boris V. Kuznetsov
20* @version $Revision$
21*/
22
23package java.security;
24
25import java.util.Iterator;
26import java.util.Random;
27import java.util.Set;
28
29import org.apache.harmony.security.fortress.Engine;
30import org.apache.harmony.security.fortress.Services;
31import org.apache.harmony.security.internal.nls.Messages;
32
33import org.apache.harmony.security.provider.crypto.SHA1PRNG_SecureRandomImpl;
34
35/**
36 * {@code SecureRandom} is an engine class which is capable of generating
37 * cryptographically secure pseudo-random numbers.
38 *
39 * @since Android 1.0
40 */
41public class SecureRandom extends Random {
42
43    private static final long serialVersionUID = 4940670005562187L;
44
45    // The service name.
46    private static final transient String SERVICE = "SecureRandom"; //$NON-NLS-1$
47
48    // Used to access common engine functionality
49    private static transient Engine engine = new Engine(SERVICE);
50
51    private Provider provider;
52
53    private SecureRandomSpi secureRandomSpi;
54
55    private String algorithm;
56
57    private byte[] state;
58
59    private byte[] randomBytes;
60
61    private int randomBytesUsed;
62
63    private long counter;
64
65    // Internal SecureRandom used for getSeed(int)
66    private static transient SecureRandom internalSecureRandom;
67
68    /**
69     * Constructs a new instance of {@code SecureRandom}. An implementation for
70     * the highest-priority provider is returned. The constructed instance will
71     * not have been seeded.
72     *
73     * @since Android 1.0
74     */
75    public SecureRandom() {
76        super(0);
77        Provider.Service service = findService();
78        if (service == null) {
79            this.provider = null;
80            this.secureRandomSpi = new SHA1PRNG_SecureRandomImpl();
81            this.algorithm = "SHA1PRNG"; //$NON-NLS-1$
82        } else {
83            try {
84                this.provider = service.getProvider();
85                this.secureRandomSpi = (SecureRandomSpi)service.newInstance(null);
86                this.algorithm = service.getAlgorithm();
87            } catch (Exception e) {
88                throw new RuntimeException(e);
89            }
90        }
91    }
92
93    /**
94     * Constructs a new instance of {@code SecureRandom}. An implementation for
95     * the highest-priority provider is returned. The constructed instance will
96     * be seeded with the parameter.
97     *
98     * @param seed
99     *            the seed for this generator.
100     * @since Android 1.0
101     */
102    public SecureRandom(byte[] seed) {
103        this();
104        setSeed(seed);
105    }
106
107    //Find SecureRandom service.
108    private Provider.Service findService() {
109        Set s;
110        Provider.Service service;
111        for (Iterator it1 = Services.getProvidersList().iterator(); it1.hasNext();) {
112            service = ((Provider)it1.next()).getService("SecureRandom"); //$NON-NLS-1$
113            if (service != null) {
114                return service;
115            }
116        }
117        return null;
118    }
119
120    /**
121     * Constructs a new instance of {@code SecureRandom} using the given
122     * implementation from the specified provider.
123     *
124     * @param secureRandomSpi
125     *            the implementation.
126     * @param provider
127     *            the security provider.
128     * @since Android 1.0
129     */
130    protected SecureRandom(SecureRandomSpi secureRandomSpi,
131                           Provider provider) {
132        this(secureRandomSpi, provider, "unknown"); //$NON-NLS-1$
133    }
134
135    // Constructor
136    private SecureRandom(SecureRandomSpi secureRandomSpi,
137                         Provider provider,
138                         String algorithm) {
139        super(0);
140        this.provider = provider;
141        this.algorithm = algorithm;
142        this.secureRandomSpi = secureRandomSpi;
143    }
144
145    /**
146     * Returns a new instance of {@code SecureRandom} that utilizes the
147     * specified algorithm.
148     *
149     * @param algorithm
150     *            the name of the algorithm to use.
151     * @return a new instance of {@code SecureRandom} that utilizes the
152     *         specified algorithm.
153     * @throws NoSuchAlgorithmException
154     *             if the specified algorithm is not available.
155     * @throws NullPointerException
156     *             if {@code algorithm} is {@code null}.
157     * @since Android 1.0
158     */
159    public static SecureRandom getInstance(String algorithm)
160                                throws NoSuchAlgorithmException {
161        if (algorithm == null) {
162            throw new NullPointerException(Messages.getString("security.01")); //$NON-NLS-1$
163        }
164        synchronized (engine) {
165            engine.getInstance(algorithm, null);
166            return new SecureRandom((SecureRandomSpi)engine.spi, engine.provider, algorithm);
167        }
168    }
169
170    /**
171     * Returns a new instance of {@code SecureRandom} that utilizes the
172     * specified algorithm from the specified provider.
173     *
174     * @param algorithm
175     *            the name of the algorithm to use.
176     * @param provider
177     *            the name of the provider.
178     * @return a new instance of {@code SecureRandom} that utilizes the
179     *         specified algorithm from the specified provider.
180     * @throws NoSuchAlgorithmException
181     *             if the specified algorithm is not available.
182     * @throws NoSuchProviderException
183     *             if the specified provider is not available.
184     * @throws NullPointerException
185     *             if {@code algorithm} is {@code null}.
186     * @since Android 1.0
187     */
188    public static SecureRandom getInstance(String algorithm, String provider)
189                                throws NoSuchAlgorithmException, NoSuchProviderException {
190        if ((provider == null) || (provider.length() == 0)) {
191            throw new IllegalArgumentException(
192                    Messages.getString("security.02")); //$NON-NLS-1$
193        }
194        Provider p = Security.getProvider(provider);
195        if (p == null) {
196            throw new NoSuchProviderException(Messages.getString("security.03", provider));  //$NON-NLS-1$
197        }
198        return getInstance(algorithm, p);
199    }
200
201    /**
202     * Returns a new instance of {@code SecureRandom} that utilizes the
203     * specified algorithm from the specified provider.
204     *
205     * @param algorithm
206     *            the name of the algorithm to use.
207     * @param provider
208     *            the security provider.
209     * @return a new instance of {@code SecureRandom} that utilizes the
210     *         specified algorithm from the specified provider.
211     * @throws NoSuchAlgorithmException
212     *             if the specified algorithm is not available.
213     * @throws NullPointerException
214     *             if {@code algorithm} is {@code null}.
215     * @since Android 1.0
216     */
217    public static SecureRandom getInstance(String algorithm, Provider provider)
218                                throws NoSuchAlgorithmException {
219        if (provider == null) {
220            throw new IllegalArgumentException(Messages.getString("security.04")); //$NON-NLS-1$
221        }
222        if (algorithm == null) {
223            throw new NullPointerException(Messages.getString("security.01")); //$NON-NLS-1$
224        }
225        synchronized (engine) {
226            engine.getInstance(algorithm, provider, null);
227            return new SecureRandom((SecureRandomSpi)engine.spi, provider, algorithm);
228        }
229    }
230
231    /**
232     * Returns the provider associated with this {@code SecureRandom}.
233     *
234     * @return the provider associated with this {@code SecureRandom}.
235     * @since Android 1.0
236     */
237    public final Provider getProvider() {
238        return provider;
239    }
240
241    /**
242     * Returns the name of the algorithm of this {@code SecureRandom}.
243     *
244     * @return the name of the algorithm of this {@code SecureRandom}.
245     * @since Android 1.0
246     */
247    public String getAlgorithm() {
248        return algorithm;
249    }
250
251    /**
252     * Reseeds this {@code SecureRandom} instance with the specified {@code
253     * seed}. The seed of this {@code SecureRandom} instance is supplemented,
254     * not replaced.
255     *
256     * @param seed
257     *            the new seed.
258     * @since Android 1.0
259     */
260    public synchronized void setSeed(byte[] seed) {
261        secureRandomSpi.engineSetSeed(seed);
262    }
263
264    /**
265     * Reseeds this this {@code SecureRandom} instance with the eight bytes
266     * described by the representation of the given {@code long seed}. The seed
267     * of this {@code SecureRandom} instance is supplemented, not replaced.
268     *
269     * @param seed
270     *            the new seed.
271     * @since Android 1.0
272     */
273    public void setSeed(long seed) {
274        if (seed == 0) {    // skip call from Random
275            return;
276        }
277        byte[] byteSeed = {
278                (byte)((seed >> 56) & 0xFF),
279                (byte)((seed >> 48) & 0xFF),
280                (byte)((seed >> 40) & 0xFF),
281                (byte)((seed >> 32) & 0xFF),
282                (byte)((seed >> 24) & 0xFF),
283                (byte)((seed >> 16) & 0xFF),
284                (byte)((seed >> 8) & 0xFF),
285                (byte)((seed) & 0xFF)
286        };
287        setSeed(byteSeed);
288    }
289
290    /**
291     * Generates and stores random bytes in the given {@code byte[]} for each
292     * array element.
293     *
294     * @param bytes
295     *            the {@code byte[]} to be filled with random bytes.
296     * @since Android 1.0
297     */
298    public synchronized void nextBytes(byte[] bytes) {
299        secureRandomSpi.engineNextBytes(bytes);
300    }
301
302    /**
303     * Generates and returns an {@code int} containing the specified number of
304     * random bits (right justified, with leading zeros).
305     *
306     * @param numBits
307     *            number of bits to be generated. An input value should be in
308     *            the range [0, 32].
309     * @return an {@code int} containing the specified number of random bits.
310     * @since Android 1.0
311     */
312    protected final int next(int numBits) {
313        if (numBits < 0) {
314            numBits = 0;
315        } else {
316            if (numBits > 32) {
317                numBits = 32;
318            }
319        }
320        int bytes = (numBits+7)/8;
321        byte[] next = new byte[bytes];
322        int ret = 0;
323
324        nextBytes(next);
325        for (int i = 0; i < bytes; i++) {
326            ret = (next[i] & 0xFF) | (ret << 8);
327        }
328        ret = ret >>> (bytes*8 - numBits);
329        return ret;
330    }
331
332    /**
333     * Generates and returns the specified number of seed bytes, computed using
334     * the seed generation algorithm used by this {@code SecureRandom}.
335     *
336     * @param numBytes
337     *            the number of seed bytes.
338     * @return the seed bytes
339     * @since Android 1.0
340     */
341    public static byte[] getSeed(int numBytes) {
342        if (internalSecureRandom == null) {
343            internalSecureRandom = new SecureRandom();
344        }
345        return internalSecureRandom.generateSeed(numBytes);
346    }
347
348    /**
349     * Generates and returns the specified number of seed bytes, computed using
350     * the seed generation algorithm used by this {@code SecureRandom}.
351     *
352     * @param numBytes
353     *            the number of seed bytes.
354     * @return the seed bytes.
355     * @since Android 1.0
356     */
357    public byte[] generateSeed(int numBytes) {
358        return secureRandomSpi.engineGenerateSeed(numBytes);
359    }
360
361}
362