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