19 package org.sleuthkit.autopsy.modules.hashdatabase;
21 import java.beans.PropertyChangeEvent;
22 import java.beans.PropertyChangeListener;
23 import java.beans.PropertyChangeSupport;
25 import java.io.FilenameFilter;
26 import java.io.IOException;
27 import java.util.ArrayList;
28 import java.util.HashSet;
29 import java.util.List;
30 import java.util.MissingResourceException;
31 import java.util.Objects;
33 import java.util.concurrent.ExecutionException;
34 import java.util.logging.Level;
35 import java.util.regex.Matcher;
36 import java.util.regex.Pattern;
37 import java.util.stream.Collectors;
38 import java.util.stream.Stream;
39 import javax.swing.JFileChooser;
40 import javax.swing.JOptionPane;
41 import javax.swing.SwingWorker;
42 import javax.swing.filechooser.FileNameExtensionFilter;
43 import org.apache.commons.io.FilenameUtils;
44 import org.apache.commons.lang.StringUtils;
45 import org.netbeans.api.progress.ProgressHandle;
46 import org.openide.modules.InstalledFileLocator;
47 import org.openide.util.NbBundle;
48 import org.openide.util.NbBundle.Messages;
49 import org.openide.windows.WindowManager;
78 private List<HashDb>
hashSets =
new ArrayList<>();
86 PropertyChangeSupport changeSupport =
new PropertyChangeSupport(
HashDbManager.class);
91 private static final String
KDB_EXT =
"kdb";
95 private static final Pattern
OFFICIAL_FILENAME = Pattern.compile(
"(?<" + DB_NAME_PARAM +
">.+?)\\.(?<" + KNOWN_STATUS_PARAM +
">.+?)\\." + KDB_EXT);
99 public boolean accept(File dir, String name) {
100 return name.endsWith(
"." + KDB_EXT);
111 DB_ADDED, DB_DELETED, DB_INDEXED
120 if (instance == null) {
127 changeSupport.addPropertyChangeListener(listener);
131 changeSupport.removePropertyChangeListener(listener);
134 synchronized boolean verifyAllDatabasesLoadedCorrectly() {
147 static String getHashDatabaseFileExtension() {
160 super(message, exception);
185 hashDb = this.addExistingHashDatabaseNoSave(hashSetName, path, searchDuringIngest, sendIngestMessages, knownFilesType);
193 if (!
new File(path).exists()) {
194 throw new HashDbManagerException(NbBundle.getMessage(
HashDbManager.class,
"HashDbManager.hashDbDoesNotExistExceptionMsg", path));
199 hashDb =
addHashDatabase(SleuthkitJNI.openHashDatabase(path), hashSetName, searchDuringIngest, sendIngestMessages, knownFilesType);
200 }
catch (TskCoreException ex) {
201 throw new HashDbManagerException(ex.getMessage());
224 public synchronized HashDb addNewHashDatabase(String hashSetName, String path,
boolean searchDuringIngest,
boolean sendIngestMessages,
239 File file =
new File(path);
241 throw new HashDbManagerException(NbBundle.getMessage(
HashDbManager.class,
"HashDbManager.hashDbFileExistsExceptionMsg", path));
243 if (!FilenameUtils.getExtension(file.getName()).equalsIgnoreCase(HASH_DATABASE_FILE_EXTENSON)) {
244 throw new HashDbManagerException(NbBundle.getMessage(
HashDbManager.class,
"HashDbManager.illegalHashDbFileNameExtensionMsg",
245 getHashDatabaseFileExtension()));
250 hashDb =
addHashDatabase(SleuthkitJNI.createHashDatabase(path), hashSetName, searchDuringIngest, sendIngestMessages, knownFilesType);
251 }
catch (TskCoreException ex) {
252 throw new HashDbManagerException(ex.getMessage());
268 private void checkDbCollision(String path, String hashSetName)
throws HashDbManagerException, MissingResourceException {
269 if (hashSetPaths.contains(path) || officialHashSetPaths.contains(path)) {
270 throw new HashDbManagerException(NbBundle.getMessage(
HashDbManager.class,
"HashDbManager.hashDbAlreadyAddedExceptionMsg", path));
273 if (hashSetNames.contains(hashSetName) || officialHashSetNames.contains(hashSetName)) {
274 throw new HashDbManagerException(NbBundle.getMessage(
HashDbManager.class,
"HashDbManager.duplicateHashSetNameExceptionMsg", hashSetName));
278 private SleuthkitHashSet
addHashDatabase(
int handle, String hashSetName,
boolean searchDuringIngest,
boolean sendIngestMessages,
HashDb.
KnownFilesType knownFilesType) throws TskCoreException {
280 SleuthkitHashSet hashDb =
new SleuthkitHashSet(handle, hashSetName, searchDuringIngest, sendIngestMessages, knownFilesType);
284 String databasePath = hashDb.getDatabasePath();
285 String indexPath = hashDb.getIndexPath();
289 hashSetNames.add(hashDb.getHashSetName());
290 if (!databasePath.equals(
"None")) {
291 hashSetPaths.add(databasePath);
293 if (!indexPath.equals(
"None")) {
294 hashSetPaths.add(indexPath);
298 hashSets.add(hashDb);
302 changeSupport.firePropertyChange(
SetEvt.
DB_ADDED.toString(), null, hashSetName);
303 }
catch (Exception e) {
304 logger.log(Level.SEVERE,
"HashDbManager listener threw exception", e);
306 NbBundle.getMessage(
this.getClass(),
"HashDbManager.moduleErr"),
307 NbBundle.getMessage(
this.getClass(),
"HashDbManager.moduleErrorListeningToUpdatesMsg"),
313 CentralRepoHashSet addExistingCentralRepoHashSet(String hashSetName, String version,
int referenceSetID,
315 boolean readOnly)
throws TskCoreException {
318 throw new TskCoreException(
"Could not load central repository hash set " + hashSetName +
" - central repository is not enabled");
321 CentralRepoHashSet db =
new CentralRepoHashSet(hashSetName, version, referenceSetID, searchDuringIngest,
322 sendIngestMessages, knownFilesType, readOnly);
325 throw new TskCoreException(
"Error finding hash set " + hashSetName +
" in central repository");
329 if(!hashSets.contains(db)) {
334 changeSupport.firePropertyChange(SetEvt.DB_ADDED.toString(), null, hashSetName);
335 }
catch (Exception e) {
336 logger.log(Level.SEVERE,
"HashDbManager listener threw exception", e);
337 MessageNotifyUtil.Notify.show(
338 NbBundle.getMessage(
this.getClass(),
"HashDbManager.moduleErr"),
339 NbBundle.getMessage(
this.getClass(),
"HashDbManager.moduleErrorListeningToUpdatesMsg"),
340 MessageNotifyUtil.MessageType.ERROR);
347 synchronized void indexHashDatabase(SleuthkitHashSet hashDb) {
348 hashDb.addPropertyChangeListener(
this);
349 HashDbIndexer creator =
new HashDbIndexer(hashDb);
355 if (event.getPropertyName().equals(SleuthkitHashSet.Event.INDEXING_DONE.name())) {
356 SleuthkitHashSet hashDb = (SleuthkitHashSet) event.getNewValue();
357 if (null != hashDb) {
359 String indexPath = hashDb.getIndexPath();
360 if (!indexPath.equals(
"None")) {
361 hashSetPaths.add(indexPath);
363 }
catch (TskCoreException ex) {
364 Logger.
getLogger(
HashDbManager.class.getName()).log(Level.SEVERE,
"Error getting index path of " + hashDb.getHashSetName() +
" hash set after indexing", ex);
386 if (ingestIsRunning) {
387 throw new HashDbManagerException(NbBundle.getMessage(
this.getClass(),
"HashDbManager.ingestRunningExceptionMsg"));
393 String hashSetName = hashDb.getHashSetName();
394 hashSetNames.remove(hashSetName);
395 hashSets.remove(hashDb);
399 if (hashDb instanceof SleuthkitHashSet) {
400 SleuthkitHashSet hashDatabase = (SleuthkitHashSet) hashDb;
402 if (hashDatabase.hasIndex()) {
403 hashSetPaths.remove(hashDatabase.getIndexPath());
405 }
catch (TskCoreException ex) {
406 Logger.
getLogger(
HashDbManager.class.getName()).log(Level.SEVERE,
"Error getting index path of " + hashDatabase.getHashSetName() +
" hash set when removing the hash set", ex);
410 if (!hashDatabase.hasIndexOnly()) {
411 hashSetPaths.remove(hashDatabase.getDatabasePath());
413 }
catch (TskCoreException ex) {
414 Logger.
getLogger(
HashDbManager.class.getName()).log(Level.SEVERE,
"Error getting hash set path of " + hashDatabase.getHashSetName() +
" hash set when removing the hash set", ex);
418 hashDatabase.close();
419 }
catch (TskCoreException ex) {
420 Logger.
getLogger(
HashDbManager.class.getName()).log(Level.SEVERE,
"Error closing " + hashDb.getHashSetName() +
" hash set when removing the hash set", ex);
426 changeSupport.firePropertyChange(
SetEvt.
DB_DELETED.toString(), null, hashSetName);
427 }
catch (Exception e) {
428 logger.log(Level.SEVERE,
"HashDbManager listener threw exception", e);
430 NbBundle.getMessage(
this.getClass(),
"HashDbManager.moduleErr"),
431 NbBundle.getMessage(
this.getClass(),
"HashDbManager.moduleErrorListeningToUpdatesMsg"),
436 void save() throws HashDbManagerException {
438 if (!HashLookupSettings.writeSettings(
new HashLookupSettings(HashLookupSettings.convertHashSetList(
this.hashSets)))) {
439 throw new HashDbManagerException(NbBundle.getMessage(
this.getClass(),
"HashDbManager.saveErrorExceptionMsg"));
441 }
catch (HashLookupSettings.HashLookupSettingsException ex) {
442 throw new HashDbManagerException(NbBundle.getMessage(
this.getClass(),
"HashDbManager.saveErrorExceptionMsg"));
456 }
catch (TskCoreException ex) {
460 return Stream.concat(this.officialHashSets.stream(), this.hashSets.stream())
461 .collect(Collectors.toList());
473 .collect(Collectors.toList());
485 .collect(Collectors.toList());
503 }
catch (TskCoreException ex) {
508 .collect(Collectors.toList());
512 List<HashDbInfo> crHashSets =
new ArrayList<>();
522 crHashSets.add(
new HashDbInfo(globalSet.getSetName(), globalSet.getVersion(),
523 globalSet.getGlobalSetID(),
KnownFilesType.
fromFileKnown(globalSet.getFileKnownStatus()), globalSet.isReadOnly(),
false, sendIngestMessages));
538 hashSetNames.clear();
539 hashSetPaths.clear();
545 for (
HashDb database : hashDatabases) {
546 if (database instanceof SleuthkitHashSet) {
548 ((SleuthkitHashSet) database).close();
549 }
catch (TskCoreException ex) {
554 hashDatabases.clear();
561 HashLookupSettings settings = HashLookupSettings.readSettings();
563 }
catch (HashLookupSettings.HashLookupSettingsException ex) {
573 officialHashSetPaths =
new HashSet<>();
574 officialHashSetNames =
new HashSet<>();
578 officialHashSets.forEach(db -> {
579 officialHashSetNames.add(db.getHashSetName());
581 String databasePath = db.getDatabasePath();
582 String indexPath = db.getIndexPath();
584 if (StringUtils.isNotBlank(databasePath) && !databasePath.equals(
"None")) {
585 officialHashSetPaths.add(databasePath);
587 if (StringUtils.isNotBlank(indexPath) && !indexPath.equals(
"None")) {
588 officialHashSetPaths.add(indexPath);
590 }
catch (TskCoreException ex) {
591 logger.log(Level.SEVERE,
"There was an error loading the official hash set name.", ex);
594 }
catch (HashDbManagerException ex) {
595 logger.log(Level.WARNING,
"There was an error loading the official hash sets.", ex);
596 officialHashSets =
new ArrayList<HashDb>();
612 "# {0} - hashSetName",
613 "HashDbManager_handleNameConflict_conflictSuffix={0} (Custom)"
615 private List<HashDbInfo>
handleNameConflict(List<HashDbInfo> curHashsets, Set<String> officialNames) {
616 Set<String> curNames =
new HashSet<String>(officialNames);
617 boolean change =
false;
618 List<HashDbInfo> newItems =
new ArrayList<>();
619 for (HashDbInfo hashset : curHashsets) {
620 String thisName = hashset.getHashSetName();
621 if (curNames.contains(thisName)) {
622 while (curNames.contains(thisName)) {
623 thisName = Bundle.HashDbManager_handleNameConflict_conflictSuffix(thisName);
626 newItems.add(
new HashDbInfo(
628 hashset.getKnownFilesType(),
629 hashset.getSearchDuringIngest(),
630 hashset.getSendIngestMessages(),
632 hashset.getReferenceSetID(),
633 hashset.getVersion(),
634 hashset.isReadOnly(),
635 hashset.isCentralRepoDatabaseType()
639 newItems.add(hashset);
642 curNames.add(thisName);
649 HashLookupSettings.writeSettings(
new HashLookupSettings(newItems));
650 HashLookupSettings toRet = HashLookupSettings.readSettings();
651 return toRet.getHashDbInfo();
652 }
catch (HashLookupSettings.HashLookupSettingsException ex) {
653 logger.log(Level.SEVERE,
"There was an error while trying to resave after name conflict.", ex);
669 File configFolder = InstalledFileLocator.getDefault().locate(
672 if (configFolder == null || !configFolder.exists() || !configFolder.isDirectory()) {
673 throw new HashDbManagerException(
"Folder provided: " + folder +
" does not exist.");
676 return Stream.of(configFolder.listFiles(DEFAULT_KDB_FILTER))
680 }
catch (HashDbManagerException | TskCoreException ex) {
681 logger.log(Level.WARNING, String.format(
"Hashset: %s could not be properly read.", f.getAbsolutePath()), ex);
685 .filter((hashdb) -> hashdb != null)
686 .collect(Collectors.toList());
702 if (file == null || !file.exists()) {
703 throw new HashDbManagerException(String.format(
"No file found for: %s", file == null ?
"<null>" : file.getAbsolutePath()));
705 String filename = file.getName();
706 Matcher match = OFFICIAL_FILENAME.matcher(filename);
708 throw new HashDbManagerException(String.format(
"File with name: %s does not match regex of: %s", filename, OFFICIAL_FILENAME.toString()));
711 String hashdbName = match.group(DB_NAME_PARAM);
712 final String knownStatus = match.group(KNOWN_STATUS_PARAM);
715 .filter(k -> k.getIdentifier().toUpperCase().equals(knownStatus.toUpperCase()))
717 .orElseThrow(() ->
new HashDbManagerException(String.format(
"No KnownFilesType matches %s for file: %s", knownStatus, filename)));
719 return new SleuthkitHashSet(
720 SleuthkitJNI.openHashDatabase(file.getAbsolutePath()),
736 @Messages({
"# {0} - hash set name",
"HashDbManager.noDbPath.message=Couldn't get valid hash set path for: {0}",
737 "HashDbManager.centralRepoLoadError.message=Error loading central repository hash sets"})
739 allDatabasesLoadedCorrectly =
true;
740 List<HashDbInfo> hashDbInfoList = settings.getHashDbInfo();
743 for (HashDbInfo hashDbInfo : hashDbInfoList) {
763 HashLookupSettings.writeSettings(
new HashLookupSettings(HashLookupSettings.convertHashSetList(
this.hashSets)));
764 allDatabasesLoadedCorrectly =
true;
765 }
catch (HashLookupSettings.HashLookupSettingsException ex) {
766 allDatabasesLoadedCorrectly =
false;
767 logger.log(Level.SEVERE,
"Could not overwrite hash set settings.", ex);
778 }
catch (TskCoreException ex) {
781 JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
782 Bundle.HashDbManager_centralRepoLoadError_message(),
783 NbBundle.getMessage(this.getClass(),
"HashDbManager.openHashDbErr"),
784 JOptionPane.ERROR_MESSAGE);
785 allDatabasesLoadedCorrectly =
false;
795 if (hashDbInfo.isFileDatabaseType()) {
796 String dbPath = this.
getValidFilePath(hashDbInfo.getHashSetName(), hashDbInfo.getPath());
797 if (dbPath != null) {
798 addHashDatabase(SleuthkitJNI.openHashDatabase(dbPath), hashDbInfo.getHashSetName(), hashDbInfo.getSearchDuringIngest(), hashDbInfo.getSendIngestMessages(), hashDbInfo.getKnownFilesType());
800 logger.log(Level.WARNING, Bundle.HashDbManager_noDbPath_message(hashDbInfo.getHashSetName()));
801 allDatabasesLoadedCorrectly =
false;
805 addExistingCentralRepoHashSet(hashDbInfo.getHashSetName(), hashDbInfo.getVersion(),
806 hashDbInfo.getReferenceSetID(),
807 hashDbInfo.getSearchDuringIngest(), hashDbInfo.getSendIngestMessages(),
808 hashDbInfo.getKnownFilesType(), hashDbInfo.isReadOnly());
811 }
catch (TskCoreException ex) {
813 JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
814 NbBundle.getMessage(this.getClass(),
815 "HashDbManager.unableToOpenHashDbMsg", hashDbInfo.getHashSetName()),
816 NbBundle.getMessage(
this.getClass(),
"HashDbManager.openHashDbErr"),
817 JOptionPane.ERROR_MESSAGE);
818 allDatabasesLoadedCorrectly =
false;
825 for (HashDbInfo hashDbInfo : crHashDbInfoList) {
827 addExistingCentralRepoHashSet(hashDbInfo.getHashSetName(), hashDbInfo.getVersion(),
828 hashDbInfo.getReferenceSetID(),
829 hashDbInfo.getSearchDuringIngest(), hashDbInfo.getSendIngestMessages(), hashDbInfo.getKnownFilesType(),
830 hashDbInfo.isReadOnly());
837 for (
HashDb db : this.hashSets) {
838 if (dbInfo.matches(db)) {
847 File database =
new File(configuredPath);
848 if (database.exists()) {
849 return configuredPath;
853 String newPath = null;
855 && JOptionPane.showConfirmDialog(WindowManager.getDefault().getMainWindow(),
856 NbBundle.getMessage(this.getClass(),
"HashDbManager.dlgMsg.dbNotFoundAtLoc",
857 hashSetName, configuredPath),
858 NbBundle.getMessage(this.getClass(),
"HashDbManager.dlgTitle.MissingDb"),
859 JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
861 if (null != newPath && !newPath.isEmpty()) {
862 database =
new File(newPath);
863 if (!database.exists()) {
872 String filePath = null;
873 JFileChooser fc =
new JFileChooser();
874 fc.setDragEnabled(
false);
875 fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
876 String[] EXTENSION =
new String[]{
"txt",
"idx",
"hash",
"Hash",
"kdb"};
877 FileNameExtensionFilter filter =
new FileNameExtensionFilter(
878 NbBundle.getMessage(
this.getClass(),
"HashDbManager.fileNameExtensionFilter.title"), EXTENSION);
879 fc.setFileFilter(filter);
880 fc.setMultiSelectionEnabled(
false);
881 if (fc.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
882 File f = fc.getSelectedFile();
884 filePath = f.getCanonicalPath();
885 }
catch (IOException ex) {
899 "HashDbManager.noChange.text=No Change",
900 "HashDbManager.known.text=Known",
901 "HashDbManager.knownBad.text=Notable"
905 KNOWN(Bundle.HashDbManager_known_text(),
"Known", TskData.FileKnown.KNOWN,
false,
false),
906 KNOWN_BAD(Bundle.HashDbManager_knownBad_text(),
"Notable", TskData.FileKnown.BAD,
true,
true),
907 NO_CHANGE(Bundle.HashDbManager_noChange_text(),
"NoChange", TskData.FileKnown.UNKNOWN,
true,
false);
915 KnownFilesType(String displayName, String identifier, TskData.FileKnown fileKnown,
916 boolean allowSendInboxMessages,
boolean defaultSendInboxMessages) {
918 this.displayName = displayName;
919 this.identifier = identifier;
920 this.fileKnown = fileKnown;
921 this.allowSendInboxMessages = allowSendInboxMessages;
922 this.defaultSendInboxMessages = defaultSendInboxMessages;
933 return allowSendInboxMessages;
944 return defaultSendInboxMessages;
958 return this.displayName;
968 return this.fileKnown;
979 if (fileKnown == null) {
984 .filter((type) -> type.getFileKnown() == fileKnown)
986 .orElseThrow(() ->
new IllegalArgumentException(
"Unknown TskData.FileKnown type: " + fileKnown));
1000 abstract String getDisplayName();
1008 abstract
void setSearchDuringIngest(
boolean useForIngest);
1012 abstract
void setSendIngestMessages(
boolean showInboxMessages);
1021 public abstract
boolean isUpdateable() throws TskCoreException;
1031 public abstract
void addHashes(Content content) throws TskCoreException;
1033 public abstract
void addHashes(Content content, String comment) throws TskCoreException;
1035 public abstract
void addHashes(List<HashEntry> hashes) throws TskCoreException;
1037 public abstract
boolean lookupMD5Quick(Content content) throws TskCoreException;
1039 public abstract HashHitInfo
lookupMD5(Content content) throws TskCoreException;
1049 abstract
boolean isValid() throws TskCoreException;
1051 public abstract String
getIndexPath() throws TskCoreException;
1053 public abstract
boolean hasIndexOnly() throws TskCoreException;
1055 public abstract
void firePropertyChange(String propertyName, Object oldValue, Object newValue);
1070 class SleuthkitHashSet extends
HashDb {
1072 private static final long serialVersionUID = 1L;
1073 private final int handle;
1074 private final String hashSetName;
1075 private boolean searchDuringIngest;
1076 private boolean sendIngestMessages;
1078 private boolean indexing;
1079 private final PropertyChangeSupport propertyChangeSupport =
new PropertyChangeSupport(
this);
1080 private final boolean officialSet;
1082 private SleuthkitHashSet(
int handle, String hashSetName,
boolean useForIngest,
boolean sendHitMessages,
KnownFilesType knownFilesType) {
1083 this(handle, hashSetName, useForIngest, sendHitMessages, knownFilesType,
false);
1086 private SleuthkitHashSet(
int handle, String hashSetName,
boolean useForIngest,
boolean sendHitMessages,
KnownFilesType knownFilesType,
boolean officialSet) {
1087 this.handle = handle;
1088 this.hashSetName = hashSetName;
1089 this.searchDuringIngest = useForIngest;
1090 this.sendIngestMessages = sendHitMessages;
1091 this.knownFilesType = knownFilesType;
1092 this.indexing =
false;
1093 this.officialSet = officialSet;
1104 propertyChangeSupport.addPropertyChangeListener(pcl);
1114 propertyChangeSupport.removePropertyChangeListener(pcl);
1127 String getDisplayName() {
1133 return SleuthkitJNI.getHashDatabasePath(handle);
1136 public void setIndexing(
boolean indexing) {
1137 this.indexing = indexing;
1142 return SleuthkitJNI.getHashDatabaseIndexPath(handle);
1147 return knownFilesType;
1152 return searchDuringIngest;
1156 void setSearchDuringIngest(
boolean useForIngest) {
1157 this.searchDuringIngest = useForIngest;
1162 return sendIngestMessages;
1166 void setSendIngestMessages(
boolean showInboxMessages) {
1167 this.sendIngestMessages = showInboxMessages;
1178 public boolean isUpdateable() throws TskCoreException {
1179 if (isOfficialSet()) {
1183 return SleuthkitJNI.isUpdateableHashDatabase(this.handle);
1195 public void addHashes(Content content)
throws TskCoreException {
1210 public void addHashes(Content content, String comment)
throws TskCoreException {
1212 assert content instanceof AbstractFile;
1214 if (content instanceof AbstractFile) {
1215 AbstractFile file = (AbstractFile) content;
1216 if (null != file.getMd5Hash()) {
1217 SleuthkitJNI.addToHashDatabase(null, file.getMd5Hash(), null, null, comment, handle);
1227 private void officialSetCheck() throws TskCoreException {
1228 if (isOfficialSet()) {
1229 throw new TskCoreException(
"Hashes cannot be added to an official set");
1241 public void addHashes(List<HashEntry> hashes)
throws TskCoreException {
1243 SleuthkitJNI.addToHashDatabase(hashes, handle);
1256 public boolean lookupMD5Quick(Content content)
throws TskCoreException {
1257 boolean result =
false;
1258 assert content instanceof AbstractFile;
1259 if (content instanceof AbstractFile) {
1260 AbstractFile file = (AbstractFile) content;
1261 if (null != file.getMd5Hash()) {
1262 result = SleuthkitJNI.lookupInHashDatabase(file.getMd5Hash(), handle);
1278 public HashHitInfo
lookupMD5(Content content)
throws TskCoreException {
1279 HashHitInfo result = null;
1281 assert content instanceof AbstractFile;
1282 if (content instanceof AbstractFile) {
1283 AbstractFile file = (AbstractFile) content;
1284 if (null != file.getMd5Hash()) {
1285 result = SleuthkitJNI.lookupInHashDatabaseVerbose(file.getMd5Hash(), handle);
1300 boolean isValid() throws TskCoreException {
1304 boolean hasIndex() throws TskCoreException {
1305 return SleuthkitJNI.hashDatabaseHasLookupIndex(handle);
1309 public boolean hasIndexOnly() throws TskCoreException {
1310 return SleuthkitJNI.hashDatabaseIsIndexOnly(handle);
1313 boolean canBeReIndexed() throws TskCoreException {
1314 return SleuthkitJNI.hashDatabaseCanBeReindexed(handle);
1317 boolean isIndexing() {
1322 public void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
1323 this.propertyChangeSupport.firePropertyChange(propertyName, oldValue, newValue);
1326 private void close() throws TskCoreException {
1327 SleuthkitJNI.closeHashDatabase(handle);
1336 public int hashCode() {
1338 code = 47 * code + Integer.hashCode(handle);
1339 code = 47 * code + Objects.hashCode(this.hashSetName);
1340 code = 47 * code + Objects.hashCode(this.propertyChangeSupport);
1341 code = 47 * code + Objects.hashCode(this.knownFilesType);
1346 public boolean equals(Object obj) {
1350 if (getClass() != obj.getClass()) {
1353 final SleuthkitHashSet other = (SleuthkitHashSet) obj;
1354 if (!Objects.equals(
this.hashSetName, other.hashSetName)) {
1357 if (this.knownFilesType != other.knownFilesType) {
1369 boolean isOfficialSet() {
1378 class CentralRepoHashSet
extends HashDb {
1380 private static final long serialVersionUID = 1L;
1381 private final String hashSetName;
1382 private boolean searchDuringIngest;
1383 private boolean sendIngestMessages;
1384 private final HashDb.KnownFilesType knownFilesType;
1385 private final int referenceSetID;
1386 private final String version;
1387 private String orgName;
1388 private final boolean readOnly;
1389 private final PropertyChangeSupport propertyChangeSupport =
new PropertyChangeSupport(
this);
1391 @Messages({
"HashDbManager.CentralRepoHashDb.orgError=Error loading organization"})
1392 private CentralRepoHashSet(String hashSetName, String version,
int referenceSetID,
1393 boolean useForIngest,
boolean sendHitMessages, HashDb.KnownFilesType knownFilesType,
1395 throws TskCoreException {
1396 this.hashSetName = hashSetName;
1397 this.version = version;
1398 this.referenceSetID = referenceSetID;
1399 this.searchDuringIngest = useForIngest;
1400 this.sendIngestMessages = sendHitMessages;
1401 this.knownFilesType = knownFilesType;
1402 this.readOnly = readOnly;
1405 orgName = CentralRepository.getInstance().getReferenceSetOrganization(referenceSetID).getName();
1406 }
catch (CentralRepoException ex) {
1407 Logger.getLogger(SleuthkitHashSet.class.getName()).log(Level.SEVERE,
"Error looking up central repository organization for reference set " + referenceSetID, ex);
1408 orgName = Bundle.HashDbManager_CentralRepoHashDb_orgError();
1420 propertyChangeSupport.addPropertyChangeListener(pcl);
1430 propertyChangeSupport.removePropertyChangeListener(pcl);
1434 public boolean hasIndexOnly() throws TskCoreException {
1444 public String getDisplayName() {
1445 if (!getVersion().isEmpty()) {
1452 String getVersion() {
1456 String getOrgName() {
1460 int getReferenceSetID() {
1461 return referenceSetID;
1476 return knownFilesType;
1481 return searchDuringIngest;
1485 void setSearchDuringIngest(
boolean useForIngest) {
1486 this.searchDuringIngest = useForIngest;
1491 return sendIngestMessages;
1495 void setSendIngestMessages(
boolean showInboxMessages) {
1496 this.sendIngestMessages = showInboxMessages;
1507 public boolean isUpdateable() throws TskCoreException {
1520 public void addHashes(Content content)
throws TskCoreException {
1535 public void addHashes(Content content, String comment)
throws TskCoreException {
1537 assert content instanceof AbstractFile;
1538 if (content instanceof AbstractFile) {
1539 AbstractFile file = (AbstractFile) content;
1540 if (null != file.getMd5Hash()) {
1541 TskData.FileKnown type = knownFilesType.getFileKnown();
1544 CentralRepoFileInstance fileInstance =
new CentralRepoFileInstance(referenceSetID, file.getMd5Hash(),
1546 CentralRepository.getInstance().addReferenceInstance(fileInstance, CentralRepository.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.FILES_TYPE_ID));
1547 }
catch (CentralRepoException | CorrelationAttributeNormalizationException ex) {
1548 throw new TskCoreException(
"Error adding hashes to " + getDisplayName(), ex);
1562 public void addHashes(List<HashEntry> hashes)
throws TskCoreException {
1563 Set<CentralRepoFileInstance> globalFileInstances =
new HashSet<>();
1564 for (HashEntry hashEntry : hashes) {
1565 TskData.FileKnown type = knownFilesType.getFileKnown();
1568 globalFileInstances.add(
new CentralRepoFileInstance(referenceSetID, hashEntry.getMd5Hash(), type, hashEntry.getComment()));
1569 }
catch (CentralRepoException | CorrelationAttributeNormalizationException ex) {
1570 throw new TskCoreException(
"Error adding hashes to " + getDisplayName(), ex);
1575 CentralRepository.getInstance().bulkInsertReferenceTypeEntries(globalFileInstances,
1576 CentralRepository.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.FILES_TYPE_ID));
1577 }
catch (CentralRepoException ex) {
1578 throw new TskCoreException(
"Error adding hashes to " + getDisplayName(), ex);
1592 public boolean lookupMD5Quick(Content content)
throws TskCoreException {
1594 assert content instanceof AbstractFile;
1595 if (content instanceof AbstractFile) {
1596 AbstractFile file = (AbstractFile) content;
1597 if (null != file.getMd5Hash()) {
1599 return CentralRepository.getInstance().isFileHashInReferenceSet(file.getMd5Hash(), this.referenceSetID);
1600 }
catch (CentralRepoException | CorrelationAttributeNormalizationException ex) {
1601 Logger.getLogger(SleuthkitHashSet.class.getName()).log(Level.SEVERE,
"Error performing central reposiotry hash lookup for hash "
1602 + file.getMd5Hash() +
" in reference set " + referenceSetID, ex);
1603 throw new TskCoreException(
"Error performing central reposiotry hash lookup", ex);
1620 public HashHitInfo
lookupMD5(Content content)
throws TskCoreException {
1621 HashHitInfo result = null;
1623 assert content instanceof AbstractFile;
1624 if (content instanceof AbstractFile) {
1625 AbstractFile file = (AbstractFile) content;
1626 if (null != file.getMd5Hash()) {
1628 return CentralRepository.getInstance().lookupHash(file.getMd5Hash(), referenceSetID);
1629 }
catch (CentralRepoException | CorrelationAttributeNormalizationException ex) {
1630 Logger.getLogger(SleuthkitHashSet.class.getName()).log(Level.SEVERE,
"Error performing central reposiotry hash lookup for hash "
1631 + file.getMd5Hash() +
" in reference set " + referenceSetID, ex);
1632 throw new TskCoreException(
"Error performing central reposiotry hash lookup", ex);
1646 if (!CentralRepository.isEnabled()) {
1650 return CentralRepository.getInstance().referenceSetIsValid(this.referenceSetID, this.hashSetName, this.version);
1651 }
catch (CentralRepoException ex) {
1652 Logger.getLogger(CentralRepoHashSet.class.getName()).log(Level.SEVERE,
"Error validating hash set " + hashSetName, ex);
1658 public void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
1659 this.propertyChangeSupport.firePropertyChange(propertyName, oldValue, newValue);
1664 return getDisplayName();
1668 public int hashCode() {
1670 code = 47 * code + Objects.hashCode(this.hashSetName);
1671 code = 47 * code + Objects.hashCode(this.version);
1672 code = 47 * code + Integer.hashCode(this.referenceSetID);
1673 code = 47 * code + Objects.hashCode(this.knownFilesType);
1678 public boolean equals(Object obj) {
1682 if (getClass() != obj.getClass()) {
1685 final CentralRepoHashSet other = (CentralRepoHashSet) obj;
1686 if (!Objects.equals(
this.hashSetName, other.hashSetName)) {
1689 if (!Objects.equals(
this.version, other.version)) {
1692 if (this.knownFilesType != other.knownFilesType) {
1704 private ProgressHandle progress = null;
1705 private SleuthkitHashSet hashDb = null;
1708 this.hashDb = hashDb;
1713 hashDb.setIndexing(
true);
1714 progress = ProgressHandle.createHandle(
1715 NbBundle.getMessage(
this.getClass(),
"HashDbManager.progress.indexingHashSet", hashDb.getHashSetName()));
1717 progress.switchToIndeterminate();
1719 SleuthkitJNI.createLookupIndexForHashDatabase(hashDb.getHandle());
1720 }
catch (TskCoreException ex) {
1722 JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
1723 NbBundle.getMessage(this.getClass(),
1724 "HashDbManager.dlgMsg.errorIndexingHashSet",
1725 hashDb.getHashSetName()),
1726 NbBundle.getMessage(
this.getClass(),
"HashDbManager.hashDbIndexingErr"),
1727 JOptionPane.ERROR_MESSAGE);
1734 hashDb.setIndexing(
false);
1740 }
catch (InterruptedException | ExecutionException ex) {
1741 logger.log(Level.SEVERE,
"Error creating index", ex);
1743 NbBundle.getMessage(
this.getClass(),
"HashDbManager.errCreatingIndex.title"),
1744 NbBundle.getMessage(
this.getClass(),
"HashDbManager.errCreatingIndex.msg", ex.getMessage()),
1747 catch (java.util.concurrent.CancellationException ex) {
1751 hashDb.firePropertyChange(SleuthkitHashSet.Event.INDEXING_DONE.toString(), null, hashDb);
1753 }
catch (Exception e) {
1754 logger.log(Level.SEVERE,
"HashDbManager listener threw exception", e);
1756 NbBundle.getMessage(
this.getClass(),
"HashDbManager.moduleErr"),
1757 NbBundle.getMessage(
this.getClass(),
"HashDbManager.moduleErrorListeningToUpdatesMsg"),
abstract boolean getSendIngestMessages()
Set< String > hashSetPaths
abstract String getIndexPath()
static final Pattern OFFICIAL_FILENAME
static final Logger logger
static final String HASH_DATABASE_FILE_EXTENSON
void loadHashsetsConfiguration()
static synchronized IngestManager getInstance()
Set< String > officialHashSetPaths
static final String DB_NAME_PARAM
Set< String > officialHashSetNames
static boolean runningWithGUI
synchronized void addPropertyChangeListener(PropertyChangeListener listener)
HashDbManagerException(String message)
void checkDbCollision(String path, String hashSetName)
List< CentralRepoFileSet > getAllReferenceSets(CorrelationAttributeInstance.Type correlationType)
static KnownFilesType fromFileKnown(TskData.FileKnown fileKnown)
abstract String getHashSetName()
List< HashDbInfo > getCentralRepoHashSetsFromDatabase()
List< HashDb > loadOfficialHashSetsFromFolder(String folder)
boolean isIngestRunning()
static final long serialVersionUID
final TskData.FileKnown fileKnown
List< HashDb > getUpdateableHashSets(List< HashDb > hashDbs)
abstract String toString()
static final String KDB_EXT
synchronized HashDb addNewHashDatabaseNoSave(String hashSetName, String path, boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType)
void configureSettings(HashLookupSettings settings, Set< String > officialSetNames)
HashDbManagerException(String message, Throwable exception)
synchronized void removeHashDatabase(HashDb hashDb)
static final String OFFICIAL_HASH_SETS_FOLDER
final boolean allowSendInboxMessages
boolean allDatabasesLoadedCorrectly
abstract void firePropertyChange(String propertyName, Object oldValue, Object newValue)
void loadOfficialHashSets()
synchronized List< HashDb > getKnownBadFileHashSets()
boolean hashDbInfoIsNew(HashDbInfo dbInfo)
TskData.FileKnown getFileKnown()
synchronized void removeHashDatabaseNoSave(HashDb hashDb)
static HashDbManager instance
Set< String > hashSetNames
static synchronized HashDbManager getInstance()
String getValidFilePath(String hashSetName, String configuredPath)
static final String KNOWN_STATUS_PARAM
abstract HashDb.KnownFilesType getKnownFilesType()
synchronized HashDb addNewHashDatabase(String hashSetName, String path, boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType)
boolean isDefaultInboxMessages()
synchronized void removePropertyChangeListener(PropertyChangeListener listener)
abstract HashHitInfo lookupMD5(Content content)
synchronized List< HashDb > getUpdateableHashSets()
synchronized List< HashDb > getAllHashSets()
abstract boolean isUpdateable()
abstract boolean lookupMD5Quick(Content content)
abstract String getDatabasePath()
void propertyChange(PropertyChangeEvent event)
void closeHashDatabases(List< HashDb > hashDatabases)
synchronized void loadLastSavedConfiguration()
HashDb getOfficialHashDbFromFile(File file)
abstract void addPropertyChangeListener(PropertyChangeListener pcl)
synchronized static Logger getLogger(String name)
final boolean defaultSendInboxMessages
static void show(String title, String message, MessageType type, ActionListener actionListener)
CorrelationAttributeInstance.Type getCorrelationTypeById(int typeId)
KnownFilesType(String displayName, String identifier, TskData.FileKnown fileKnown, boolean allowSendInboxMessages, boolean defaultSendInboxMessages)
boolean isInboxMessagesAllowed()
abstract boolean hasIndexOnly()
SleuthkitHashSet addHashDatabase(int handle, String hashSetName, boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType)
abstract boolean getSearchDuringIngest()
static CentralRepository getInstance()
void updateHashSetsFromCentralRepository()
synchronized List< HashDb > getKnownFileHashSets()
void configureLocalDb(HashDbInfo hashDbInfo)
synchronized HashDb addExistingHashDatabase(String hashSetName, String path, boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType)
static final int FILES_TYPE_ID
static final FilenameFilter DEFAULT_KDB_FILTER
static boolean isEnabled()
abstract void addHashes(Content content)
abstract void removePropertyChangeListener(PropertyChangeListener pcl)
List< HashDb > officialHashSets
List< HashDbInfo > handleNameConflict(List< HashDbInfo > curHashsets, Set< String > officialNames)