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