Home | History | Annotate | Download | only in crypto
      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 package org.apache.harmony.security.tests.provider.crypto;
     19 
     20 import java.lang.reflect.Field;
     21 import java.lang.reflect.Method;
     22 import java.security.NoSuchAlgorithmException;
     23 import java.security.NoSuchProviderException;
     24 import java.security.SecureRandom;
     25 
     26 import junit.framework.TestCase;
     27 
     28 /**
     29  * Tests against methods in SecureRandom class object using
     30  * SHA1PRNG_SecureRandomImpl.
     31  */
     32 public class SHA1PRNG_SecureRandomTest extends TestCase {
     33 
     34     private static final int LENGTH = 20; // constant defining loop limit
     35 
     36     private static final int INCR = 2; // constant defining loop increment
     37 
     38     private static final String algorithm = "SHA1PRNG"; // algorithm's name
     39 
     40     private static final String provider = "Crypto"; // provider's name
     41 
     42     private static SecureRandom sr; // fields used by tests
     43 
     44     private static SecureRandom sr2; //
     45 
     46     /*
     47      * @see TestCase#setUp()
     48      */
     49     protected void setUp() throws Exception {
     50         super.setUp();
     51         sr = SecureRandom.getInstance(algorithm, provider);
     52         sr2 = SecureRandom.getInstance(algorithm, provider);
     53     }
     54 
     55     /**
     56      * test against the "void generateSeed(int)" method; it checks out that the
     57      * method throws NegativeArraySizeException if argument <0
     58      */
     59     public final void testGenerateSeedint01() {
     60         try {
     61             sr.generateSeed(-1);
     62             fail("generateSeed(-1) :: No NegativeArraySizeException");
     63         } catch (NegativeArraySizeException e) {
     64         }
     65     }
     66 
     67     /**
     68      * test against the "void generateSeed(int)" method; it checks out that
     69      * number of bits returned is equal to one requested; the check includes
     70      * case for argument's value == 0;
     71      */
     72     public final void testGenerateSeedint02() {
     73         for (int i = 0; i < LENGTH; i++) {
     74             byte[] myBytes = sr.generateSeed(i);
     75             assertFalse("unexpected: myBytes.length != i  :: i==" + i + " myBytes.length="
     76                     + myBytes.length, myBytes.length != i);
     77         }
     78     }
     79 
     80     /**
     81      * test against the "void generateSeed(int)" method; it checks out the
     82      * quality of entropy (# of different bytes in sequential calls is more or
     83      * equal to 50%)
     84      */
     85     public final void testGenerateSeedint03() {
     86         byte[] myBytes1;
     87         byte[] myBytes2;
     88 
     89         for (int i = 0; i < LENGTH; i += INCR) {
     90             int n = 0;
     91             myBytes1 = sr.generateSeed(i);
     92             myBytes2 = sr.generateSeed(i);
     93 
     94             for (int j = 0; j < i; j++) {
     95                 if (myBytes1[j] == myBytes2[j]) {
     96                     n++;
     97                 }
     98             }
     99             assertFalse("unexpected: n*2 > i  :: i=" + i + " n=" + n, n * 2 > i);
    100         }
    101     }
    102 
    103     /**
    104      * test against the "void nextBytes(byte[])" method; it checks out that the
    105      * method throws NPE if argument supplied is null
    106      */
    107     public final void testNextBytesbyteArray01() {
    108         try {
    109             sr.nextBytes(null);
    110             fail("unexpected: nextBytes(null) :: No NullPointerException");
    111         } catch (NullPointerException e) {
    112         }
    113     }
    114 
    115     /**
    116      * test against the "void nextBytes(byte[])" method; it checks out that
    117      * different SecureRandom objects being supplied with the same seed return
    118      * the same sequencies of bytes as results of their "nextBytes(byte[])"
    119      * methods
    120      */
    121     public final void testNextBytesbyteArray02() {
    122         byte[] myBytes;
    123         byte[] myBytes1;
    124         byte[] myBytes2;
    125 
    126         // case1: sequencies are of the same length
    127         for (int i = 1; i < LENGTH; i += INCR) {
    128             myBytes = new byte[i];
    129 
    130             for (int j = 1; j < i; j++) {
    131                 myBytes[j] = (byte) (j & 0xFF);
    132             }
    133             sr.setSeed(myBytes);
    134             sr2.setSeed(myBytes);
    135 
    136             for (int k = 1; k < LENGTH; k += INCR) {
    137                 myBytes1 = new byte[k];
    138                 myBytes2 = new byte[k];
    139                 sr.nextBytes(myBytes1);
    140                 sr2.nextBytes(myBytes2);
    141 
    142                 for (int l = 0; l < k; l++) {
    143                     assertFalse("unexpected: myBytes1[l] != myBytes2[l]  :: l==" + l + " k=" + k
    144                             + " i=" + i + " myBytes1[l]=" + myBytes1[l] + " myBytes2[l]="
    145                             + myBytes2[l], myBytes1[l] != myBytes2[l]);
    146                 }
    147             }
    148         }
    149 
    150         // case2: sequencies are of different lengths
    151         for (int n = 1; n < LENGTH; n += INCR) {
    152             int n1 = 10;
    153             int n2 = 20;
    154             int n3 = 100;
    155             byte[][] bytes1 = new byte[10][n1];
    156             byte[][] bytes2 = new byte[5][n2];
    157 
    158             for (int k = 0; k < bytes1.length; k++) {
    159                 sr.nextBytes(bytes1[k]);
    160             }
    161             for (int k = 0; k < bytes2.length; k++) {
    162                 sr2.nextBytes(bytes2[k]);
    163             }
    164 
    165             for (int k = 0; k < n3; k++) {
    166                 int i1 = k / n1;
    167                 int i2 = k % n1;
    168                 int i3 = k / n2;
    169                 int i4 = k % n2;
    170                 assertTrue("non-equality: i1=" + i1 + " i2=" + i2 + " i3=" + i3 + " i4=" + i4,
    171                         bytes1[i1][i2] == bytes2[i3][i4]);
    172             }
    173         }
    174     }
    175 
    176     /**
    177      * test against the "void nextBytes(byte[])" method; it checks out that
    178      * different SecureRandom objects being supplied with seed by themselves
    179      * return different sequencies of bytes as results of their
    180      * "nextBytes(byte[])" methods
    181      */
    182     public final void testNextBytesbyteArray03() throws NoSuchAlgorithmException,
    183             NoSuchProviderException {
    184         /* these are needed to test new SecureRandom objects in loop */
    185         SecureRandom sr1;
    186         SecureRandom sr2;
    187 
    188         byte[] myBytes1;
    189         byte[] myBytes2;
    190 
    191         for (int i = 1; i < LENGTH / 2; i += INCR) {
    192             sr1 = SecureRandom.getInstance(algorithm, provider);
    193             sr2 = SecureRandom.getInstance(algorithm, provider);
    194 
    195             boolean flag = true;
    196 
    197             myBytes1 = new byte[i];
    198             myBytes2 = new byte[i];
    199 
    200             sr1.nextBytes(myBytes1);
    201             sr2.nextBytes(myBytes2);
    202             for (int j = 0; j < i; j++) {
    203                 flag &= myBytes1[j] == myBytes2[j];
    204             }
    205 
    206             // check again to avoid intermittent failures
    207             sr1.nextBytes(myBytes1);
    208             sr2.nextBytes(myBytes2);
    209             for (int j = 0; j < i; j++) {
    210                 flag &= myBytes1[j] == myBytes2[j];
    211             }
    212 
    213             if (flag) {
    214                 // probability of false failure is 1.5*10^-5 per run for i=1 or
    215                 // less for i > 1
    216                 fail("TESTING RANDOM NUMBER GENERATOR QUALITY: IGNORE THIS FAILURE IF INTERMITTENT :: i="
    217                         + i);
    218             }
    219         }
    220     }
    221 
    222     /**
    223      * test against the "void nextBytes(byte[])" method; it checks out behavior
    224      * of SecureRandom object in cases of passing byte array of zero length to
    225      * "nextBytes(byte[])" method. The test contains two testcases: - first
    226      * testcase checks out that if for two newly created SecureRandom objects
    227      * invocation of "nextBytes(new byte[0])" method are first ones then further
    228      * calls to nextBytes(..) methods return different byte arrays, that is,
    229      * first "nextBytes(new byte[0])" aslo randomizes internal state; - second
    230      * testcase checks out that if for two newly created SecureRandom objects
    231      * invocation of "setSeed(..)" methods are first ones then further calls to
    232      * "nextBytes(new byte[0])" methods has no effect
    233      */
    234     public final void testNextBytesbyteArray04() throws NoSuchAlgorithmException,
    235             NoSuchProviderException {
    236         /*
    237          * these are needed to test new SecureRandom objects in loop
    238          */
    239         SecureRandom sr1;
    240         SecureRandom sr2;
    241 
    242         byte[] myBytes;
    243         byte[] myBytes1;
    244         byte[] myBytes2;
    245 
    246         // case 1:
    247         for (int i = 1; i < LENGTH / 2; i += INCR) {
    248             sr1 = SecureRandom.getInstance(algorithm, provider);
    249             sr2 = SecureRandom.getInstance(algorithm, provider);
    250 
    251             sr1.nextBytes(new byte[0]);
    252             sr2.nextBytes(new byte[0]);
    253 
    254             boolean flag = true;
    255 
    256             myBytes1 = new byte[i];
    257             myBytes2 = new byte[i];
    258 
    259             sr1.nextBytes(myBytes1);
    260             sr2.nextBytes(myBytes2);
    261             for (int j = 0; j < i; j++) {
    262                 flag &= myBytes1[j] == myBytes2[j];
    263             }
    264 
    265             // check again to avoid intermittent failures
    266             sr1.nextBytes(myBytes1);
    267             sr2.nextBytes(myBytes2);
    268             for (int j = 0; j < i; j++) {
    269                 flag &= myBytes1[j] == myBytes2[j];
    270             }
    271 
    272             if (flag) {
    273                 // probability of false failure is 1.5*10^-5 per run for i=1 or
    274                 // less for i > 1
    275                 fail("TESTING RANDOM NUMBER GENERATOR QUALITY: IGNORE THIS FAILURE IF INTERMITTENT :: i="
    276                         + i);
    277             }
    278         }
    279 
    280         myBytes = new byte[] {
    281             (byte) 0
    282         };
    283 
    284         // case2:
    285         for (int n = 1; n < LENGTH; n += INCR) {
    286             byte[][] bytes1 = new byte[2][n];
    287             byte[][] bytes2 = new byte[2][n];
    288 
    289             sr1 = SecureRandom.getInstance(algorithm, provider);
    290             sr2 = SecureRandom.getInstance(algorithm, provider);
    291 
    292             sr1.setSeed(myBytes);
    293             sr2.setSeed(myBytes);
    294 
    295             sr1.nextBytes(bytes1[0]);
    296             sr1.nextBytes(bytes1[1]);
    297 
    298             sr2.nextBytes(bytes2[0]);
    299             sr2.nextBytes(new byte[0]);
    300             sr2.nextBytes(bytes2[1]);
    301 
    302             for (int k = 0; k < 2; k++) {
    303                 for (int j = 0; j < n; j++) {
    304                     assertTrue("non-equality: k=" + k + " j=" + j + " bytes1[k][j]=" + bytes1[k][j]
    305                             + " bytes2[k][j]=" + bytes2[k][j], bytes1[k][j] == bytes2[k][j]);
    306                 }
    307             }
    308         }
    309     }
    310 
    311     /**
    312      * test against the "void setSeed(byte[])" method; it checks out that the
    313      * method throws NPE if argument supplied is null
    314      */
    315     public final void testSetSeedbyteArray01() {
    316         try {
    317             sr.setSeed(null);
    318             fail("setSeed(null) :: No NullPointerException");
    319         } catch (NullPointerException e) {
    320         }
    321     }
    322 
    323     /**
    324      * test against the "void setSeed(byte[])" method; it checks out that
    325      * "setSeed(byte[])" method supplements its argument to current seed rather
    326      * than replaces current seed
    327      */
    328     public final void testSetSeedbyteArray02() throws NoSuchFieldException, SecurityException,
    329             IllegalAccessException {
    330         byte[] seed = new byte[LENGTH];
    331         byte[] bytes1 = new byte[LENGTH];
    332         byte[] bytes2 = new byte[LENGTH];
    333         boolean b;
    334 
    335         for (int i = 0; i < seed.length; i++) {
    336             seed[i] = (byte) i;
    337         }
    338 
    339         sr.setSeed(seed);
    340         sr.setSeed(seed);
    341         sr2.setSeed(seed);
    342 
    343         sr.nextBytes(bytes1);
    344         sr2.nextBytes(bytes2);
    345 
    346         b = true;
    347         for (int j = 0; j < bytes1.length; j++) {
    348             b &= bytes1[j] == bytes2[j];
    349         }
    350         assertFalse("unexpected: sequences are equal", b);
    351     }
    352 
    353     /**
    354      * test against the "void setSeed(byte[])" method; it checks out that the
    355      * "byte[0]" argument has no effect; there are two testcases: - if one of
    356      * two SecureRandom objects supplied with the same seed is additionally
    357      * supplied with such array, "nextBytes(..)" of both objects return the same
    358      * bytes; - two byte arrays returned by "nextBytes(..)" in following
    359      * sequence nextBytes(..); setSeed(new byte[0]); nextBytes(..); don't
    360      * contain the same byte sequencies.
    361      */
    362     public final void testSetSeedbyteArray03() throws NoSuchFieldException, SecurityException,
    363             IllegalAccessException {
    364         byte[] seed = new byte[LENGTH];
    365         byte[] bytes1;
    366         byte[] bytes2;
    367 
    368         for (int i = 0; i < seed.length; i++) {
    369             seed[i] = (byte) i;
    370         }
    371 
    372         // testcase begins with "bytes1" and "bytes2" of zero length
    373         for (int i = 0; i < LENGTH; i++) {
    374             bytes1 = new byte[i];
    375             bytes2 = new byte[i];
    376 
    377             sr.setSeed(seed);
    378             sr.setSeed(new byte[0]);
    379             sr.nextBytes(bytes1);
    380 
    381             sr2.setSeed(seed);
    382             sr2.nextBytes(bytes2);
    383 
    384             for (int j = 0; j < bytes1.length; j++) {
    385                 assertEquals("bytes1[j] != bytes2[j] :: j=" + j, bytes1[j], bytes2[j]);
    386             }
    387         }
    388 
    389         for (int i = 1; i < LENGTH; i++) {
    390             bytes1 = new byte[i];
    391             bytes2 = new byte[i];
    392 
    393             sr.setSeed(seed);
    394             sr.nextBytes(bytes1);
    395             sr.setSeed(new byte[0]);
    396             sr.nextBytes(bytes2);
    397 
    398             boolean b = true;
    399             for (int j = 0; j < bytes1.length; j++) {
    400                 b &= bytes1[j] == bytes2[j];
    401             }
    402             assertFalse("sequences are equal i=" + i, b);
    403         }
    404     }
    405 
    406     public void testSeedIsFullLength() throws Exception {
    407         Class<?> srClass = Class.forName(
    408                 "org.apache.harmony.security.provider.crypto.SHA1PRNG_SecureRandomImpl");
    409         Field seedField = srClass.getDeclaredField("seed");
    410         seedField.setAccessible(true);
    411 
    412         Method nextBytesMethod = srClass.getDeclaredMethod("engineNextBytes", byte[].class);
    413         nextBytesMethod.setAccessible(true);
    414 
    415         byte[] bytes = new byte[1];
    416 
    417         // Iterate 8 times to make sure the probability of a false positive is
    418         // extremely rare.
    419         for (int i = 0; i < 8; i++) {
    420             Object sr = srClass.newInstance();
    421             nextBytesMethod.invoke(sr, bytes);
    422             int[] seed = (int[]) seedField.get(sr);
    423 
    424             // If the first integer is not zero, it is fixed.
    425             if (seed[0] != 0) {
    426                 return; // Success
    427             }
    428         }
    429 
    430         fail("Fallback SHA1PRNG_SecureRandomImpl should not clobber seed internally");
    431     }
    432 }
    433