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