1 7 22 23 package de.schlichtherle.crypto.io.raes; 24 25 import de.schlichtherle.crypto.generators.DigestRandom; 26 import de.schlichtherle.crypto.modes.SICSeekableBlockCipher; 27 import de.schlichtherle.io.rof.ReadOnlyFile; 28 import de.schlichtherle.io.rof.SimpleReadOnlyFile; 29 import de.schlichtherle.util.Arrays; 30 31 import java.io.File ; 32 import java.io.FileOutputStream ; 33 import java.io.IOException ; 34 import java.io.OutputStream ; 35 import java.util.Random ; 36 import java.util.logging.Logger ; 37 38 import junit.framework.*; 39 40 import org.bouncycastle.crypto.digests.SHA256Digest; 41 42 45 public class RaesTest extends TestCase { 46 47 private static final Logger logger = Logger.getLogger( 48 RaesTest.class.getName()); 49 50 private static final String PASSWD = "secret"; 51 52 private static final Random rnd = new DigestRandom(new SHA256Digest()); 53 54 private static final int[] keyStrengths = { 55 Type0RaesParameters.KEY_STRENGTH_128, 56 Type0RaesParameters.KEY_STRENGTH_192, 57 Type0RaesParameters.KEY_STRENGTH_256 58 }; 59 60 private static RaesParameters createRaesParameters() { 61 return new Type0RaesParameters() { 62 boolean secondTry; 63 64 public char[] getOpenPasswd() { 65 if (secondTry) { 66 logger.finer("First returned password was wrong, providing the right one now!"); 67 return PASSWD.toCharArray(); 68 } else { 69 secondTry = true; 70 return rnd.nextBoolean() 71 ? PASSWD.toCharArray() 72 : "wrong".toCharArray(); 73 } 74 } 75 76 public void invalidOpenPasswd() { 77 logger.finer("Password wrong!"); 78 } 79 80 public char[] getCreatePasswd() { 81 return PASSWD.toCharArray(); 82 } 83 84 public int getKeyStrength() { 85 return keyStrengths[rnd.nextInt(keyStrengths.length)]; 86 } 87 88 public void setKeyStrength(int keyStrength) { 89 logger.finer("Key strength: " + keyStrength); 90 } 91 }; 92 } 93 94 public static Test suite() throws Exception { 95 boolean ea = false; 96 assert ea = true; logger.config("Java assertions enabled: " + ea); 98 if (!ea) 99 logger.info("You should enable assertions for additional white box testing."); 100 101 TestSuite suite = new TestSuite(RaesTest.class); 102 105 106 return suite; 107 } 108 109 110 private byte[] data; 111 112 private File plainFile; 113 private ReadOnlyFile srof; 114 115 119 private SICSeekableBlockCipher decryptEngine; 120 121 private File cipherFile; 122 private RaesReadOnlyFile rrof; 123 124 public RaesTest(String testName) throws Exception { 125 super(testName); 126 } 127 128 protected void setUp() throws Exception { 129 final int length = 1 + rnd.nextInt(1024 * 1024); 131 data = new byte[length]; 132 assertTrue(data.length > 0); 133 rnd.nextBytes(data); 134 135 final File dir = new File(System.getProperty("java.io.tmpdir")); 136 137 createCipherFile(dir); 139 140 plainFile = File.createTempFile("tmp", ".bin", dir); 142 final OutputStream out = new FileOutputStream (plainFile); 143 out.write(data); 144 out.close(); 145 assertEquals(data.length, plainFile.length()); 146 147 srof = new SimpleReadOnlyFile(plainFile); 149 } 150 151 private void createCipherFile(File dir) 152 throws IOException { 153 cipherFile = File.createTempFile("tmp", ".bin.rae", dir); 154 final RaesOutputStream out = RaesOutputStream.getInstance( 155 new FileOutputStream (cipherFile), 156 createRaesParameters()); 157 158 int n; 160 for (int off = 0; off < data.length; off += n) { 161 if (rnd.nextBoolean()) { 162 n = 1; 164 out.write(data[off]); 165 } else { 166 n = rnd.nextInt(data.length / 100); 168 n = Math.min(n, data.length - off); 169 out.write(data, off, n); 170 } 171 if (rnd.nextBoolean()) 172 out.flush(); } 174 175 logger.fine("Encrypted " + data.length + " bytes of random data using PBE/Hmac-SHA-256/AES-" + out.getKeySizeBits() + "/CTR."); 176 out.close(); 177 178 rrof = RaesReadOnlyFile.getInstance(cipherFile, createRaesParameters()); 180 } 181 182 protected void tearDown() throws Exception { 183 boolean deleted; 184 185 decryptEngine = null; 186 187 srof.close(); 188 srof = null; 189 190 deleted = plainFile.delete(); 191 if (!deleted && plainFile.exists()) 192 logger.fine("Warning: " + plainFile + ": Could not delete!"); 193 plainFile = null; 194 195 rrof.close(); 196 rrof = null; 197 198 deleted = cipherFile.delete(); 199 if (!deleted && cipherFile.exists()) 200 logger.fine("Warning: " + cipherFile + ": Could not delete!"); 201 cipherFile = null; 202 203 data = null; 204 } 205 206 public void testClose() throws IOException { 207 logger.fine("testClose"); 208 209 rrof.close(); 210 211 try { 212 rrof.length(); 213 fail("This should throw an IOException!"); 214 } catch (IOException expected) { 215 } 217 218 try { 219 rrof.getFilePointer(); 220 fail("This should throw an IOException!"); 221 } catch (IOException expected) { 222 } 224 225 try { 226 rrof.seek(0); 227 fail("This should throw an IOException!"); 228 } catch (IOException expected) { 229 } 231 232 try { 233 rrof.read(); 234 fail("Reading from a closed file should throw an IOException!"); 235 } catch (IOException expected) { 236 } 238 239 assertEquals(0, rrof.read(new byte[0])); 240 241 try { 242 rrof.read(new byte[1]); 243 fail("Reading from a closed file should throw an IOException!"); 244 } catch (IOException expected) { 245 } 247 248 assertEquals(0, rrof.read(new byte[0], 0, 0)); 249 250 try { 251 rrof.read(new byte[1], 0, 1); 252 fail("Reading from a closed file should throw an IOException!"); 253 } catch (IOException expected) { 254 } 256 257 rrof.readFully(new byte[0]); 258 259 try { 260 rrof.readFully(new byte[1]); 261 fail("Reading from a closed file should throw an IOException!"); 262 } catch (IOException expected) { 263 } 265 266 rrof.readFully(new byte[0], 0, 0); 267 268 try { 269 rrof.readFully(new byte[1], 0, 1); 270 fail("Reading from a closed file should throw an IOException!"); 271 } catch (IOException expected) { 272 } 274 275 assertEquals(0, rrof.skipBytes(0)); 276 assertEquals(0, rrof.skipBytes(-1)); 277 278 try { 279 rrof.skipBytes(1); 280 fail("Skipping bytes in a closed file should throw an IOException!"); 281 } catch (IOException expected) { 282 } 284 285 rrof.close(); 286 287 srof.close(); 288 289 try { 290 srof.length(); 291 fail("This should throw an IOException!"); 292 } catch (IOException expected) { 293 } 295 296 try { 297 srof.getFilePointer(); 298 fail("This should throw an IOException!"); 299 } catch (IOException expected) { 300 } 302 303 try { 304 srof.seek(0); 305 fail("This should throw an IOException!"); 306 } catch (IOException expected) { 307 } 309 310 try { 311 srof.read(); 312 fail("Reading from a closed file should throw an IOException!"); 313 } catch (IOException expected) { 314 } 316 317 assertEquals(0, srof.read(new byte[0])); 318 319 try { 320 srof.read(new byte[1]); 321 fail("Reading from a closed file should throw an IOException!"); 322 } catch (IOException expected) { 323 } 325 326 assertEquals(0, srof.read(new byte[0], 0, 0)); 327 328 try { 329 srof.read(new byte[1], 0, 1); 330 fail("Reading from a closed file should throw an IOException!"); 331 } catch (IOException expected) { 332 } 334 335 srof.readFully(new byte[0]); 336 337 try { 338 srof.readFully(new byte[1]); 339 fail("Reading from a closed file should throw an IOException!"); 340 } catch (IOException expected) { 341 } 343 344 srof.readFully(new byte[0], 0, 0); 345 346 try { 347 srof.readFully(new byte[1], 0, 1); 348 fail("Reading from a closed file should throw an IOException!"); 349 } catch (IOException expected) { 350 } 352 353 assertEquals(0, srof.skipBytes(0)); 354 assertEquals(0, srof.skipBytes(-1)); 355 356 try { 357 srof.skipBytes(1); 358 fail("Skipping bytes in a closed file should throw an IOException!"); 359 } catch (IOException expected) { 360 } 362 363 srof.close(); 364 } 365 366 public void testLength() throws Exception { 367 logger.fine("testLength"); 368 369 for (int i = 10; --i >= 0; ) { 370 final ReadOnlyFile rrof2 = RaesReadOnlyFile.getInstance( 371 cipherFile, createRaesParameters()); 372 373 assertEquals(data.length, rrof2.length()); 374 assertEquals(data.length, srof.length()); 375 376 rrof2.close(); 377 } 378 } 379 380 public void testSeekAndGetFilePointer() throws IOException { 381 logger.fine("testSeekAndGetFilePointer (Monte Carlo algorithm)"); 382 383 assertEquals(0, rrof.getFilePointer()); 384 assertEquals(0, srof.getFilePointer()); 385 386 testSeekAndGetFilePointer(rrof, 0); 387 testSeekAndGetFilePointer(srof, 0); 388 389 final long length = rrof.length(); 390 for (int i = 100; --i >= 0; ) { 391 final long tooSmall = rnd.nextLong() | 0x8000000000000000L; 392 try { 393 testSeekAndGetFilePointer(rrof, tooSmall); 394 fail("Seeking to a negative position should throw an IOException!"); 395 } catch (IOException expected) { 396 } 398 try { 399 testSeekAndGetFilePointer(srof, tooSmall); 400 fail("Seeking to a negative position should throw an IOException!"); 401 } catch (IOException expected) { 402 } 404 405 final int off = rnd.nextInt((int) length); 406 testSeekAndGetFilePointer(rrof, off); 407 testSeekAndGetFilePointer(srof, off); 408 409 final long tooLarge = Math.max( 410 length + 1, rnd.nextLong() & 0x7fffffffffffffffL); 411 try { 412 testSeekAndGetFilePointer(rrof, tooLarge); 413 fail("Seeking past the file length should throw an IOException!"); 414 } catch (IOException expected) { 415 } 417 try { 422 testSeekAndGetFilePointer(srof, tooLarge); 423 } catch (IOException mayHappen) { 424 } 425 } 426 427 testSeekAndGetFilePointer(rrof, length); 428 } 429 430 private void testSeekAndGetFilePointer( 431 final ReadOnlyFile rof, 432 final long pos) throws IOException { 433 rof.seek(pos); 434 assertEquals(pos, rof.getFilePointer()); 435 } 436 437 public void testSkipBytes() throws IOException { 438 logger.fine("testSkipBytes (Las Vegas algorithm)"); 439 440 final long length = rrof.length(); 441 for (int off = 0; off < (int) length; off++) { 442 assertEquals(data[off], (byte) rrof.read()); 443 assertEquals(data[off], (byte) srof.read()); 444 int n = rnd.nextInt((int) (length / 100)); 445 n = rrof.skipBytes(n); 446 assertEquals(n, srof.skipBytes(n)); 447 off += n; 448 } 449 assertEquals(-1, rrof.read()); 450 assertEquals(-1, srof.read()); 451 assertEquals(0, rrof.skipBytes(1)); 452 assertEquals(0, srof.skipBytes(1)); 453 } 454 455 public void testForwardReadBytes() throws IOException { 456 logger.fine("testForwardReadBytes"); 457 458 final long length = rrof.length(); 459 for (int off = 0; off < length; off++) { 460 assertEquals(data[off], (byte) rrof.read()); 461 assertEquals(data[off], (byte) srof.read()); 462 } 463 assertEquals(-1, rrof.read()); 464 assertEquals(-1, srof.read()); 465 } 466 467 public void testBackwardReadBytes() throws IOException { 468 logger.fine("testBackwardReadBytes"); 469 470 final long length = rrof.length(); 471 testSeekAndGetFilePointer(rrof, length); 472 assertEquals(-1, rrof.read()); 473 testSeekAndGetFilePointer(srof, length); 474 assertEquals(-1, srof.read()); 475 476 for (int off = (int) length; --off >= 0; ) { 477 testSeekAndGetFilePointer(rrof, off); 478 assertEquals(data[off], (byte) rrof.read()); 479 testSeekAndGetFilePointer(srof, off); 480 assertEquals(data[off], (byte) srof.read()); 481 } 482 } 483 484 public void testRandomReadBytes() throws IOException { 485 logger.fine("testRandomReadBytes (Monte Carlo algorithm)"); 486 487 final long length = rrof.length(); 488 for (int i = 100; --i >= 0; ) { 489 int off = rnd.nextInt((int) length); 490 testSeekAndGetFilePointer(rrof, off); 491 assertEquals(data[off], (byte) rrof.read()); 492 testSeekAndGetFilePointer(srof, off); 493 assertEquals(data[off], (byte) srof.read()); 494 } 495 496 testSeekAndGetFilePointer(rrof, length); 497 assertEquals(-1, rrof.read()); 498 testSeekAndGetFilePointer(srof, length); 499 assertEquals(-1, srof.read()); 500 } 501 502 public void testForwardReadChunks() throws IOException { 503 logger.fine("testForwardReadChunks (Las Vegas algorithm)"); 504 505 final long length = rrof.length(); 506 int off = 0; 507 int read; 508 do { 509 final byte[] buf = new byte[rnd.nextInt((int) (length / 100))]; 510 read = rrof.read(buf); 511 if (read < 0) 512 break; 513 if (buf.length > 0) { 514 assertTrue(read > 0); 515 assertTrue(Arrays.equals(data, off, buf, 0, read)); 516 assertEquals(read, srof.read(buf)); 517 assertTrue(Arrays.equals(data, off, buf, 0, read)); 518 } else { 519 assertTrue(read == 0); 520 assertEquals(0, srof.read(buf)); 521 } 522 off += read; 523 } while (true); 524 assertEquals(off, length); 525 assertEquals(-1, read); 526 assertEquals(-1, srof.read(new byte[1])); 527 assertEquals( 0, rrof.read(new byte[0])); 528 assertEquals( 0, srof.read(new byte[0])); 529 } 530 531 public void testRandomReadChunksAndAuthenticate() throws IOException { 532 logger.fine("testRandomReadChunksAndAuthenticate (Monte Carlo algorithm)"); 533 534 final long length = rrof.length(); 535 for (int i = 100; --i >= 0; ) { 536 int off = rnd.nextInt((int) length); 537 testSeekAndGetFilePointer(rrof, off); 538 testSeekAndGetFilePointer(srof, off); 539 final byte[] buf = new byte[rnd.nextInt((int) (length / 100))]; 540 int read = rrof.read(buf); 541 if (buf.length > 0) { 542 assertTrue(read > 0); 543 assertTrue(Arrays.equals(data, off, buf, 0, read)); 544 assertEquals(read, srof.read(buf)); 545 assertTrue(Arrays.equals(data, off, buf, 0, read)); 546 } else { 547 assertTrue(read == 0); 548 assertEquals(0, srof.read(buf)); 549 } 550 rrof.authenticate(); 553 } 554 } 555 } 556 | Popular Tags |