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