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 org.apache.harmony.security.tests.java.security;
19
20import java.security.NoSuchAlgorithmException;
21import java.security.NoSuchProviderException;
22import java.security.Provider;
23import java.security.SecureRandom;
24import java.security.SecureRandomSpi;
25import java.security.Security;
26import junit.framework.TestCase;
27
28public class SecureRandom2Test extends TestCase {
29
30    private static final byte[] SEED_BYTES = { (byte) 33, (byte) 15, (byte) -3,
31            (byte) 22, (byte) 77, (byte) -16, (byte) -33, (byte) 56 };
32
33    private static final int SEED_SIZE = 539;
34
35    private static final long SEED_VALUE = 5335486759L;
36
37    public void testGetProvider() {
38        SecureRandom sr1 = new SecureRandom();
39        assertNotNull(sr1.getProvider());
40
41        SecureRandom sr2 = new SecureRandom(SEED_BYTES);
42        assertNotNull(sr2.getProvider());
43
44        MyProvider p = new MyProvider();
45
46        MySecureRandom sr3 = new MySecureRandom(new MySecureRandomSpi(), p);
47        assertEquals(p, sr3.getProvider());
48        try {
49            SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
50            assertNotNull(random.getProvider());
51        } catch (NoSuchAlgorithmException e) {
52            fail("Unexpected NoSuchAlgorithmException");
53        }
54    }
55
56    /**
57     * java.security.SecureRandom#SecureRandom()
58     */
59    public void test_Constructor() {
60        // Test for method java.security.SecureRandom()
61        try {
62            new SecureRandom();
63        } catch (Exception e) {
64            fail("Constructor threw exception : " + e);
65        }
66    }
67
68    /**
69     * java.security.SecureRandom#SecureRandom(byte[])
70     */
71    public void test_Constructor$B() {
72        // Test for method java.security.SecureRandom(byte [])
73        try {
74            new SecureRandom(SEED_BYTES);
75        } catch (Exception e) {
76            fail("Constructor threw exception : " + e);
77        }
78
79        try {
80            new SecureRandom(null);
81            fail("NullPointerException was not thrown for NULL parameter");
82        } catch (NullPointerException e) {
83            //expected
84        }
85    }
86
87    /**
88     * java.security.SecureRandom#SecureRandom(java.security.SecureRandomSpi, java.security.Provider)
89     */
90    public void test_ConstructorLjava_security_SecureRandomSpi_java_security_Provider() {
91        try {
92            new MySecureRandom(null, null);
93        } catch (Exception e) {
94            fail("Constructor threw exception : " + e);
95        }
96
97        try {
98            MyProvider p = new MyProvider();
99            MySecureRandom sr = new MySecureRandom(new MySecureRandomSpi(), p);
100            assertEquals("unknown", sr.getAlgorithm());
101            assertEquals(p, sr.getProvider());
102
103            sr = new MySecureRandom(new MySecureRandomSpi(), null);
104            sr = new MySecureRandom(null, p);
105        } catch (Exception e) {
106            fail("Constructor threw exception : " + e);
107        }
108
109    }
110
111    /**
112     * java.security.SecureRandom#generateSeed(int)
113     */
114    public void test_generateSeedI() {
115        // Test for method byte [] java.security.SecureRandom.generateSeed(int)
116        byte[] seed = new SecureRandom().generateSeed(SEED_SIZE);
117        assertEquals("seed has incorrect size", SEED_SIZE, seed.length);
118
119        try {
120            new SecureRandom().generateSeed(-42);
121            fail("expected an exception");
122        } catch (Exception e) {
123            // ok
124        }
125
126    }
127    /**
128     * java.security.SecureRandom#getInstance(java.lang.String)
129     */
130    public void test_getInstanceLjava_lang_String() {
131        // Test for method java.security.SecureRandom
132        // java.security.SecureRandom.getInstance(java.lang.String)
133        try {
134            SecureRandom.getInstance("SHA1PRNG");
135        } catch (NoSuchAlgorithmException e) {
136            fail("getInstance did not find a SHA1PRNG algorithm");
137        }
138
139        try {
140            SecureRandom.getInstance("MD2");
141            fail("NoSuchAlgorithmException should be thrown for MD2 algorithm");
142        } catch (NoSuchAlgorithmException e) {
143            //expected
144        }
145    }
146
147    /**
148     * java.security.SecureRandom#getInstance(java.lang.String, java.lang.String)
149     */
150    public void test_getInstanceLjava_lang_StringLjava_lang_String() {
151        // Test for method java.security.SecureRandom
152        // java.security.SecureRandom.getInstance(java.lang.String,
153        // java.lang.String)
154        try {
155            Provider[] providers = Security
156                    .getProviders("SecureRandom.SHA1PRNG");
157            if (providers != null) {
158                for (int i = 0; i < providers.length; i++) {
159                    SecureRandom
160                            .getInstance("SHA1PRNG", providers[i].getName());
161                }// end for
162            } else {
163                fail("No providers support SHA1PRNG");
164            }
165        } catch (NoSuchAlgorithmException e) {
166            fail("getInstance did not find a SHA1PRNG algorithm");
167        } catch (NoSuchProviderException e) {
168            fail("getInstance did not find the provider for SHA1PRNG");
169        }
170    }
171
172    /**
173     * java.security.SecureRandom#getSeed(int)
174     */
175    public void test_getSeedI() {
176        // Test for method byte [] java.security.SecureRandom.getSeed(int)
177        byte[] seed = SecureRandom.getSeed(SEED_SIZE);
178        assertEquals("seed has incorrect size", SEED_SIZE, seed.length);
179
180        try {
181            new SecureRandom().getSeed(-42);
182            fail("expected an exception");
183        } catch (Exception e) {
184            // ok
185        }
186    }
187
188    /**
189     * java.security.SecureRandom#nextBytes(byte[])
190     */
191    public void test_nextBytes$B() {
192        // Test for method void java.security.SecureRandom.nextBytes(byte [])
193        byte[] bytes = new byte[313];
194        try {
195            new SecureRandom().nextBytes(bytes);
196        } catch (Exception e) {
197            fail("next bytes not ok : " + e);
198        }
199
200        try {
201            new SecureRandom().nextBytes(null);
202            fail("expected exception");
203        } catch (Exception e) {
204            // ok
205        }
206    }
207
208    /**
209     * java.security.SecureRandom#setSeed(byte[])
210     */
211    public void test_setSeed$B() {
212        // Test for method void java.security.SecureRandom.setSeed(byte [])
213        try {
214            new SecureRandom().setSeed(SEED_BYTES);
215        } catch (Exception e) {
216            fail("seed generation with bytes failed : " + e);
217        }
218
219        try {
220            new SecureRandom().setSeed(null);
221            fail("expected exception");
222        } catch (Exception e) {
223            // ok
224        }
225    }
226
227    /**
228     * java.security.SecureRandom#setSeed(long)
229     */
230    public void test_setSeedJ() {
231        // Test for method void java.security.SecureRandom.setSeed(long)
232        try {
233            new SecureRandom().setSeed(SEED_VALUE);
234        } catch (Exception e) {
235            fail("seed generation with long failed : " + e);
236        }
237
238        try {
239            new SecureRandom().setSeed(-1);
240        } catch (Exception e) {
241            fail("unexpected exception: " + e);
242        }
243    }
244
245    /**
246     * java.security.SecureRandom#getAlgorithm()
247     */
248    public void test_getAlgorithm() {
249        // Regression for HARMONY-750
250
251        SecureRandomSpi spi = new SecureRandomSpi() {
252
253            protected void engineSetSeed(byte[] arg) {
254            }
255
256            protected void engineNextBytes(byte[] arg) {
257            }
258
259            protected byte[] engineGenerateSeed(int arg) {
260                return null;
261            }
262        };
263
264        SecureRandom sr = new SecureRandom(spi, null) {
265        };
266
267        assertEquals("unknown", sr.getAlgorithm());
268
269
270    }
271
272    // Regression Test for HARMONY-3552.
273    public void test_nextJ() throws Exception {
274        MySecureRandom mySecureRandom = new MySecureRandom(
275                new MySecureRandomSpi(), null);
276        int numBits = 29;
277        int random = mySecureRandom.getNext(numBits);
278        assertEquals(numBits, Integer.bitCount(random));
279
280        numBits = 0;
281        random = mySecureRandom.getNext(numBits);
282        assertEquals(numBits, Integer.bitCount(random));
283
284        numBits = 40;
285        random = mySecureRandom.getNext(numBits);
286        assertEquals(32, Integer.bitCount(random));
287
288        numBits = -1;
289        random = mySecureRandom.getNext(numBits);
290        assertEquals(0, Integer.bitCount(random));
291
292
293    }
294
295    /**
296     * Two {@link SecureRandom} objects, created with
297     * {@link SecureRandom#getInstance(String)} and initialized before use
298     * with the same seed, should return the same results.<p>
299     *
300     * In the future, it may sense to disallow seeding {@code SecureRandom},
301     * as it tends to be error prone and open up security holes.
302     * See {@link SecureRandom} for more details about insecure seeding.
303     *
304     * Note that this only works with the Harmony "Crypto" provider.
305     */
306    public void testSameSeedGeneratesSameResults() throws Exception {
307        byte[] seed1 = { 'a', 'b', 'c' };
308        SecureRandom sr1 = SecureRandom.getInstance("SHA1PRNG", "Crypto");
309        sr1.setSeed(seed1);
310
311        byte[] seed2 = { 'a', 'b', 'c' };
312        SecureRandom sr2 = SecureRandom.getInstance("SHA1PRNG", "Crypto");
313        sr2.setSeed(seed2);
314
315        assertTrue(sr1.nextLong() == sr2.nextLong());
316    }
317
318    /**
319     * Assert that a {@link SecureRandom} object seeded from a constant
320     * seed always returns the same value, even across VM restarts.
321     *
322     * Future versions of Android may change the implementation of
323     * SHA1PRNG, so users of {@code SecureRandom} should not assume
324     * the same seed will always produce the same value.  This test
325     * is not a guarantee of future compatibility.
326     *
327     * In fact, this test only works with the Harmony "Crypto" provider.
328     */
329    public void testAlwaysSameValueWithSameSeed() throws Exception {
330        byte[] seed1 = { 'a', 'b', 'c' };
331        SecureRandom sr1 = SecureRandom.getInstance("SHA1PRNG", "Crypto");
332        sr1.setSeed(seed1);
333
334        // This long value has no special meaning and may change in the future.
335        assertEquals(6180693691264871500l, sr1.nextLong());
336    }
337
338    /**
339     * Validate that calling {@link SecureRandom#setSeed} <b>after</b> generating
340     * a random number compliments, but doesn't replace, the existing seed.
341     *
342     * Compare this test to {@link #testAlwaysSameValueWithSameSeed()}.
343     */
344    public void testSetSeedComplimentsAfterFirstRandomNumber() throws Exception {
345        byte[] seed1 = { 'a', 'b', 'c' };
346        SecureRandom sr1 = SecureRandom.getInstance("SHA1PRNG");
347        sr1.nextInt();
348        sr1.setSeed(seed1);
349
350        // This long value has no special meaning
351        assertTrue(6180693691264871500l != sr1.nextLong());
352    }
353
354    class MySecureRandom extends SecureRandom {
355        private static final long serialVersionUID = 1L;
356
357        public MySecureRandom(SecureRandomSpi secureRandomSpi, Provider provider) {
358            super(secureRandomSpi, provider);
359        }
360
361        public int getNext(int numBits) {
362            return super.next(numBits);
363        }
364    }
365
366    class MySecureRandomSpi extends SecureRandomSpi {
367        private static final long serialVersionUID = 1L;
368
369        @Override
370        protected byte[] engineGenerateSeed(int arg0) {
371            return null;
372        }
373
374        @Override
375        protected void engineNextBytes(byte[] bytes) {
376            for (int i = 0; i < bytes.length; i++) {
377                bytes[i] = (byte) 0xFF;
378            }
379        }
380
381        @Override
382        protected void engineSetSeed(byte[] arg0) {
383            return;
384        }
385    }
386
387    class MyProvider extends Provider {
388
389        MyProvider() {
390            super("MyProvider", 1.0, "Provider for testing");
391            put("MessageDigest.SHA-1", "SomeClassName");
392            put("MessageDigest.abc", "SomeClassName");
393            put("Alg.Alias.MessageDigest.SHA1", "SHA-1");
394        }
395
396        MyProvider(String name, double version, String info) {
397            super(name, version, info);
398        }
399
400        public void putService(Provider.Service s) {
401            super.putService(s);
402        }
403
404        public void removeService(Provider.Service s) {
405            super.removeService(s);
406        }
407
408    }
409}
410