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;
64 computeHashes = settings.shouldComputeHashes();
65 verifyHashes = settings.shouldVerifyHashes();
69 "DataSourceIntegrityIngestModule.startup.noCheckboxesSelected=At least one of the checkboxes must be selected"
76 if (!(computeHashes || verifyHashes)) {
77 throw new IngestModuleException(Bundle.DataSourceIntegrityIngestModule_startup_noCheckboxesSelected());
83 "DataSourceIntegrityIngestModule.process.skipCompute=Not computing new hashes for {0} since the option was disabled",
85 "DataSourceIntegrityIngestModule.process.skipVerify=Not verifying existing hashes for {0} since the option was disabled",
87 "DataSourceIntegrityIngestModule.process.hashAlgorithmError=Error creating message digest for {0} algorithm",
89 "DataSourceIntegrityIngestModule.process.hashMatch=<li>{0} hash verified </li>",
91 "DataSourceIntegrityIngestModule.process.hashNonMatch=<li>{0} hash not verified </li>",
92 "# {0} - calculatedHashValue",
93 "# {1} - storedHashValue",
94 "DataSourceIntegrityIngestModule.process.hashList=<ul><li>Calculated hash: {0} </li><li>Stored hash: {1} </li></ul>",
96 "# {1} - calculatedHashValue",
97 "DataSourceIntegrityIngestModule.process.calcHashWithType=<li>Calculated {0} hash: {1} </li>",
99 "DataSourceIntegrityIngestModule.process.calculateHashDone=<p>Data Source Hash Calculation Results for {0} </p>",
100 "DataSourceIntegrityIngestModule.process.hashesCalculated= hashes calculated",
102 "DataSourceIntegrityIngestModule.process.errorSavingHashes= Error saving hashes for image {0} to the database",
104 "DataSourceIntegrityIngestModule.process.errorLoadingHashes= Error loading hashes for image {0} from the database",
105 "# {0} - hashAlgorithm",
106 "# {1} - calculatedHashValue",
107 "# {2} - storedHashValue",
108 "DataSourceIntegrityIngestModule.process.hashFailedForArtifact={0} hash verification failed:\n Calculated hash: {1}\n Stored hash: {2}\n",
110 "DataSourceIntegrityIngestModule.process.verificationSuccess=Integrity of {0} verified",
112 "DataSourceIntegrityIngestModule.process.verificationFailure={0} failed integrity verification",
116 String imgName = dataSource.getName();
119 if (!(dataSource instanceof Image)) {
120 logger.log(Level.INFO,
"Skipping non-image {0}", imgName);
122 NbBundle.getMessage(this.getClass(),
123 "DataSourceIntegrityIngestModule.process.skipNonEwf",
127 Image img = (Image) dataSource;
130 long size = img.getSize();
132 logger.log(Level.WARNING,
"Size of image {0} was 0 when queried.", imgName);
134 NbBundle.getMessage(this.getClass(),
135 "DataSourceIntegrityIngestModule.process.errGetSizeOfImg",
145 if (img.getMd5() != null && ! img.getMd5().isEmpty()) {
148 if (img.getSha1() != null && ! img.getSha1().isEmpty()) {
151 if (img.getSha256() != null && ! img.getSha256().isEmpty()) {
154 }
catch (TskCoreException ex) {
155 String msg = Bundle.DataSourceIntegrityIngestModule_process_errorLoadingHashes(imgName);
157 logger.log(Level.SEVERE, msg, ex);
163 if (hashDataList.isEmpty()) {
171 logger.log(Level.INFO,
"Not computing hashes for {0} since the option was disabled", imgName);
173 Bundle.DataSourceIntegrityIngestModule_process_skipCompute(imgName)));
176 logger.log(Level.INFO,
"Not verifying hashes for {0} since the option was disabled", imgName);
178 Bundle.DataSourceIntegrityIngestModule_process_skipVerify(imgName)));
186 hashDataList.add(
new HashData(type,
""));
191 for (
HashData hashData:hashDataList) {
193 hashData.digest = MessageDigest.getInstance(hashData.type.getName());
194 }
catch (NoSuchAlgorithmException ex) {
195 String msg = Bundle.DataSourceIntegrityIngestModule_process_hashAlgorithmError(hashData.type.getName());
197 logger.log(Level.SEVERE, msg, ex);
205 long chunkSize = 64 * img.getSsize();
206 chunkSize = (chunkSize == 0) ? DEFAULT_CHUNK_SIZE : chunkSize;
209 int totalChunks = (int) Math.ceil((
double) size / (
double) chunkSize);
210 logger.log(Level.INFO,
"Total chunks = {0}", totalChunks);
213 logger.log(Level.INFO,
"Starting hash verification of {0}", img.getName());
215 logger.log(Level.INFO,
"Starting hash calculation for {0}", img.getName());
218 NbBundle.getMessage(this.getClass(),
219 "DataSourceIntegrityIngestModule.process.startingImg",
226 byte[] data =
new byte[(int) chunkSize];
228 for (
int i = 0; i < totalChunks; i++) {
233 read = img.read(data, i * chunkSize, chunkSize);
234 }
catch (TskCoreException ex) {
235 String msg = NbBundle.getMessage(this.getClass(),
236 "DataSourceIntegrityIngestModule.process.errReadImgAtChunk", imgName, i);
238 logger.log(Level.SEVERE, msg, ex);
243 if (read == chunkSize) {
244 for (
HashData struct:hashDataList) {
245 struct.digest.update(data);
248 byte[] subData = Arrays.copyOfRange(data, 0, read);
249 for (
HashData struct:hashDataList) {
250 struct.digest.update(subData);
257 for(
HashData hashData:hashDataList) {
258 hashData.calculatedHash = DatatypeConverter.printHexBinary(hashData.digest.digest()).toLowerCase();
259 logger.log(Level.INFO,
"Hash calculated from {0}: {1}",
new Object[]{imgName, hashData.calculatedHash});
264 boolean verified =
true;
265 String detailedResults = NbBundle
266 .getMessage(this.getClass(),
"DataSourceIntegrityIngestModule.shutDown.verifyResultsHeader", imgName);
267 String hashResults =
"";
268 String artifactComment =
"";
270 for (
HashData hashData:hashDataList) {
271 if (hashData.storedHash.equals(hashData.calculatedHash)) {
272 hashResults += Bundle.DataSourceIntegrityIngestModule_process_hashMatch(hashData.type.name) +
" ";
275 hashResults += Bundle.DataSourceIntegrityIngestModule_process_hashNonMatch(hashData.type.name) +
" ";
276 artifactComment += Bundle.DataSourceIntegrityIngestModule_process_hashFailedForArtifact(hashData.type.name,
277 hashData.calculatedHash, hashData.storedHash) +
" ";
279 hashResults += Bundle.DataSourceIntegrityIngestModule_process_hashList(hashData.calculatedHash, hashData.storedHash);
282 String verificationResultStr;
283 String messageResultStr;
287 verificationResultStr = NbBundle.getMessage(this.getClass(),
"DataSourceIntegrityIngestModule.shutDown.verified");
288 messageResultStr = Bundle.DataSourceIntegrityIngestModule_process_verificationSuccess(imgName);
291 verificationResultStr = NbBundle.getMessage(this.getClass(),
"DataSourceIntegrityIngestModule.shutDown.notVerified");
292 messageResultStr = Bundle.DataSourceIntegrityIngestModule_process_verificationFailure(imgName);
295 detailedResults += NbBundle.getMessage(this.getClass(),
"DataSourceIntegrityIngestModule.shutDown.resultLi", verificationResultStr);
296 detailedResults += hashResults;
300 BlackboardArtifact verificationFailedArtifact =
Case.
getCurrentCase().
getSleuthkitCase().newBlackboardArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_VERIFICATION_FAILED, img.getId());
301 verificationFailedArtifact.addAttribute(
new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT,
303 }
catch (TskCoreException ex) {
304 logger.log(Level.SEVERE,
"Error creating 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
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()