19 package org.sleuthkit.autopsy.modules.hashdatabase;
 
   21 import java.util.ArrayList;
 
   22 import java.util.Arrays;
 
   23 import java.util.HashMap;
 
   24 import java.util.List;
 
   25 import java.util.concurrent.atomic.AtomicLong;
 
   26 import java.util.function.Function;
 
   27 import java.util.logging.Level;
 
   28 import java.util.stream.Stream;
 
   29 import org.openide.util.NbBundle;
 
   30 import org.openide.util.NbBundle.Messages;
 
   59     "HashDbIngestModule.noKnownBadHashDbSetMsg=No notable hash set.",
 
   60     "HashDbIngestModule.knownBadFileSearchWillNotExecuteWarn=Notable file search will not be executed.",
 
   61     "HashDbIngestModule.noKnownHashDbSetMsg=No known hash set.",
 
   62     "HashDbIngestModule.knownFileSearchWillNotExecuteWarn=Known file search will not be executed.",
 
   63     "# {0} - fileName", 
"HashDbIngestModule.lookingUpKnownBadHashValueErr=Error encountered while looking up notable hash value for {0}.",
 
   64     "# {0} - fileName", 
"HashDbIngestModule.lookingUpNoChangeHashValueErr=Error encountered while looking up no change hash value for {0}.",
 
   65     "# {0} - fileName", 
"HashDbIngestModule.lookingUpKnownHashValueErr=Error encountered while looking up known hash value for {0}.",})
 
   70     private final Function<AbstractFile, String> knownBadLookupError
 
   71             = (file) -> Bundle.HashDbIngestModule_lookingUpKnownBadHashValueErr(file.getName());
 
   73     private final Function<AbstractFile, String> noChangeLookupError
 
   74             = (file) -> Bundle.HashDbIngestModule_lookingUpNoChangeHashValueErr(file.getName());
 
   76     private final Function<AbstractFile, String> knownLookupError
 
   77             = (file) -> Bundle.HashDbIngestModule_lookingUpKnownHashValueErr(file.getName());
 
   79     private static final int MAX_COMMENT_SIZE = 500;
 
   83     private final HashLookupModuleSettings 
settings;
 
   84     private final List<HashDb> knownBadHashSets = 
new ArrayList<>();
 
   85     private final List<HashDb> knownHashSets = 
new ArrayList<>();
 
   86     private final List<HashDb> noChangeHashSets = 
new ArrayList<>();
 
   88     private static final HashMap<Long, IngestJobTotals> totalsForIngestJobs = 
new HashMap<>();
 
   97         private final AtomicLong totalKnownBadCount = 
new AtomicLong(0);
 
   98         private final AtomicLong totalNoChangeCount = 
new AtomicLong(0);
 
   99         private final AtomicLong totalCalctime = 
new AtomicLong(0);
 
  100         private final AtomicLong totalLookuptime = 
