blob: 88cc0155ecc9a9d544d282dceda92ec6dc5b4e33 [file] [log] [blame]
/*
* 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);
}
}
}