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