| /* |
| * 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. |
| */ |
| |
| /** |
| * @author Vladimir N. Molotkov |
| * @version $Revision$ |
| */ |
| |
| package org.apache.harmony.security.tests.java.security; |
| |
| import java.io.ByteArrayInputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.security.DigestInputStream; |
| import java.security.MessageDigest; |
| import java.security.NoSuchAlgorithmException; |
| import java.util.Arrays; |
| |
| import junit.framework.TestCase; |
| |
| import org.apache.harmony.security.tests.support.MDGoldenData; |
| |
| /** |
| * Tests for fields and methods of class <code>DigestInputStream</code> |
| * |
| */ |
| public class DigestInputStreamTest extends TestCase { |
| |
| /** |
| * Message digest algorithm name used during testing |
| */ |
| private static final String algorithmName[] = { |
| "SHA-1", |
| "SHA", |
| "SHA1", |
| "SHA-256", |
| "SHA-384", |
| "SHA-512", |
| "MD5", |
| }; |
| /** |
| * Chunk size for read(byte, off, len) tests |
| */ |
| private static final int CHUNK_SIZE = 32; |
| /** |
| * Test message for digest computations |
| */ |
| private static final byte[] myMessage = MDGoldenData.getMessage(); |
| /** |
| * The length of test message |
| */ |
| private static final int MY_MESSAGE_LEN = myMessage.length; |
| |
| // |
| // Tests |
| // |
| |
| /** |
| * Test #1 for <code>DigestInputStream</code> constructor<br> |
| * |
| * Assertion: creates new <code>DigestInputStream</code> instance |
| * using valid parameters (both non <code>null</code>) |
| * |
| * @throws NoSuchAlgorithmException |
| */ |
| public final void testDigestInputStream01() { |
| for (int i=0; i<algorithmName.length; i++) { |
| try { |
| MessageDigest md = MessageDigest.getInstance(algorithmName[i]); |
| InputStream is = new ByteArrayInputStream(myMessage); |
| InputStream dis = new DigestInputStream(is, md); |
| assertTrue(dis instanceof DigestInputStream); |
| return; |
| } catch (NoSuchAlgorithmException e) { |
| // allowed failure |
| } |
| } |
| fail(getName() + ": no MessageDigest algorithms available - test not performed"); |
| } |
| |
| /** |
| * Test #2 for <code>DigestInputStream</code> constructor<br> |
| * |
| * Assertion: creates new <code>DigestInputStream</code> instance |
| * using valid parameters (both <code>null</code>) |
| */ |
| public final void testDigestInputStream02() { |
| InputStream dis = new DigestInputStream(null, null); |
| assertTrue(dis instanceof DigestInputStream); |
| } |
| |
| /** |
| * Test #1 for <code>read()</code> method<br> |
| * |
| * Assertion: returns the byte read<br> |
| * Assertion: updates associated digest<br> |
| */ |
| public final void testRead01() |
| throws IOException { |
| for (int ii=0; ii<algorithmName.length; ii++) { |
| try { |
| MessageDigest md = MessageDigest.getInstance(algorithmName[ii]); |
| InputStream is = new ByteArrayInputStream(myMessage); |
| DigestInputStream dis = new DigestInputStream(is, md); |
| for (int i=0; i<MY_MESSAGE_LEN; i++) { |
| // check that read() returns valid values |
| assertTrue("retval", ((byte)dis.read() == myMessage[i])); |
| } |
| // check that associated digest has been updated properly |
| assertTrue("update", |
| Arrays.equals( |
| dis.getMessageDigest().digest(), |
| MDGoldenData.getDigest(algorithmName[ii]))); |
| return; |
| } catch (NoSuchAlgorithmException e) { |
| // allowed failure |
| } |
| } |
| fail(getName() + ": no MessageDigest algorithms available - test not performed"); |
| } |
| |
| /** |
| * Test #2 for <code>read()</code> method<br> |
| * |
| * Assertion: returns -1 if EOS had been |
| * reached but not read before method call<br> |
| * |
| * Assertion: must not update digest if EOS had been |
| * reached but not read before method call<br> |
| */ |
| public final void testRead02() |
| throws IOException { |
| for (int ii=0; ii<algorithmName.length; ii++) { |
| try { |
| MessageDigest md = MessageDigest.getInstance(algorithmName[ii]); |
| InputStream is = new ByteArrayInputStream(myMessage); |
| DigestInputStream dis = new DigestInputStream(is, md); |
| for (int i=0; i<MY_MESSAGE_LEN; i++) { |
| dis.read(); |
| } |
| // check that subsequent read() calls return -1 (eos) |
| assertEquals("retval1", -1, dis.read()); |
| assertEquals("retval2", -1, dis.read()); |
| assertEquals("retval3", -1, dis.read()); |
| // check that 3 previous read() calls did not update digest |
| assertTrue("update", |
| Arrays.equals(dis.getMessageDigest().digest(), |
| MDGoldenData.getDigest(algorithmName[ii]))); |
| return; |
| } catch (NoSuchAlgorithmException e) { |
| // allowed failure |
| } |
| } |
| fail(getName() + ": no MessageDigest algorithms available - test not performed"); |
| } |
| |
| /** |
| * Test #3 for <code>read()</code> method<br> |
| * Test #1 for <code>on(boolean)</code> method<br> |
| * |
| * Assertion: <code>read()</code> must not update digest if it is off<br> |
| * Assertion: <code>on(boolean)</code> turns digest functionality on |
| * (if <code>true</code> passed as a parameter) or off (if <code>false</code> |
| * passed) |
| */ |
| public final void testRead03() |
| throws IOException { |
| for (int ii=0; ii<algorithmName.length; ii++) { |
| try { |
| MessageDigest md = MessageDigest.getInstance(algorithmName[ii]); |
| InputStream is = new ByteArrayInputStream(myMessage); |
| DigestInputStream dis = new DigestInputStream(is, md); |
| |
| // turn digest off |
| dis.on(false); |
| |
| for (int i=0; i<MY_MESSAGE_LEN; i++) { |
| dis.read(); |
| } |
| |
| // check that digest value has not been updated by read() |
| assertTrue(Arrays.equals(dis.getMessageDigest().digest(), |
| MDGoldenData.getDigest(algorithmName[ii]+"_NU"))); |
| return; |
| } catch (NoSuchAlgorithmException e) { |
| // allowed failure |
| } |
| } |
| fail(getName() + ": no MessageDigest algorithms available - test not performed"); |
| } |
| |
| /** |
| * Test #4 for <code>read()</code> method<br> |
| * |
| * Assertion: broken <code>DigestInputStream</code>instance: |
| * <code>InputStream</code> not set. <code>read()</code> must |
| * not work |
| */ |
| public final void testRead04() throws IOException { |
| for (int ii=0; ii<algorithmName.length; ii++) { |
| try { |
| MessageDigest md = MessageDigest.getInstance(algorithmName[ii]); |
| DigestInputStream dis = new DigestInputStream(null, md); |
| // must result in an exception |
| try { |
| for (int i=0; i<MY_MESSAGE_LEN; i++) { |
| dis.read(); |
| } |
| } catch (Exception e) { |
| // Expected. |
| return; |
| } |
| |
| fail("InputStream not set. read() must not work"); |
| |
| } catch (NoSuchAlgorithmException e) { |
| // allowed failure |
| } |
| } |
| fail(getName() + ": no MessageDigest algorithms available - test not performed"); |
| } |
| |
| /** |
| * Test #5 for <code>read()</code> method<br> |
| * |
| * Assertion: broken <code>DigestInputStream</code>instance: |
| * associated <code>MessageDigest</code> not set. |
| * <code>read()</code> must not work when digest |
| * functionality is on |
| */ |
| public final void testRead05() { |
| InputStream is = new ByteArrayInputStream(myMessage); |
| DigestInputStream dis = new DigestInputStream(is, null); |
| |
| // must result in an exception |
| try { |
| for (int i=0; i<MY_MESSAGE_LEN; i++) { |
| dis.read(); |
| } |
| fail("read() must not work when digest functionality is on"); |
| } catch (Exception e) { |
| // Expected. |
| } |
| } |
| |
| /** |
| * Test #6 for <code>read()</code> method<br> |
| * Test #2 for <code>on(boolean)</code> method<br> |
| * |
| * Assertion: broken <code>DigestInputStream</code>instance: |
| * associated <code>MessageDigest</code> not set. |
| * <code>read()</code> must work when digest |
| * functionality is off |
| */ |
| public final void testRead06() |
| throws IOException { |
| InputStream is = new ByteArrayInputStream(myMessage); |
| // construct object without digest |
| DigestInputStream dis = new DigestInputStream(is, null); |
| // set digest functionality to off |
| dis.on(false); |
| // the following must pass without any exception |
| for (int i=0; i<MY_MESSAGE_LEN; i++) { |
| assertTrue((byte)dis.read() == myMessage[i]); |
| } |
| } |
| |
| /** |
| * Test #1 for <code>read(byte[],int,int)</code> method<br> |
| * |
| * Assertion: returns the number of bytes read<br> |
| * |
| * Assertion: put bytes read into specified array at specified offset<br> |
| * |
| * Assertion: updates associated digest<br> |
| */ |
| public final void testReadbyteArrayintint01() |
| throws IOException { |
| for (int ii=0; ii<algorithmName.length; ii++) { |
| try { |
| MessageDigest md = MessageDigest.getInstance(algorithmName[ii]); |
| InputStream is = new ByteArrayInputStream(myMessage); |
| DigestInputStream dis = new DigestInputStream(is, md); |
| byte[] bArray = new byte[MY_MESSAGE_LEN]; |
| |
| // check that read(byte[],int,int) returns valid value |
| assertTrue("retval", |
| dis.read(bArray, 0, bArray.length) == MY_MESSAGE_LEN); |
| // check that bArray has been filled properly |
| assertTrue("bArray", Arrays.equals(myMessage, bArray)); |
| // check that associated digest has been updated properly |
| assertTrue("update", Arrays.equals(dis.getMessageDigest().digest(), |
| MDGoldenData.getDigest(algorithmName[ii]))); |
| return; |
| } catch (NoSuchAlgorithmException e) { |
| // allowed failure |
| } |
| } |
| fail(getName() + ": no MessageDigest algorithms available - test not performed"); |
| } |
| |
| /** |
| * Test #2 for <code>read(byte[],int,int)</code> method<br> |
| * |
| * Assertion: returns the number of bytes read<br> |
| * |
| * Assertion: put bytes read into specified array at specified offset<br> |
| * |
| * Assertion: updates associated digest<br> |
| */ |
| public final void testReadbyteArrayintint02() |
| throws IOException { |
| // check precondition |
| assertEquals(0, MY_MESSAGE_LEN % CHUNK_SIZE); |
| |
| for (int ii=0; ii<algorithmName.length; ii++) { |
| try { |
| MessageDigest md = MessageDigest.getInstance(algorithmName[ii]); |
| InputStream is = new ByteArrayInputStream(myMessage); |
| DigestInputStream dis = new DigestInputStream(is, md); |
| byte[] bArray = new byte[MY_MESSAGE_LEN]; |
| |
| for (int i=0; i<MY_MESSAGE_LEN/CHUNK_SIZE; i++) { |
| // check that read(byte[],int,int) returns valid value |
| assertTrue("retval", |
| dis.read(bArray, i*CHUNK_SIZE, CHUNK_SIZE) == CHUNK_SIZE); |
| } |
| // check that bArray has been filled properly |
| assertTrue("bArray", Arrays.equals(myMessage, bArray)); |
| // check that associated digest has been updated properly |
| assertTrue("update", Arrays.equals(dis.getMessageDigest().digest(), |
| MDGoldenData.getDigest(algorithmName[ii]))); |
| return; |
| } catch (NoSuchAlgorithmException e) { |
| // allowed failure |
| } |
| } |
| fail(getName() + ": no MessageDigest algorithms available - test not performed"); |
| } |
| |
| |
| /** |
| * Test #3 for <code>read(byte[],int,int)</code> method<br> |
| * |
| * Assertion: returns the number of bytes read<br> |
| * |
| * Assertion: put bytes read into specified array at specified offset<br> |
| * |
| * Assertion: updates associated digest<br> |
| */ |
| public final void testReadbyteArrayintint03() |
| throws IOException { |
| // check precondition |
| assertTrue(MY_MESSAGE_LEN % (CHUNK_SIZE+1) != 0); |
| |
| for (int ii=0; ii<algorithmName.length; ii++) { |
| try { |
| MessageDigest md = MessageDigest.getInstance(algorithmName[ii]); |
| InputStream is = new ByteArrayInputStream(myMessage); |
| DigestInputStream dis = new DigestInputStream(is, md); |
| byte[] bArray = new byte[MY_MESSAGE_LEN]; |
| |
| for (int i=0; i<MY_MESSAGE_LEN/(CHUNK_SIZE+1); i++) { |
| // check that read(byte[],int,int) returns valid value |
| assertTrue("retval1", |
| dis.read(bArray, i*(CHUNK_SIZE+1), CHUNK_SIZE+1) == |
| CHUNK_SIZE + 1); |
| } |
| |
| // check that last call returns right |
| // number of remaining bytes |
| assertTrue("retval2", |
| dis.read(bArray, |
| MY_MESSAGE_LEN/(CHUNK_SIZE+1)*(CHUNK_SIZE+1), |
| MY_MESSAGE_LEN % (CHUNK_SIZE+1)) == |
| (MY_MESSAGE_LEN % (CHUNK_SIZE+1))); |
| |
| // check that bArray has been filled properly |
| assertTrue("bArray", Arrays.equals(myMessage, bArray)); |
| // check that associated digest has been updated properly |
| assertTrue("update", Arrays.equals(dis.getMessageDigest().digest(), |
| MDGoldenData.getDigest(algorithmName[ii]))); |
| return; |
| } catch (NoSuchAlgorithmException e) { |
| // allowed failure |
| } |
| } |
| fail(getName() + ": no MessageDigest algorithms available - test not performed"); |
| } |
| |
| /** |
| * Test #4 for <code>read(byte[],int,int)</code> method<br> |
| * |
| * Assertion: returns the number of bytes read<br> |
| * |
| * Assertion: updates associated digest<br> |
| */ |
| public final void testReadbyteArrayintint04() |
| throws IOException { |
| for (int ii=0; ii<algorithmName.length; ii++) { |
| try { |
| MessageDigest md = MessageDigest.getInstance(algorithmName[ii]); |
| InputStream is = new ByteArrayInputStream(myMessage); |
| DigestInputStream dis = new DigestInputStream(is, md); |
| byte[] bArray = new byte[MY_MESSAGE_LEN]; |
| // read all but EOS |
| dis.read(bArray, 0, bArray.length); |
| // check that subsequent read(byte[],int,int) calls return -1 (EOS) |
| assertEquals("retval1", -1, dis.read(bArray, 0, 1)); |
| assertEquals("retval2", -1, dis.read(bArray, 0, bArray.length)); |
| assertEquals("retval3", -1, dis.read(bArray, 0, 1)); |
| // check that 3 previous read() calls did not update digest |
| assertTrue("update", |
| Arrays.equals(dis.getMessageDigest().digest(), |
| MDGoldenData.getDigest(algorithmName[ii]))); |
| return; |
| } catch (NoSuchAlgorithmException e) { |
| // allowed failure |
| } |
| } |
| fail(getName() + ": no MessageDigest algorithms available - test not performed"); |
| } |
| |
| /** |
| * Test #5 for <code>read(byte[],int,int)</code> method<br> |
| * |
| * Assertion: returns the number of bytes read<br> |
| * |
| * Assertion: put bytes read into specified array at specified offset<br> |
| * |
| * Assertion: does not update associated digest if |
| * digest functionality is off<br> |
| */ |
| public final void testReadbyteArrayintint05() |
| throws IOException { |
| // check precondition |
| assertEquals(0, MY_MESSAGE_LEN % CHUNK_SIZE); |
| |
| for (int ii=0; ii<algorithmName.length; ii++) { |
| try { |
| MessageDigest md = MessageDigest.getInstance(algorithmName[ii]); |
| InputStream is = new ByteArrayInputStream(myMessage); |
| DigestInputStream dis = new DigestInputStream(is, md); |
| byte[] bArray = new byte[MY_MESSAGE_LEN]; |
| |
| // turn digest off |
| dis.on(false); |
| |
| for (int i=0; i<MY_MESSAGE_LEN/CHUNK_SIZE; i++) { |
| dis.read(bArray, i*CHUNK_SIZE, CHUNK_SIZE); |
| } |
| // check that digest has not been updated |
| assertTrue(Arrays.equals(dis.getMessageDigest().digest(), |
| MDGoldenData.getDigest(algorithmName[ii]+"_NU"))); |
| return; |
| } catch (NoSuchAlgorithmException e) { |
| // allowed failure |
| } |
| } |
| fail(getName() + ": no MessageDigest algorithms available - test not performed"); |
| } |
| |
| /** |
| * Test for <code>getMessageDigest()</code> method<br> |
| * |
| * Assertion: returns associated message digest<br> |
| */ |
| public final void testGetMessageDigest() { |
| for (int ii=0; ii<algorithmName.length; ii++) { |
| try { |
| MessageDigest md = MessageDigest.getInstance(algorithmName[ii]); |
| DigestInputStream dis = new DigestInputStream(null, md); |
| |
| assertTrue(dis.getMessageDigest() == md); |
| return; |
| } catch (NoSuchAlgorithmException e) { |
| // allowed failure |
| } |
| } |
| fail(getName() + ": no MessageDigest algorithms available - test not performed"); |
| } |
| |
| |
| /** |
| * Test for <code>setMessageDigest()</code> method<br> |
| * |
| * Assertion: set associated message digest<br> |
| */ |
| public final void testSetMessageDigest() { |
| for (int ii=0; ii<algorithmName.length; ii++) { |
| try { |
| DigestInputStream dis = new DigestInputStream(null, null); |
| MessageDigest md = MessageDigest.getInstance(algorithmName[ii]); |
| dis.setMessageDigest(md); |
| |
| assertTrue(dis.getMessageDigest() == md); |
| return; |
| } catch (NoSuchAlgorithmException e) { |
| // allowed failure |
| } |
| } |
| fail(getName() + ": no MessageDigest algorithms available - test not performed"); |
| } |
| |
| /** |
| * Test for <code>on()</code> method<br> |
| * Assertion: turns digest functionality on or off |
| */ |
| public final void testOn() throws IOException { |
| for (int ii=0; ii<algorithmName.length; ii++) { |
| try { |
| MessageDigest md = MessageDigest.getInstance(algorithmName[ii]); |
| InputStream is = new ByteArrayInputStream(myMessage); |
| DigestInputStream dis = new DigestInputStream(is, md); |
| |
| // turn digest off |
| dis.on(false); |
| |
| for (int i=0; i<MY_MESSAGE_LEN-1; i++) { |
| dis.read(); |
| } |
| |
| // turn digest on |
| dis.on(true); |
| |
| // read remaining byte |
| dis.read(); |
| |
| byte[] digest = dis.getMessageDigest().digest(); |
| |
| // check that digest value has been |
| // updated by the last read() call |
| assertFalse( |
| Arrays.equals(digest,MDGoldenData.getDigest(algorithmName[ii])) || |
| Arrays.equals(digest,MDGoldenData.getDigest(algorithmName[ii]+"_NU"))); |
| return; |
| } catch (NoSuchAlgorithmException e) { |
| // allowed failure |
| } |
| } |
| fail(getName() + ": no MessageDigest algorithms available - test not performed"); |
| } |
| |
| /** |
| * Test for <code>toString()</code> method<br> |
| * Assertion: returns <code>String</code> representation of this object |
| */ |
| public final void testToString() { |
| for (int ii=0; ii<algorithmName.length; ii++) { |
| try { |
| MessageDigest md = MessageDigest.getInstance(algorithmName[ii]); |
| InputStream is = new ByteArrayInputStream(myMessage); |
| DigestInputStream dis = new DigestInputStream(is, md); |
| |
| assertNotNull(dis.toString()); |
| return; |
| } catch (NoSuchAlgorithmException e) { |
| // allowed failure |
| } |
| } |
| fail(getName() + ": no MessageDigest algorithms available - test not performed"); |
| } |
| |
| } |