Reworked validation to run in module.

This commit is contained in:
U-BASIS\dgrove 2018-02-13 13:16:16 -05:00
parent e69934fb86
commit 5d9f999399
3 changed files with 104 additions and 60 deletions

View File

@ -23,6 +23,7 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.Collections; import java.util.Collections;
import java.util.logging.Level; import java.util.logging.Level;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.services.Blackboard; import org.sleuthkit.autopsy.casemodule.services.Blackboard;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
@ -49,12 +50,16 @@ final class EncryptionDetectionFileIngestModule extends FileIngestModuleAdapter
static final boolean DEFAULT_CONFIG_FILE_SIZE_MULTIPLE_ENFORCED = true; static final boolean DEFAULT_CONFIG_FILE_SIZE_MULTIPLE_ENFORCED = true;
static final boolean DEFAULT_CONFIG_SLACK_FILES_ALLOWED = true; static final boolean DEFAULT_CONFIG_SLACK_FILES_ALLOWED = true;
private static final double MINIMUM_ENTROPY_INPUT_RANGE_MIN = 6.0;
private static final double MINIMUM_ENTROPY_INPUT_RANGE_MAX = 8.0;
private static final int MINIMUM_FILE_SIZE_INPUT_RANGE_MIN = 1;
private static final int FILE_SIZE_MODULUS = 512; private static final int FILE_SIZE_MODULUS = 512;
private static final double ONE_OVER_LOG2 = 1.4426950408889634073599246810019; // (1 / log(2)) private static final double ONE_OVER_LOG2 = 1.4426950408889634073599246810019; // (1 / log(2))
private static final int BYTE_OCCURENCES_BUFFER_SIZE = 256; private static final int BYTE_OCCURENCES_BUFFER_SIZE = 256;
private final IngestServices SERVICES = IngestServices.getInstance(); private final IngestServices services = IngestServices.getInstance();
private final Logger LOGGER = SERVICES.getLogger(EncryptionDetectionModuleFactory.getModuleName()); private final Logger logger = services.getLogger(EncryptionDetectionModuleFactory.getModuleName());
private FileTypeDetector fileTypeDetector; private FileTypeDetector fileTypeDetector;
private Blackboard blackboard; private Blackboard blackboard;
private double calculatedEntropy; private double calculatedEntropy;
@ -79,8 +84,9 @@ final class EncryptionDetectionFileIngestModule extends FileIngestModuleAdapter
@Override @Override
public void startUp(IngestJobContext context) throws IngestModule.IngestModuleException { public void startUp(IngestJobContext context) throws IngestModule.IngestModuleException {
blackboard = Case.getCurrentCase().getServices().getBlackboard();
try { try {
validateSettings();
blackboard = Case.getCurrentCase().getServices().getBlackboard();
fileTypeDetector = new FileTypeDetector(); fileTypeDetector = new FileTypeDetector();
} catch (FileTypeDetector.FileTypeDetectorInitException ex) { } catch (FileTypeDetector.FileTypeDetectorInitException ex) {
throw new IngestModule.IngestModuleException("Failed to create file type detector", ex); throw new IngestModule.IngestModuleException("Failed to create file type detector", ex);
@ -95,13 +101,33 @@ final class EncryptionDetectionFileIngestModule extends FileIngestModuleAdapter
return flagFile(file); return flagFile(file);
} }
} catch (IOException | TskCoreException ex) { } catch (IOException | TskCoreException ex) {
LOGGER.log(Level.SEVERE, String.format("Unable to process file '%s'", file.getParentPath() + file.getName()), ex); logger.log(Level.SEVERE, String.format("Unable to process file '%s'", file.getParentPath() + file.getName()), ex);
return IngestModule.ProcessResult.ERROR; return IngestModule.ProcessResult.ERROR;
} }
return IngestModule.ProcessResult.OK; return IngestModule.ProcessResult.OK;
} }
/**
* Validate ingest module settings.
*
* @throws IngestModule.IngestModuleException If the input is empty,
* invalid, or out of range.
*/
@NbBundle.Messages({
"EncryptionDetectionFileIngestModule.errorMessage.minimumEntropyInput=Minimum entropy input must be a number between 6.0 and 8.0.",
"EncryptionDetectionFileIngestModule.errorMessage.minimumFileSizeInput=Minimum file size input must be an integer (in megabytes) of 1 or greater."
})
private void validateSettings() throws IngestModule.IngestModuleException {
if (minimumEntropy < MINIMUM_ENTROPY_INPUT_RANGE_MIN || minimumEntropy > MINIMUM_ENTROPY_INPUT_RANGE_MAX) {
throw new IngestModule.IngestModuleException(Bundle.EncryptionDetectionFileIngestModule_errorMessage_minimumEntropyInput());
}
if (minimumFileSize < MINIMUM_FILE_SIZE_INPUT_RANGE_MIN) {
throw new IngestModule.IngestModuleException(Bundle.EncryptionDetectionFileIngestModule_errorMessage_minimumFileSizeInput());
}
}
/** /**
* Create a blackboard artifact. * Create a blackboard artifact.
* *
@ -120,13 +146,13 @@ final class EncryptionDetectionFileIngestModule extends FileIngestModuleAdapter
*/ */
blackboard.indexArtifact(artifact); blackboard.indexArtifact(artifact);
} catch (Blackboard.BlackboardException ex) { } catch (Blackboard.BlackboardException ex) {
LOGGER.log(Level.SEVERE, "Unable to index blackboard artifact " + artifact.getArtifactID(), ex); //NON-NLS logger.log(Level.SEVERE, "Unable to index blackboard artifact " + artifact.getArtifactID(), ex); //NON-NLS
} }
/* /*
* Send an event to update the view with the new result. * Send an event to update the view with the new result.
*/ */
SERVICES.fireModuleDataEvent(new ModuleDataEvent(EncryptionDetectionModuleFactory.getModuleName(), BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_SUSPECTED, Collections.singletonList(artifact))); services.fireModuleDataEvent(new ModuleDataEvent(EncryptionDetectionModuleFactory.getModuleName(), BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_SUSPECTED, Collections.singletonList(artifact)));
/* /*
* Make an ingest inbox message. * Make an ingest inbox message.
@ -135,7 +161,7 @@ final class EncryptionDetectionFileIngestModule extends FileIngestModuleAdapter
detailsSb.append("File: ").append(file.getParentPath()).append(file.getName()).append("<br/>\n"); detailsSb.append("File: ").append(file.getParentPath()).append(file.getName()).append("<br/>\n");
detailsSb.append("Entropy: ").append(calculatedEntropy); detailsSb.append("Entropy: ").append(calculatedEntropy);
SERVICES.postMessage(IngestMessage.createDataMessage(EncryptionDetectionModuleFactory.getModuleName(), services.postMessage(IngestMessage.createDataMessage(EncryptionDetectionModuleFactory.getModuleName(),
"Encryption Detected Match: " + file.getName(), "Encryption Detected Match: " + file.getName(),
detailsSb.toString(), detailsSb.toString(),
file.getName(), file.getName(),
@ -143,7 +169,7 @@ final class EncryptionDetectionFileIngestModule extends FileIngestModuleAdapter
return IngestModule.ProcessResult.OK; return IngestModule.ProcessResult.OK;
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
LOGGER.log(Level.SEVERE, String.format("Failed to create blackboard artifact for '%s'.", file.getParentPath() + file.getName()), ex); //NON-NLS logger.log(Level.SEVERE, String.format("Failed to create blackboard artifact for '%s'.", file.getParentPath() + file.getName()), ex); //NON-NLS
return IngestModule.ProcessResult.ERROR; return IngestModule.ProcessResult.ERROR;
} }
} }

View File

@ -136,8 +136,8 @@
</Component> </Component>
<Component class="javax.swing.JFormattedTextField" name="minimumFileSizeTextbox"> <Component class="javax.swing.JFormattedTextField" name="minimumFileSizeTextbox">
<Properties> <Properties>
<Property name="formatterFactory" type="javax.swing.JFormattedTextField$AbstractFormatterFactory" editor="org.netbeans.modules.form.editors.AbstractFormatterFactoryEditor"> <Property name="formatterFactory" type="javax.swing.JFormattedTextField$AbstractFormatterFactory" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Format format="#0" subtype="-1" type="0"/> <Connection code="minimumFileSizeTextFormatterFactory" type="code"/>
</Property> </Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/modules/encryptiondetection/Bundle.properties" key="EncryptionDetectionIngestJobSettingsPanel.minimumFileSizeTextbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/> <ResourceString bundle="org/sleuthkit/autopsy/modules/encryptiondetection/Bundle.properties" key="EncryptionDetectionIngestJobSettingsPanel.minimumFileSizeTextbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
@ -150,7 +150,7 @@
<Component class="javax.swing.JFormattedTextField" name="minimumEntropyTextbox"> <Component class="javax.swing.JFormattedTextField" name="minimumEntropyTextbox">
<Properties> <Properties>
<Property name="formatterFactory" type="javax.swing.JFormattedTextField$AbstractFormatterFactory" editor="org.netbeans.modules.form.RADConnectionPropertyEditor"> <Property name="formatterFactory" type="javax.swing.JFormattedTextField$AbstractFormatterFactory" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="entropyFormatterFactory" type="code"/> <Connection code="minimumEntropyTextFormatterFactory" type="code"/>
</Property> </Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/modules/encryptiondetection/Bundle.properties" key="EncryptionDetectionIngestJobSettingsPanel.minimumEntropyTextbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/> <ResourceString bundle="org/sleuthkit/autopsy/modules/encryptiondetection/Bundle.properties" key="EncryptionDetectionIngestJobSettingsPanel.minimumEntropyTextbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2017 Basis Technology Corp. * Copyright 2017-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -18,12 +18,11 @@
*/ */
package org.sleuthkit.autopsy.modules.encryptiondetection; package org.sleuthkit.autopsy.modules.encryptiondetection;
import java.text.NumberFormat; import java.text.ParseException;
import javax.swing.JFormattedTextField.AbstractFormatterFactory; import java.util.logging.Level;
import javax.swing.text.DefaultFormatter;
import javax.swing.text.DefaultFormatterFactory; import javax.swing.text.DefaultFormatterFactory;
import javax.swing.text.NumberFormatter; import org.sleuthkit.autopsy.coreutils.Logger;
import org.openide.util.NbBundle;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings; import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings;
import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettingsPanel; import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettingsPanel;
@ -33,10 +32,12 @@ import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettingsPanel;
final class EncryptionDetectionIngestJobSettingsPanel extends IngestModuleIngestJobSettingsPanel { final class EncryptionDetectionIngestJobSettingsPanel extends IngestModuleIngestJobSettingsPanel {
private static final int MEGABYTE_SIZE = 1048576; private static final int MEGABYTE_SIZE = 1048576;
private static final double MINIMUM_ENTROPY_INPUT_RANGE_MIN = 6.0; private static final int INVALID_TEXT_FIELD_INPUT_RETURN = -1;
private static final double MINIMUM_ENTROPY_INPUT_RANGE_MAX = 8.0;
private static final int MINIMUM_FILE_SIZE_INPUT_RANGE_MIN = 1; private final Logger logger = Logger.getLogger(EncryptionDetectionIngestJobSettingsPanel.class.getName());
private AbstractFormatterFactory entropyFormatterFactory = null;
private final DefaultFormatterFactory minimumFileSizeTextFormatterFactory = new DefaultFormatterFactory(new MinimumFileSizeTextFormatter());;
private final DefaultFormatterFactory minimumEntropyTextFormatterFactory = new DefaultFormatterFactory(new MinimumEntropyTextFormatter());;
/** /**
* Instantiate the ingest job settings panel. * Instantiate the ingest job settings panel.
@ -44,12 +45,6 @@ final class EncryptionDetectionIngestJobSettingsPanel extends IngestModuleIngest
* @param settings The ingest job settings. * @param settings The ingest job settings.
*/ */
public EncryptionDetectionIngestJobSettingsPanel(EncryptionDetectionIngestJobSettings settings) { public EncryptionDetectionIngestJobSettingsPanel(EncryptionDetectionIngestJobSettings settings) {
NumberFormatter entropyFormatter = new NumberFormatter(NumberFormat.getNumberInstance());
entropyFormatter.setValueClass(Float.TYPE);
entropyFormatter.setMinimum(0);
entropyFormatter.setMaximum(Float.MAX_VALUE);
entropyFormatterFactory = new DefaultFormatterFactory(entropyFormatter);
initComponents(); initComponents();
customizeComponents(settings); customizeComponents(settings);
} }
@ -68,9 +63,6 @@ final class EncryptionDetectionIngestJobSettingsPanel extends IngestModuleIngest
@Override @Override
public IngestModuleIngestJobSettings getSettings() { public IngestModuleIngestJobSettings getSettings() {
//DLG: validateMinimumEntropy();
//DLG: validateMinimumFileSize();
return new EncryptionDetectionIngestJobSettings( return new EncryptionDetectionIngestJobSettings(
Double.valueOf(minimumEntropyTextbox.getText()), Double.valueOf(minimumEntropyTextbox.getText()),
Integer.valueOf(minimumFileSizeTextbox.getText()) * MEGABYTE_SIZE, Integer.valueOf(minimumFileSizeTextbox.getText()) * MEGABYTE_SIZE,
@ -79,42 +71,68 @@ final class EncryptionDetectionIngestJobSettingsPanel extends IngestModuleIngest
} }
/** /**
* Validate the minimum entropy input. * Formatter to handle minimum entropy text input.
*
* @throws IllegalArgumentException If the input is empty, invalid, or out
* of range.
*/ */
@Messages({ private final class MinimumEntropyTextFormatter extends DefaultFormatter {
"EncryptionDetectionIngestJobSettingsPanel.minimumEntropyInput.validationError.text=Minimum entropy input must be a number between 6.0 and 8.0."
}) /**
private void validateMinimumEntropy() throws IllegalArgumentException { * Create an instance of the formatter.
try { */
double minimumEntropy = Double.valueOf(minimumEntropyTextbox.getText()); MinimumEntropyTextFormatter() {
if (minimumEntropy < MINIMUM_ENTROPY_INPUT_RANGE_MIN || minimumEntropy > MINIMUM_ENTROPY_INPUT_RANGE_MAX) { super();
throw new IllegalArgumentException(NbBundle.getMessage(this.getClass(), "EncryptionDetectionIngestJobSettingsPanel.minimumEntropyInput.validationError.text")); }
@Override
public String valueToString(Object object) throws ParseException {
return super.valueToString(object);
}
@Override
public Object stringToValue(String string) throws ParseException {
try {
return Double.parseDouble(string);
} catch (NumberFormatException ex) {
logger.log(Level.WARNING, String.format("The text input '%s' for minimum entropy is not valid.", string), ex);
/*
* Return a valid number outside the acceptable value range so
* it can be run through the validator in the file ingest
* module.
*/
return new Double(INVALID_TEXT_FIELD_INPUT_RETURN);
} }
} catch (NumberFormatException ex) {
throw new IllegalArgumentException(NbBundle.getMessage(this.getClass(), "EncryptionDetectionIngestJobSettingsPanel.minimumEntropyInput.validationError.text"));
} }
} }
/** /**
* Validate the minimum file size input. * Formatter to handle minimum file size text input.
*
* @throws IllegalArgumentException If the input is empty, invalid, or out
* of range.
*/ */
@Messages({ private final class MinimumFileSizeTextFormatter extends DefaultFormatter {
"EncryptionDetectionIngestJobSettingsPanel.minimumFileSizeInput.validationError.text=Minimum file size input must be an integer (in megabytes) of 1 or greater."
}) /**
private void validateMinimumFileSize() throws IllegalArgumentException { * Create an instance of the formatter.
try { */
int minimumFileSize = Integer.valueOf(minimumFileSizeTextbox.getText()); MinimumFileSizeTextFormatter() {
if (minimumFileSize < MINIMUM_FILE_SIZE_INPUT_RANGE_MIN) { super();
throw new IllegalArgumentException(NbBundle.getMessage(this.getClass(), "EncryptionDetectionIngestJobSettingsPanel.minimumFileSizeInput.validationError.text")); }
@Override
public String valueToString(Object object) throws ParseException {
return super.valueToString(object);
}
@Override
public Object stringToValue(String string) throws ParseException {
try {
return Integer.parseInt(string);
} catch (NumberFormatException ex) {
logger.log(Level.WARNING, String.format("The text input '%s' for minimum file size is not valid.", string), ex);
/*
* Return a valid number outside the acceptable value range so
* it can still be run through the validator in the file ingest
* module.
*/
return INVALID_TEXT_FIELD_INPUT_RETURN;
} }
} catch (NumberFormatException ex) {
throw new IllegalArgumentException(NbBundle.getMessage(this.getClass(), "EncryptionDetectionIngestJobSettingsPanel.minimumFileSizeInput.validationError.text"));
} }
} }
@ -155,7 +173,7 @@ final class EncryptionDetectionIngestJobSettingsPanel extends IngestModuleIngest
detectionSettingsLabel.setFont(new java.awt.Font("Tahoma", 1, 11)); // NOI18N detectionSettingsLabel.setFont(new java.awt.Font("Tahoma", 1, 11)); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(detectionSettingsLabel, org.openide.util.NbBundle.getMessage(EncryptionDetectionIngestJobSettingsPanel.class, "EncryptionDetectionIngestJobSettingsPanel.detectionSettingsLabel.text")); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(detectionSettingsLabel, org.openide.util.NbBundle.getMessage(EncryptionDetectionIngestJobSettingsPanel.class, "EncryptionDetectionIngestJobSettingsPanel.detectionSettingsLabel.text")); // NOI18N
minimumFileSizeTextbox.setFormatterFactory(new javax.swing.text.DefaultFormatterFactory(new javax.swing.text.NumberFormatter(new java.text.DecimalFormat("#0")))); minimumFileSizeTextbox.setFormatterFactory(minimumFileSizeTextFormatterFactory);
minimumFileSizeTextbox.setText(org.openide.util.NbBundle.getMessage(EncryptionDetectionIngestJobSettingsPanel.class, "EncryptionDetectionIngestJobSettingsPanel.minimumFileSizeTextbox.text")); // NOI18N minimumFileSizeTextbox.setText(org.openide.util.NbBundle.getMessage(EncryptionDetectionIngestJobSettingsPanel.class, "EncryptionDetectionIngestJobSettingsPanel.minimumFileSizeTextbox.text")); // NOI18N
minimumFileSizeTextbox.addActionListener(new java.awt.event.ActionListener() { minimumFileSizeTextbox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) { public void actionPerformed(java.awt.event.ActionEvent evt) {
@ -163,7 +181,7 @@ final class EncryptionDetectionIngestJobSettingsPanel extends IngestModuleIngest
} }
}); });
minimumEntropyTextbox.setFormatterFactory(entropyFormatterFactory); minimumEntropyTextbox.setFormatterFactory(minimumEntropyTextFormatterFactory);
minimumEntropyTextbox.setText(org.openide.util.NbBundle.getMessage(EncryptionDetectionIngestJobSettingsPanel.class, "EncryptionDetectionIngestJobSettingsPanel.minimumEntropyTextbox.text")); // NOI18N minimumEntropyTextbox.setText(org.openide.util.NbBundle.getMessage(EncryptionDetectionIngestJobSettingsPanel.class, "EncryptionDetectionIngestJobSettingsPanel.minimumEntropyTextbox.text")); // NOI18N
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);