diff --git a/ewfVerify/src/org/sleuthkit/autopsy/ewfverify/EwfVerifyIngestModule.java b/ewfVerify/src/org/sleuthkit/autopsy/ewfverify/EwfVerifyIngestModule.java index 891f6ae9ca..f7f8c8c1ab 100755 --- a/ewfVerify/src/org/sleuthkit/autopsy/ewfverify/EwfVerifyIngestModule.java +++ b/ewfVerify/src/org/sleuthkit/autopsy/ewfverify/EwfVerifyIngestModule.java @@ -23,6 +23,8 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.logging.Level; import java.util.logging.Logger; +import javax.xml.bind.DatatypeConverter; +import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.StopWatch; import org.sleuthkit.autopsy.ingest.IngestDataSourceWorkerController; import org.sleuthkit.autopsy.ingest.IngestMessage; @@ -33,6 +35,7 @@ import org.sleuthkit.autopsy.ingest.IngestServices; import org.sleuthkit.autopsy.ingest.PipelineContext; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.Image; +import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; @@ -44,82 +47,117 @@ public class EwfVerifyIngestModule extends IngestModuleDataSource { private static final String MODULE_NAME = "ewf Verify"; private static final String MODULE_VERSION = "1.0"; private static final String MODULE_DESCRIPTION = "Validates the integrity of E01 files."; - private static final long CHUNK_SIZE = 16 * 1024; + private static final long DEFAULT_CHUNK_SIZE = 32 * 1024; private IngestServices services; private volatile boolean running = false; private Image img; + private String imgName; private MessageDigest md; - private Logger logger; + private static Logger logger = null; private static int messageId = 0; private volatile boolean cancelled = false; private boolean verified = false; + private SleuthkitCase skCase; public EwfVerifyIngestModule() { } @Override public void process(PipelineContext pipelineContext, Content dataSource, IngestDataSourceWorkerController controller) { + imgName = dataSource.getName(); try { img = dataSource.getImage(); } catch (TskCoreException ex) { img = null; logger.log(Level.SEVERE, "Failed to get image from Content.", ex); - services.postMessage(IngestMessage.createMessage(++messageId, MessageType.ERROR, this, "Error processing " + dataSource.getName())); + services.postMessage(IngestMessage.createMessage(++messageId, MessageType.ERROR, this, + "Error processing " + imgName)); + return; } + // Skip images that are not E01 if (img.getType() != TskData.TSK_IMG_TYPE_ENUM.TSK_IMG_TYPE_EWF_EWF) { img = null; - // TODO notify? logger.log(Level.INFO, "Skipping non-ewf image " + img.getName()); + services.postMessage(IngestMessage.createMessage(++messageId, MessageType.INFO, this, + "Skipping non-ewf image " + imgName)); + return; + } + + // Get the hash stored in the E01 file from the database + String storedHash = ""; + if (skCase.imageHasHash(img)) { + try { + storedHash = skCase.getImageHash(img).toLowerCase(); + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, "Failed to get stored hash from image " + imgName, ex); + services.postMessage(IngestMessage.createMessage(++messageId, MessageType.ERROR, this, + "Error retrieving stored hash value from " + imgName)); + return; + } + } else { + services.postMessage(IngestMessage.createMessage(++messageId, MessageType.ERROR, this, + "Image " + imgName + " does not have stored hash.")); return; } - services.postMessage(IngestMessage.createMessage(++messageId, MessageType.INFO, this, "Starting " + dataSource.getName())); - long size = img.getSize(); // size of the image + logger.log(Level.INFO, "Starting ewf verification of " + img.getName()); + services.postMessage(IngestMessage.createMessage(++messageId, MessageType.INFO, this, + "Starting " + imgName)); - // TODO handle size = 0 + long size = img.getSize(); + if (size == 0) { + logger.log(Level.WARNING, "Size of image " + imgName + " was 0 when queried."); + services.postMessage(IngestMessage.createMessage(++messageId, MessageType.ERROR, this, + "Error getting size of " + imgName + ". Image will not be processed.")); + } - int totalChunks = (int) Math.ceil(size / CHUNK_SIZE); - System.out.println("TOTAL CHUNKS = " + totalChunks); + // Libewf uses a sector size of 64 times the sector size, which is the + // motivation for using it here. + long chunkSize = 64 * img.getSsize(); + chunkSize = (chunkSize == 0) ? DEFAULT_CHUNK_SIZE : chunkSize; + + int totalChunks = (int) Math.ceil(size / chunkSize); + logger.log(Level.INFO, "Total chunks = " + totalChunks); int read; - // TODO find an appropriate size for this. byte[] data; controller.switchToDeterminate(totalChunks); running = true; - StopWatch timer = new StopWatch(); - timer.start(); + // Read in byte size chunks and update the hash value with the data. for (int i = 0; i < totalChunks; i++) { - if (cancelled) { - timer.stop(); + if (controller.isCancelled()) { running = false; return; } - data = new byte[ (int) CHUNK_SIZE ]; + data = new byte[ (int) chunkSize ]; try { - read = img.read(data, i * CHUNK_SIZE, CHUNK_SIZE); + read = img.read(data, i * chunkSize, chunkSize); } catch (TskCoreException ex) { services.postMessage(IngestMessage.createMessage(++messageId, MessageType.ERROR, this, "Error processing " + img.getName())); - logger.log(Level.SEVERE, "Error reading from image: " + img.getName(), ex); + logger.log(Level.SEVERE, "Error reading from image: " + imgName, ex); + return; } md.update(data); controller.progress(i); } - timer.stop(); - byte[] byteHash = md.digest(); - String hash = bytesToString(byteHash); - System.out.println("MD5 HASH: " + hash); - System.out.println("GENERATING HASH TOOK " + timer.getElapsedTimeSecs() + " SECONDS"); + + // Finish generating the hash and get it as a string value + String hash = DatatypeConverter.printHexBinary(md.digest()).toLowerCase(); +// String hash = bytesToString(md.digest()); + verified = hash.equals(storedHash); + logger.log(Level.INFO, "Calculated MD5 hash: " + hash); running = false; - // TODO logic to check if it is verified. - verified = true; } @Override public void init(IngestModuleInit initContext) { services = IngestServices.getDefault(); - logger = services.getLogger(this); + skCase = Case.getCurrentCase().getSleuthkitCase(); + if (logger == null) { + logger = services.getLogger(this); + } try { md = MessageDigest.getInstance("MD5"); } catch (NoSuchAlgorithmException ex) { @@ -129,18 +167,19 @@ public class EwfVerifyIngestModule extends IngestModuleDataSource { cancelled = false; running = false; img = null; + imgName = ""; } @Override public void complete() { logger.info("complete() " + this.getName()); String msg = verified ? " verified." : " not verified."; - services.postMessage(IngestMessage.createMessage(++messageId, MessageType.INFO, this, img.getName() + msg)); + services.postMessage(IngestMessage.createMessage(++messageId, MessageType.INFO, this, imgName + msg)); + logger.info(imgName + msg); } @Override public void stop() { - cancelled = true; } @Override @@ -162,12 +201,4 @@ public class EwfVerifyIngestModule extends IngestModuleDataSource { public boolean hasBackgroundJobsRunning() { return running; } - - private String bytesToString(byte[] byteHash) { - StringBuilder sb = new StringBuilder(); - for (byte b : byteHash) { - sb.append(String.format("%02x", b&0xff)); - } - return sb.toString(); - } }