19 package org.sleuthkit.autopsy.modules.encryptiondetection;
21 import java.io.BufferedInputStream;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.util.Collections;
25 import java.util.logging.Level;
47 static final double DEFAULT_CONFIG_MINIMUM_ENTROPY = 7.5;
48 static final int DEFAULT_CONFIG_MINIMUM_FILE_SIZE = 5242880;
49 static final boolean DEFAULT_CONFIG_FILE_SIZE_MULTIPLE_ENFORCED =
true;
50 static final boolean DEFAULT_CONFIG_SLACK_FILES_ALLOWED =
true;
52 private static final int FILE_SIZE_MODULUS = 512;
53 private static final double ONE_OVER_LOG2 = 1.4426950408889634073599246810019;
54 private static final int BYTE_OCCURENCES_BUFFER_SIZE = 256;
60 private double calculatedEntropy;
62 private final double minimumEntropy;
63 private final int minimumFileSize;
64 private final boolean fileSizeMultipleEnforced;
65 private final boolean slackFilesAllowed;
73 EncryptionDetectionFileIngestModule(EncryptionDetectionIngestJobSettings settings) {
74 minimumEntropy = settings.getMinimumEntropy();
75 minimumFileSize = settings.getMinimumFileSize();
76 fileSizeMultipleEnforced = settings.isFileSizeMultipleEnforced();
77 slackFilesAllowed = settings.isSlackFilesAllowed();
94 if (isFileEncrypted(file)) {
95 return flagFile(file);
97 }
catch (IOException | TskCoreException ex) {
98 LOGGER.log(Level.SEVERE, String.format(
"Unable to process file '%s'", file.getParentPath() + file.getName()), ex);
115 BlackboardArtifact artifact = file.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_SUSPECTED);
123 LOGGER.log(Level.SEVERE,
"Unable to index blackboard artifact " + artifact.getArtifactID(), ex);
134 StringBuilder detailsSb =
new StringBuilder();
135 detailsSb.append(
"File: ").append(file.getParentPath()).append(file.getName()).append(
"<br/>\n");
136 detailsSb.append(
"Entropy: ").append(calculatedEntropy);
139 "Encryption Detected Match: " + file.getName(),
140 detailsSb.toString(),
145 }
catch (TskCoreException ex) {
146 LOGGER.log(Level.SEVERE, String.format(
"Failed to create blackboard artifact for '%s'.", file.getParentPath() + file.getName()), ex);
161 private boolean isFileEncrypted(AbstractFile file)
throws IOException, TskCoreException {
167 boolean possiblyEncrypted =
false;
172 if (!file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS)
173 && !file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS)
174 && !file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR)
175 && !file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL_DIR)
176 && (!file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.SLACK) || slackFilesAllowed)) {
180 if (!file.getKnown().equals(TskData.FileKnown.KNOWN)) {
184 long contentSize = file.getSize();
185 if (contentSize >= minimumFileSize) {
186 if (!fileSizeMultipleEnforced || (contentSize % FILE_SIZE_MODULUS) == 0) {
190 String mimeType = fileTypeDetector.
getMIMEType(file);
191 if (mimeType.equals(
"application/octet-stream")) {
192 possiblyEncrypted =
true;
199 if (possiblyEncrypted) {
201 calculatedEntropy = calculateEntropy(file);
202 if (calculatedEntropy >= minimumEntropy) {
205 }
catch (IOException ex) {
206 throw new IOException(
"Unable to calculate the entropy.", ex);
224 private double calculateEntropy(AbstractFile file)
throws IOException {
230 InputStream in = null;
231 BufferedInputStream bin = null;
234 in =
new ReadContentInputStream(file);
235 bin =
new BufferedInputStream(in);
240 int[] byteOccurences =
new int[BYTE_OCCURENCES_BUFFER_SIZE];
242 while ((readByte = bin.read()) != -1) {
243 byteOccurences[readByte]++;
249 long dataLength = file.getSize() - 1;
250 double entropyAccumulator = 0;
251 for (
int i = 0; i < BYTE_OCCURENCES_BUFFER_SIZE; i++) {
252 if (byteOccurences[i] > 0) {
253 double byteProbability = (double) byteOccurences[i] / (
double) dataLength;
254 entropyAccumulator += (byteProbability * Math.log(byteProbability) * ONE_OVER_LOG2);
258 return -entropyAccumulator;
260 }
catch (IOException ex) {
261 throw new IOException(
"IOException occurred while trying to read data from InputStream.", ex);
270 }
catch (IOException ex) {
271 throw new IOException(
"Failed to close InputStream.", ex);
static IngestMessage createDataMessage(String source, String subject, String detailsHtml, String uniqueKey, BlackboardArtifact data)
Logger getLogger(String moduleDisplayName)
String getMIMEType(AbstractFile file)
void postMessage(final IngestMessage message)
void fireModuleDataEvent(ModuleDataEvent moduleDataEvent)
Blackboard getBlackboard()
synchronized void indexArtifact(BlackboardArtifact artifact)
static Case getCurrentCase()
static synchronized IngestServices getInstance()