19 package org.sleuthkit.autopsy.modules.dataSourceIntegrity;
21 import java.security.MessageDigest;
22 import java.security.NoSuchAlgorithmException;
23 import java.util.ArrayList;
24 import java.util.List;
25 import java.util.logging.Level;
26 import javax.xml.bind.DatatypeConverter;
27 import java.util.Arrays;
38 import org.openide.util.NbBundle;
65 computeHashes = settings.shouldComputeHashes();
66 verifyHashes = settings.shouldVerifyHashes();
70 "DataSourceIntegrityIngestModule.startup.noCheckboxesSelected=At least one of the checkboxes must be selected"
77 if (!(computeHashes || verifyHashes)) {
78 throw new IngestModuleException(Bundle.DataSourceIntegrityIngestModule_startup_noCheckboxesSelected());
84 "DataSourceIntegrityIngestModule.process.skipCompute=Not computing new hashes for {0} since the option was disabled",
86 "DataSourceIntegrityIngestModule.process.skipVerify=Not verifying existing hashes for {0} since the option was disabled",
88 "DataSourceIntegrityIngestModule.process.hashAlgorithmError=Error creating message digest for {0} algorithm",
90 "DataSourceIntegrityIngestModule.process.hashMatch=<li>{0} hash verified </li>",
92 "DataSourceIntegrityIngestModule.process.hashNonMatch=<li>{0} hash not verified </li>",
93 "# {0} - calculatedHashValue",
94 "# {1} - storedHashValue",
95 "DataSourceIntegrityIngestModule.process.hashList=<ul><li>Calculated hash: {0} </li><li>Stored hash: {1} </li></ul>",
97 "# {1} - calculatedHashValue",
98 "DataSourceIntegrityIngestModule.process.calcHashWithType=<li>Calculated {0} hash: {1} </li>",
100 "DataSourceIntegrityIngestModule.process.calculateHashDone=<p>Data Source Hash Calculation Results for {0} </p>",
101 "DataSourceIntegrityIngestModule.process.hashesCalculated= hashes calculated",
103 "DataSourceIntegrityIngestModule.process.errorSavingHashes= Error saving hashes for image {0} to the database",
105 "DataSourceIntegrityIngestModule.process.errorLoadingHashes= Error loading hashes for image {0} from the database",
106 "# {0} - hashAlgorithm",
107 "# {1} - calculatedHashValue",
108 "# {2} - storedHashValue",
109 "DataSourceIntegrityIngestModule.process.hashFailedForArtifact={0} hash verification failed:\n Calculated hash: {1}\n Stored hash: {2}\n",
111 "DataSourceIntegrityIngestModule.process.verificationSuccess=Integrity of {0} verified",
113 "DataSourceIntegrityIngestModule.process.verificationFailure={0} failed integrity verification",
117 String imgName = dataSource.getName();
120 if (!(dataSource instanceof Image)) {
121 logger.log(Level.INFO,
"Skipping non-image {0}", imgName);
123 NbBundle.getMessage(this.getClass(),
124 "DataSourceIntegrityIngestModule.process.skipNonEwf",
128 Image img = (Image) dataSource;
131 long size = img.getSize();
133 logger.log(Level.WARNING,
"Size of image {0} was 0 when queried.", imgName);
142 if (img.getMd5() != null && ! img.getMd5().isEmpty()) {
145 if (img.getSha1() != null && ! img.getSha1().isEmpty()) {
148 if (img.getSha256() != null && ! img.getSha256().isEmpty()) {
151 }
catch (TskCoreException ex) {
152 String msg = Bundle.DataSourceIntegrityIngestModule_process_errorLoadingHashes(imgName);
154 logger.log(Level.SEVERE, msg, ex);
160 if (hashDataList.isEmpty()) {
168 logger.log(Level.INFO,
"Not computing hashes for {0} since the option was disabled", imgName);
170 Bundle.DataSourceIntegrityIngestModule_process_skipCompute(imgName)));
173 logger.log(Level.INFO,
"Not verifying hashes for {0} since the option was disabled", imgName);
175 Bundle.DataSourceIntegrityIngestModule_process_skipVerify(imgName)));
183 hashDataList.add(
new HashData(type,
""));
188 for (
HashData hashData:hashDataList) {
190 hashData.digest = MessageDigest.getInstance(hashData.type.getName());
191 }
catch (NoSuchAlgorithmException ex) {
192 String msg = Bundle.DataSourceIntegrityIngestModule_process_hashAlgorithmError(hashData.type.getName());
194 logger.log(Level.SEVERE, msg, ex);
202 long chunkSize = 64 * img.getSsize();
203 chunkSize = (chunkSize == 0) ? DEFAULT_CHUNK_SIZE : chunkSize;
206 int totalChunks = (int) Math.ceil((
double) size / (
double) chunkSize);
207 logger.log(Level.INFO,
"Total chunks = {0}", totalChunks);
210 logger.log(Level.INFO,
"Starting hash verification of {0}", img.getName());
212 logger.log(Level.INFO,
"Starting hash calculation for {0}", img.getName());
215 NbBundle.getMessage(this.getClass(),
216 "DataSourceIntegrityIngestModule.process.startingImg",
223 byte[] data =
new byte[(int) chunkSize];
225 for (
int i = 0; i < totalChunks; i++) {
230 read = img.read(data, i * chunkSize, chunkSize);
231 }
catch (TskCoreException ex) {
232 String msg = NbBundle.getMessage(this.getClass(),
233 "DataSourceIntegrityIngestModule.process.errReadImgAtChunk", imgName, i);
235 logger.log(Level.SEVERE, msg, ex);
240 if (read == chunkSize) {
241 for (
HashData struct:hashDataList) {
242 struct.digest.update(data);
245 byte[] subData = Arrays.copyOfRange(data, 0, read);
246 for (
HashData struct:hashDataList) {
247 struct.digest.update(subData);
254 for(
HashData hashData:hashDataList) {
255 hashData.calculatedHash = DatatypeConverter.printHexBinary(hashData.digest.digest()).toLowerCase();
256 logger.log(Level.INFO,
"Hash calculated from {0}: {1}",
new Object[]{imgName, hashData.calculatedHash});
261 boolean verified =
true;
262 String detailedResults = NbBundle
263 .getMessage(this.getClass(),
"DataSourceIntegrityIngestModule.shutDown.verifyResultsHeader", imgName);
264 String hashResults =
"";
265 String artifactComment =
"";
267 for (
HashData hashData:hashDataList) {
268 if (hashData.storedHash.equals(hashData.calculatedHash)) {
269 hashResults += Bundle.DataSourceIntegrityIngestModule_process_hashMatch(hashData.type.name) +
" ";
272 hashResults += Bundle.DataSourceIntegrityIngestModule_process_hashNonMatch(hashData.type.name) +
" ";
273 artifactComment += Bundle.DataSourceIntegrityIngestModule_process_hashFailedForArtifact(hashData.type.name,
274 hashData.calculatedHash, hashData.storedHash) +
" ";
276 hashResults += Bundle.DataSourceIntegrityIngestModule_process_hashList(hashData.calculatedHash, hashData.storedHash);
279 String verificationResultStr;
280 String messageResultStr;
284 verificationResultStr = NbBundle.getMessage(this.getClass(),
"DataSourceIntegrityIngestModule.shutDown.verified");
285 messageResultStr = Bundle.DataSourceIntegrityIngestModule_process_verificationSuccess(imgName);
288 verificationResultStr = NbBundle.getMessage(this.getClass(),
"DataSourceIntegrityIngestModule.shutDown.notVerified");
289 messageResultStr = Bundle.DataSourceIntegrityIngestModule_process_verificationFailure(imgName);
292 detailedResults += NbBundle.getMessage(this.getClass(),
"DataSourceIntegrityIngestModule.shutDown.resultLi", verificationResultStr);
293 detailedResults += hashResults;
297 BlackboardArtifact verificationFailedArtifact =
Case.
getCurrentCase().
getSleuthkitCase().newBlackboardArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_VERIFICATION_FAILED, img.getId());
298 verificationFailedArtifact.addAttribute(
new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT,
301 }
catch (TskCoreException ex) {
302 logger.log(Level.SEVERE,
"Error creating verification failed artifact", ex);
303 }
catch (Blackboard.BlackboardException ex) {
304 logger.log(Level.SEVERE,
"Error posting verification failed artifact", ex);
309 messageResultStr, detailedResults));
314 String results = Bundle.DataSourceIntegrityIngestModule_process_calculateHashDone(imgName);
316 for (
HashData hashData:hashDataList) {
317 switch (hashData.type) {
320 img.setMD5(hashData.calculatedHash);
321 }
catch (TskDataException ex) {
322 logger.log(Level.SEVERE,
"Error setting calculated hash", ex);
327 img.setSha1(hashData.calculatedHash);
328 }
catch (TskDataException ex) {
329 logger.log(Level.SEVERE,
"Error setting calculated hash", ex);
334 img.setSha256(hashData.calculatedHash);
335 }
catch (TskDataException ex) {
336 logger.log(Level.SEVERE,
"Error setting calculated hash", ex);
342 results += Bundle.DataSourceIntegrityIngestModule_process_calcHashWithType(hashData.type.name, hashData.calculatedHash);
347 imgName + Bundle.DataSourceIntegrityIngestModule_process_hashesCalculated(), results));
349 }
catch (TskCoreException ex) {
350 String msg = Bundle.DataSourceIntegrityIngestModule_process_errorSavingHashes(imgName);
352 logger.log(Level.SEVERE,
"Error saving hash for image " + imgName +
" to database", ex);
static final IngestServices services
org.sleuthkit.datamodel.Blackboard getArtifactsBlackboard()
static final Logger logger
static IngestMessage createMessage(MessageType messageType, String source, String subject, String detailsHtml)
final List< HashData > hashDataList
void postMessage(final IngestMessage message)
final boolean verifyHashes
SleuthkitCase getSleuthkitCase()
static final long DEFAULT_CHUNK_SIZE
boolean dataSourceIngestIsCancelled()
void switchToDeterminate(int workUnits)
static Case getCurrentCase()
synchronized static Logger getLogger(String name)
final boolean computeHashes
ProcessResult process(Content dataSource, DataSourceIngestModuleProgress statusHelper)
void progress(int workUnits)
void startUp(IngestJobContext context)
static synchronized IngestServices getInstance()