Home | History | Annotate | Download | only in security
      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 /**
     19 * @author Vladimir N. Molotkov
     20 * @version $Revision$
     21 */
     22 
     23 package org.apache.harmony.security.tests.java.security;
     24 
     25 import java.io.ByteArrayInputStream;
     26 import java.io.IOException;
     27 import java.io.InputStream;
     28 import java.security.DigestInputStream;
     29 import java.security.MessageDigest;
     30 import java.security.NoSuchAlgorithmException;
     31 import java.util.Arrays;
     32 
     33 import junit.framework.TestCase;
     34 
     35 import org.apache.harmony.security.tests.support.MDGoldenData;
     36 
     37 /**
     38  * Tests for fields and methods of class <code>DigestInputStream</code>
     39  *
     40  */
     41 public class DigestInputStreamTest extends TestCase {
     42 
     43     /**
     44      * Message digest algorithm name used during testing
     45      */
     46     private static final String algorithmName[] = {
     47             "SHA-1",
     48             "SHA",
     49             "SHA1",
     50             "SHA-256",
     51             "SHA-384",
     52             "SHA-512",
     53             "MD5",
     54     };
     55     /**
     56      * Chunk size for read(byte, off, len) tests
     57      */
     58     private static final int CHUNK_SIZE = 32;
     59     /**
     60      * Test message for digest computations
     61      */
     62     private static final byte[] myMessage = MDGoldenData.getMessage();
     63     /**
     64      * The length of test message
     65      */
     66     private static final int MY_MESSAGE_LEN = myMessage.length;
     67 
     68     //
     69     // Tests
     70     //
     71 
     72     /**
     73      * Test #1 for <code>DigestInputStream</code> constructor<br>
     74      *
     75      * Assertion: creates new <code>DigestInputStream</code> instance
     76      * using valid parameters (both non <code>null</code>)
     77      *
     78      * @throws NoSuchAlgorithmException
     79      */
     80     public final void testDigestInputStream01()  {
     81         for (int i=0; i<algorithmName.length; i++) {
     82             try {
     83                 MessageDigest md = MessageDigest.getInstance(algorithmName[i]);
     84                 InputStream is = new ByteArrayInputStream(myMessage);
     85                 InputStream dis = new DigestInputStream(is, md);
     86                 assertTrue(dis instanceof DigestInputStream);
     87                 return;
     88             } catch (NoSuchAlgorithmException e) {
     89                 // allowed failure
     90             }
     91         }
     92         fail(getName() + ": no MessageDigest algorithms available - test not performed");
     93     }
     94 
     95     /**
     96      * Test #2 for <code>DigestInputStream</code> constructor<br>
     97      *
     98      * Assertion: creates new <code>DigestInputStream</code> instance
     99      * using valid parameters (both <code>null</code>)
    100      */
    101     public final void testDigestInputStream02() {
    102         InputStream dis = new DigestInputStream(null, null);
    103         assertTrue(dis instanceof DigestInputStream);
    104     }
    105 
    106     /**
    107      * Test #1 for <code>read()</code> method<br>
    108      *
    109      * Assertion: returns the byte read<br>
    110      * Assertion: updates associated digest<br>
    111      */
    112     public final void testRead01()
    113         throws IOException {
    114         for (int ii=0; ii<algorithmName.length; ii++) {
    115             try {
    116                 MessageDigest md = MessageDigest.getInstance(algorithmName[ii]);
    117                 InputStream is = new ByteArrayInputStream(myMessage);
    118                 DigestInputStream dis = new DigestInputStream(is, md);
    119                 for (int i=0; i<MY_MESSAGE_LEN; i++) {
    120                     // check that read() returns valid values
    121                     assertTrue("retval", ((byte)dis.read() == myMessage[i]));
    122                 }
    123                 // check that associated digest has been updated properly
    124                 assertTrue("update",
    125                         Arrays.equals(
    126                                 dis.getMessageDigest().digest(),
    127                                 MDGoldenData.getDigest(algorithmName[ii])));
    128                 return;
    129             } catch (NoSuchAlgorithmException e) {
    130                 // allowed failure
    131             }
    132         }
    133         fail(getName() + ": no MessageDigest algorithms available - test not performed");
    134     }
    135 
    136     /**
    137      * Test #2 for <code>read()</code> method<br>
    138      *
    139      * Assertion: returns -1 if EOS had been
    140      * reached but not read before method call<br>
    141      *
    142      * Assertion: must not update digest if EOS had been
    143      * reached but not read before method call<br>
    144      */
    145     public final void testRead02()
    146         throws IOException {
    147         for (int ii=0; ii<algorithmName.length; ii++) {
    148             try {
    149                 MessageDigest md = MessageDigest.getInstance(algorithmName[ii]);
    150                 InputStream is = new ByteArrayInputStream(myMessage);
    151                 DigestInputStream dis = new DigestInputStream(is, md);
    152                 for (int i=0; i<MY_MESSAGE_LEN; i++) {
    153                     dis.read();
    154                 }
    155                 // check that subsequent read() calls return -1 (eos)
    156                 assertEquals("retval1", -1, dis.read());
    157                 assertEquals("retval2", -1, dis.read());
    158                 assertEquals("retval3", -1, dis.read());
    159                 // check that 3 previous read() calls did not update digest
    160                 assertTrue("update",
    161                         Arrays.equals(dis.getMessageDigest().digest(),
    162                                 MDGoldenData.getDigest(algorithmName[ii])));
    163                 return;
    164             } catch (NoSuchAlgorithmException e) {
    165                 // allowed failure
    166             }
    167         }
    168         fail(getName() + ": no MessageDigest algorithms available - test not performed");
    169     }
    170 
    171     /**
    172      * Test #3 for <code>read()</code> method<br>
    173      * Test #1 for <code>on(boolean)</code> method<br>
    174      *
    175      * Assertion: <code>read()</code> must not update digest if it is off<br>
    176      * Assertion: <code>on(boolean)</code> turns digest functionality on
    177      * (if <code>true</code> passed as a parameter) or off (if <code>false</code>
    178      *  passed)
    179      */
    180     public final void testRead03()
    181         throws IOException {
    182         for (int ii=0; ii<algorithmName.length; ii++) {
    183             try {
    184                 MessageDigest md = MessageDigest.getInstance(algorithmName[ii]);
    185                 InputStream is = new ByteArrayInputStream(myMessage);
    186                 DigestInputStream dis = new DigestInputStream(is, md);
    187 
    188                 // turn digest off
    189                 dis.on(false);
    190 
    191                 for (int i=0; i<MY_MESSAGE_LEN; i++) {
    192                     dis.read();
    193                 }
    194 
    195                 // check that digest value has not been updated by read()
    196                 assertTrue(Arrays.equals(dis.getMessageDigest().digest(),
    197                         MDGoldenData.getDigest(algorithmName[ii]+"_NU")));
    198                 return;
    199             } catch (NoSuchAlgorithmException e) {
    200                 // allowed failure
    201             }
    202         }
    203         fail(getName() + ": no MessageDigest algorithms available - test not performed");
    204     }
    205 
    206     /**
    207      * Test #4 for <code>read()</code> method<br>
    208      *
    209      * Assertion: broken <code>DigestInputStream</code>instance:
    210      * <code>InputStream</code> not set. <code>read()</code> must
    211      * not work
    212      */
    213     public final void testRead04() throws IOException {
    214         for (int ii=0; ii<algorithmName.length; ii++) {
    215             try {
    216                 MessageDigest md = MessageDigest.getInstance(algorithmName[ii]);
    217                 DigestInputStream dis = new DigestInputStream(null, md);
    218                 // must result in an exception
    219                 try {
    220                     for (int i=0; i<MY_MESSAGE_LEN; i++) {
    221                         dis.read();
    222                     }
    223                 } catch (Exception e) {
    224                     // Expected.
    225                     return;
    226                 }
    227 
    228                 fail("InputStream not set. read() must not work");
    229 
    230             } catch (NoSuchAlgorithmException e) {
    231                 // allowed failure
    232             }
    233         }
    234         fail(getName() + ": no MessageDigest algorithms available - test not performed");
    235     }
    236 
    237     /**
    238      * Test #5 for <code>read()</code> method<br>
    239      *
    240      * Assertion: broken <code>DigestInputStream</code>instance:
    241      * associated <code>MessageDigest</code> not set.
    242      * <code>read()</code> must not work when digest
    243      * functionality is on
    244      */
    245     public final void testRead05() {
    246         InputStream is = new ByteArrayInputStream(myMessage);
    247         DigestInputStream dis = new DigestInputStream(is, null);
    248 
    249         // must result in an exception
    250         try {
    251             for (int i=0; i<MY_MESSAGE_LEN; i++) {
    252                 dis.read();
    253             }
    254             fail("read() must not work when digest functionality is on");
    255         } catch (Exception e) {
    256             // Expected.
    257         }
    258     }
    259 
    260     /**
    261      * Test #6 for <code>read()</code> method<br>
    262      * Test #2 for <code>on(boolean)</code> method<br>
    263      *
    264      * Assertion: broken <code>DigestInputStream</code>instance:
    265      * associated <code>MessageDigest</code> not set.
    266      * <code>read()</code> must work when digest
    267      * functionality is off
    268      */
    269     public final void testRead06()
    270         throws IOException {
    271         InputStream is = new ByteArrayInputStream(myMessage);
    272         // construct object without digest
    273         DigestInputStream dis = new DigestInputStream(is, null);
    274         // set digest functionality to off
    275         dis.on(false);
    276         // the following must pass without any exception
    277         for (int i=0; i<MY_MESSAGE_LEN; i++) {
    278             assertTrue((byte)dis.read() == myMessage[i]);
    279         }
    280     }
    281 
    282     /**
    283      * Test #1 for <code>read(byte[],int,int)</code> method<br>
    284      *
    285      * Assertion: returns the number of bytes read<br>
    286      *
    287      * Assertion: put bytes read into specified array at specified offset<br>
    288      *
    289      * Assertion: updates associated digest<br>
    290      */
    291     public final void testReadbyteArrayintint01()
    292         throws IOException {
    293         for (int ii=0; ii<algorithmName.length; ii++) {
    294             try {
    295                 MessageDigest md = MessageDigest.getInstance(algorithmName[ii]);
    296                 InputStream is = new ByteArrayInputStream(myMessage);
    297                 DigestInputStream dis = new DigestInputStream(is, md);
    298                 byte[] bArray = new byte[MY_MESSAGE_LEN];
    299 
    300                 // check that read(byte[],int,int) returns valid value
    301                 assertTrue("retval",
    302                         dis.read(bArray, 0, bArray.length) == MY_MESSAGE_LEN);
    303                 // check that bArray has been filled properly
    304                 assertTrue("bArray", Arrays.equals(myMessage, bArray));
    305                 // check that associated digest has been updated properly
    306                 assertTrue("update", Arrays.equals(dis.getMessageDigest().digest(),
    307                         MDGoldenData.getDigest(algorithmName[ii])));
    308                 return;
    309             } catch (NoSuchAlgorithmException e) {
    310                 // allowed failure
    311             }
    312         }
    313         fail(getName() + ": no MessageDigest algorithms available - test not performed");
    314     }
    315 
    316     /**
    317      * Test #2 for <code>read(byte[],int,int)</code> method<br>
    318      *
    319      * Assertion: returns the number of bytes read<br>
    320      *
    321      * Assertion: put bytes read into specified array at specified offset<br>
    322      *
    323      * Assertion: updates associated digest<br>
    324      */
    325     public final void testReadbyteArrayintint02()
    326         throws IOException {
    327         // check precondition
    328         assertEquals(0, MY_MESSAGE_LEN % CHUNK_SIZE);
    329 
    330         for (int ii=0; ii<algorithmName.length; ii++) {
    331             try {
    332                 MessageDigest md = MessageDigest.getInstance(algorithmName[ii]);
    333                 InputStream is = new ByteArrayInputStream(myMessage);
    334                 DigestInputStream dis = new DigestInputStream(is, md);
    335                 byte[] bArray = new byte[MY_MESSAGE_LEN];
    336 
    337                 for (int i=0; i<MY_MESSAGE_LEN/CHUNK_SIZE; i++) {
    338                     // check that read(byte[],int,int) returns valid value
    339                     assertTrue("retval",
    340                             dis.read(bArray, i*CHUNK_SIZE, CHUNK_SIZE) == CHUNK_SIZE);
    341                 }
    342                 // check that bArray has been filled properly
    343                 assertTrue("bArray", Arrays.equals(myMessage, bArray));
    344                 // check that associated digest has been updated properly
    345                 assertTrue("update", Arrays.equals(dis.getMessageDigest().digest(),
    346                         MDGoldenData.getDigest(algorithmName[ii])));
    347                 return;
    348             } catch (NoSuchAlgorithmException e) {
    349                 // allowed failure
    350             }
    351         }
    352         fail(getName() + ": no MessageDigest algorithms available - test not performed");
    353     }
    354 
    355 
    356     /**
    357      * Test #3 for <code>read(byte[],int,int)</code> method<br>
    358      *
    359      * Assertion: returns the number of bytes read<br>
    360      *
    361      * Assertion: put bytes read into specified array at specified offset<br>
    362      *
    363      * Assertion: updates associated digest<br>
    364      */
    365     public final void testReadbyteArrayintint03()
    366         throws IOException {
    367         // check precondition
    368         assertTrue(MY_MESSAGE_LEN % (CHUNK_SIZE+1) != 0);
    369 
    370         for (int ii=0; ii<algorithmName.length; ii++) {
    371             try {
    372                 MessageDigest md = MessageDigest.getInstance(algorithmName[ii]);
    373                 InputStream is = new ByteArrayInputStream(myMessage);
    374                 DigestInputStream dis = new DigestInputStream(is, md);
    375                 byte[] bArray = new byte[MY_MESSAGE_LEN];
    376 
    377                 for (int i=0; i<MY_MESSAGE_LEN/(CHUNK_SIZE+1); i++) {
    378                     // check that read(byte[],int,int) returns valid value
    379                     assertTrue("retval1",
    380                             dis.read(bArray, i*(CHUNK_SIZE+1), CHUNK_SIZE+1) ==
    381                                 CHUNK_SIZE + 1);
    382                 }
    383 
    384                 // check that last call returns right
    385                 // number of remaining bytes
    386                 assertTrue("retval2",
    387                         dis.read(bArray,
    388                                 MY_MESSAGE_LEN/(CHUNK_SIZE+1)*(CHUNK_SIZE+1),
    389                                 MY_MESSAGE_LEN % (CHUNK_SIZE+1)) ==
    390                                     (MY_MESSAGE_LEN % (CHUNK_SIZE+1)));
    391 
    392                 // check that bArray has been filled properly
    393                 assertTrue("bArray", Arrays.equals(myMessage, bArray));
    394                 // check that associated digest has been updated properly
    395                 assertTrue("update", Arrays.equals(dis.getMessageDigest().digest(),
    396                         MDGoldenData.getDigest(algorithmName[ii])));
    397                 return;
    398             } catch (NoSuchAlgorithmException e) {
    399                 // allowed failure
    400             }
    401         }
    402         fail(getName() + ": no MessageDigest algorithms available - test not performed");
    403     }
    404 
    405     /**
    406      * Test #4 for <code>read(byte[],int,int)</code> method<br>
    407      *
    408      * Assertion: returns the number of bytes read<br>
    409      *
    410      * Assertion: updates associated digest<br>
    411      */
    412     public final void testReadbyteArrayintint04()
    413         throws IOException {
    414         for (int ii=0; ii<algorithmName.length; ii++) {
    415             try {
    416                 MessageDigest md = MessageDigest.getInstance(algorithmName[ii]);
    417                 InputStream is = new ByteArrayInputStream(myMessage);
    418                 DigestInputStream dis = new DigestInputStream(is, md);
    419                 byte[] bArray = new byte[MY_MESSAGE_LEN];
    420                 // read all but EOS
    421                 dis.read(bArray, 0, bArray.length);
    422                 // check that subsequent read(byte[],int,int) calls return -1 (EOS)
    423                 assertEquals("retval1", -1, dis.read(bArray, 0, 1));
    424                 assertEquals("retval2", -1, dis.read(bArray, 0, bArray.length));
    425                 assertEquals("retval3", -1, dis.read(bArray, 0, 1));
    426                 // check that 3 previous read() calls did not update digest
    427                 assertTrue("update",
    428                         Arrays.equals(dis.getMessageDigest().digest(),
    429                                 MDGoldenData.getDigest(algorithmName[ii])));
    430                 return;
    431             } catch (NoSuchAlgorithmException e) {
    432                 // allowed failure
    433             }
    434         }
    435         fail(getName() + ": no MessageDigest algorithms available - test not performed");
    436     }
    437 
    438     /**
    439      * Test #5 for <code>read(byte[],int,int)</code> method<br>
    440      *
    441      * Assertion: returns the number of bytes read<br>
    442      *
    443      * Assertion: put bytes read into specified array at specified offset<br>
    444      *
    445      * Assertion: does not update associated digest if
    446      * digest functionality is off<br>
    447      */
    448     public final void testReadbyteArrayintint05()
    449         throws IOException {
    450         // check precondition
    451         assertEquals(0, MY_MESSAGE_LEN % CHUNK_SIZE);
    452 
    453         for (int ii=0; ii<algorithmName.length; ii++) {
    454             try {
    455                 MessageDigest md = MessageDigest.getInstance(algorithmName[ii]);
    456                 InputStream is = new ByteArrayInputStream(myMessage);
    457                 DigestInputStream dis = new DigestInputStream(is, md);
    458                 byte[] bArray = new byte[MY_MESSAGE_LEN];
    459 
    460                 // turn digest off
    461                 dis.on(false);
    462 
    463                 for (int i=0; i<MY_MESSAGE_LEN/CHUNK_SIZE; i++) {
    464                     dis.read(bArray, i*CHUNK_SIZE, CHUNK_SIZE);
    465                 }
    466                 // check that digest has not been updated
    467                 assertTrue(Arrays.equals(dis.getMessageDigest().digest(),
    468                         MDGoldenData.getDigest(algorithmName[ii]+"_NU")));
    469                 return;
    470             } catch (NoSuchAlgorithmException e) {
    471                 // allowed failure
    472             }
    473         }
    474         fail(getName() + ": no MessageDigest algorithms available - test not performed");
    475     }
    476 
    477     /**
    478      * Test for <code>getMessageDigest()</code> method<br>
    479      *
    480      * Assertion: returns associated message digest<br>
    481      */
    482     public final void testGetMessageDigest() {
    483         for (int ii=0; ii<algorithmName.length; ii++) {
    484             try {
    485                 MessageDigest md = MessageDigest.getInstance(algorithmName[ii]);
    486                 DigestInputStream dis = new DigestInputStream(null, md);
    487 
    488                 assertTrue(dis.getMessageDigest() == md);
    489                 return;
    490             } catch (NoSuchAlgorithmException e) {
    491                 // allowed failure
    492             }
    493         }
    494         fail(getName() + ": no MessageDigest algorithms available - test not performed");
    495     }
    496 
    497 
    498     /**
    499      * Test for <code>setMessageDigest()</code> method<br>
    500      *
    501      * Assertion: set associated message digest<br>
    502      */
    503     public final void testSetMessageDigest() {
    504         for (int ii=0; ii<algorithmName.length; ii++) {
    505             try {
    506                 DigestInputStream dis = new DigestInputStream(null, null);
    507                 MessageDigest md = MessageDigest.getInstance(algorithmName[ii]);
    508                 dis.setMessageDigest(md);
    509 
    510                 assertTrue(dis.getMessageDigest() == md);
    511                 return;
    512             } catch (NoSuchAlgorithmException e) {
    513                 // allowed failure
    514             }
    515         }
    516         fail(getName() + ": no MessageDigest algorithms available - test not performed");
    517     }
    518 
    519     /**
    520      * Test for <code>on()</code> method<br>
    521      * Assertion: turns digest functionality on or off
    522      */
    523     public final void testOn() throws IOException {
    524         for (int ii=0; ii<algorithmName.length; ii++) {
    525             try {
    526                 MessageDigest md = MessageDigest.getInstance(algorithmName[ii]);
    527                 InputStream is = new ByteArrayInputStream(myMessage);
    528                 DigestInputStream dis = new DigestInputStream(is, md);
    529 
    530                 // turn digest off
    531                 dis.on(false);
    532 
    533                 for (int i=0; i<MY_MESSAGE_LEN-1; i++) {
    534                     dis.read();
    535                 }
    536 
    537                 // turn digest on
    538                 dis.on(true);
    539 
    540                 // read remaining byte
    541                 dis.read();
    542 
    543                 byte[] digest = dis.getMessageDigest().digest();
    544 
    545                 // check that digest value has been
    546                 // updated by the last read() call
    547                 assertFalse(
    548                         Arrays.equals(digest,MDGoldenData.getDigest(algorithmName[ii])) ||
    549                         Arrays.equals(digest,MDGoldenData.getDigest(algorithmName[ii]+"_NU")));
    550                 return;
    551             } catch (NoSuchAlgorithmException e) {
    552                 // allowed failure
    553             }
    554         }
    555         fail(getName() + ": no MessageDigest algorithms available - test not performed");
    556     }
    557 
    558     /**
    559      * Test for <code>toString()</code> method<br>
    560      * Assertion: returns <code>String</code> representation of this object
    561      */
    562     public final void testToString() {
    563         for (int ii=0; ii<algorithmName.length; ii++) {
    564             try {
    565                 MessageDigest md = MessageDigest.getInstance(algorithmName[ii]);
    566                 InputStream is = new ByteArrayInputStream(myMessage);
    567                 DigestInputStream dis = new DigestInputStream(is, md);
    568 
    569                 assertNotNull(dis.toString());
    570                 return;
    571             } catch (NoSuchAlgorithmException e) {
    572                 // allowed failure
    573             }
    574         }
    575         fail(getName() + ": no MessageDigest algorithms available - test not performed");
    576     }
    577 
    578 }
    579