diff --git a/Core/nbproject/project.xml b/Core/nbproject/project.xml
index 987b2ffe78..0e6b98892f 100755
--- a/Core/nbproject/project.xml
+++ b/Core/nbproject/project.xml
@@ -313,6 +313,7 @@
org.sleuthkit.autopsy.ingest
org.sleuthkit.autopsy.keywordsearchservice
org.sleuthkit.autopsy.menuactions
+ org.sleuthkit.autopsy.modules.encryptiondetection
org.sleuthkit.autopsy.modules.filetypeid
org.sleuthkit.autopsy.modules.hashdatabase
org.sleuthkit.autopsy.modules.vmextractor
diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/AutopsyOptionsPanel.form b/Core/src/org/sleuthkit/autopsy/corecomponents/AutopsyOptionsPanel.form
index 06607d7d9b..2e618379e4 100755
--- a/Core/src/org/sleuthkit/autopsy/corecomponents/AutopsyOptionsPanel.form
+++ b/Core/src/org/sleuthkit/autopsy/corecomponents/AutopsyOptionsPanel.form
@@ -22,12 +22,18 @@
-
+
+
+
+
-
+
+
+
+
@@ -46,247 +52,336 @@
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
-
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/AutopsyOptionsPanel.java b/Core/src/org/sleuthkit/autopsy/corecomponents/AutopsyOptionsPanel.java
index 4f95087f66..435bdc99b4 100755
--- a/Core/src/org/sleuthkit/autopsy/corecomponents/AutopsyOptionsPanel.java
+++ b/Core/src/org/sleuthkit/autopsy/corecomponents/AutopsyOptionsPanel.java
@@ -18,9 +18,18 @@
*/
package org.sleuthkit.autopsy.corecomponents;
+import java.awt.image.BufferedImage;
import java.io.File;
+import java.io.IOException;
+import java.util.logging.Level;
+import javax.imageio.ImageIO;
+import javax.swing.ImageIcon;
import javax.swing.JFileChooser;
+import javax.swing.JOptionPane;
import org.netbeans.spi.options.OptionsPanelController;
+import org.openide.util.NbBundle;
+import org.sleuthkit.autopsy.coreutils.Logger;
+import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.casemodule.GeneralFilter;
import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
@@ -29,16 +38,23 @@ import org.sleuthkit.autopsy.report.ReportBranding;
/**
* Options panel that allow users to set application preferences.
*/
+@Messages({"AutopsyOptionsPanel.agencyLogoPreview.text=
No logo
selected
",
+ "AutopsyOptionsPanel.logoPanel.border.title=Logo",
+ "AutopsyOptionsPanel.viewPanel.border.title=View",
+ "AutopsyOptionsPanel.invalidImageFile.msg=The selected file was not able to be used as an agency logo.",
+ "AutopsyOptionsPanel.invalidImageFile.title=Invalid Image File"})
final class AutopsyOptionsPanel extends javax.swing.JPanel {
private static final long serialVersionUID = 1L;
private final JFileChooser fc;
+ private static final Logger logger = Logger.getLogger(AutopsyOptionsPanel.class.getName());
AutopsyOptionsPanel() {
initComponents();
fc = new JFileChooser();
fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
fc.setMultiSelectionEnabled(false);
+ fc.setAcceptAllFileFilterUsed(false);
fc.setFileFilter(new GeneralFilter(GeneralFilter.GRAPHIC_IMAGE_EXTS, GeneralFilter.GRAPHIC_IMG_DECR));
}
@@ -53,7 +69,31 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
boolean useLocalTime = UserPreferences.displayTimesInLocalTime();
useLocalTimeRB.setSelected(useLocalTime);
useGMTTimeRB.setSelected(!useLocalTime);
- agencyLogoPathField.setText(ModuleSettings.getConfigSetting(ReportBranding.MODULE_NAME, ReportBranding.AGENCY_LOGO_PATH_PROP));
+ String path = ModuleSettings.getConfigSetting(ReportBranding.MODULE_NAME, ReportBranding.AGENCY_LOGO_PATH_PROP);
+ try {
+ updateAgencyLogo(path);
+ } catch (IOException ex) {
+ logger.log(Level.WARNING, "Error loading image from previously saved agency logo path", ex);
+ }
+ }
+
+ private void updateAgencyLogo(String path) throws IOException {
+ agencyLogoPathField.setText(path);
+ ImageIcon agencyLogoIcon = new ImageIcon();
+ agencyLogoPreview.setText(Bundle.AutopsyOptionsPanel_agencyLogoPreview_text());
+ if (!agencyLogoPathField.getText().isEmpty()) {
+ File file = new File(agencyLogoPathField.getText());
+ if (file.exists()) {
+ BufferedImage image = ImageIO.read(file); //create it as an image first to support BMP files
+ if (image == null) {
+ throw new IOException("Unable to read file as a BufferedImage for file " + file.toString());
+ }
+ agencyLogoIcon = new ImageIcon(image.getScaledInstance(64, 64, 4));
+ agencyLogoPreview.setText("");
+ }
+ }
+ agencyLogoPreview.setIcon(agencyLogoIcon);
+ agencyLogoPreview.repaint();
}
void store() {
@@ -64,8 +104,8 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
UserPreferences.setHideSlackFilesInViewsTree(viewsHideSlackCB.isSelected());
UserPreferences.setDisplayTimesInLocalTime(useLocalTimeRB.isSelected());
if (!agencyLogoPathField.getText().isEmpty()) {
- File image = new File(agencyLogoPathField.getText());
- if (image.exists()) {
+ File file = new File(agencyLogoPathField.getText());
+ if (file.exists()) {
ModuleSettings.setConfigSetting(ReportBranding.MODULE_NAME, ReportBranding.AGENCY_LOGO_PATH_PROP, agencyLogoPathField.getText());
}
}
@@ -87,24 +127,87 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
buttonGroup3 = new javax.swing.ButtonGroup();
jScrollPane1 = new javax.swing.JScrollPane();
jPanel1 = new javax.swing.JPanel();
- useBestViewerRB = new javax.swing.JRadioButton();
- keepCurrentViewerRB = new javax.swing.JRadioButton();
- jLabelSelectFile = new javax.swing.JLabel();
- jLabelTimeDisplay = new javax.swing.JLabel();
- useLocalTimeRB = new javax.swing.JRadioButton();
- useGMTTimeRB = new javax.swing.JRadioButton();
- jLabelHideKnownFiles = new javax.swing.JLabel();
- dataSourcesHideKnownCB = new javax.swing.JCheckBox();
- viewsHideKnownCB = new javax.swing.JCheckBox();
- dataSourcesHideSlackCB = new javax.swing.JCheckBox();
- viewsHideSlackCB = new javax.swing.JCheckBox();
- jLabelHideSlackFiles = new javax.swing.JLabel();
+ logoPanel = new javax.swing.JPanel();
agencyLogoImageLabel = new javax.swing.JLabel();
agencyLogoPathField = new javax.swing.JTextField();
browseLogosButton = new javax.swing.JButton();
+ agencyLogoPreview = new javax.swing.JLabel();
+ viewPanel = new javax.swing.JPanel();
+ jLabelSelectFile = new javax.swing.JLabel();
+ useBestViewerRB = new javax.swing.JRadioButton();
+ keepCurrentViewerRB = new javax.swing.JRadioButton();
+ jLabelHideKnownFiles = new javax.swing.JLabel();
+ dataSourcesHideKnownCB = new javax.swing.JCheckBox();
+ viewsHideKnownCB = new javax.swing.JCheckBox();
+ jLabelHideSlackFiles = new javax.swing.JLabel();
+ dataSourcesHideSlackCB = new javax.swing.JCheckBox();
+ viewsHideSlackCB = new javax.swing.JCheckBox();
+ jLabelTimeDisplay = new javax.swing.JLabel();
+ useLocalTimeRB = new javax.swing.JRadioButton();
+ useGMTTimeRB = new javax.swing.JRadioButton();
jScrollPane1.setBorder(null);
+ logoPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.logoPanel.border.title"))); // NOI18N
+
+ org.openide.awt.Mnemonics.setLocalizedText(agencyLogoImageLabel, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.agencyLogoImageLabel.text")); // NOI18N
+
+ agencyLogoPathField.setEditable(false);
+ agencyLogoPathField.setBackground(new java.awt.Color(255, 255, 255));
+ agencyLogoPathField.setText(org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.agencyLogoPathField.text")); // NOI18N
+ agencyLogoPathField.setFocusable(false);
+ agencyLogoPathField.setRequestFocusEnabled(false);
+
+ org.openide.awt.Mnemonics.setLocalizedText(browseLogosButton, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.browseLogosButton.text")); // NOI18N
+ browseLogosButton.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ browseLogosButtonActionPerformed(evt);
+ }
+ });
+
+ agencyLogoPreview.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
+ org.openide.awt.Mnemonics.setLocalizedText(agencyLogoPreview, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.agencyLogoPreview.text")); // NOI18N
+ agencyLogoPreview.setBorder(javax.swing.BorderFactory.createEtchedBorder());
+ agencyLogoPreview.setMaximumSize(new java.awt.Dimension(64, 64));
+ agencyLogoPreview.setMinimumSize(new java.awt.Dimension(64, 64));
+ agencyLogoPreview.setPreferredSize(new java.awt.Dimension(64, 64));
+
+ javax.swing.GroupLayout logoPanelLayout = new javax.swing.GroupLayout(logoPanel);
+ logoPanel.setLayout(logoPanelLayout);
+ logoPanelLayout.setHorizontalGroup(
+ logoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, logoPanelLayout.createSequentialGroup()
+ .addContainerGap()
+ .addGroup(logoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addComponent(agencyLogoImageLabel)
+ .addGroup(logoPanelLayout.createSequentialGroup()
+ .addGap(10, 10, 10)
+ .addComponent(agencyLogoPathField, javax.swing.GroupLayout.PREFERRED_SIZE, 259, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(browseLogosButton)))
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+ .addComponent(agencyLogoPreview, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addContainerGap(149, Short.MAX_VALUE))
+ );
+ logoPanelLayout.setVerticalGroup(
+ logoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(logoPanelLayout.createSequentialGroup()
+ .addGroup(logoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addComponent(agencyLogoPreview, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addGroup(logoPanelLayout.createSequentialGroup()
+ .addContainerGap()
+ .addComponent(agencyLogoImageLabel)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addGroup(logoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+ .addComponent(agencyLogoPathField)
+ .addComponent(browseLogosButton))))
+ .addGap(0, 0, 0))
+ );
+
+ viewPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.viewPanel.border.title"))); // NOI18N
+
+ org.openide.awt.Mnemonics.setLocalizedText(jLabelSelectFile, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.jLabelSelectFile.text")); // NOI18N
+
buttonGroup1.add(useBestViewerRB);
org.openide.awt.Mnemonics.setLocalizedText(useBestViewerRB, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.useBestViewerRB.text")); // NOI18N
useBestViewerRB.setToolTipText(org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.useBestViewerRB.toolTipText")); // NOI18N
@@ -123,7 +226,37 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
}
});
- org.openide.awt.Mnemonics.setLocalizedText(jLabelSelectFile, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.jLabelSelectFile.text")); // NOI18N
+ org.openide.awt.Mnemonics.setLocalizedText(jLabelHideKnownFiles, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.jLabelHideKnownFiles.text")); // NOI18N
+
+ org.openide.awt.Mnemonics.setLocalizedText(dataSourcesHideKnownCB, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.dataSourcesHideKnownCB.text")); // NOI18N
+ dataSourcesHideKnownCB.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ dataSourcesHideKnownCBActionPerformed(evt);
+ }
+ });
+
+ org.openide.awt.Mnemonics.setLocalizedText(viewsHideKnownCB, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.viewsHideKnownCB.text")); // NOI18N
+ viewsHideKnownCB.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ viewsHideKnownCBActionPerformed(evt);
+ }
+ });
+
+ org.openide.awt.Mnemonics.setLocalizedText(jLabelHideSlackFiles, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.jLabelHideSlackFiles.text")); // NOI18N
+
+ org.openide.awt.Mnemonics.setLocalizedText(dataSourcesHideSlackCB, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.dataSourcesHideSlackCB.text")); // NOI18N
+ dataSourcesHideSlackCB.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ dataSourcesHideSlackCBActionPerformed(evt);
+ }
+ });
+
+ org.openide.awt.Mnemonics.setLocalizedText(viewsHideSlackCB, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.viewsHideSlackCB.text")); // NOI18N
+ viewsHideSlackCB.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ viewsHideSlackCBActionPerformed(evt);
+ }
+ });
org.openide.awt.Mnemonics.setLocalizedText(jLabelTimeDisplay, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.jLabelTimeDisplay.text")); // NOI18N
@@ -143,93 +276,34 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
}
});
- org.openide.awt.Mnemonics.setLocalizedText(jLabelHideKnownFiles, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.jLabelHideKnownFiles.text")); // NOI18N
-
- org.openide.awt.Mnemonics.setLocalizedText(dataSourcesHideKnownCB, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.dataSourcesHideKnownCB.text")); // NOI18N
- dataSourcesHideKnownCB.addActionListener(new java.awt.event.ActionListener() {
- public void actionPerformed(java.awt.event.ActionEvent evt) {
- dataSourcesHideKnownCBActionPerformed(evt);
- }
- });
-
- org.openide.awt.Mnemonics.setLocalizedText(viewsHideKnownCB, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.viewsHideKnownCB.text")); // NOI18N
- viewsHideKnownCB.addActionListener(new java.awt.event.ActionListener() {
- public void actionPerformed(java.awt.event.ActionEvent evt) {
- viewsHideKnownCBActionPerformed(evt);
- }
- });
-
- org.openide.awt.Mnemonics.setLocalizedText(dataSourcesHideSlackCB, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.dataSourcesHideSlackCB.text")); // NOI18N
- dataSourcesHideSlackCB.addActionListener(new java.awt.event.ActionListener() {
- public void actionPerformed(java.awt.event.ActionEvent evt) {
- dataSourcesHideSlackCBActionPerformed(evt);
- }
- });
-
- org.openide.awt.Mnemonics.setLocalizedText(viewsHideSlackCB, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.viewsHideSlackCB.text")); // NOI18N
- viewsHideSlackCB.addActionListener(new java.awt.event.ActionListener() {
- public void actionPerformed(java.awt.event.ActionEvent evt) {
- viewsHideSlackCBActionPerformed(evt);
- }
- });
-
- org.openide.awt.Mnemonics.setLocalizedText(jLabelHideSlackFiles, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.jLabelHideSlackFiles.text")); // NOI18N
-
- org.openide.awt.Mnemonics.setLocalizedText(agencyLogoImageLabel, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.agencyLogoImageLabel.text")); // NOI18N
-
- agencyLogoPathField.setEditable(false);
- agencyLogoPathField.setBackground(new java.awt.Color(255, 255, 255));
- agencyLogoPathField.setText(org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.agencyLogoPathField.text")); // NOI18N
- agencyLogoPathField.setFocusable(false);
- agencyLogoPathField.setRequestFocusEnabled(false);
-
- org.openide.awt.Mnemonics.setLocalizedText(browseLogosButton, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.browseLogosButton.text")); // NOI18N
- browseLogosButton.addActionListener(new java.awt.event.ActionListener() {
- public void actionPerformed(java.awt.event.ActionEvent evt) {
- browseLogosButtonActionPerformed(evt);
- }
- });
-
- javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
- jPanel1.setLayout(jPanel1Layout);
- jPanel1Layout.setHorizontalGroup(
- jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addGroup(jPanel1Layout.createSequentialGroup()
+ javax.swing.GroupLayout viewPanelLayout = new javax.swing.GroupLayout(viewPanel);
+ viewPanel.setLayout(viewPanelLayout);
+ viewPanelLayout.setHorizontalGroup(
+ viewPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, viewPanelLayout.createSequentialGroup()
.addContainerGap()
- .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addGroup(jPanel1Layout.createSequentialGroup()
- .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addComponent(jLabelTimeDisplay)
- .addComponent(jLabelHideKnownFiles)
- .addComponent(jLabelSelectFile)
- .addGroup(jPanel1Layout.createSequentialGroup()
- .addGap(10, 10, 10)
- .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addComponent(useLocalTimeRB)
- .addComponent(useGMTTimeRB)
- .addComponent(keepCurrentViewerRB)
- .addComponent(useBestViewerRB)
- .addComponent(dataSourcesHideKnownCB)
- .addComponent(viewsHideKnownCB))))
- .addContainerGap(140, Short.MAX_VALUE))
- .addGroup(jPanel1Layout.createSequentialGroup()
- .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addComponent(jLabelHideSlackFiles)
- .addComponent(agencyLogoImageLabel)
- .addGroup(jPanel1Layout.createSequentialGroup()
- .addGap(10, 10, 10)
- .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addGroup(jPanel1Layout.createSequentialGroup()
- .addComponent(agencyLogoPathField, javax.swing.GroupLayout.PREFERRED_SIZE, 259, javax.swing.GroupLayout.PREFERRED_SIZE)
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
- .addComponent(browseLogosButton))
- .addComponent(dataSourcesHideSlackCB)
- .addComponent(viewsHideSlackCB))))
- .addGap(0, 0, Short.MAX_VALUE))))
+ .addGroup(viewPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(viewPanelLayout.createSequentialGroup()
+ .addGap(10, 10, 10)
+ .addGroup(viewPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addComponent(useGMTTimeRB)
+ .addComponent(keepCurrentViewerRB)
+ .addComponent(useBestViewerRB)
+ .addGroup(viewPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addComponent(useLocalTimeRB)
+ .addComponent(dataSourcesHideSlackCB)
+ .addComponent(viewsHideSlackCB)
+ .addComponent(dataSourcesHideKnownCB)
+ .addComponent(viewsHideKnownCB))))
+ .addComponent(jLabelHideSlackFiles)
+ .addComponent(jLabelTimeDisplay)
+ .addComponent(jLabelHideKnownFiles)
+ .addComponent(jLabelSelectFile))
+ .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
- jPanel1Layout.setVerticalGroup(
- jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addGroup(jPanel1Layout.createSequentialGroup()
+ viewPanelLayout.setVerticalGroup(
+ viewPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, viewPanelLayout.createSequentialGroup()
.addContainerGap()
.addComponent(jLabelSelectFile)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
@@ -253,14 +327,28 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(useLocalTimeRB)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
- .addComponent(useGMTTimeRB)
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
- .addComponent(agencyLogoImageLabel)
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
- .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
- .addComponent(agencyLogoPathField)
- .addComponent(browseLogosButton))
- .addGap(35, 35, 35))
+ .addComponent(useGMTTimeRB))
+ );
+
+ javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
+ jPanel1.setLayout(jPanel1Layout);
+ jPanel1Layout.setHorizontalGroup(
+ jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup()
+ .addContainerGap()
+ .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
+ .addComponent(viewPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addComponent(logoPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+ .addContainerGap())
+ );
+ jPanel1Layout.setVerticalGroup(
+ jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(jPanel1Layout.createSequentialGroup()
+ .addGap(0, 0, 0)
+ .addComponent(viewPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addGap(0, 0, 0)
+ .addComponent(logoPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addGap(0, 0, 0))
);
jScrollPane1.setViewportView(jPanel1);
@@ -269,11 +357,15 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addComponent(jScrollPane1, javax.swing.GroupLayout.Alignment.TRAILING)
+ .addGroup(layout.createSequentialGroup()
+ .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 672, Short.MAX_VALUE)
+ .addGap(0, 0, 0))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addComponent(jScrollPane1)
+ .addGroup(layout.createSequentialGroup()
+ .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 489, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addGap(0, 0, Short.MAX_VALUE))
);
}// //GEN-END:initComponents
@@ -310,17 +402,32 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
}//GEN-LAST:event_viewsHideSlackCBActionPerformed
private void browseLogosButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseLogosButtonActionPerformed
+ String oldLogoPath = agencyLogoPathField.getText();
int returnState = fc.showOpenDialog(this);
if (returnState == JFileChooser.APPROVE_OPTION) {
String path = fc.getSelectedFile().getPath();
- agencyLogoPathField.setText(path);
- firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
+ try {
+ updateAgencyLogo(path);
+ firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
+ } catch (IOException | IndexOutOfBoundsException ex) {
+ JOptionPane.showMessageDialog(null,
+ NbBundle.getMessage(this.getClass(),
+ "AutopsyOptionsPanel.invalidImageFile.msg"),
+ NbBundle.getMessage(this.getClass(), "AutopsyOptionsPanel.invalidImageFile.title"),
+ JOptionPane.ERROR_MESSAGE);
+ try {
+ updateAgencyLogo(oldLogoPath); //restore previous setting if new one is invalid
+ } catch (IOException ex1) {
+ logger.log(Level.WARNING, "Error loading image from previously saved agency logo path", ex1);
+ }
+ }
}
}//GEN-LAST:event_browseLogosButtonActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JLabel agencyLogoImageLabel;
private javax.swing.JTextField agencyLogoPathField;
+ private javax.swing.JLabel agencyLogoPreview;
private javax.swing.JButton browseLogosButton;
private javax.swing.ButtonGroup buttonGroup1;
private javax.swing.ButtonGroup buttonGroup3;
@@ -333,9 +440,11 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
private javax.swing.JPanel jPanel1;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JRadioButton keepCurrentViewerRB;
+ private javax.swing.JPanel logoPanel;
private javax.swing.JRadioButton useBestViewerRB;
private javax.swing.JRadioButton useGMTTimeRB;
private javax.swing.JRadioButton useLocalTimeRB;
+ private javax.swing.JPanel viewPanel;
private javax.swing.JCheckBox viewsHideKnownCB;
private javax.swing.JCheckBox viewsHideSlackCB;
// End of variables declaration//GEN-END:variables
diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties
index 5ac6cbd626..26a2cc03e0 100755
--- a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties
+++ b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties
@@ -1,7 +1,7 @@
CTL_DataContentAction=DataContent
CTL_DataContentTopComponent=Data Content
CTL_CustomAboutAction=About
-OptionsCategory_Name_General=View
+OptionsCategory_Name_General=Application
OptionsCategory_Keywords_General=Autopsy Options
HINT_DataContentTopComponent=This is a DataContent window
HINT_NodeTableTopComponent=This is a DataResult window
@@ -198,7 +198,6 @@ AutopsyOptionsPanel.agencyLogoPathField.text=
SortChooserDialog.label=remove
SortChooser.addCriteriaButton.text=Add Sort Criteria
DataResultViewerThumbnail.sortButton.text=Sort
-
CriterionChooser.ascendingRadio.text=\u25b2 Ascending\n
CriterionChooser.removeButton.text=Remove
CriterionChooser.descendingRadio.text=\u25bc Descending
diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypeExtensions.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypeExtensions.java
index 4195b33008..eafa8377b2 100755
--- a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypeExtensions.java
+++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypeExtensions.java
@@ -38,6 +38,7 @@ public class FileTypeExtensions {
private final static List WEB_EXTENSIONS = Arrays.asList(".html", ".htm", ".css", ".js", ".php", ".aspx"); //NON-NLS
private final static List PDF_EXTENSIONS = Arrays.asList(".pdf"); //NON-NLS
private final static List ARCHIVE_EXTENSIONS = Arrays.asList(".zip", ".rar", ".7zip", ".7z", ".arj", ".tar", ".gzip", ".bzip", ".bzip2", ".cab", ".jar", ".cpio", ".ar", ".gz", ".tgz", ".bz2"); //NON-NLS
+ private final static List DATABASE_EXTENSIONS = Arrays.asList(".db", ".db3", ".sqlite", ".sqlite3"); //NON-NLS
public static List getImageExtensions() {
return IMAGE_EXTENSIONS;
@@ -75,6 +76,10 @@ public class FileTypeExtensions {
return ARCHIVE_EXTENSIONS;
}
+ public static List getDatabaseExtensions() {
+ return DATABASE_EXTENSIONS;
+ }
+
private FileTypeExtensions() {
}
diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java
index 305da8e953..2341fff12c 100755
--- a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java
+++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java
@@ -34,6 +34,7 @@ import org.openide.nodes.Children;
import org.openide.nodes.Node;
import org.openide.nodes.Sheet;
import org.openide.util.NbBundle;
+import org.openide.util.NbBundle.Messages;
import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.core.UserPreferences;
@@ -423,6 +424,7 @@ public final class FileTypesByExtension implements AutopsyVisitableItem {
}
// root node filters
+ @Messages({"FileTypeExtensionFilters.tskDatabaseFilter.text=Databases"})
public static enum RootFilter implements AutopsyVisitableItem, SearchFilterInterface {
TSK_IMAGE_FILTER(0, "TSK_IMAGE_FILTER", //NON-NLS
@@ -437,10 +439,13 @@ public final class FileTypesByExtension implements AutopsyVisitableItem {
TSK_ARCHIVE_FILTER(3, "TSK_ARCHIVE_FILTER", //NON-NLS
NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.tskArchiveFilter.text"),
FileTypeExtensions.getArchiveExtensions()),
- TSK_DOCUMENT_FILTER(3, "TSK_DOCUMENT_FILTER", //NON-NLS
+ TSK_DATABASE_FILTER(4, "TSK_DATABASE_FILTER", //NON-NLS
+ NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.tskDatabaseFilter.text"),
+ FileTypeExtensions.getDatabaseExtensions()),
+ TSK_DOCUMENT_FILTER(5, "TSK_DOCUMENT_FILTER", //NON-NLS
NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.tskDocumentFilter.text"),
Arrays.asList(".htm", ".html", ".doc", ".docx", ".odt", ".xls", ".xlsx", ".ppt", ".pptx", ".pdf", ".txt", ".rtf")), //NON-NLS
- TSK_EXECUTABLE_FILTER(3, "TSK_EXECUTABLE_FILTER", //NON-NLS
+ TSK_EXECUTABLE_FILTER(6, "TSK_EXECUTABLE_FILTER", //NON-NLS
NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.tskExecFilter.text"),
FileTypeExtensions.getExecutableExtensions()); //NON-NLS
diff --git a/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionFileIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionFileIngestModule.java
new file mode 100755
index 0000000000..f18911c016
--- /dev/null
+++ b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionFileIngestModule.java
@@ -0,0 +1,263 @@
+/*
+ * Autopsy Forensic Browser
+ *
+ * Copyright 2017 Basis Technology Corp.
+ * Contact: carrier sleuthkit org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.sleuthkit.autopsy.modules.encryptiondetection;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Paths;
+import java.util.Collections;
+import java.util.logging.Level;
+import org.sleuthkit.autopsy.casemodule.Case;
+import org.sleuthkit.autopsy.casemodule.services.Blackboard;
+import org.sleuthkit.autopsy.coreutils.Logger;
+import org.sleuthkit.autopsy.ingest.FileIngestModuleAdapter;
+import org.sleuthkit.autopsy.ingest.IngestJobContext;
+import org.sleuthkit.autopsy.ingest.IngestMessage;
+import org.sleuthkit.autopsy.ingest.IngestModule;
+import org.sleuthkit.autopsy.ingest.IngestServices;
+import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
+import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector;
+import org.sleuthkit.datamodel.AbstractFile;
+import org.sleuthkit.datamodel.BlackboardArtifact;
+import org.sleuthkit.datamodel.ReadContentInputStream;
+import org.sleuthkit.datamodel.TskCoreException;
+import org.sleuthkit.datamodel.TskData;
+
+/**
+ * File ingest module to detect encryption.
+ */
+final class EncryptionDetectionFileIngestModule extends FileIngestModuleAdapter {
+
+ private static final double ENTROPY_THRESHOLD = 7.5;
+ private static final int FILE_SIZE_THRESHOLD = 5242880; // 5MB
+ private static final int FILE_SIZE_MODULUS = 512;
+ private static final double ONE_OVER_LOG2 = 1.4426950408889634073599246810019; // (1 / log(2))
+ private static final int BYTE_OCCURENCES_BUFFER_SIZE = 256;
+
+ private final IngestServices SERVICES = IngestServices.getInstance();
+ private final Logger LOGGER = SERVICES.getLogger(EncryptionDetectionModuleFactory.getModuleName());
+ private FileTypeDetector fileTypeDetector;
+ private Blackboard blackboard;
+ private double entropy;
+
+ /**
+ * Create a EncryptionDetectionFileIngestModule object that will detect files
+ * that are encrypted and create blackboard artifacts as appropriate.
+ */
+ EncryptionDetectionFileIngestModule() {
+ }
+
+ @Override
+ public void startUp(IngestJobContext context) throws IngestModule.IngestModuleException {
+ blackboard = Case.getCurrentCase().getServices().getBlackboard();
+ try {
+ fileTypeDetector = new FileTypeDetector();
+ } catch (FileTypeDetector.FileTypeDetectorInitException ex) {
+ throw new IngestModule.IngestModuleException("Failed to create file type detector", ex);
+ }
+ }
+
+ @Override
+ public IngestModule.ProcessResult process(AbstractFile file) {
+
+ try {
+ if (isFileEncrypted(file)) {
+ return flagFile(file);
+ }
+ } catch (IOException | TskCoreException ex) {
+ LOGGER.log(Level.SEVERE, String.format("Unable to process file '%s'", Paths.get(file.getParentPath(), file.getName())), ex);
+ return IngestModule.ProcessResult.ERROR;
+ }
+
+ return IngestModule.ProcessResult.OK;
+ }
+
+ /**
+ * Create a blackboard artifact.
+ *
+ * @param The file to be processed.
+ *
+ * @return 'OK' if the file was processed successfully, or 'ERROR' if there
+ * was a problem.
+ */
+ private IngestModule.ProcessResult flagFile(AbstractFile file) {
+ try {
+ BlackboardArtifact artifact = file.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED);
+
+ try {
+ /*
+ * Index the artifact for keyword search.
+ */
+ blackboard.indexArtifact(artifact);
+ } catch (Blackboard.BlackboardException ex) {
+ 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.
+ */
+ SERVICES.fireModuleDataEvent(new ModuleDataEvent(EncryptionDetectionModuleFactory.getModuleName(), BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED, Collections.singletonList(artifact)));
+
+ /*
+ * Make an ingest inbox message.
+ */
+ StringBuilder detailsSb = new StringBuilder();
+ detailsSb.append("File: ").append(file.getParentPath()).append(file.getName()).append("
\n");
+ detailsSb.append("Entropy: ").append(entropy);
+
+ SERVICES.postMessage(IngestMessage.createDataMessage(EncryptionDetectionModuleFactory.getModuleName(),
+ "Encryption Detected Match: " + file.getName(),
+ detailsSb.toString(),
+ file.getName(),
+ artifact));
+
+ return IngestModule.ProcessResult.OK;
+ } catch (TskCoreException ex) {
+ LOGGER.log(Level.SEVERE, String.format("Failed to create blackboard artifact for '%s'.", Paths.get(file.getParentPath(), file.getName())), ex); //NON-NLS
+ return IngestModule.ProcessResult.ERROR;
+ }
+ }
+
+ /**
+ * This method checks if the AbstractFile input is encrypted. Initial
+ * qualifications require that it be an actual file that is not known, meets
+ * file size requirements, and has a MIME type of
+ * 'application/octet-stream'.
+ *
+ * @param file AbstractFile to be checked.
+ *
+ * @return True if the AbstractFile is encrypted.
+ */
+ private boolean isFileEncrypted(AbstractFile file) throws IOException, TskCoreException {
+ /*
+ * Criteria for the checks in this method are partially based on
+ * http://www.forensicswiki.org/wiki/TrueCrypt#Detection
+ */
+
+ boolean possiblyEncrypted = false;
+
+ /*
+ * Qualify the file type.
+ */
+ if (!file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS)
+ && !file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS)
+ && !file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR)
+ && !file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL_DIR)) {
+ /*
+ * Qualify the file against hash databases.
+ */
+ if (!file.getKnown().equals(TskData.FileKnown.KNOWN)) {
+ /*
+ * Qualify the size.
+ */
+ long contentSize = file.getSize();
+ if (contentSize >= FILE_SIZE_THRESHOLD && (contentSize % FILE_SIZE_MODULUS) == 0) {
+ /*
+ * Qualify the MIME type.
+ */
+ try {
+ String mimeType = fileTypeDetector.getFileType(file);
+ if (mimeType != null && mimeType.equals("application/octet-stream")) {
+ possiblyEncrypted = true;
+ }
+ } catch (TskCoreException ex) {
+ throw new TskCoreException("Failed to detect the file type.", ex);
+ }
+ }
+ }
+ }
+
+ if (possiblyEncrypted) {
+ try {
+ entropy = calculateEntropy(file);
+ if (entropy > ENTROPY_THRESHOLD) {
+ return true;
+ }
+ } catch (IOException ex) {
+ throw new IOException("Unable to calculate the entropy.", ex);
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Calculate the entropy of the file. The result is used to qualify the file
+ * as an encrypted file.
+ *
+ * @param file The file to be calculated against.
+ *
+ * @return The entropy of the file.
+ *
+ * @throws IOException If there is a failure closing or reading from the
+ * InputStream.
+ */
+ private double calculateEntropy(AbstractFile file) throws IOException {
+ /*
+ * Logic in this method is based on
+ * https://github.com/willjasen/entropy/blob/master/entropy.java
+ */
+
+ InputStream in = null;
+ BufferedInputStream bin = null;
+
+ try {
+ in = new ReadContentInputStream(file);
+ bin = new BufferedInputStream(in);
+
+ /*
+ * Determine the number of times each byte value appears.
+ */
+ int[] byteOccurences = new int[BYTE_OCCURENCES_BUFFER_SIZE];
+ int readByte;
+ while ((readByte = bin.read()) != -1) {
+ byteOccurences[readByte]++;
+ }
+
+ /*
+ * Calculate the entropy based on the byte occurence counts.
+ */
+ long dataLength = file.getSize() - 1;
+ double entropyAccumulator = 0;
+ for (int i = 0; i < BYTE_OCCURENCES_BUFFER_SIZE; i++) {
+ if (byteOccurences[i] > 0) {
+ double byteProbability = (double) byteOccurences[i] / (double) dataLength;
+ entropyAccumulator += (byteProbability * Math.log(byteProbability) * ONE_OVER_LOG2);
+ }
+ }
+
+ return -entropyAccumulator;
+
+ } catch (IOException ex) {
+ throw new IOException("IOException occurred while trying to read data from InputStream.", ex);
+ } finally {
+ try {
+ if (in != null) {
+ in.close();
+ }
+ if (bin != null) {
+ bin.close();
+ }
+ } catch (IOException ex) {
+ throw new IOException("Failed to close InputStream.", ex);
+ }
+ }
+ }
+}
diff --git a/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionModuleFactory.java b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionModuleFactory.java
new file mode 100755
index 0000000000..53eca1aec6
--- /dev/null
+++ b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionModuleFactory.java
@@ -0,0 +1,73 @@
+/*
+ * Autopsy Forensic Browser
+ *
+ * Copyright 2017 Basis Technology Corp.
+ * Contact: carrier sleuthkit org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.sleuthkit.autopsy.modules.encryptiondetection;
+
+import org.openide.util.NbBundle;
+import org.openide.util.NbBundle.Messages;
+import org.openide.util.lookup.ServiceProvider;
+import org.sleuthkit.autopsy.coreutils.Version;
+import org.sleuthkit.autopsy.ingest.FileIngestModule;
+import org.sleuthkit.autopsy.ingest.IngestModuleFactory;
+import org.sleuthkit.autopsy.ingest.IngestModuleFactoryAdapter;
+import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings;
+
+/**
+ * A factory that creates file ingest modules that detect encryption.
+ */
+@ServiceProvider(service = IngestModuleFactory.class)
+@Messages({
+ "EncryptionDetectionFileIngestModule.moduleName.text=Encryption Detection",
+ "EncryptionDetectionFileIngestModule.getDesc.text=Looks for large files with high entropy."
+})
+public class EncryptionDetectionModuleFactory extends IngestModuleFactoryAdapter {
+
+ @Override
+ public String getModuleDisplayName() {
+ return getModuleName();
+ }
+
+ /**
+ * Get the name of the module.
+ *
+ * @return The module name.
+ */
+ static String getModuleName() {
+ return NbBundle.getMessage(EncryptionDetectionFileIngestModule.class, "EncryptionDetectionFileIngestModule.moduleName.text");
+ }
+
+ @Override
+ public String getModuleDescription() {
+ return NbBundle.getMessage(EncryptionDetectionFileIngestModule.class, "EncryptionDetectionFileIngestModule.getDesc.text");
+ }
+
+ @Override
+ public String getModuleVersionNumber() {
+ return Version.getVersion();
+ }
+
+ @Override
+ public boolean isFileIngestModuleFactory() {
+ return true;
+ }
+
+ @Override
+ public FileIngestModule createFileIngestModule(IngestModuleIngestJobSettings ingestOptions) {
+ return new EncryptionDetectionFileIngestModule();
+ }
+}
\ No newline at end of file