new AtomicLong(0);
 
  105         if (totals == null) {
 
  107             totalsForIngestJobs.put(ingestJobId, totals);
 
  122         this.settings = settings;
 
  128         jobId = context.getJobId();
 
  129         if (!hashDbManager.verifyAllDatabasesLoadedCorrectly()) {
 
  130             throw new IngestModuleException(
"Could not load all hash sets");
 
  137             getTotalsForIngestJobs(jobId);
 
  140             if (knownBadHashSets.isEmpty()) {
 
  143                         Bundle.HashDbIngestModule_noKnownBadHashDbSetMsg(),
 
  144                         Bundle.HashDbIngestModule_knownBadFileSearchWillNotExecuteWarn()));
 
  147             if (knownHashSets.isEmpty()) {
 
  150                         Bundle.HashDbIngestModule_noKnownHashDbSetMsg(),
 
  151                         Bundle.HashDbIngestModule_knownFileSearchWillNotExecuteWarn()));
 
  163         for (
HashDb db : allHashSets) {
 
  164             if (settings.isHashSetEnabled(db)) {
 
  167                         switch (db.getKnownFilesType()) {
 
  169                                 knownHashSets.add(db);
 
  172                                 knownBadHashSets.add(db);
 
  175                                 noChangeHashSets.add(db);
 
  178                                 throw new TskCoreException(
"Unknown KnownFilesType: " + db.getKnownFilesType());
 
  182                     logger.log(Level.WARNING, 
"Error getting index status for " + db.getDisplayName() + 
" hash set", ex); 
 
  190         "HashDbIngestModule.dialogTitle.errorFindingArtifacts=Error Finding Artifacts: {0}",
 
  192         "HashDbIngestModule.errorMessage.lookingForFileArtifacts=Error encountered while looking for existing artifacts for {0}." 
  199             logger.log(Level.SEVERE, 
"Exception while getting open case.", ex); 
 
  203         if (shouldSkip(file)) {
 
  212             calculateHashes(file, totals);
 
  214             logger.log(Level.WARNING, String.format(
"Error calculating hash of file '%s' (id=%d).", file.
getName(), file.
getId()), ex); 
 
  217                     NbBundle.getMessage(this.getClass(), 
"HashDbIngestModule.fileReadErrorMsg", file.
getName()),
 
  218                     NbBundle.getMessage(
this.getClass(), 
"HashDbIngestModule.calcHashValueErr",
 
  230         boolean foundBad = knownBadResult.isFound();
 
  231         if (knownBadResult.isError()) {
 
  239         if (noChangeResult.isError()) {
 
  247             for (
HashDb db : knownHashSets) {
 
  249                     long lookupstart = System.currentTimeMillis();
 
  250                     if (db.lookupMD5Quick(file)) {
 
  254                     long delta = (System.currentTimeMillis() - lookupstart);
 
  258                     reportLookupError(ex, file, knownLookupError);
 
  292         if ((knownHashSets.isEmpty()) && (knownBadHashSets.isEmpty()) && (!settings.shouldCalculateHashes())) {
 
  309         logger.log(Level.WARNING, String.format(
 
  310                 "Couldn't lookup notable hash for file '%s' (id=%d) - see sleuthkit log for details", file.
getName(), file.
getId()), ex); 
 
  313                 NbBundle.getMessage(this.getClass(), 
"HashDbIngestModule.hashLookupErrorMsg", file.
getName()),
 
  314                 lookupErrorMessage.apply(file)));
 
  370             List<HashDb> hashSets, 
TskData.
FileKnown statusIfFound, Function<AbstractFile, String> lookupErrorMessage) {
 
  372         boolean found = 
false;
 
  373         boolean wasError = 
false;
 
  374         for (
HashDb db : hashSets) {
 
  376                 long lookupstart = System.currentTimeMillis();
 
  378                 if (null != hashInfo) {
 
  381                     totalCount.incrementAndGet();
 
  383                     String comment = generateComment(hashInfo);
 
  384                     if (!createArtifactIfNotExists(file, comment, db)) {
 
  388                 long delta = (System.currentTimeMillis() - lookupstart);
 
  389                 totalLookupTime.addAndGet(delta);
 
  392                 reportLookupError(ex, file, lookupErrorMessage);
 
  409         ArrayList<String> comments = hashInfo.
getComments();
 
  411         for (String c : comments) {
 
  416             if (comment.length() > MAX_COMMENT_SIZE) {
 
  417                 comment = comment.substring(0, MAX_COMMENT_SIZE) + 
"...";
 
  438         List<BlackboardAttribute> attributesList = 
new ArrayList<>();
 
  443                 postHashSetHitToBlackboard(file, file.
getMd5Hash(), db, comment);
 
  446             logger.log(Level.SEVERE, String.format(
 
  447                     "A problem occurred while checking for existing artifacts for file '%s' (id=%d).", file.
getName(), file.
getId()), ex); 
 
  450                     Bundle.HashDbIngestModule_dialogTitle_errorFindingArtifacts(file.
getName()),
 
  451                     Bundle.HashDbIngestModule_errorMessage_lookingForFileArtifacts(file.
getName())));
 
  469         if ((md5Hash != null && ! md5Hash.isEmpty())
 
  470                 && (sha256Hash != null && ! sha256Hash.isEmpty())) {
 
  475         long calcstart = System.currentTimeMillis();
 
  482             if (file.
getSize() < 1000000) {
 
  496         long delta = (System.currentTimeMillis() - calcstart);
 
  497         totals.totalCalctime.addAndGet(delta);
 
  506         if (knownFilesType == null) {
 
  509         switch (knownFilesType) {
 
  528         "HashDbIngestModule.indexError.message=Failed to index hashset hit artifact for keyword search." 
  534             List<BlackboardAttribute> attributes = Arrays.asList(
 
  543                     null, db.getDisplayName(), null,
 
  545             ).getAnalysisResult();
 
  554                 logger.log(Level.SEVERE, 
"Unable to index blackboard artifact " + badFile.
getArtifactID(), ex); 
 
  556                         Bundle.HashDbIngestModule_indexError_message(), badFile.
getDisplayName());
 
  560                 StringBuilder detailsSb = 
new StringBuilder();
 
  562                 detailsSb.append(
"<table border='0' cellpadding='4' width='280'>"); 
 
  564                 detailsSb.append(
"<tr>"); 
 
  565                 detailsSb.append(
"<th>") 
 
  566                         .append(NbBundle.getMessage(
this.getClass(), 
"HashDbIngestModule.postToBB.fileName"))
 
  568                 detailsSb.append(
"<td>") 
 
  569                         .append(abstractFile.
getName())
 
  571                 detailsSb.append(
"</tr>"); 
 
  573                 detailsSb.append(
"<tr>"); 
 
  574                 detailsSb.append(
"<th>") 
 
  575                         .append(NbBundle.getMessage(
this.getClass(), 
"HashDbIngestModule.postToBB.md5Hash"))
 
  577                 detailsSb.append(
"<td>").append(md5Hash).append(
"</td>"); 
 
  578                 detailsSb.append(
"</tr>"); 
 
  580                 detailsSb.append(
"<tr>"); 
 
  581                 detailsSb.append(
"<th>") 
 
  582                         .append(NbBundle.getMessage(
this.getClass(), 
"HashDbIngestModule.postToBB.hashsetName"))
 
  584                 detailsSb.append(
"<td>").append(db.getDisplayName()).append(
"</td>"); 
 
  585                 detailsSb.append(
"</tr>"); 
 
  587                 detailsSb.append(
"</table>"); 
 
  590                         NbBundle.getMessage(this.getClass(), 
"HashDbIngestModule.postToBB.knownBadMsg", abstractFile.
getName()),
 
  591                         detailsSb.toString(),
 
  592                         abstractFile.
getName() + md5Hash,
 
  596             logger.log(Level.WARNING, 
"Error creating blackboard artifact", ex); 
 
  608     @Messages(
"HashDbIngestModule.complete.noChangesFound=No Change items found:")
 
  609     private static synchronized 
void postSummary(
long jobId, List<
HashDb> knownBadHashSets,
 
  610             List<
HashDb> noChangeHashSets, List<
HashDb> knownHashSets) {
 
  613         totalsForIngestJobs.remove(jobId);
 
  615         if ((!knownBadHashSets.isEmpty()) || (!knownHashSets.isEmpty()) || (!noChangeHashSets.isEmpty())) {
 
  616             StringBuilder detailsSb = 
new StringBuilder();
 
  619                 "<table border='0' cellpadding='4' width='280'>" +
 
  620                     "<tr><td>" + NbBundle.getMessage(
HashDbIngestModule.class, 
"HashDbIngestModule.complete.knownBadsFound") + 
"</td>" +
 
  623                     "<tr><td>" + Bundle.HashDbIngestModule_complete_noChangesFound() + 
"</td>" +
 
  626                     "<tr><td>" + NbBundle.getMessage(
HashDbIngestModule.class, 
"HashDbIngestModule.complete.totalCalcTime") + 
 
  627                     "</td><td>" + jobTotals.
totalCalctime.get() + 
"</td></tr>\n" +
 
  629                     "<tr><td>" + NbBundle.getMessage(
HashDbIngestModule.class, 
"HashDbIngestModule.complete.totalLookupTime") + 
 
  630                     "</td><td>" + jobTotals.
totalLookuptime.get() + 
"</td></tr>\n</table>" +
 
  632                     "<p>" + NbBundle.getMessage(
HashDbIngestModule.class, 
"HashDbIngestModule.complete.databasesUsed") + 
"</p>\n<ul>"); 
 
  634             Stream.concat(knownBadHashSets.stream(), noChangeHashSets.stream()).forEach((db) -> {
 
  638             detailsSb.append(
"</ul>"); 
 
  643                     NbBundle.getMessage(
HashDbIngestModule.class, 
"HashDbIngestModule.complete.hashLookupResults"),
 
  644                     detailsSb.toString()));
 
  651             postSummary(jobId, knownBadHashSets, noChangeHashSets, knownHashSets);
 
abstract boolean getSendIngestMessages()
static final Score SCORE_UNKNOWN
void postArtifact(BlackboardArtifact artifact, String moduleName)
static final Score SCORE_NOTABLE
synchronized long decrementAndGet(long jobId)
ProcessResult process(AbstractFile file)
static IngestMessage createDataMessage(String source, String subject, String detailsHtml, String uniqueKey, BlackboardArtifact data)
Blackboard getBlackboard()
final HashLookupModuleSettings settings
void setSha256Hash(String sha256Hash)
static IngestMessage createErrorMessage(String source, String subject, String detailsHtml)
void initializeHashsets(List< HashDb > allHashSets)
TskData.TSK_DB_FILES_TYPE_ENUM getType()
final AtomicLong totalNoChangeCount
AnalysisResultAdded newAnalysisResult(BlackboardArtifact.Type artifactType, Score score, String conclusion, String configuration, String justification, Collection< BlackboardAttribute > attributesList)
abstract String getHashSetName()
void startUp(org.sleuthkit.autopsy.ingest.IngestJobContext context)
synchronized long incrementAndGet(long jobId)
static IngestMessage createMessage(MessageType messageType, String source, String subject, String detailsHtml)
static synchronized IngestJobTotals getTotalsForIngestJobs(long ingestJobId)
final AtomicLong totalLookuptime
void calculateHashes(AbstractFile file, IngestJobTotals totals)
final AtomicLong totalCalctime
static TimingMetric getTimingMetric(String name)
static List< HashResult > calculateHashes(Content content, Collection< HashType > hashTypes)
final SleuthkitCase skCase
void setKnown(TskData.FileKnown knownState)
static synchronized HashDbManager getInstance()
boolean artifactExists(Content content, BlackboardArtifact.Type artifactType, Collection< BlackboardAttribute > attributes)
boolean isMetaFlagSet(TSK_FS_META_FLAG_ENUM metaFlag)
FindInHashsetsResult findInHashsets(AbstractFile file, AtomicLong totalCount, AtomicLong totalLookupTime, List< HashDb > hashSets, TskData.FileKnown statusIfFound, Function< AbstractFile, String > lookupErrorMessage)
final AtomicLong totalKnownBadCount
abstract HashDb.KnownFilesType getKnownFilesType()
void postMessage(final IngestMessage message)
ArrayList< String > getComments()
void reportLookupError(TskException ex, AbstractFile file, Function< AbstractFile, String > lookupErrorMessage)
SleuthkitCase getSleuthkitCase()
synchronized List< HashDb > getAllHashSets()
static void submitTimingMetric(TimingMetric metric)
static final Type TSK_HASHSET_HIT
static void error(String title, String message)
synchronized static Logger getLogger(String name)
void setMd5Hash(String md5Hash)
static Case getCurrentCaseThrows()
static IngestMessage createWarningMessage(String source, String subject, String detailsHtml)
static final Score SCORE_NONE
boolean createArtifactIfNotExists(AbstractFile file, String comment, HashDb db)
boolean shouldSkip(AbstractFile file)
void postHashSetHitToBlackboard(AbstractFile abstractFile, String md5Hash, HashDb db, String comment)
static void submitNormalizedTimingMetric(TimingMetric metric, long normalization)
String generateComment(HashHitInfo hashInfo)
static String getModuleName()
Score getScore(HashDb.KnownFilesType knownFilesType)
static synchronized IngestServices getInstance()