Autopsy 4.22.1
Graphical digital forensics platform for The Sleuth Kit and other tools.
EncryptionDetectionDataSourceIngestModule.java
Go to the documentation of this file.
1/*
2 * Autopsy Forensic Browser
3 *
4 * Copyright 2018-2021 Basis Technology Corp.
5 * Contact: carrier <at> sleuthkit <dot> org
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19package org.sleuthkit.autopsy.modules.encryptiondetection;
20
21import java.io.IOException;
22import java.util.Arrays;
23import java.util.List;
24import java.util.logging.Level;
25import org.openide.util.NbBundle.Messages;
26import org.sleuthkit.autopsy.casemodule.Case;
27import org.sleuthkit.autopsy.coreutils.Logger;
28import org.sleuthkit.autopsy.ingest.DataSourceIngestModule;
29import org.sleuthkit.autopsy.ingest.DataSourceIngestModuleProgress;
30import org.sleuthkit.autopsy.ingest.IngestJobContext;
31import org.sleuthkit.autopsy.ingest.IngestMessage;
32import org.sleuthkit.autopsy.ingest.IngestModule;
33import org.sleuthkit.autopsy.ingest.IngestServices;
34import org.sleuthkit.datamodel.Blackboard;
35import org.sleuthkit.datamodel.BlackboardArtifact;
36import org.sleuthkit.datamodel.BlackboardAttribute;
37import org.sleuthkit.datamodel.Content;
38import org.sleuthkit.datamodel.Image;
39import org.sleuthkit.datamodel.ReadContentInputStream;
40import org.sleuthkit.datamodel.Score;
41import org.sleuthkit.datamodel.TskCoreException;
42import org.sleuthkit.datamodel.Volume;
43import org.sleuthkit.datamodel.VolumeSystem;
44
48final class EncryptionDetectionDataSourceIngestModule implements DataSourceIngestModule {
49
50 private final IngestServices services = IngestServices.getInstance();
51 private final Logger logger = services.getLogger(EncryptionDetectionModuleFactory.getModuleName());
52 private Blackboard blackboard;
53 private double calculatedEntropy;
54 private final double minimumEntropy;
55 private IngestJobContext context;
56
64 EncryptionDetectionDataSourceIngestModule(EncryptionDetectionIngestJobSettings settings) {
65 minimumEntropy = settings.getMinimumEntropy();
66 }
67
68 @Override
69 public void startUp(IngestJobContext context) throws IngestModule.IngestModuleException {
70 validateSettings();
71 blackboard = Case.getCurrentCase().getSleuthkitCase().getBlackboard();
72 this.context = context;
73 }
74
75 @Messages({
76 "EncryptionDetectionDataSourceIngestModule.artifactComment.bitlocker=Bitlocker encryption detected.",
77 "EncryptionDetectionDataSourceIngestModule.artifactComment.suspected=Suspected encryption due to high entropy (%f).",
78 "EncryptionDetectionDataSourceIngestModule.processing.message=Checking image for encryption."
79 })
80 @Override
81 public ProcessResult process(Content dataSource, DataSourceIngestModuleProgress progressBar) {
82
83 try {
84 if (dataSource instanceof Image) {
85
86 if (((Image) dataSource).getPaths().length == 0) {
87 logger.log(Level.SEVERE, String.format("Unable to process data source '%s' - image has no paths", dataSource.getName()));
88 return IngestModule.ProcessResult.ERROR;
89 }
90
91 List<VolumeSystem> volumeSystems = ((Image) dataSource).getVolumeSystems();
92 progressBar.switchToDeterminate(volumeSystems.size());
93 int numVolSystemsChecked = 0;
94 progressBar.progress(Bundle.EncryptionDetectionDataSourceIngestModule_processing_message(), 0);
95 for (VolumeSystem volumeSystem : volumeSystems) {
96
97 if (context.dataSourceIngestIsCancelled()) {
98 return ProcessResult.OK;
99 }
100
101 for (Volume volume : volumeSystem.getVolumes()) {
102
103 if (context.dataSourceIngestIsCancelled()) {
104 return ProcessResult.OK;
105 }
106 if (BitlockerDetection.isBitlockerVolume(volume)) {
107 return flagVolume(volume, BlackboardArtifact.Type.TSK_ENCRYPTION_DETECTED, Score.SCORE_NOTABLE,
108 Bundle.EncryptionDetectionDataSourceIngestModule_artifactComment_bitlocker());
109 }
110
111 if (context.dataSourceIngestIsCancelled()) {
112 return ProcessResult.OK;
113 }
114 if (isVolumeEncrypted(volume)) {
115 return flagVolume(volume, BlackboardArtifact.Type.TSK_ENCRYPTION_SUSPECTED, Score.SCORE_LIKELY_NOTABLE,
116 String.format(Bundle.EncryptionDetectionDataSourceIngestModule_artifactComment_suspected(), calculatedEntropy));
117 }
118 }
119 // Update progress bar
120 numVolSystemsChecked++;
121 progressBar.progress(Bundle.EncryptionDetectionDataSourceIngestModule_processing_message(), numVolSystemsChecked);
122 }
123 }
124 } catch (ReadContentInputStream.ReadContentInputStreamException ex) {
125 logger.log(Level.WARNING, String.format("Unable to read data source '%s'", dataSource.getName()), ex);
126 return IngestModule.ProcessResult.ERROR;
127 } catch (IOException | TskCoreException ex) {
128 logger.log(Level.SEVERE, String.format("Unable to process data source '%s'", dataSource.getName()), ex);
129 return IngestModule.ProcessResult.ERROR;
130 }
131
132 return IngestModule.ProcessResult.OK;
133 }
134
143 private void validateSettings() throws IngestModule.IngestModuleException {
144 EncryptionDetectionTools.validateMinEntropyValue(minimumEntropy);
145 }
146
159 private IngestModule.ProcessResult flagVolume(Volume volume, BlackboardArtifact.Type artifactType, Score score, String comment) {
160
161 if (context.dataSourceIngestIsCancelled()) {
162 return ProcessResult.OK;
163 }
164
165 try {
166 BlackboardArtifact artifact = volume.newAnalysisResult(artifactType, score, null, null, comment,
167 Arrays.asList(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT, EncryptionDetectionModuleFactory.getModuleName(), comment)))
168 .getAnalysisResult();
169
170 try {
171 /*
172 * post the artifact which will index the artifact for keyword
173 * search, and fire an event to notify UI of this new artifact
174 */
175 blackboard.postArtifact(artifact, EncryptionDetectionModuleFactory.getModuleName(), context.getJobId());
176 } catch (Blackboard.BlackboardException ex) {
177 logger.log(Level.SEVERE, "Unable to index blackboard artifact " + artifact.getArtifactID(), ex); //NON-NLS
178 }
179
180 /*
181 * Make an ingest inbox message.
182 */
183 StringBuilder detailsSb = new StringBuilder("");
184 detailsSb.append("File: ");
185 Content parentFile = volume.getParent();
186 if (parentFile != null) {
187 detailsSb.append(volume.getParent().getUniquePath());
188 }
189 detailsSb.append(volume.getName());
190 if (artifactType.equals(BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_SUSPECTED)) {
191 detailsSb.append("<br/>\nEntropy: ").append(calculatedEntropy);
192 }
193
194 services.postMessage(IngestMessage.createDataMessage(EncryptionDetectionModuleFactory.getModuleName(),
195 artifactType.getDisplayName() + " Match: " + volume.getName(),
196 detailsSb.toString(),
197 volume.getName(),
198 artifact));
199
200 return IngestModule.ProcessResult.OK;
201 } catch (TskCoreException ex) {
202 logger.log(Level.SEVERE, String.format("Failed to create blackboard artifact for '%s'.", volume.getName()), ex); //NON-NLS
203 return IngestModule.ProcessResult.ERROR;
204 }
205 }
206
215 private boolean isVolumeEncrypted(Volume volume) throws ReadContentInputStream.ReadContentInputStreamException, IOException, TskCoreException {
216 /*
217 * Criteria for the checks in this method are partially based on
218 * http://www.forensicswiki.org/wiki/TrueCrypt#Detection
219 */
220 if (volume.getFileSystems().isEmpty()) {
221 calculatedEntropy = EncryptionDetectionTools.calculateEntropy(volume, context);
222 if (calculatedEntropy >= minimumEntropy) {
223 return true;
224 }
225 }
226 return false;
227 }
228}

Copyright © 2012-2024 Sleuth Kit Labs. Generated on:
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.