/* * 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.provider.crypto; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.SecureRandom; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * Tests against methods in SecureRandom class object using SHA1PRNG_SecureRandomImpl. */ public class SHA1PRNG_SecureRandomTest extends TestCase { private static final int LENGTH = 20; // constant defining loop limit private static final int INCR = 2; // constant defining loop increment private static final String algorithm = "SHA1PRNG"; // algorithm's name private static final String provider = "Crypto"; // provider's name private static SecureRandom sr; // fields used by tests private static SecureRandom sr2; // /* * @see TestCase#setUp() */ protected void setUp() throws Exception { super.setUp(); sr = SecureRandom.getInstance(algorithm, provider); sr2 = SecureRandom.getInstance(algorithm, provider); } /** * test against the "void generateSeed(int)" method; * it checks out that the method throws NegativeArraySizeException if argument <0 */ public final void testGenerateSeedint01() { try { sr.generateSeed(-1); fail("generateSeed(-1) :: No NegativeArraySizeException"); } catch (NegativeArraySizeException e) { } } /** * test against the "void generateSeed(int)" method; * it checks out that number of bits returned is equal to one requested; * the check includes case for argument's value == 0; */ public final void testGenerateSeedint02() { for ( int i = 0; i < LENGTH; i++ ) { byte[] myBytes = sr.generateSeed(i); assertFalse("unexpected: myBytes.length != i :: i==" + i + " myBytes.length=" + myBytes.length, myBytes.length != i); } } /** * test against the "void generateSeed(int)" method; * it checks out the quality of entropy * (# of different bytes in sequential calls is more or equal to 50%) */ public final void testGenerateSeedint03() { byte[] myBytes1; byte[] myBytes2; for ( int i = 0; i < LENGTH; i+=INCR ) { int n = 0; myBytes1 = sr.generateSeed(i); myBytes2 = sr.generateSeed(i); for ( int j = 0; j < i; j++ ) { if ( myBytes1[j] == myBytes2[j] ) { n++; } } assertFalse("unexpected: n*2 > i :: i=" + i + " n=" + n, n*2 > i ); } } /** * test against the "void nextBytes(byte[])" method; * it checks out that the method throws NPE if argument supplied is null */ public final void testNextBytesbyteArray01() { try { sr.nextBytes(null); fail("unexpected: nextBytes(null) :: No NullPointerException"); } catch (NullPointerException e) { } } /** * test against the "void nextBytes(byte[])" method; * it checks out that different SecureRandom objects * being supplied with the same seed return the same sequencies of bytes * as results of their "nextBytes(byte[])" methods */ public final void testNextBytesbyteArray02() { byte[] myBytes; byte[] myBytes1; byte[] myBytes2; // case1: sequencies are of the same length for ( int i = 1; i < LENGTH; i+=INCR ) { myBytes = new byte[i]; for ( int j = 1; j < i ; j++ ) { myBytes[j] = (byte)(j&0xFF); } sr.setSeed(myBytes); sr2.setSeed(myBytes); for ( int k = 1; k < LENGTH; k+=INCR ) { myBytes1 = new byte[k]; myBytes2 = new byte[k]; sr.nextBytes(myBytes1); sr2.nextBytes(myBytes2); for ( int l = 0; l < k; l++ ) { assertFalse("unexpected: myBytes1[l] != myBytes2[l] :: l==" + l + " k=" + k + " i=" + i + " myBytes1[l]=" + myBytes1[l] + " myBytes2[l]=" + myBytes2[l], myBytes1[l] != myBytes2[l] ); } } } // case2: sequencies are of different lengths for ( int n = 1; n < LENGTH; n+=INCR ) { int n1 = 10; int n2 = 20; int n3 = 100; byte[][] bytes1 = new byte[10][n1]; byte[][] bytes2 = new byte[ 5][n2]; for ( int k = 0; k < bytes1.length; k++ ) { sr.nextBytes(bytes1[k]); } for ( int k = 0; k < bytes2.length; k++) { sr2.nextBytes(bytes2[k]); } for ( int k = 0; k < n3 ; k++ ) { int i1 = k /n1; int i2 = k %n1; int i3 = k /n2; int i4 = k %n2; assertTrue("non-equality: i1="+ i1 +" i2="+i2 +" i3="+i3 +" i4=" +i4, bytes1[i1][i2] == bytes2[i3][i4]); } } } /** * test against the "void nextBytes(byte[])" method; * it checks out that different SecureRandom objects * being supplied with seed by themselves return different sequencies of bytes * as results of their "nextBytes(byte[])" methods */ public final void testNextBytesbyteArray03() throws NoSuchAlgorithmException, NoSuchProviderException { SecureRandom sr1; // these are needed to test new SecureRandom objects in loop SecureRandom sr2; // byte[] myBytes1; byte[] myBytes2; for ( int i = 1; i < LENGTH/2; i+=INCR ) { sr1 = SecureRandom.getInstance(algorithm, provider); sr2 = SecureRandom.getInstance(algorithm, provider); boolean flag = true; myBytes1 = new byte[i]; myBytes2 = new byte[i]; sr1.nextBytes(myBytes1); sr2.nextBytes(myBytes2); for ( int j = 0; j < i; j++ ) { flag &= myBytes1[j] == myBytes2[j]; } // check again to avoid intermittent failures sr1.nextBytes(myBytes1); sr2.nextBytes(myBytes2); for ( int j = 0; j < i; j++ ) { flag &= myBytes1[j] == myBytes2[j]; } if ( flag ) { // probability of false failure is 1.5*10^-5 per run for i=1 or less for i > 1 fail("TESTING RANDOM NUMBER GENERATOR QUALITY: IGNORE THIS FAILURE IF INTERMITTENT :: i=" + i); } } } /** * test against the "void nextBytes(byte[])" method; * it checks out behavior of SecureRandom object in cases of passing * byte array of zero length to "nextBytes(byte[])" method. * The test contains two testcases: * - first testcase checks out that if for two newly created SecureRandom objects * invocation of "nextBytes(new byte[0])" method are first ones * then further calls to nextBytes(..) methods return different byte arrays, * that is, first "nextBytes(new byte[0])" aslo randomizes internal state; * - second testcase checks out that if for two newly created SecureRandom objects * invocation of "setSeed(..)" methods are first ones * then further calls to "nextBytes(new byte[0])" methods has no effect */ public final void testNextBytesbyteArray04() throws NoSuchAlgorithmException, NoSuchProviderException { SecureRandom sr1; // these are needed to test new SecureRandom objects in loop SecureRandom sr2; // byte[] myBytes; byte[] myBytes1; byte[] myBytes2; // case 1: for ( int i = 1; i < LENGTH/2; i+=INCR ) { sr1 = SecureRandom.getInstance(algorithm, provider); sr2 = SecureRandom.getInstance(algorithm, provider); sr1.nextBytes(new byte[0]); sr2.nextBytes(new byte[0]); boolean flag = true; myBytes1 = new byte[i]; myBytes2 = new byte[i]; sr1.nextBytes(myBytes1); sr2.nextBytes(myBytes2); for ( int j = 0; j < i; j++ ) { flag &= myBytes1[j] == myBytes2[j]; } // check again to avoid intermittent failures sr1.nextBytes(myBytes1); sr2.nextBytes(myBytes2); for ( int j = 0; j < i; j++ ) { flag &= myBytes1[j] == myBytes2[j]; } if ( flag ) { // probability of false failure is 1.5*10^-5 per run for i=1 or less for i > 1 fail("TESTING RANDOM NUMBER GENERATOR QUALITY: IGNORE THIS FAILURE IF INTERMITTENT :: i=" + i); } } myBytes = new byte[] { (byte)0 }; // case2: for ( int n = 1; n < LENGTH; n+=INCR ) { byte[][] bytes1 = new byte[2][n]; byte[][] bytes2 = new byte[2][n]; sr1 = SecureRandom.getInstance(algorithm, provider); sr2 = SecureRandom.getInstance(algorithm, provider); sr1.setSeed(myBytes); sr2.setSeed(myBytes); sr1.nextBytes(bytes1[0]); sr1.nextBytes(bytes1[1]); sr2.nextBytes(bytes2[0]); sr2.nextBytes(new byte[0]); sr2.nextBytes(bytes2[1]); for ( int k = 0; k < 2 ; k++ ) { for ( int j = 0; j < n; j++ ) { assertTrue("non-equality: k="+ k +" j="+j + " bytes1[k][j]="+bytes1[k][j] +" bytes2[k][j]=" +bytes2[k][j], bytes1[k][j] == bytes2[k][j] ); } } } } /** * test against the "void setSeed(byte[])" method; * it checks out that the method throws NPE if argument supplied is null */ public final void testSetSeedbyteArray01() { try { sr.setSeed(null); fail("setSeed(null) :: No NullPointerException"); } catch (NullPointerException e) { } } /** * test against the "void setSeed(byte[])" method; * it checks out that "setSeed(byte[])" method supplements its argument to current seed * rather than replaces current seed */ public final void testSetSeedbyteArray02() throws NoSuchFieldException, SecurityException, IllegalAccessException { byte[] seed = new byte[LENGTH]; byte[] bytes1 = new byte[LENGTH]; byte[] bytes2 = new byte[LENGTH]; boolean b; for (int i = 0; i < seed.length; i++) { seed[i] = (byte)i; } sr.setSeed(seed); sr.setSeed(seed); sr2.setSeed(seed); sr.nextBytes(bytes1); sr2.nextBytes(bytes2); b = true; for (int j = 0; j < bytes1.length; j++) { b &= bytes1[j] == bytes2[j]; } assertFalse("unexpected: sequences are equal", b); } /** * test against the "void setSeed(byte[])" method; * it checks out that the "byte[0]" argument has no effect; there are two testcases: * - if one of two SecureRandom objects supplied with the same seed is additionally * supplied with such array, "nextBytes(..)" of both objects return the same bytes; * - two byte arrays returned by "nextBytes(..)" in following sequence * nextBytes(..); setSeed(new byte[0]); nextBytes(..); * don't contain the same byte sequencies. */ public final void testSetSeedbyteArray03() throws NoSuchFieldException, SecurityException, IllegalAccessException { byte[] seed = new byte[LENGTH]; byte[] bytes1; byte[] bytes2; for (int i = 0; i < seed.length; i++) { seed[i] = (byte)i; } // testcase begins with "bytes1" and "bytes2" of zero length for ( int i = 0; i < LENGTH; i++ ) { bytes1 = new byte[i]; bytes2 = new byte[i]; sr.setSeed(seed); sr.setSeed(new byte[0]); sr.nextBytes(bytes1); sr2.setSeed(seed); sr2.nextBytes(bytes2); for (int j = 0; j < bytes1.length; j++) { assertEquals("bytes1[j] != bytes2[j] :: j=" +j, bytes1[j], bytes2[j]); } } for ( int i = 1; i < LENGTH; i++ ) { bytes1 = new byte[i]; bytes2 = new byte[i]; sr.setSeed(seed); sr.nextBytes(bytes1); sr.setSeed(new byte[0]); sr.nextBytes(bytes2); boolean b = true; for (int j = 0; j < bytes1.length; j++) { b &= bytes1[j] == bytes2[j] ; } assertFalse("sequences are equal i=" + i, b); } } public static Test suite() { return new TestSuite(SHA1PRNG_SecureRandomTest.class); } }