| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.apache.harmony.security.tests.java.security; |
| |
| import dalvik.annotation.TestTargetClass; |
| import dalvik.annotation.TestTargetNew; |
| import dalvik.annotation.TestTargets; |
| import dalvik.annotation.TestLevel; |
| |
| import java.security.NoSuchAlgorithmException; |
| import java.security.NoSuchProviderException; |
| import java.security.Provider; |
| import java.security.SecureRandom; |
| import java.security.SecureRandomSpi; |
| import java.security.Security; |
| |
| import junit.framework.TestCase; |
| @TestTargetClass(SecureRandom.class) |
| public class SecureRandom2Test extends TestCase { |
| |
| private static final byte[] SEED_BYTES = { (byte) 33, (byte) 15, (byte) -3, |
| (byte) 22, (byte) 77, (byte) -16, (byte) -33, (byte) 56 }; |
| |
| private static final int SEED_SIZE = 539; |
| |
| private static final long SEED_VALUE = 5335486759L; |
| |
| @TestTargetNew( |
| level = TestLevel.COMPLETE, |
| notes = "", |
| method = "getProvider", |
| args = {} |
| ) |
| public void testGetProvider() { |
| SecureRandom sr1 = new SecureRandom(); |
| assertNotNull(sr1.getProvider()); |
| |
| SecureRandom sr2 = new SecureRandom(SEED_BYTES); |
| assertNotNull(sr2.getProvider()); |
| |
| MyProvider p = new MyProvider(); |
| |
| MySecureRandom sr3 = new MySecureRandom(new MySecureRandomSpi(), p); |
| assertEquals(p, sr3.getProvider()); |
| try { |
| SecureRandom random = SecureRandom.getInstance("SHA1PRNG"); |
| assertNotNull(random.getProvider()); |
| } catch (NoSuchAlgorithmException e) { |
| fail("Unexpected NoSuchAlgorithmException"); |
| } |
| } |
| |
| /** |
| * @tests java.security.SecureRandom#SecureRandom() |
| */ |
| @TestTargetNew( |
| level = TestLevel.COMPLETE, |
| notes = "", |
| method = "SecureRandom", |
| args = {} |
| ) |
| public void test_Constructor() { |
| // Test for method java.security.SecureRandom() |
| try { |
| new SecureRandom(); |
| } catch (Exception e) { |
| fail("Constructor threw exception : " + e); |
| } |
| } |
| |
| /** |
| * @tests java.security.SecureRandom#SecureRandom(byte[]) |
| */ |
| @TestTargetNew( |
| level = TestLevel.COMPLETE, |
| notes = "", |
| method = "SecureRandom", |
| args = {byte[].class} |
| ) |
| public void test_Constructor$B() { |
| // Test for method java.security.SecureRandom(byte []) |
| try { |
| new SecureRandom(SEED_BYTES); |
| } catch (Exception e) { |
| fail("Constructor threw exception : " + e); |
| } |
| |
| try { |
| new SecureRandom(null); |
| fail("NullPointerException was not thrown for NULL parameter"); |
| } catch (NullPointerException e) { |
| //expected |
| } |
| } |
| |
| /** |
| * @tests java.security.SecureRandom#SecureRandom(java.security.SecureRandomSpi, |
| * java.security.Provider) |
| */ |
| @TestTargetNew( |
| level = TestLevel.COMPLETE, |
| notes = "", |
| method = "SecureRandom", |
| args = {java.security.SecureRandomSpi.class, java.security.Provider.class} |
| ) |
| public void test_ConstructorLjava_security_SecureRandomSpi_java_security_Provider() { |
| try { |
| new MySecureRandom(null, null); |
| } catch (Exception e) { |
| fail("Constructor threw exception : " + e); |
| } |
| |
| try { |
| MyProvider p = new MyProvider(); |
| MySecureRandom sr = new MySecureRandom(new MySecureRandomSpi(), p); |
| assertEquals("unknown", sr.getAlgorithm()); |
| assertEquals(p, sr.getProvider()); |
| |
| sr = new MySecureRandom(new MySecureRandomSpi(), null); |
| sr = new MySecureRandom(null, p); |
| } catch (Exception e) { |
| fail("Constructor threw exception : " + e); |
| } |
| |
| } |
| |
| /** |
| * @tests java.security.SecureRandom#generateSeed(int) |
| */ |
| @TestTargetNew( |
| level = TestLevel.PARTIAL_COMPLETE, |
| notes = "", |
| method = "generateSeed", |
| args = {int.class} |
| ) |
| public void test_generateSeedI() { |
| // Test for method byte [] java.security.SecureRandom.generateSeed(int) |
| byte[] seed = new SecureRandom().generateSeed(SEED_SIZE); |
| assertEquals("seed has incorrect size", SEED_SIZE, seed.length); |
| |
| try { |
| new SecureRandom().generateSeed(-42); |
| fail("expected an exception"); |
| } catch (Exception e) { |
| // ok |
| } |
| |
| } |
| /** |
| * @tests java.security.SecureRandom#getInstance(java.lang.String) |
| */ |
| @TestTargetNew( |
| level = TestLevel.COMPLETE, |
| notes = "", |
| method = "getInstance", |
| args = {java.lang.String.class} |
| ) |
| public void test_getInstanceLjava_lang_String() { |
| // Test for method java.security.SecureRandom |
| // java.security.SecureRandom.getInstance(java.lang.String) |
| try { |
| SecureRandom.getInstance("SHA1PRNG"); |
| } catch (NoSuchAlgorithmException e) { |
| fail("getInstance did not find a SHA1PRNG algorithm"); |
| } |
| |
| try { |
| SecureRandom.getInstance("MD2"); |
| fail("NoSuchAlgorithmException should be thrown for MD2 algorithm"); |
| } catch (NoSuchAlgorithmException e) { |
| //expected |
| } |
| } |
| |
| /** |
| * @tests java.security.SecureRandom#getInstance(java.lang.String, |
| * java.lang.String) |
| */ |
| @TestTargetNew( |
| level = TestLevel.PARTIAL, |
| notes = "NoSuchAlgorithmException, NoSuchProviderException, IllegalArgumentException checking missed", |
| method = "getInstance", |
| args = {java.lang.String.class, java.lang.String.class} |
| ) |
| public void test_getInstanceLjava_lang_StringLjava_lang_String() { |
| // Test for method java.security.SecureRandom |
| // java.security.SecureRandom.getInstance(java.lang.String, |
| // java.lang.String) |
| try { |
| Provider[] providers = Security |
| .getProviders("SecureRandom.SHA1PRNG"); |
| if (providers != null) { |
| for (int i = 0; i < providers.length; i++) { |
| SecureRandom |
| .getInstance("SHA1PRNG", providers[i].getName()); |
| }// end for |
| } else { |
| fail("No providers support SHA1PRNG"); |
| } |
| } catch (NoSuchAlgorithmException e) { |
| fail("getInstance did not find a SHA1PRNG algorithm"); |
| } catch (NoSuchProviderException e) { |
| fail("getInstance did not find the provider for SHA1PRNG"); |
| } |
| } |
| |
| /** |
| * @tests java.security.SecureRandom#getSeed(int) |
| */ |
| @TestTargetNew( |
| level = TestLevel.PARTIAL_COMPLETE, |
| notes = "Verification of negative parameter missed", |
| method = "getSeed", |
| args = {int.class} |
| ) |
| public void test_getSeedI() { |
| // Test for method byte [] java.security.SecureRandom.getSeed(int) |
| byte[] seed = SecureRandom.getSeed(SEED_SIZE); |
| assertEquals("seed has incorrect size", SEED_SIZE, seed.length); |
| |
| try { |
| new SecureRandom().getSeed(-42); |
| fail("expected an exception"); |
| } catch (Exception e) { |
| // ok |
| } |
| } |
| |
| /** |
| * @tests java.security.SecureRandom#nextBytes(byte[]) |
| */ |
| @TestTargetNew( |
| level = TestLevel.PARTIAL_COMPLETE, |
| notes = "Null array checking missed", |
| method = "nextBytes", |
| args = {byte[].class} |
| ) |
| public void test_nextBytes$B() { |
| // Test for method void java.security.SecureRandom.nextBytes(byte []) |
| byte[] bytes = new byte[313]; |
| try { |
| new SecureRandom().nextBytes(bytes); |
| } catch (Exception e) { |
| fail("next bytes not ok : " + e); |
| } |
| |
| try { |
| new SecureRandom().nextBytes(null); |
| fail("expected exception"); |
| } catch (Exception e) { |
| // ok |
| } |
| } |
| |
| /** |
| * @tests java.security.SecureRandom#setSeed(byte[]) |
| */ |
| @TestTargetNew( |
| level = TestLevel.PARTIAL_COMPLETE, |
| notes = "Null array checking missed", |
| method = "setSeed", |
| args = {byte[].class} |
| ) |
| public void test_setSeed$B() { |
| // Test for method void java.security.SecureRandom.setSeed(byte []) |
| try { |
| new SecureRandom().setSeed(SEED_BYTES); |
| } catch (Exception e) { |
| fail("seed generation with bytes failed : " + e); |
| } |
| |
| try { |
| new SecureRandom().setSeed(null); |
| fail("expected exception"); |
| } catch (Exception e) { |
| // ok |
| } |
| } |
| |
| /** |
| * @tests java.security.SecureRandom#setSeed(long) |
| */ |
| @TestTargetNew( |
| level = TestLevel.PARTIAL_COMPLETE, |
| notes = "", |
| method = "setSeed", |
| args = {long.class} |
| ) |
| public void test_setSeedJ() { |
| // Test for method void java.security.SecureRandom.setSeed(long) |
| try { |
| new SecureRandom().setSeed(SEED_VALUE); |
| } catch (Exception e) { |
| fail("seed generation with long failed : " + e); |
| } |
| |
| try { |
| new SecureRandom().setSeed(-1); |
| } catch (Exception e) { |
| fail("unexpected exception: " + e); |
| } |
| } |
| |
| /** |
| * @tests java.security.SecureRandom#getAlgorithm() |
| */ |
| @TestTargetNew( |
| level = TestLevel.COMPLETE, |
| notes = "", |
| method = "getAlgorithm", |
| args = {} |
| ) |
| public void test_getAlgorithm() { |
| // Regression for HARMONY-750 |
| |
| SecureRandomSpi spi = new SecureRandomSpi() { |
| |
| protected void engineSetSeed(byte[] arg) { |
| } |
| |
| protected void engineNextBytes(byte[] arg) { |
| } |
| |
| protected byte[] engineGenerateSeed(int arg) { |
| return null; |
| } |
| }; |
| |
| SecureRandom sr = new SecureRandom(spi, null) { |
| }; |
| |
| assertEquals("unknown", sr.getAlgorithm()); |
| |
| |
| } |
| |
| // Regression Test for HARMONY-3552. |
| @TestTargetNew( |
| level = TestLevel.COMPLETE, |
| notes = "", |
| method = "next", |
| args = {int.class} |
| ) |
| public void test_nextJ() throws Exception { |
| MySecureRandom mySecureRandom = new MySecureRandom( |
| new MySecureRandomSpi(), null); |
| int numBits = 29; |
| int random = mySecureRandom.getNext(numBits); |
| assertEquals(numBits, Integer.bitCount(random)); |
| |
| numBits = 0; |
| random = mySecureRandom.getNext(numBits); |
| assertEquals(numBits, Integer.bitCount(random)); |
| |
| numBits = 40; |
| random = mySecureRandom.getNext(numBits); |
| assertEquals(32, Integer.bitCount(random)); |
| |
| numBits = -1; |
| random = mySecureRandom.getNext(numBits); |
| assertEquals(0, Integer.bitCount(random)); |
| |
| |
| } |
| |
| /** |
| * Two {@link SecureRandom} objects, created with |
| * {@link SecureRandom#getInstance(String)} and initialized before use |
| * with the same seed, should return the same results.<p> |
| * |
| * In the future, it may sense to disallow seeding {@code SecureRandom}, |
| * as it tends to be error prone and open up security holes. |
| * See {@link SecureRandom} for more details about insecure seeding. |
| * |
| * @see #testSameSeedGeneratesSameResultsWhenConstructorIsUsed() |
| */ |
| public void testSameSeedGeneratesSameResults() throws Exception { |
| byte[] seed1 = { 'a', 'b', 'c' }; |
| SecureRandom sr1 = SecureRandom.getInstance("SHA1PRNG"); |
| sr1.setSeed(seed1); |
| |
| byte[] seed2 = { 'a', 'b', 'c' }; |
| SecureRandom sr2 = SecureRandom.getInstance("SHA1PRNG"); |
| sr2.setSeed(seed2); |
| |
| assertTrue(sr1.nextLong() == sr2.nextLong()); |
| } |
| |
| /** |
| * Same tests as {@link #testSameSeedGeneratesSameResults()}, except |
| * here we use the constructor, not {@link SecureRandom#getInstance(String)}. |
| * |
| * Note that Android behaves differently than the reference implementation. |
| * This test fails on the reference implementation. |
| * |
| * In the future, it may make sense to change our implementation to |
| * match the reference implementation. It may also make sense to |
| * disallow seeding {@code SecureRandom} completely, as it tends to |
| * be error prone and open up security holes. See {@link SecureRandom} |
| * for more details about insecure seeding. |
| */ |
| public void testSameSeedGeneratesSameResultsWhenConstructorIsUsed() { |
| byte[] seed1 = { 'a', 'b', 'c' }; |
| SecureRandom sr1 = new SecureRandom(); |
| sr1.setSeed(seed1); |
| |
| byte[] seed2 = { 'a', 'b', 'c' }; |
| SecureRandom sr2 = new SecureRandom(); |
| sr2.setSeed(seed2); |
| |
| assertTrue(sr1.nextLong() == sr2.nextLong()); |
| } |
| |
| /** |
| * Assert that a {@link SecureRandom} object seeded from a constant |
| * seed always returns the same value, even across VM restarts. |
| * |
| * Future versions of Android may change the implementation of |
| * SHA1PRNG, so users of {@code SecureRandom} should not assume |
| * the same seed will always produce the same value. This test |
| * is not a guarantee of future compatibility. |
| */ |
| public void testAlwaysSameValueWithSameSeed() throws Exception { |
| byte[] seed1 = { 'a', 'b', 'c' }; |
| SecureRandom sr1 = SecureRandom.getInstance("SHA1PRNG"); |
| sr1.setSeed(seed1); |
| |
| // This long value has no special meaning and may change in the future. |
| assertEquals(6180693691264871500l, sr1.nextLong()); |
| } |
| |
| /** |
| * Validate that calling {@link SecureRandom#setSeed} <b>after</b> generating |
| * a random number compliments, but doesn't replace, the existing seed. |
| * |
| * Compare this test to {@link #testAlwaysSameValueWithSameSeed()}. |
| */ |
| public void testSetSeedComplimentsAfterFirstRandomNumber() throws Exception { |
| byte[] seed1 = { 'a', 'b', 'c' }; |
| SecureRandom sr1 = SecureRandom.getInstance("SHA1PRNG"); |
| sr1.nextInt(); |
| sr1.setSeed(seed1); |
| |
| // This long value has no special meaning |
| assertTrue(6180693691264871500l != sr1.nextLong()); |
| } |
| |
| class MySecureRandom extends SecureRandom { |
| private static final long serialVersionUID = 1L; |
| |
| public MySecureRandom(SecureRandomSpi secureRandomSpi, Provider provider) { |
| super(secureRandomSpi, provider); |
| } |
| |
| public int getNext(int numBits) { |
| return super.next(numBits); |
| } |
| } |
| |
| class MySecureRandomSpi extends SecureRandomSpi { |
| private static final long serialVersionUID = 1L; |
| |
| @Override |
| protected byte[] engineGenerateSeed(int arg0) { |
| return null; |
| } |
| |
| @Override |
| protected void engineNextBytes(byte[] bytes) { |
| for (int i = 0; i < bytes.length; i++) { |
| bytes[i] = (byte) 0xFF; |
| } |
| } |
| |
| @Override |
| protected void engineSetSeed(byte[] arg0) { |
| return; |
| } |
| } |
| |
| class MyProvider extends Provider { |
| |
| MyProvider() { |
| super("MyProvider", 1.0, "Provider for testing"); |
| put("MessageDigest.SHA-1", "SomeClassName"); |
| put("MessageDigest.abc", "SomeClassName"); |
| put("Alg.Alias.MessageDigest.SHA1", "SHA-1"); |
| } |
| |
| MyProvider(String name, double version, String info) { |
| super(name, version, info); |
| } |
| |
| public void putService(Provider.Service s) { |
| super.putService(s); |
| } |
| |
| public void removeService(Provider.Service s) { |
| super.removeService(s); |
| } |
| |
| } |
| } |