diff --git a/bindings/java/src/org/sleuthkit/datamodel/AbstractFile.java b/bindings/java/src/org/sleuthkit/datamodel/AbstractFile.java index 93d7e571d5414d7fbfae210b24c90725d5454e01..8daf6c2266a7032e01934d1dbdbc836668889a39 100644 --- a/bindings/java/src/org/sleuthkit/datamodel/AbstractFile.java +++ b/bindings/java/src/org/sleuthkit/datamodel/AbstractFile.java @@ -79,6 +79,11 @@ public abstract class AbstractFile extends AbstractContent { */ protected String md5Hash; private boolean md5HashDirty = false; + /* + * SHA-256 hash + */ + protected String sha256Hash; + private boolean sha256HashDirty = false; private String mimeType; private boolean mimeTypeDirty = false; private static final Logger LOGGER = Logger.getLogger(AbstractFile.class.getName()); @@ -114,6 +119,8 @@ public abstract class AbstractFile extends AbstractContent { * @param gid * @param md5Hash md5sum of the file, or null or "NULL" if not * present + * @param sha256Hash sha256 hash of the file, or null or "NULL" if not + * present * @param knownState knownState status of the file, or null if * unknown (default) * @param parentPath @@ -134,7 +141,7 @@ public abstract class AbstractFile extends AbstractContent { long ctime, long crtime, long atime, long mtime, short modes, int uid, int gid, - String md5Hash, FileKnown knownState, + String md5Hash, String sha256Hash, FileKnown knownState, String parentPath, String mimeType, String extension) { @@ -159,6 +166,7 @@ public abstract class AbstractFile extends AbstractContent { this.modes = TskData.TSK_FS_META_MODE_ENUM.valuesOf(modes); this.md5Hash = md5Hash; + this.sha256Hash = sha256Hash; if (knownState == null) { this.knownState = FileKnown.UNKNOWN; } else { @@ -470,6 +478,28 @@ public void setMd5Hash(String md5Hash) { public String getMd5Hash() { return this.md5Hash; } + + /** + * Sets the SHA-256 hash for this file. + * + * IMPORTANT: The SHA-256 hash is set for this AbstractFile object, but it is + * not saved to the case database until AbstractFile.save is called. + * + * @param sha256Hash The SHA-256 hash of the file. + */ + public void setSha256Hash(String sha256Hash) { + this.sha256Hash = sha256Hash; + this.sha256HashDirty = true; + } + + /** + * Get the SHA-256 hash value as calculated, if present + * + * @return SHA-256 hash string, if it is present or null if it is not + */ + public String getSha256Hash() { + return this.sha256Hash; + } /** * Sets the known state for this file. @@ -1055,7 +1085,7 @@ public String toString(boolean preserveState) { + "\t" + "metaAddr " + metaAddr + "\t" + "metaSeq " + metaSeq + "\t" + "metaFlags " + metaFlags //NON-NLS + "\t" + "metaType " + metaType + "\t" + "modes " + modes //NON-NLS + "\t" + "parentPath " + parentPath + "\t" + "size " + size //NON-NLS - + "\t" + "knownState " + knownState + "\t" + "md5Hash " + md5Hash //NON-NLS + + "\t" + "knownState " + knownState + "\t" + "md5Hash " + md5Hash + "\t" + "sha256Hash " + sha256Hash //NON-NLS + "\t" + "localPathSet " + localPathSet + "\t" + "localPath " + localPath //NON-NLS + "\t" + "localAbsPath " + localAbsPath + "\t" + "localFile " + localFile //NON-NLS + "]\t"; @@ -1099,7 +1129,7 @@ public MimeMatchEnum isMimeType(SortedSet<String> mimeTypes) { public void save() throws TskCoreException { // No fields have been updated - if (!(md5HashDirty || mimeTypeDirty || knownStateDirty)) { + if (!(md5HashDirty || sha256HashDirty || mimeTypeDirty || knownStateDirty)) { return; } @@ -1113,6 +1143,12 @@ public void save() throws TskCoreException { } queryStr += "md5 = '" + this.getMd5Hash() + "'"; } + if (sha256HashDirty) { + if (!queryStr.isEmpty()) { + queryStr += ", "; + } + queryStr += "sha256 = '" + this.getSha256Hash() + "'"; + } if (knownStateDirty) { if (!queryStr.isEmpty()) { queryStr += ", "; @@ -1128,6 +1164,7 @@ public void save() throws TskCoreException { connection.executeUpdate(statement, queryStr); md5HashDirty = false; + sha256HashDirty = false; mimeTypeDirty = false; knownStateDirty = false; } catch (SQLException ex) { @@ -1185,7 +1222,7 @@ protected AbstractFile(SleuthkitCase db, long objId, TskData.TSK_FS_ATTR_TYPE_EN TSK_FS_NAME_TYPE_ENUM dirType, TSK_FS_META_TYPE_ENUM metaType, TSK_FS_NAME_FLAG_ENUM dirFlag, short metaFlags, long size, long ctime, long crtime, long atime, long mtime, short modes, int uid, int gid, String md5Hash, FileKnown knownState, String parentPath) { - this(db, objId, db.getDataSourceObjectId(objId), attrType, (int) attrId, name, fileType, metaAddr, metaSeq, dirType, metaType, dirFlag, metaFlags, size, ctime, crtime, atime, mtime, modes, uid, gid, md5Hash, knownState, parentPath, null, null); + this(db, objId, db.getDataSourceObjectId(objId), attrType, (int) attrId, name, fileType, metaAddr, metaSeq, dirType, metaType, dirFlag, metaFlags, size, ctime, crtime, atime, mtime, modes, uid, gid, md5Hash, null, knownState, parentPath, null, null); } /** @@ -1230,7 +1267,7 @@ protected AbstractFile(SleuthkitCase db, long objId, TskData.TSK_FS_ATTR_TYPE_EN String name, TskData.TSK_DB_FILES_TYPE_ENUM fileType, long metaAddr, int metaSeq, TSK_FS_NAME_TYPE_ENUM dirType, TSK_FS_META_TYPE_ENUM metaType, TSK_FS_NAME_FLAG_ENUM dirFlag, short metaFlags, long size, long ctime, long crtime, long atime, long mtime, short modes, int uid, int gid, String md5Hash, FileKnown knownState, String parentPath, String mimeType) { - this(db, objId, dataSourceObjectId, attrType, (int) attrId, name, fileType, metaAddr, metaSeq, dirType, metaType, dirFlag, metaFlags, size, ctime, crtime, atime, mtime, modes, uid, gid, md5Hash, knownState, parentPath, null, null); + this(db, objId, dataSourceObjectId, attrType, (int) attrId, name, fileType, metaAddr, metaSeq, dirType, metaType, dirFlag, metaFlags, size, ctime, crtime, atime, mtime, modes, uid, gid, md5Hash, null, knownState, parentPath, null, null); } /** diff --git a/bindings/java/src/org/sleuthkit/datamodel/CaseDatabaseFactory.java b/bindings/java/src/org/sleuthkit/datamodel/CaseDatabaseFactory.java index 9b38c21b07e5e6f91b757d746eb65c2a631e57b1..eca9630950c463208eac5a2b6e5c4367ecebbc3f 100644 --- a/bindings/java/src/org/sleuthkit/datamodel/CaseDatabaseFactory.java +++ b/bindings/java/src/org/sleuthkit/datamodel/CaseDatabaseFactory.java @@ -202,7 +202,8 @@ private void createFileTables(Statement stmt) throws SQLException { + "dir_type INTEGER, meta_type INTEGER, dir_flags INTEGER, meta_flags INTEGER, size " + dbQueryHelper.getBigIntType() + ", " + "ctime " + dbQueryHelper.getBigIntType() + ", " + "crtime " + dbQueryHelper.getBigIntType() + ", atime " + dbQueryHelper.getBigIntType() + ", " - + "mtime " + dbQueryHelper.getBigIntType() + ", mode INTEGER, uid INTEGER, gid INTEGER, md5 TEXT, known INTEGER, " + + "mtime " + dbQueryHelper.getBigIntType() + ", mode INTEGER, uid INTEGER, gid INTEGER, md5 TEXT, sha256 TEXT, " + + "known INTEGER, " + "parent_path TEXT, mime_type TEXT, extension TEXT, " + "FOREIGN KEY(obj_id) REFERENCES tsk_objects(obj_id) ON DELETE CASCADE, " + "FOREIGN KEY(fs_obj_id) REFERENCES tsk_fs_info(obj_id) ON DELETE CASCADE, " diff --git a/bindings/java/src/org/sleuthkit/datamodel/CommunicationsManager.java b/bindings/java/src/org/sleuthkit/datamodel/CommunicationsManager.java index 4fefb10606bb1f8cb59694f35222527d843212a3..5b1aaa05fd99b552781a4e35e92474933ba5cf7d 100644 --- a/bindings/java/src/org/sleuthkit/datamodel/CommunicationsManager.java +++ b/bindings/java/src/org/sleuthkit/datamodel/CommunicationsManager.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.datamodel; +import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; @@ -35,6 +36,7 @@ import java.util.logging.Logger; import org.sleuthkit.datamodel.Blackboard.BlackboardException; import org.sleuthkit.datamodel.SleuthkitCase.CaseDbConnection; +import org.sleuthkit.datamodel.SleuthkitCase.CaseDbTransaction; import static org.sleuthkit.datamodel.SleuthkitCase.closeResultSet; import static org.sleuthkit.datamodel.SleuthkitCase.closeStatement; @@ -364,7 +366,7 @@ public void addRelationships(AccountFileInstance sender, List<AccountFileInstanc * correctly. */ // Currently we do not save the direction of communication - List<Long> accountIDs = new ArrayList<Long>(); + List<Long> accountIDs = new ArrayList<>(); if (null != sender) { accountIDs.add(sender.getAccount().getAccountID()); @@ -381,17 +383,50 @@ public void addRelationships(AccountFileInstance sender, List<AccountFileInstanc + "Recipient source ID" + recipient.getDataSourceObjectID() + " != relationship source ID" + sourceArtifact.getDataSourceObjectID()); } } + + // Set up the query for the prepared statement + String query = "INTO account_relationships (account1_id, account2_id, relationship_source_obj_id, date_time, relationship_type, data_source_obj_id ) " + + "VALUES (?,?,?,?,?,?)"; + switch (db.getDatabaseType()) { + case POSTGRESQL: + query = "INSERT " + query + " ON CONFLICT DO NOTHING"; + break; + case SQLITE: + query = "INSERT OR IGNORE " + query; + break; + default: + throw new TskCoreException("Unknown DB Type: " + db.getDatabaseType().name()); + } + + CaseDbTransaction trans = db.beginTransaction(); + try { + SleuthkitCase.CaseDbConnection connection = trans.getConnection(); + PreparedStatement preparedStatement = connection.getPreparedStatement(query, Statement.NO_GENERATED_KEYS); + + for (int i = 0; i < accountIDs.size(); i++) { + for (int j = i + 1; j < accountIDs.size(); j++) { + long account1_id = accountIDs.get(i); + long account2_id = accountIDs.get(j); + + preparedStatement.clearParameters(); + preparedStatement.setLong(1, account1_id); + preparedStatement.setLong(2, account2_id); + preparedStatement.setLong(3, sourceArtifact.getId()); + if (dateTime > 0) { + preparedStatement.setLong(4, dateTime); + } else { + preparedStatement.setNull(4, java.sql.Types.BIGINT); + } + preparedStatement.setInt(5, relationshipType.getTypeID()); + preparedStatement.setLong(6, sourceArtifact.getDataSourceObjectID()); - for (int i = 0; i < accountIDs.size(); i++) { - for (int j = i + 1; j < accountIDs.size(); j++) { - try { - addAccountsRelationship(accountIDs.get(i), accountIDs.get(j), - sourceArtifact, relationshipType, dateTime); - } catch (TskCoreException ex) { - // @@@ This should probably not be caught and instead we stop adding - LOGGER.log(Level.WARNING, "Error adding relationship", ex); //NON-NLS + connection.executeUpdate(preparedStatement); } } + trans.commit(); + } catch (SQLException ex) { + trans.rollback(); + throw new TskCoreException("Error adding accounts relationship", ex); } } @@ -586,55 +621,6 @@ public org.sleuthkit.datamodel.Account.Type getAccountType(String accountTypeNam } } - /** - * Add a row in account relationships table. - * - * @param account1_id account_id for account1 - * @param account2_id account_id for account2 - * @param relationshipaArtifact relationship artifact - * @param relationshipType The type of relationship to be created - * @param dateTime datetime of communication/relationship as - * epoch seconds - * - * @throws TskCoreException exception thrown if a critical error occurs - * within TSK core - */ - private void addAccountsRelationship(long account1_id, long account2_id, BlackboardArtifact relationshipaArtifact, Relationship.Type relationshipType, long dateTime) throws TskCoreException { - CaseDbConnection connection = db.getConnection(); - db.acquireSingleUserCaseWriteLock(); - Statement s = null; - ResultSet rs = null; - - try { - String dateTimeValStr = (dateTime > 0) ? Long.toString(dateTime) : "NULL"; - - connection.beginTransaction(); - s = connection.createStatement(); - String query = "INTO account_relationships (account1_id, account2_id, relationship_source_obj_id, date_time, relationship_type, data_source_obj_id ) " - + "VALUES ( " + account1_id + ", " + account2_id + ", " + relationshipaArtifact.getId() + ", " + dateTimeValStr + ", " + relationshipType.getTypeID() + ", " + relationshipaArtifact.getDataSourceObjectID() + ")"; - switch (db.getDatabaseType()) { - case POSTGRESQL: - query = "INSERT " + query + " ON CONFLICT DO NOTHING"; - break; - case SQLITE: - query = "INSERT OR IGNORE " + query; - break; - default: - throw new TskCoreException("Unknown DB Type: " + db.getDatabaseType().name()); - } - s.execute(query); //NON-NLS - connection.commitTransaction(); - } catch (SQLException ex) { - connection.rollbackTransaction(); - throw new TskCoreException("Error adding accounts relationship", ex); - } finally { - closeResultSet(rs); - closeStatement(s); - connection.close(); - db.releaseSingleUserCaseWriteLock(); - } - } - /** * Returns a list of AccountDeviceInstances that have at least one * relationship that meets the criteria listed in the filters. diff --git a/bindings/java/src/org/sleuthkit/datamodel/DerivedFile.java b/bindings/java/src/org/sleuthkit/datamodel/DerivedFile.java index 71833aeafe70f0cf1fd563d7e7e4bbe3dfbb1977..ef147fb10c980eb874594e42931342e0ba336dd2 100644 --- a/bindings/java/src/org/sleuthkit/datamodel/DerivedFile.java +++ b/bindings/java/src/org/sleuthkit/datamodel/DerivedFile.java @@ -91,7 +91,7 @@ public class DerivedFile extends AbstractFile { TSK_FS_NAME_FLAG_ENUM dirFlag, short metaFlags, long size, long ctime, long crtime, long atime, long mtime, - String md5Hash, FileKnown knownState, + String md5Hash, String sha256Hash, FileKnown knownState, String parentPath, String localPath, long parentId, @@ -102,7 +102,7 @@ public class DerivedFile extends AbstractFile { // through the class hierarchy contructors. super(db, objId, dataSourceObjectId, TskData.TSK_FS_ATTR_TYPE_ENUM.TSK_FS_ATTR_TYPE_DEFAULT, 0, name, TSK_DB_FILES_TYPE_ENUM.LOCAL, 0L, 0, dirType, metaType, dirFlag, - metaFlags, size, ctime, crtime, atime, mtime, (short) 0, 0, 0, md5Hash, knownState, parentPath, mimeType, extension); + metaFlags, size, ctime, crtime, atime, mtime, (short) 0, 0, 0, md5Hash, sha256Hash, knownState, parentPath, mimeType, extension); setLocalFilePath(localPath); setEncodingType(encodingType); } @@ -305,7 +305,7 @@ protected DerivedFile(SleuthkitCase db, long parentId) { this(db, objId, db.getDataSourceObjectId(objId), name, dirType, metaType, dirFlag, metaFlags, size, ctime, crtime, atime, mtime, - md5Hash, knownState, + md5Hash, null, knownState, parentPath, localPath, parentId, null, TskData.EncodingType.NONE, null); } diff --git a/bindings/java/src/org/sleuthkit/datamodel/Directory.java b/bindings/java/src/org/sleuthkit/datamodel/Directory.java index 1806328ced74c3f8887864fab873832bbbb64e41..39b0c62188ef261354eedeb1596ba6f6f2fd0e6f 100644 --- a/bindings/java/src/org/sleuthkit/datamodel/Directory.java +++ b/bindings/java/src/org/sleuthkit/datamodel/Directory.java @@ -85,8 +85,8 @@ public class Directory extends FsContent { long size, long ctime, long crtime, long atime, long mtime, short modes, int uid, int gid, - String md5Hash, FileKnown knownState, String parentPath) { - super(db, objId, dataSourceObjectId, fsObjId, attrType, attrId, name, TskData.TSK_DB_FILES_TYPE_ENUM.FS, metaAddr, metaSeq, dirType, metaType, dirFlag, metaFlags, size, ctime, crtime, atime, mtime, modes, uid, gid, md5Hash, knownState, parentPath, null, null); + String md5Hash, String sha256Hash, FileKnown knownState, String parentPath) { + super(db, objId, dataSourceObjectId, fsObjId, attrType, attrId, name, TskData.TSK_DB_FILES_TYPE_ENUM.FS, metaAddr, metaSeq, dirType, metaType, dirFlag, metaFlags, size, ctime, crtime, atime, mtime, modes, uid, gid, md5Hash, sha256Hash, knownState, parentPath, null, null); } /** @@ -247,6 +247,6 @@ protected Directory(SleuthkitCase db, long ctime, long crtime, long atime, long mtime, short modes, int uid, int gid, String md5Hash, FileKnown knownState, String parentPath) { - this(db, objId, dataSourceObjectId, fsObjId, attrType, (int) attrId, name, metaAddr, metaSeq, dirType, metaType, dirFlag, metaFlags, size, ctime, crtime, atime, mtime, modes, uid, gid, md5Hash, knownState, parentPath); + this(db, objId, dataSourceObjectId, fsObjId, attrType, (int) attrId, name, metaAddr, metaSeq, dirType, metaType, dirFlag, metaFlags, size, ctime, crtime, atime, mtime, modes, uid, gid, md5Hash, null, knownState, parentPath); } } diff --git a/bindings/java/src/org/sleuthkit/datamodel/File.java b/bindings/java/src/org/sleuthkit/datamodel/File.java index fc561a85ddbf7119417f9dee4fbb79cb36afd5b6..c6758c0ff88657acb513b55810acbc445b518df3 100644 --- a/bindings/java/src/org/sleuthkit/datamodel/File.java +++ b/bindings/java/src/org/sleuthkit/datamodel/File.java @@ -89,9 +89,9 @@ public class File extends FsContent { long size, long ctime, long crtime, long atime, long mtime, short modes, int uid, int gid, - String md5Hash, FileKnown knownState, String parentPath, String mimeType, + String md5Hash, String sha256Hash, FileKnown knownState, String parentPath, String mimeType, String extension) { - super(db, objId, dataSourceObjectId, fsObjId, attrType, attrId, name, TskData.TSK_DB_FILES_TYPE_ENUM.FS, metaAddr, metaSeq, dirType, metaType, dirFlag, metaFlags, size, ctime, crtime, atime, mtime, modes, uid, gid, md5Hash, knownState, parentPath, mimeType, extension); + super(db, objId, dataSourceObjectId, fsObjId, attrType, attrId, name, TskData.TSK_DB_FILES_TYPE_ENUM.FS, metaAddr, metaSeq, dirType, metaType, dirFlag, metaFlags, size, ctime, crtime, atime, mtime, modes, uid, gid, md5Hash, sha256Hash, knownState, parentPath, mimeType, extension); } /** @@ -245,6 +245,6 @@ protected File(SleuthkitCase db, String name, long metaAddr, int metaSeq, TSK_FS_NAME_TYPE_ENUM dirType, TSK_FS_META_TYPE_ENUM metaType, TSK_FS_NAME_FLAG_ENUM dirFlag, short metaFlags, long size, long ctime, long crtime, long atime, long mtime, short modes, int uid, int gid, String md5Hash, FileKnown knownState, String parentPath, String mimeType) { - this(db, objId, dataSourceObjectId, fsObjId, attrType, (int) attrId, name, metaAddr, metaSeq, dirType, metaType, dirFlag, metaFlags, size, ctime, crtime, atime, mtime, modes, uid, gid, md5Hash, knownState, parentPath, mimeType, null); + this(db, objId, dataSourceObjectId, fsObjId, attrType, (int) attrId, name, metaAddr, metaSeq, dirType, metaType, dirFlag, metaFlags, size, ctime, crtime, atime, mtime, modes, uid, gid, md5Hash, null, knownState, parentPath, mimeType, null); } } diff --git a/bindings/java/src/org/sleuthkit/datamodel/FsContent.java b/bindings/java/src/org/sleuthkit/datamodel/FsContent.java index ec7c55591800d5332801436cc3c5149368f5397c..aa4bb739d06a0bad71b343ab9766c75f5f38511a 100644 --- a/bindings/java/src/org/sleuthkit/datamodel/FsContent.java +++ b/bindings/java/src/org/sleuthkit/datamodel/FsContent.java @@ -120,11 +120,11 @@ public abstract class FsContent extends AbstractFile { long size, long ctime, long crtime, long atime, long mtime, short modes, int uid, int gid, - String md5Hash, FileKnown knownState, + String md5Hash, String sha256Hash, FileKnown knownState, String parentPath, String mimeType, String extension) { - super(db, objId, dataSourceObjectId, attrType, attrId, name, fileType, metaAddr, metaSeq, dirType, metaType, dirFlag, metaFlags, size, ctime, crtime, atime, mtime, modes, uid, gid, md5Hash, knownState, parentPath, mimeType, extension); + super(db, objId, dataSourceObjectId, attrType, attrId, name, fileType, metaAddr, metaSeq, dirType, metaType, dirFlag, metaFlags, size, ctime, crtime, atime, mtime, modes, uid, gid, md5Hash, sha256Hash, knownState, parentPath, mimeType, extension); this.fsObjId = fsObjId; } @@ -383,7 +383,7 @@ public String toString(boolean preserveState) { String name, long metaAddr, int metaSeq, TSK_FS_NAME_TYPE_ENUM dirType, TSK_FS_META_TYPE_ENUM metaType, TSK_FS_NAME_FLAG_ENUM dirFlag, short metaFlags, long size, long ctime, long crtime, long atime, long mtime, short modes, int uid, int gid, String md5Hash, FileKnown knownState, String parentPath) { - this(db, objId, db.getDataSourceObjectId(objId), fsObjId, attrType, (int) attrId, name, TSK_DB_FILES_TYPE_ENUM.FS, metaAddr, metaSeq, dirType, metaType, dirFlag, metaFlags, size, ctime, crtime, atime, mtime, modes, uid, gid, md5Hash, knownState, parentPath, null, null); + this(db, objId, db.getDataSourceObjectId(objId), fsObjId, attrType, (int) attrId, name, TSK_DB_FILES_TYPE_ENUM.FS, metaAddr, metaSeq, dirType, metaType, dirFlag, metaFlags, size, ctime, crtime, atime, mtime, modes, uid, gid, md5Hash, null, knownState, parentPath, null, null); } /** @@ -442,6 +442,6 @@ public String toString(boolean preserveState) { String name, long metaAddr, int metaSeq, TSK_FS_NAME_TYPE_ENUM dirType, TSK_FS_META_TYPE_ENUM metaType, TSK_FS_NAME_FLAG_ENUM dirFlag, short metaFlags, long size, long ctime, long crtime, long atime, long mtime, short modes, int uid, int gid, String md5Hash, FileKnown knownState, String parentPath, String mimeType) { - this(db, objId, dataSourceObjectId, fsObjId, attrType, (int) attrId, name, TSK_DB_FILES_TYPE_ENUM.FS, metaAddr, metaSeq, dirType, metaType, dirFlag, metaFlags, size, ctime, crtime, atime, mtime, modes, uid, gid, md5Hash, knownState, parentPath, mimeType, null); + this(db, objId, dataSourceObjectId, fsObjId, attrType, (int) attrId, name, TSK_DB_FILES_TYPE_ENUM.FS, metaAddr, metaSeq, dirType, metaType, dirFlag, metaFlags, size, ctime, crtime, atime, mtime, modes, uid, gid, md5Hash, null, knownState, parentPath, mimeType, null); } } diff --git a/bindings/java/src/org/sleuthkit/datamodel/HashUtility.java b/bindings/java/src/org/sleuthkit/datamodel/HashUtility.java index 9077126c9286e6b53ca62e7a403f34116fc41e6d..d8618b0ee606a08b9875d2a7f0e06dba818f62b9 100644 --- a/bindings/java/src/org/sleuthkit/datamodel/HashUtility.java +++ b/bindings/java/src/org/sleuthkit/datamodel/HashUtility.java @@ -1,7 +1,7 @@ /* * Sleuth Kit Data Model * - * Copyright 2011 Basis Technology Corp. + * Copyright 2011-2020 Basis Technology Corp. * Contact: carrier <at> sleuthkit <dot> org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,12 +19,16 @@ package org.sleuthkit.datamodel; import java.io.IOException; -import java.math.BigInteger; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; -import java.io.InputStream; +import java.util.Map; +import java.util.HashMap; +import java.util.Arrays; /** * Utility to calculate a hash for FsContent and store in TSK database @@ -34,39 +38,60 @@ public class HashUtility { private final static int BUFFER_SIZE = 16 * 1024; /** - * Calculate the MD5 hash for the given FsContent + * Calculate hashes of the content object. * - * @param content content object whose md5 hash we want to calculate + * @param content The content object to hash + * @param hashTypes The types of hash to compute * - * @return md5 of the given FsContent object + * @return A list of the hash results * - * @throws java.io.IOException + * @throws TskCoreException */ - static public String calculateMd5Hash(Content content) throws IOException { - String hashText = ""; - InputStream in = new ReadContentInputStream(content); - Logger logger = Logger.getLogger(HashUtility.class.getName()); - try { - byte[] buffer = new byte[BUFFER_SIZE]; - MessageDigest md = MessageDigest.getInstance("md5"); //NON-NLS - int len = in.read(buffer); - while (len != -1) { - md.update(buffer, 0, len); - len = in.read(buffer); + static public List<HashResult> calculateHashes(Content content, Collection<HashType> hashTypes) throws TskCoreException { + Map<HashType, MessageDigest> digests = new HashMap<>(); + + for (HashType type : hashTypes) { + try { + digests.put(type, MessageDigest.getInstance(type.getName())); + } catch (NoSuchAlgorithmException ex) { + throw new TskCoreException("No algorithm found matching name " + type.getName(), ex); + } + } + + // Read in byte size chunks and update the hash value with the data. + byte[] data = new byte[BUFFER_SIZE]; + int totalChunks = (int) Math.ceil((double) content.getSize() / (double) BUFFER_SIZE); + int read; + for (int i = 0; i < totalChunks; i++) { + try { + read = content.read(data, i * BUFFER_SIZE, BUFFER_SIZE); + } catch (TskCoreException ex) { + throw new TskCoreException("Error reading data at address " + i * BUFFER_SIZE + " from content with ID: " + content.getId(), ex); + } + + // Only update with the read bytes. + if (read == BUFFER_SIZE) { + for (HashType type : hashTypes) { + digests.get(type).update(data); + } + } else { + byte[] subData = Arrays.copyOfRange(data, 0, read); + for (HashType type : hashTypes) { + digests.get(type).update(subData); + } } - byte[] hash = md.digest(); - BigInteger bigInt = new BigInteger(1, hash); - hashText = bigInt.toString(16); - // zero padding - while (hashText.length() < 32) { - hashText = "0" + hashText; + } + + List<HashResult> results = new ArrayList<>(); + for (HashType type : hashTypes) { + byte hashData[] = digests.get(type).digest(); + StringBuilder sb = new StringBuilder(); + for (byte b : hashData) { + sb.append(String.format("%02x", b)); } - } catch (NoSuchAlgorithmException ex) { - logger.log(Level.WARNING, "No algorithm known as 'md5'", ex); //NON-NLS - } finally { - in.close(); + results.add(new HashResult(type, sb.toString())); } - return hashText; + return results; } /** @@ -114,6 +139,46 @@ public static boolean isValidSha256Hash(String sha256Hash) { public static boolean isNoDataMd5(String md5) { return md5.toLowerCase().equals("d41d8cd98f00b204e9800998ecf8427e"); //NON-NLS } + + /** + * Utility class to hold a hash value along with its type. + */ + public static class HashResult { + + private final HashType type; + private final String value; + + public HashResult(HashType type, String value) { + this.type = type; + this.value = value; + } + + public HashType getType() { + return type; + } + + public String getValue() { + return value; + } + } + + /** + * Hash types that can be calculated. + */ + public enum HashType { + MD5("MD5"), + SHA256("SHA-256"); + + private final String name; // This should be the string expected by MessageDigest + + HashType(String name) { + this.name = name; + } + + String getName() { + return name; + } + } /** * Calculate the MD5 hash for the given FsContent and store it in the @@ -125,7 +190,7 @@ public static boolean isNoDataMd5(String md5) { * * @throws java.io.IOException * - * @deprecated + * @deprecated Use calculateHashes() instead */ @Deprecated static public String calculateMd5(AbstractFile file) throws IOException { @@ -138,4 +203,29 @@ static public String calculateMd5(AbstractFile file) throws IOException { } return md5Hash; } + + /** + * Calculate the MD5 hash for the given FsContent + * + * @param content content object whose md5 hash we want to calculate + * + * @return md5 of the given FsContent object + * + * @throws java.io.IOException + * + * @decprecated Use calculateHashes() instead + */ + @Deprecated + static public String calculateMd5Hash(Content content) throws IOException { + try { + List<HashResult> results = calculateHashes(content, Arrays.asList(HashType.MD5)); + return results.stream() + .filter(result -> result.getType().equals(HashType.MD5)) + .findFirst().get().getValue(); + + } catch (TskCoreException ex) { + // Wrap in an IOException to retain the current method signature + throw new IOException(ex); + } + } } diff --git a/bindings/java/src/org/sleuthkit/datamodel/LayoutFile.java b/bindings/java/src/org/sleuthkit/datamodel/LayoutFile.java index de5dd75938e3e8d7c48157de2481153844bfd364..ab98c64e75a8ffc50219df350fbe2c63b2a539f6 100644 --- a/bindings/java/src/org/sleuthkit/datamodel/LayoutFile.java +++ b/bindings/java/src/org/sleuthkit/datamodel/LayoutFile.java @@ -91,9 +91,9 @@ public class LayoutFile extends AbstractFile { TSK_FS_NAME_FLAG_ENUM dirFlag, short metaFlags, long size, long ctime, long crtime, long atime, long mtime, - String md5Hash, FileKnown knownState, + String md5Hash, String sha256Hash, FileKnown knownState, String parentPath, String mimeType) { - super(db, objId, dataSourceObjectId, TSK_FS_ATTR_TYPE_ENUM.TSK_FS_ATTR_TYPE_DEFAULT, 0, name, fileType, 0L, 0, dirType, metaType, dirFlag, metaFlags, size, ctime, crtime, atime, mtime, (short) 0, 0, 0, md5Hash, knownState, parentPath, mimeType, SleuthkitCase.extractExtension(name)); + super(db, objId, dataSourceObjectId, TSK_FS_ATTR_TYPE_ENUM.TSK_FS_ATTR_TYPE_DEFAULT, 0, name, fileType, 0L, 0, dirType, metaType, dirFlag, metaFlags, size, ctime, crtime, atime, mtime, (short) 0, 0, 0, md5Hash, sha256Hash, knownState, parentPath, mimeType, SleuthkitCase.extractExtension(name)); } /** @@ -280,6 +280,6 @@ protected LayoutFile(SleuthkitCase db, long objId, String name, TSK_FS_NAME_TYPE_ENUM dirType, TSK_FS_META_TYPE_ENUM metaType, TSK_FS_NAME_FLAG_ENUM dirFlag, short metaFlags, long size, String md5Hash, FileKnown knownState, String parentPath) { - this(db, objId, db.getDataSourceObjectId(objId), name, fileType, dirType, metaType, dirFlag, metaFlags, size, 0L, 0L, 0L, 0L, md5Hash, knownState, parentPath, null); + this(db, objId, db.getDataSourceObjectId(objId), name, fileType, dirType, metaType, dirFlag, metaFlags, size, 0L, 0L, 0L, 0L, md5Hash, null, knownState, parentPath, null); } } diff --git a/bindings/java/src/org/sleuthkit/datamodel/LocalDirectory.java b/bindings/java/src/org/sleuthkit/datamodel/LocalDirectory.java index 5b1be320ef22031fc98441e3c913ee57b6ec80ea..8eafbefdbf6f4ea45cd4677d9107701fbf6ef4a3 100644 --- a/bindings/java/src/org/sleuthkit/datamodel/LocalDirectory.java +++ b/bindings/java/src/org/sleuthkit/datamodel/LocalDirectory.java @@ -62,11 +62,11 @@ public class LocalDirectory extends SpecialDirectory { String name, TSK_FS_NAME_TYPE_ENUM dirType, TSK_FS_META_TYPE_ENUM metaType, TSK_FS_NAME_FLAG_ENUM dirFlag, short metaFlags, - String md5Hash, FileKnown knownState, + String md5Hash, String sha256Hash, FileKnown knownState, String parentPath) { super(db, objId, dataSourceObjectId, TSK_FS_ATTR_TYPE_ENUM.TSK_FS_ATTR_TYPE_DEFAULT, 0, name, TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL_DIR, 0L, 0, dirType, metaType, dirFlag, - metaFlags, 0L, 0L, 0L, 0L, 0L, (short) 0, 0, 0, md5Hash, knownState, parentPath, null); + metaFlags, 0L, 0L, 0L, 0L, 0L, (short) 0, 0, 0, md5Hash, sha256Hash, knownState, parentPath, null); } /** diff --git a/bindings/java/src/org/sleuthkit/datamodel/LocalFile.java b/bindings/java/src/org/sleuthkit/datamodel/LocalFile.java index b174a5cd1c652dab00c36d41f6bbf100e9f802a8..99abf74e70cd7f77cbaa062e0fa1316072064611 100644 --- a/bindings/java/src/org/sleuthkit/datamodel/LocalFile.java +++ b/bindings/java/src/org/sleuthkit/datamodel/LocalFile.java @@ -83,7 +83,7 @@ public class LocalFile extends AbstractFile { TSK_FS_NAME_FLAG_ENUM dirFlag, short metaFlags, long size, long ctime, long crtime, long atime, long mtime, - String mimeType, String md5Hash, FileKnown knownState, + String mimeType, String md5Hash, String sha256Hash, FileKnown knownState, long parentId, String parentPath, long dataSourceObjectId, String localPath, @@ -91,7 +91,7 @@ public class LocalFile extends AbstractFile { String extension) { super(db, objId, dataSourceObjectId, TSK_FS_ATTR_TYPE_ENUM.TSK_FS_ATTR_TYPE_DEFAULT, 0, name, fileType, 0L, 0, dirType, metaType, dirFlag, - metaFlags, size, ctime, crtime, atime, mtime, (short) 0, 0, 0, md5Hash, knownState, parentPath, mimeType, extension); + metaFlags, size, ctime, crtime, atime, mtime, (short) 0, 0, 0, md5Hash, sha256Hash, knownState, parentPath, mimeType, extension); // TODO (AUT-1904): The parent id should be passed to AbstractContent // through the class hierarchy contructors, using // AbstractContent.UNKNOWN_ID as needed. @@ -218,7 +218,7 @@ protected LocalFile(SleuthkitCase db, dirFlag, metaFlags, size, ctime, crtime, atime, mtime, - null, md5Hash, knownState, + null, md5Hash, null, knownState, AbstractContent.UNKNOWN_ID, parentPath, db.getDataSourceObjectId(objId), localPath, diff --git a/bindings/java/src/org/sleuthkit/datamodel/LocalFilesDataSource.java b/bindings/java/src/org/sleuthkit/datamodel/LocalFilesDataSource.java index 1d2e25eedc0a26384d1a1946f33735097e36cc18..0572291890859ea7ecaa7a61236cde43b1c102e5 100755 --- a/bindings/java/src/org/sleuthkit/datamodel/LocalFilesDataSource.java +++ b/bindings/java/src/org/sleuthkit/datamodel/LocalFilesDataSource.java @@ -61,13 +61,14 @@ public class LocalFilesDataSource extends VirtualDirectory implements DataSource * @param metaFlags The meta flags for the virtual directory. * @param timezone The timezone for the data source. * @param md5Hash The MD5 hash for the virtual directory. + * @param sha256Hash The SHA-256 hash for the virtual directory. * @param knownState The known state for the virtual directory * @param parentPath The parent path for the virtual directory, * should be "/" if the virtual directory is a * data source. */ - public LocalFilesDataSource(SleuthkitCase db, long objId, long dataSourceObjectId, String deviceId, String name, TskData.TSK_FS_NAME_TYPE_ENUM dirType, TskData.TSK_FS_META_TYPE_ENUM metaType, TskData.TSK_FS_NAME_FLAG_ENUM dirFlag, short metaFlags, String timezone, String md5Hash, TskData.FileKnown knownState, String parentPath) { - super(db, objId, dataSourceObjectId, name, dirType, metaType, dirFlag, metaFlags, md5Hash, knownState, parentPath); + public LocalFilesDataSource(SleuthkitCase db, long objId, long dataSourceObjectId, String deviceId, String name, TskData.TSK_FS_NAME_TYPE_ENUM dirType, TskData.TSK_FS_META_TYPE_ENUM metaType, TskData.TSK_FS_NAME_FLAG_ENUM dirFlag, short metaFlags, String timezone, String md5Hash, String sha256Hash, TskData.FileKnown knownState, String parentPath) { + super(db, objId, dataSourceObjectId, name, dirType, metaType, dirFlag, metaFlags, md5Hash, sha256Hash, knownState, parentPath); this.objectId = objId; this.deviceId = deviceId; this.timezone = timezone; @@ -233,4 +234,35 @@ private static void closeStatement(Statement statement) { } } } + + /** + * Constructs a local/logical files and/or directories data source. + * + * @param db The case database. + * @param objId The object id of the virtual directory. + * @param dataSourceObjectId The object id of the data source for the + * virtual directory; same as objId if the virtual + * directory is a data source. + * @param name The name of the virtual directory. + * @param dirType The TSK_FS_NAME_TYPE_ENUM for the virtual + * directory. + * @param deviceId The device ID for the data source. + * @param metaType The TSK_FS_META_TYPE_ENUM for the virtual + * directory. + * @param dirFlag The TSK_FS_META_TYPE_ENUM for the virtual + * directory. + * @param metaFlags The meta flags for the virtual directory. + * @param timezone The timezone for the data source. + * @param md5Hash The MD5 hash for the virtual directory. + * @param knownState The known state for the virtual directory + * @param parentPath The parent path for the virtual directory, + * should be "/" if the virtual directory is a + * data source. + * + * @deprecated Use version with SHA-256 parameter + */ + @Deprecated + public LocalFilesDataSource(SleuthkitCase db, long objId, long dataSourceObjectId, String deviceId, String name, TskData.TSK_FS_NAME_TYPE_ENUM dirType, TskData.TSK_FS_META_TYPE_ENUM metaType, TskData.TSK_FS_NAME_FLAG_ENUM dirFlag, short metaFlags, String timezone, String md5Hash, TskData.FileKnown knownState, String parentPath) { + this(db, objId, dataSourceObjectId, deviceId, name, dirType, metaType, dirFlag, metaFlags, timezone, md5Hash, null, knownState, parentPath); + } } diff --git a/bindings/java/src/org/sleuthkit/datamodel/SlackFile.java b/bindings/java/src/org/sleuthkit/datamodel/SlackFile.java index f3e0d23b14e71a6a96e3c636860b4abd90e46d58..df038e6021013a8f0a5b706e27721a721b2856d5 100644 --- a/bindings/java/src/org/sleuthkit/datamodel/SlackFile.java +++ b/bindings/java/src/org/sleuthkit/datamodel/SlackFile.java @@ -89,9 +89,9 @@ public class SlackFile extends FsContent { long size, long ctime, long crtime, long atime, long mtime, short modes, int uid, int gid, - String md5Hash, FileKnown knownState, String parentPath, String mimeType, + String md5Hash, String sha256Hash, FileKnown knownState, String parentPath, String mimeType, String extension) { - super(db, objId, dataSourceObjectId, fsObjId, attrType, attrId, name, TskData.TSK_DB_FILES_TYPE_ENUM.SLACK, metaAddr, metaSeq, dirType, metaType, dirFlag, metaFlags, size, ctime, crtime, atime, mtime, modes, uid, gid, md5Hash, knownState, parentPath, mimeType, extension); + super(db, objId, dataSourceObjectId, fsObjId, attrType, attrId, name, TskData.TSK_DB_FILES_TYPE_ENUM.SLACK, metaAddr, metaSeq, dirType, metaType, dirFlag, metaFlags, size, ctime, crtime, atime, mtime, modes, uid, gid, md5Hash, sha256Hash, knownState, parentPath, mimeType, extension); } /** diff --git a/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java b/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java index 7024417ce66c424273822a8b6cacd50b58fb6b6f..f380bc88aedeeeaa47004a371a6fd833317bb446 100644 --- a/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java +++ b/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java @@ -98,7 +98,7 @@ public class SleuthkitCase { * tsk/auto/tsk_db.h. */ static final CaseDbSchemaVersionNumber CURRENT_DB_SCHEMA_VERSION - = new CaseDbSchemaVersionNumber(8, 5); + = new CaseDbSchemaVersionNumber(8, 6); private static final long BASE_ARTIFACT_ID = Long.MIN_VALUE; // Artifact ids will start at the lowest negative value private static final Logger logger = Logger.getLogger(SleuthkitCase.class.getName()); @@ -914,6 +914,7 @@ private void updateDatabaseSchema(String dbPath) throws Exception { dbSchemaVersion = updateFromSchema8dot2toSchema8dot3(dbSchemaVersion, connection); dbSchemaVersion = updateFromSchema8dot3toSchema8dot4(dbSchemaVersion, connection); dbSchemaVersion = updateFromSchema8dot4toSchema8dot5(dbSchemaVersion, connection); + dbSchemaVersion = updateFromSchema8dot5toSchema8dot6(dbSchemaVersion, connection); statement = connection.createStatement(); connection.executeUpdate(statement, "UPDATE tsk_db_info SET schema_ver = " + dbSchemaVersion.getMajor() + ", schema_minor_ver = " + dbSchemaVersion.getMinor()); //NON-NLS connection.executeUpdate(statement, "UPDATE tsk_db_info_extended SET value = " + dbSchemaVersion.getMajor() + " WHERE name = '" + SCHEMA_MAJOR_VERSION_KEY + "'"); //NON-NLS @@ -2190,6 +2191,28 @@ private CaseDbSchemaVersionNumber updateFromSchema8dot4toSchema8dot5(CaseDbSchem releaseSingleUserCaseWriteLock(); } } + + private CaseDbSchemaVersionNumber updateFromSchema8dot5toSchema8dot6(CaseDbSchemaVersionNumber schemaVersion, CaseDbConnection connection) throws SQLException, TskCoreException { + if (schemaVersion.getMajor() != 8) { + return schemaVersion; + } + + if (schemaVersion.getMinor() != 5) { + return schemaVersion; + } + + Statement statement = connection.createStatement(); + acquireSingleUserCaseWriteLock(); + try { + statement.execute("ALTER TABLE tsk_files ADD COLUMN sha256 TEXT"); + + return new CaseDbSchemaVersionNumber(8, 6); + + } finally { + closeStatement(statement); + releaseSingleUserCaseWriteLock(); + } + } /** * Inserts a row for the given account type in account_types table, if one @@ -2829,7 +2852,7 @@ public List<DataSource> getDataSources() throws TskCoreException { final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue() | TSK_FS_META_FLAG_ENUM.USED.getValue()); String parentPath = "/"; //NON-NLS - dataSource = new LocalFilesDataSource(this, objectId, objectId, deviceId, dsName, dirType, metaType, dirFlag, metaFlags, timezone, null, FileKnown.UNKNOWN, parentPath); + dataSource = new LocalFilesDataSource(this, objectId, objectId, deviceId, dsName, dirType, metaType, dirFlag, metaFlags, timezone, null, null, FileKnown.UNKNOWN, parentPath); } else { /* * Data found in 'tsk_image_info', so we build an Image. @@ -2928,7 +2951,7 @@ public DataSource getDataSource(long objectId) throws TskDataException, TskCoreE final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue() | TSK_FS_META_FLAG_ENUM.USED.getValue()); String parentPath = "/"; //NON-NLS - dataSource = new LocalFilesDataSource(this, objectId, objectId, deviceId, dsName, dirType, metaType, dirFlag, metaFlags, timezone, null, FileKnown.UNKNOWN, parentPath); + dataSource = new LocalFilesDataSource(this, objectId, objectId, deviceId, dsName, dirType, metaType, dirFlag, metaFlags, timezone, null, null, FileKnown.UNKNOWN, parentPath); } else { /* * Data found in 'tsk_image_info', so we build an Image. @@ -5643,11 +5666,12 @@ public VirtualDirectory addVirtualDirectory(long parentId, String directoryName, statement.setNull(14, java.sql.Types.BIGINT); statement.setNull(15, java.sql.Types.VARCHAR); // MD5 - statement.setByte(16, FileKnown.UNKNOWN.getFileKnownValue()); // Known - statement.setNull(17, java.sql.Types.VARCHAR); // MIME type + statement.setNull(16, java.sql.Types.VARCHAR); // SHA-256 + statement.setByte(17, FileKnown.UNKNOWN.getFileKnownValue()); // Known + statement.setNull(18, java.sql.Types.VARCHAR); // MIME type // parent path - statement.setString(18, parentPath); + statement.setString(19, parentPath); // data source object id (same as object id if this is a data source) long dataSourceObjectId; @@ -5656,14 +5680,14 @@ public VirtualDirectory addVirtualDirectory(long parentId, String directoryName, } else { dataSourceObjectId = getDataSourceObjectId(connection, parentId); } - statement.setLong(19, dataSourceObjectId); + statement.setLong(20, dataSourceObjectId); //extension, since this is not really file we just set it to null - statement.setString(20, null); + statement.setString(21, null); connection.executeUpdate(statement); return new VirtualDirectory(this, newObjId, dataSourceObjectId, directoryName, dirType, - metaType, dirFlag, metaFlags, null, FileKnown.UNKNOWN, + metaType, dirFlag, metaFlags, null, null, FileKnown.UNKNOWN, parentPath); } catch (SQLException e) { throw new TskCoreException("Error creating virtual directory '" + directoryName + "'", e); @@ -5739,7 +5763,7 @@ public LocalDirectory addLocalDirectory(long parentId, String directoryName, Cas // Insert a row for the local directory into the tsk_files table. // INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type, meta_type, - // dir_flags, meta_flags, size, ctime, crtime, atime, mtime, md5, known, mime_type, parent_path, data_source_obj_id) + // dir_flags, meta_flags, size, ctime, crtime, atime, mtime, md5, sha256, known, mime_type, parent_path, data_source_obj_id) // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE); statement.clearParameters(); @@ -5778,23 +5802,24 @@ public LocalDirectory addLocalDirectory(long parentId, String directoryName, Cas statement.setNull(14, java.sql.Types.BIGINT); statement.setNull(15, java.sql.Types.VARCHAR); // MD5 - statement.setByte(16, FileKnown.UNKNOWN.getFileKnownValue()); // Known - statement.setNull(17, java.sql.Types.VARCHAR); // MIME type + statement.setNull(16, java.sql.Types.VARCHAR); // SHA-256 + statement.setByte(17, FileKnown.UNKNOWN.getFileKnownValue()); // Known + statement.setNull(18, java.sql.Types.VARCHAR); // MIME type // parent path - statement.setString(18, parentPath); + statement.setString(19, parentPath); // data source object id long dataSourceObjectId = getDataSourceObjectId(connection, parentId); - statement.setLong(19, dataSourceObjectId); + statement.setLong(20, dataSourceObjectId); //extension, since this is a directory we just set it to null - statement.setString(20, null); + statement.setString(21, null); connection.executeUpdate(statement); return new LocalDirectory(this, newObjId, dataSourceObjectId, directoryName, dirType, - metaType, dirFlag, metaFlags, null, FileKnown.UNKNOWN, + metaType, dirFlag, metaFlags, null, null, FileKnown.UNKNOWN, parentPath); } catch (SQLException e) { throw new TskCoreException("Error creating local directory '" + directoryName + "'", e); @@ -5866,15 +5891,16 @@ public LocalFilesDataSource addLocalFilesDataSource(String deviceId, String root preparedStatement.setNull(13, java.sql.Types.BIGINT); preparedStatement.setNull(14, java.sql.Types.BIGINT); preparedStatement.setNull(15, java.sql.Types.VARCHAR); // MD5 - preparedStatement.setByte(16, FileKnown.UNKNOWN.getFileKnownValue()); // Known - preparedStatement.setNull(17, java.sql.Types.VARCHAR); // MIME type + preparedStatement.setNull(16, java.sql.Types.VARCHAR); // SHA-256 + preparedStatement.setByte(17, FileKnown.UNKNOWN.getFileKnownValue()); // Known + preparedStatement.setNull(18, java.sql.Types.VARCHAR); // MIME type String parentPath = "/"; //NON-NLS - preparedStatement.setString(18, parentPath); - preparedStatement.setLong(19, newObjId); - preparedStatement.setString(20, null); //extension, just set it to null + preparedStatement.setString(19, parentPath); + preparedStatement.setLong(20, newObjId); + preparedStatement.setString(21, null); //extension, just set it to null connection.executeUpdate(preparedStatement); - return new LocalFilesDataSource(this, newObjId, newObjId, deviceId, rootDirectoryName, dirType, metaType, dirFlag, metaFlags, timeZone, null, FileKnown.UNKNOWN, parentPath); + return new LocalFilesDataSource(this, newObjId, newObjId, deviceId, rootDirectoryName, dirType, metaType, dirFlag, metaFlags, timeZone, null, null, FileKnown.UNKNOWN, parentPath); } catch (SQLException ex) { throw new TskCoreException(String.format("Error creating local files data source with device id %s and directory name %s", deviceId, rootDirectoryName), ex); @@ -6248,7 +6274,7 @@ public FsContent addFileSystemFile(long dataSourceObjId, long fsObjId, connection.executeUpdate(statement); DerivedFile derivedFile = new DerivedFile(this, objectId, dataSourceObjId, fileName, dirType, metaType, dirFlag, metaFlags, - size, ctime, crtime, atime, mtime, null, null, parentPath, null, parent.getId(), null, null, extension); + size, ctime, crtime, atime, mtime, null, null, null, parentPath, null, parent.getId(), null, null, extension); timelineManager.addEventsForNewFile(derivedFile, connection); @@ -6259,7 +6285,7 @@ public FsContent addFileSystemFile(long dataSourceObjId, long fsObjId, attrType, attrId, fileName, metaAddr, metaSeq, dirType, metaType, dirFlag, metaFlags, size, ctime, crtime, atime, mtime, - (short) 0, 0, 0, null, null, parentPath, null, + (short) 0, 0, 0, null, null, null, parentPath, null, extension); } catch (SQLException ex) { @@ -6376,13 +6402,14 @@ public final List<LayoutFile> addLayoutFiles(Content parent, List<TskFileRange> prepStmt.setNull(13, java.sql.Types.BIGINT); // atime prepStmt.setNull(14, java.sql.Types.BIGINT); // mtime prepStmt.setNull(15, java.sql.Types.VARCHAR); // MD5 - prepStmt.setByte(16, FileKnown.UNKNOWN.getFileKnownValue()); // Known - prepStmt.setNull(17, java.sql.Types.VARCHAR); // MIME type - prepStmt.setNull(18, java.sql.Types.VARCHAR); // parent path - prepStmt.setLong(19, parent.getId()); // data_source_obj_id + prepStmt.setNull(16, java.sql.Types.VARCHAR); // SHA-256 + prepStmt.setByte(17, FileKnown.UNKNOWN.getFileKnownValue()); // Known + prepStmt.setNull(18, java.sql.Types.VARCHAR); // MIME type + prepStmt.setNull(19, java.sql.Types.VARCHAR); // parent path + prepStmt.setLong(20, parent.getId()); // data_source_obj_id //extension, since this is not a FS file we just set it to null - prepStmt.setString(20, null); + prepStmt.setString(21, null); connection.executeUpdate(prepStmt); /* @@ -6412,7 +6439,7 @@ public final List<LayoutFile> addLayoutFiles(Content parent, List<TskFileRange> TSK_FS_META_FLAG_ENUM.UNALLOC.getValue(), fileRange.getByteLen(), 0L, 0L, 0L, 0L, - null, + null, null, FileKnown.UNKNOWN, parent.getUniquePath(), null)); @@ -6560,11 +6587,12 @@ public final List<LayoutFile> addCarvedFiles(CarvingResult carvingResult) throws prepStmt.setNull(13, java.sql.Types.BIGINT); // atime prepStmt.setNull(14, java.sql.Types.BIGINT); // mtime prepStmt.setNull(15, java.sql.Types.VARCHAR); // MD5 - prepStmt.setByte(16, FileKnown.UNKNOWN.getFileKnownValue()); // Known - prepStmt.setNull(17, java.sql.Types.VARCHAR); // MIME type - prepStmt.setString(18, parentPath); // parent path - prepStmt.setLong(19, carvedFilesDir.getDataSourceObjectId()); // data_source_obj_id - prepStmt.setString(20, extractExtension(carvedFile.getName())); //extension + prepStmt.setNull(16, java.sql.Types.VARCHAR); // SHA-256 + prepStmt.setByte(17, FileKnown.UNKNOWN.getFileKnownValue()); // Known + prepStmt.setNull(18, java.sql.Types.VARCHAR); // MIME type + prepStmt.setString(19, parentPath); // parent path + prepStmt.setLong(20, carvedFilesDir.getDataSourceObjectId()); // data_source_obj_id + prepStmt.setString(21, extractExtension(carvedFile.getName())); //extension connection.executeUpdate(prepStmt); /* @@ -6596,7 +6624,7 @@ public final List<LayoutFile> addCarvedFiles(CarvingResult carvingResult) throws TSK_FS_META_FLAG_ENUM.UNALLOC.getValue(), carvedFile.getSizeInBytes(), 0L, 0L, 0L, 0L, - null, + null, null, FileKnown.UNKNOWN, parentPath, null)); @@ -6728,18 +6756,19 @@ public DerivedFile addDerivedFile(String fileName, String localPath, statement.setLong(14, mtime); statement.setNull(15, java.sql.Types.VARCHAR); // MD5 - statement.setByte(16, FileKnown.UNKNOWN.getFileKnownValue()); // Known - statement.setNull(17, java.sql.Types.VARCHAR); // MIME type + statement.setNull(16, java.sql.Types.VARCHAR); // SHA-256 + statement.setByte(17, FileKnown.UNKNOWN.getFileKnownValue()); // Known + statement.setNull(18, java.sql.Types.VARCHAR); // MIME type //parent path - statement.setString(18, parentPath); + statement.setString(19, parentPath); // root data source object id long dataSourceObjId = getDataSourceObjectId(connection, parentId); - statement.setLong(19, dataSourceObjId); + statement.setLong(20, dataSourceObjId); final String extension = extractExtension(fileName); //extension - statement.setString(20, extension); + statement.setString(21, extension); connection.executeUpdate(statement); @@ -6747,7 +6776,7 @@ public DerivedFile addDerivedFile(String fileName, String localPath, addFilePath(connection, newObjId, localPath, encodingType); DerivedFile derivedFile = new DerivedFile(this, newObjId, dataSourceObjId, fileName, dirType, metaType, dirFlag, metaFlags, - savedSize, ctime, crtime, atime, mtime, null, null, parentPath, localPath, parentId, null, encodingType, extension); + savedSize, ctime, crtime, atime, mtime, null, null, null, parentPath, localPath, parentId, null, encodingType, extension); timelineManager.addEventsForNewFile(derivedFile, connection); transaction.commit(); @@ -6857,7 +6886,7 @@ public DerivedFile updateDerivedFile(DerivedFile derivedFile, String localPath, long dataSourceObjId = getDataSourceObjectId(connection, parentId); final String extension = extractExtension(derivedFile.getName()); return new DerivedFile(this, derivedFile.getId(), dataSourceObjId, derivedFile.getName(), dirType, metaType, dirFlag, metaFlags, - savedSize, ctime, crtime, atime, mtime, null, null, parentPath, localPath, parentId, null, encodingType, extension); + savedSize, ctime, crtime, atime, mtime, null, null, null, parentPath, localPath, parentId, null, encodingType, extension); } catch (SQLException ex) { connection.rollbackTransaction(); throw new TskCoreException("Failed to add derived file to case database", ex); @@ -6974,7 +7003,7 @@ public LocalFile addLocalFile(String fileName, String localPath, */ public LocalFile addLocalFile(String fileName, String localPath, long size, long ctime, long crtime, long atime, long mtime, - String md5, FileKnown known, String mimeType, + String md5, String sha256, FileKnown known, String mimeType, boolean isFile, TskData.EncodingType encodingType, Content parent, CaseDbTransaction transaction) throws TskCoreException { CaseDbConnection connection = transaction.getConnection(); @@ -7013,12 +7042,13 @@ public LocalFile addLocalFile(String fileName, String localPath, statement.setLong(13, atime); statement.setLong(14, mtime); statement.setString(15, md5); + statement.setString(16, sha256); if (known != null) { - statement.setByte(16, known.getFileKnownValue()); + statement.setByte(17, known.getFileKnownValue()); } else { - statement.setByte(16, FileKnown.UNKNOWN.getFileKnownValue()); + statement.setByte(17, FileKnown.UNKNOWN.getFileKnownValue()); } - statement.setString(17, mimeType); + statement.setString(18, mimeType); String parentPath; long dataSourceObjId; @@ -7034,10 +7064,10 @@ public LocalFile addLocalFile(String fileName, String localPath, parentPath = "/"; dataSourceObjId = getDataSourceObjectId(connection, parent.getId()); } - statement.setString(18, parentPath); - statement.setLong(19, dataSourceObjId); + statement.setString(19, parentPath); + statement.setLong(20, dataSourceObjId); final String extension = extractExtension(fileName); - statement.setString(20, extension); + statement.setString(21, extension); connection.executeUpdate(statement); addFilePath(connection, objectId, localPath, encodingType); @@ -7051,7 +7081,7 @@ public LocalFile addLocalFile(String fileName, String localPath, metaFlags, savedSize, ctime, crtime, atime, mtime, - mimeType, md5, known, + mimeType, md5, sha256, known, parent.getId(), parentPath, dataSourceObjId, localPath, @@ -7200,12 +7230,13 @@ public LayoutFile addLayoutFile(String fileName, prepStmt.setLong(13, atime); // atime prepStmt.setLong(14, mtime); // mtime prepStmt.setNull(15, java.sql.Types.VARCHAR); // MD5 - prepStmt.setByte(16, FileKnown.UNKNOWN.getFileKnownValue()); // Known - prepStmt.setNull(17, java.sql.Types.VARCHAR); // MIME type - prepStmt.setString(18, parentPath); // parent path - prepStmt.setLong(19, parent.getDataSource().getId()); // data_source_obj_id + prepStmt.setNull(16, java.sql.Types.VARCHAR); // SHA-256 + prepStmt.setByte(17, FileKnown.UNKNOWN.getFileKnownValue()); // Known + prepStmt.setNull(18, java.sql.Types.VARCHAR); // MIME type + prepStmt.setString(19, parentPath); // parent path + prepStmt.setLong(20, parent.getDataSource().getId()); // data_source_obj_id - prepStmt.setString(20, extractExtension(fileName)); //extension + prepStmt.setString(21, extractExtension(fileName)); //extension connection.executeUpdate(prepStmt); /* @@ -7237,7 +7268,7 @@ public LayoutFile addLayoutFile(String fileName, metaFlag.getValue(), savedSize, ctime, crtime, atime, mtime, - null, + null, null, FileKnown.UNKNOWN, parentPath, null); @@ -7580,31 +7611,33 @@ public List<TskFileRange> getFileRanges(long id) throws TskCoreException { public Image getImageById(long id) throws TskCoreException { CaseDbConnection connection = connections.getConnection(); acquireSingleUserCaseReadLock(); - Statement s1 = null; - ResultSet rs1 = null; - Statement s2 = null; - ResultSet rs2 = null; + Statement s = null; + ResultSet rs = null; try { - s1 = connection.createStatement(); - rs1 = connection.executeQuery(s1, "SELECT tsk_image_info.type, tsk_image_info.ssize, tsk_image_info.tzone, tsk_image_info.size, tsk_image_info.md5, tsk_image_info.sha1, tsk_image_info.sha256, tsk_image_info.display_name, data_source_info.device_id " + s = connection.createStatement(); + rs = connection.executeQuery(s, "SELECT tsk_image_info.type, tsk_image_info.ssize, tsk_image_info.tzone, tsk_image_info.size, tsk_image_info.md5, tsk_image_info.sha1, tsk_image_info.sha256, tsk_image_info.display_name, data_source_info.device_id, tsk_image_names.name " + "FROM tsk_image_info " + "INNER JOIN data_source_info ON tsk_image_info.obj_id = data_source_info.obj_id " + + "LEFT JOIN tsk_image_names ON tsk_image_names.obj_id = data_source_info.obj_id " + "WHERE tsk_image_info.obj_id = " + id); //NON-NLS - if (rs1.next()) { - s2 = connection.createStatement(); - rs2 = connection.executeQuery(s2, "SELECT name FROM tsk_image_names WHERE tsk_image_names.obj_id = " + id); //NON-NLS - List<String> imagePaths = new ArrayList<String>(); - while (rs2.next()) { - imagePaths.add(rs2.getString("name")); + + List<String> imagePaths = new ArrayList<>(); + long type, ssize, size; + String tzone, md5, sha1, sha256, name, device_id, imagePath; + + if (rs.next()) { + imagePath = rs.getString("name"); + if (imagePath != null) { + imagePaths.add(imagePath); } - long type = rs1.getLong("type"); //NON-NLS - long ssize = rs1.getLong("ssize"); //NON-NLS - String tzone = rs1.getString("tzone"); //NON-NLS - long size = rs1.getLong("size"); //NON-NLS - String md5 = rs1.getString("md5"); //NON-NLS - String sha1 = rs1.getString("sha1"); //NON-NLS - String sha256 = rs1.getString("sha256"); //NON-NLS - String name = rs1.getString("display_name"); + type = rs.getLong("type"); //NON-NLS + ssize = rs.getLong("ssize"); //NON-NLS + tzone = rs.getString("tzone"); //NON-NLS + size = rs.getLong("size"); //NON-NLS + md5 = rs.getString("md5"); //NON-NLS + sha1 = rs.getString("sha1"); //NON-NLS + sha256 = rs.getString("sha256"); //NON-NLS + name = rs.getString("display_name"); if (name == null) { if (imagePaths.size() > 0) { String path = imagePaths.get(0); @@ -7613,20 +7646,26 @@ public Image getImageById(long id) throws TskCoreException { name = ""; } } - String device_id = rs1.getString("device_id"); - - return new Image(this, id, type, device_id, ssize, name, - imagePaths.toArray(new String[imagePaths.size()]), tzone, md5, sha1, sha256, size); + device_id = rs.getString("device_id"); } else { throw new TskCoreException("No image found for id: " + id); } + + // image can have multiple paths, therefore there can be multiple rows in the result set + while (rs.next()) { + imagePath = rs.getString("name"); + if (imagePath != null) { + imagePaths.add(imagePath); + } + } + + return new Image(this, id, type, device_id, ssize, name, + imagePaths.toArray(new String[imagePaths.size()]), tzone, md5, sha1, sha256, size); } catch (SQLException ex) { throw new TskCoreException("Error getting Image by id, id = " + id, ex); } finally { - closeResultSet(rs2); - closeStatement(s2); - closeResultSet(rs1); - closeStatement(s1); + closeResultSet(rs); + closeStatement(s); connection.close(); releaseSingleUserCaseReadLock(); } @@ -8292,31 +8331,32 @@ public Map<Long, List<String>> getImagePaths() throws TskCoreException { CaseDbConnection connection = connections.getConnection(); acquireSingleUserCaseReadLock(); Statement s1 = null; - Statement s2 = null; ResultSet rs1 = null; - ResultSet rs2 = null; try { s1 = connection.createStatement(); - rs1 = connection.executeQuery(s1, "SELECT obj_id FROM tsk_image_info"); //NON-NLS - s2 = connection.createStatement(); + rs1 = connection.executeQuery(s1, "SELECT tsk_image_info.obj_id, tsk_image_names.name FROM tsk_image_info " + + "LEFT JOIN tsk_image_names ON tsk_image_info.obj_id = tsk_image_names.obj_id"); //NON-NLS Map<Long, List<String>> imgPaths = new LinkedHashMap<Long, List<String>>(); while (rs1.next()) { long obj_id = rs1.getLong("obj_id"); //NON-NLS - rs2 = connection.executeQuery(s2, "SELECT * FROM tsk_image_names WHERE obj_id = " + obj_id); //NON-NLS - List<String> paths = new ArrayList<String>(); - while (rs2.next()) { - paths.add(rs2.getString("name")); - } - rs2.close(); - rs2 = null; - imgPaths.put(obj_id, paths); + String name = rs1.getString("name"); //NON-NLS + List<String> imagePaths = imgPaths.get(obj_id); + if (imagePaths == null) { + List<String> paths = new ArrayList<String>(); + if (name != null) { + paths.add(name); + } + imgPaths.put(obj_id, paths); + } else { + if (name != null) { + imagePaths.add(name); + } + } } return imgPaths; } catch (SQLException ex) { throw new TskCoreException("Error getting image paths.", ex); } finally { - closeResultSet(rs2); - closeStatement(s2); closeResultSet(rs1); closeStatement(s1); connection.close(); @@ -8530,7 +8570,7 @@ private List<AbstractFile> resultSetToAbstractFiles(ResultSet rs, CaseDbConnecti TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), rs.getShort("meta_flags"), //NON-NLS rs.getLong("size"), //NON-NLS rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS - rs.getString("md5"), FileKnown.valueOf(rs.getByte("known")), parentPath, rs.getString("mime_type")); //NON-NLS + rs.getString("md5"), rs.getString("sha256"), FileKnown.valueOf(rs.getByte("known")), parentPath, rs.getString("mime_type")); //NON-NLS results.add(lf); } else if (type == TSK_DB_FILES_TYPE_ENUM.DERIVED.getFileType()) { final DerivedFile df; @@ -8575,7 +8615,7 @@ org.sleuthkit.datamodel.File file(ResultSet rs, FileSystem fs) throws SQLExcepti rs.getShort("meta_flags"), rs.getLong("size"), //NON-NLS rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS (short) rs.getInt("mode"), rs.getInt("uid"), rs.getInt("gid"), //NON-NLS - rs.getString("md5"), FileKnown.valueOf(rs.getByte("known")), //NON-NLS + rs.getString("md5"), rs.getString("sha256"), FileKnown.valueOf(rs.getByte("known")), //NON-NLS rs.getString("parent_path"), rs.getString("mime_type"), rs.getString("extension")); //NON-NLS f.setFileSystem(fs); return f; @@ -8602,7 +8642,7 @@ Directory directory(ResultSet rs, FileSystem fs) throws SQLException { rs.getShort("meta_flags"), rs.getLong("size"), //NON-NLS rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS rs.getShort("mode"), rs.getInt("uid"), rs.getInt("gid"), //NON-NLS - rs.getString("md5"), FileKnown.valueOf(rs.getByte("known")), //NON-NLS + rs.getString("md5"), rs.getString("sha256"), FileKnown.valueOf(rs.getByte("known")), //NON-NLS rs.getString("parent_path")); //NON-NLS dir.setFileSystem(fs); return dir; @@ -8659,6 +8699,7 @@ VirtualDirectory virtualDirectory(ResultSet rs, CaseDbConnection connection) thr rs.getShort("meta_flags"), timeZone, rs.getString("md5"), + rs.getString("sha256"), FileKnown.valueOf(rs.getByte("known")), parentPath); } else { @@ -8668,7 +8709,7 @@ VirtualDirectory virtualDirectory(ResultSet rs, CaseDbConnection connection) thr TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), //NON-NLS - rs.getShort("meta_flags"), rs.getString("md5"), //NON-NLS + rs.getShort("meta_flags"), rs.getString("md5"), rs.getString("sha256"), //NON-NLS FileKnown.valueOf(rs.getByte("known")), parentPath); //NON-NLS return vd; } @@ -8693,7 +8734,7 @@ LocalDirectory localDirectory(ResultSet rs) throws SQLException { TSK_FS_NAME_TYPE_ENUM.valueOf(rs.getShort("dir_type")), //NON-NLS TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), //NON-NLS - rs.getShort("meta_flags"), rs.getString("md5"), //NON-NLS + rs.getShort("meta_flags"), rs.getString("md5"), rs.getString("sha256"), //NON-NLS FileKnown.valueOf(rs.getByte("known")), parentPath); //NON-NLS return ld; } @@ -8746,7 +8787,7 @@ private DerivedFile derivedFile(ResultSet rs, CaseDbConnection connection, long TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), rs.getShort("meta_flags"), //NON-NLS rs.getLong("size"), //NON-NLS rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS - rs.getString("md5"), FileKnown.valueOf(rs.getByte("known")), //NON-NLS + rs.getString("md5"), rs.getString("sha256"), FileKnown.valueOf(rs.getByte("known")), //NON-NLS parentPath, localPath, parentId, rs.getString("mime_type"), encodingType, rs.getString("extension")); return df; @@ -8799,7 +8840,7 @@ private LocalFile localFile(ResultSet rs, CaseDbConnection connection, long pare TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), rs.getShort("meta_flags"), //NON-NLS rs.getLong("size"), //NON-NLS rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS - rs.getString("mime_type"), rs.getString("md5"), FileKnown.valueOf(rs.getByte("known")), //NON-NLS + rs.getString("mime_type"), rs.getString("md5"), rs.getString("sha256"), FileKnown.valueOf(rs.getByte("known")), //NON-NLS parentId, parentPath, rs.getLong("data_source_obj_id"), localPath, encodingType, rs.getString("extension")); return file; @@ -8827,7 +8868,7 @@ org.sleuthkit.datamodel.SlackFile slackFile(ResultSet rs, FileSystem fs) throws rs.getShort("meta_flags"), rs.getLong("size"), //NON-NLS rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS (short) rs.getInt("mode"), rs.getInt("uid"), rs.getInt("gid"), //NON-NLS - rs.getString("md5"), FileKnown.valueOf(rs.getByte("known")), //NON-NLS + rs.getString("md5"), rs.getString("sha256"), FileKnown.valueOf(rs.getByte("known")), //NON-NLS rs.getString("parent_path"), rs.getString("mime_type"), rs.getString("extension")); //NON-NLS f.setFileSystem(fs); return f; @@ -8889,7 +8930,7 @@ List<Content> fileChildren(ResultSet rs, CaseDbConnection connection, long paren TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), rs.getShort("meta_flags"), rs.getLong("size"), rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), - rs.getString("md5"), + rs.getString("md5"), rs.getString("sha256"), FileKnown.valueOf(rs.getByte("known")), parentPath, rs.getString("mime_type")); children.add(lf); break; @@ -11162,8 +11203,8 @@ private enum PREPARED_STATEMENT { SELECT_FILE_DERIVATION_METHOD("SELECT tool_name, tool_version, other FROM tsk_files_derived_method WHERE derived_id = ?"), //NON-NLS SELECT_MAX_OBJECT_ID("SELECT MAX(obj_id) AS max_obj_id FROM tsk_objects"), //NON-NLS INSERT_OBJECT("INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)"), //NON-NLS - INSERT_FILE("INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type, meta_type, dir_flags, meta_flags, size, ctime, crtime, atime, mtime, md5, known, mime_type, parent_path, data_source_obj_id,extension) " //NON-NLS - + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"), //NON-NLS + INSERT_FILE("INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type, meta_type, dir_flags, meta_flags, size, ctime, crtime, atime, mtime, md5, sha256, known, mime_type, parent_path, data_source_obj_id,extension) " //NON-NLS + + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"), //NON-NLS INSERT_FILE_SYSTEM_FILE("INSERT INTO tsk_files(obj_id, fs_obj_id, data_source_obj_id, attr_type, attr_id, name, meta_addr, meta_seq, type, has_path, dir_type, meta_type, dir_flags, meta_flags, size, ctime, crtime, atime, mtime, parent_path, extension)" + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"), // NON-NLS UPDATE_DERIVED_FILE("UPDATE tsk_files SET type = ?, dir_type = ?, meta_type = ?, dir_flags = ?, meta_flags = ?, size= ?, ctime= ?, crtime= ?, atime= ?, mtime= ?, mime_type = ? " @@ -12574,6 +12615,47 @@ public DerivedFile addDerivedFile(String fileName, String localPath, isFile, parentFile, rederiveDetails, toolName, toolVersion, otherDetails, TskData.EncodingType.NONE); } + + /** + * Adds a local/logical file to the case database. The database operations + * are done within a caller-managed transaction; the caller is responsible + * for committing or rolling back the transaction. + * + * @param fileName The name of the file. + * @param localPath The absolute path (including the file name) of the + * local/logical in secondary storage. + * @param size The size of the file in bytes. + * @param ctime The changed time of the file. + * @param crtime The creation time of the file. + * @param atime The accessed time of the file + * @param mtime The modified time of the file. + * @param md5 The MD5 hash of the file + * @param known The known status of the file (can be null) + * @param mimeType The MIME type of the file + * @param isFile True, unless the file is a directory. + * @param encodingType Type of encoding used on the file + * @param parent The parent of the file (e.g., a virtual directory) + * @param transaction A caller-managed transaction within which the add + * file operations are performed. + * + * @return An object representing the local/logical file. + * + * @throws TskCoreException if there is an error completing a case database + * operation. + * + * @deprecated Use the newer version with explicit sha256 parameter + */ + @Deprecated + public LocalFile addLocalFile(String fileName, String localPath, + long size, long ctime, long crtime, long atime, long mtime, + String md5, FileKnown known, String mimeType, + boolean isFile, TskData.EncodingType encodingType, + Content parent, CaseDbTransaction transaction) throws TskCoreException { + + return addLocalFile(fileName, localPath, size, ctime, crtime, atime, mtime, + md5, null, known, mimeType, isFile, encodingType, + parent, transaction); + } /** * Adds a local/logical file to the case database. The database operations diff --git a/bindings/java/src/org/sleuthkit/datamodel/SpecialDirectory.java b/bindings/java/src/org/sleuthkit/datamodel/SpecialDirectory.java index cfd95d2429fcc91768617ae333f82fb7dfe726e5..5db5888d5b34d8a0ebbd926d18b1fa52559c2512 100644 --- a/bindings/java/src/org/sleuthkit/datamodel/SpecialDirectory.java +++ b/bindings/java/src/org/sleuthkit/datamodel/SpecialDirectory.java @@ -43,12 +43,12 @@ public abstract class SpecialDirectory extends AbstractFile { long ctime, long crtime, long atime, long mtime, short modes, int uid, int gid, - String md5Hash, FileKnown knownState, + String md5Hash, String sha256Hash, FileKnown knownState, String parentPath, String mimeType) { super(db, objId, dataSourceObjectId, attrType, attrId, name, fileType, metaAddr, metaSeq, dirType, metaType, dirFlag, - metaFlags, size, ctime, crtime, atime, mtime, modes, uid, gid, md5Hash, knownState, parentPath, mimeType, null); + metaFlags, size, ctime, crtime, atime, mtime, modes, uid, gid, md5Hash, sha256Hash, knownState, parentPath, mimeType, null); } /** diff --git a/bindings/java/src/org/sleuthkit/datamodel/TskCaseDbBridge.java b/bindings/java/src/org/sleuthkit/datamodel/TskCaseDbBridge.java index 6fcf0a38fb77eebfeb5d6238e150ab1f8f4ceb0e..c66755ac36cabafe5c6a2ba38df60417ecc73adc 100644 --- a/bindings/java/src/org/sleuthkit/datamodel/TskCaseDbBridge.java +++ b/bindings/java/src/org/sleuthkit/datamodel/TskCaseDbBridge.java @@ -884,7 +884,7 @@ private long addFileToDb(long parentObjId, TskData.TSK_FS_META_TYPE_ENUM.valueOf((short) metaType), TskData.TSK_FS_NAME_FLAG_ENUM.valueOf(dirFlags), (short) metaFlags, - size, ctime, crtime, atime, mtime, null, null, escaped_path, null, parentObjId, null, null, extension); + size, ctime, crtime, atime, mtime, null, null, null, escaped_path, null, parentObjId, null, null, extension); timelineManager.addEventsForNewFileQuiet(derivedFile, connection); } diff --git a/bindings/java/src/org/sleuthkit/datamodel/VirtualDirectory.java b/bindings/java/src/org/sleuthkit/datamodel/VirtualDirectory.java index b636cd786d0c2dee9e0522a0880876790cbe13b0..729707128e93f097312caca5a16222c30927943b 100644 --- a/bindings/java/src/org/sleuthkit/datamodel/VirtualDirectory.java +++ b/bindings/java/src/org/sleuthkit/datamodel/VirtualDirectory.java @@ -74,11 +74,11 @@ public class VirtualDirectory extends SpecialDirectory { String name, TSK_FS_NAME_TYPE_ENUM dirType, TSK_FS_META_TYPE_ENUM metaType, TSK_FS_NAME_FLAG_ENUM dirFlag, short metaFlags, - String md5Hash, FileKnown knownState, + String md5Hash, String sha256Hash, FileKnown knownState, String parentPath) { super(db, objId, dataSourceObjectId, TSK_FS_ATTR_TYPE_ENUM.TSK_FS_ATTR_TYPE_DEFAULT, 0, name, TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR, 0L, 0, dirType, metaType, dirFlag, - metaFlags, 0L, 0L, 0L, 0L, 0L, (short) 0, 0, 0, md5Hash, knownState, parentPath, null); + metaFlags, 0L, 0L, 0L, 0L, 0L, (short) 0, 0, 0, md5Hash, sha256Hash, knownState, parentPath, null); } /** diff --git a/tools/fiwalk/src/arff.cpp b/tools/fiwalk/src/arff.cpp index cfc4429f59eea2651cc14f47ec537b1ba054a3b1..1297d11ff9276820c8ed6e10011894bd768604ae 100644 --- a/tools/fiwalk/src/arff.cpp +++ b/tools/fiwalk/src/arff.cpp @@ -66,7 +66,7 @@ bool arff::is_weka_date(const string &s) s[10]==' ' && isdigit(s[11]) && isdigit(s[12]) && s[13]==':' && isdigit(s[14]) && isdigit(s[15]) && s[16]==':' && - isdigit(s[17]) && isdigit(s[17]) && s.size()==19) return true; + isdigit(s[17]) && isdigit(s[18]) && s.size()==19) return true; return false; } diff --git a/travis_install_libs.sh b/travis_install_libs.sh index 1acf2cd70b101c1915296758134c30ae97faa008..05812f1f5b50470eaaeed3e878480fcfe006dcfc 100755 --- a/travis_install_libs.sh +++ b/travis_install_libs.sh @@ -13,6 +13,6 @@ installLib() { cd .. } -installLib libvhdi 20200810 -installLib libvmdk 20200810 +installLib libvhdi 20201018 +installLib libvmdk 20200926 diff --git a/tsk/auto/tsk_db.h b/tsk/auto/tsk_db.h index 096764acb30ad4047d5d4c860443b4e5c36ba16a..0976f70e8be16488527d02bc240fe50e9bdf54d0 100755 --- a/tsk/auto/tsk_db.h +++ b/tsk/auto/tsk_db.h @@ -31,7 +31,7 @@ using std::string; * Keep these values in sync with CURRENT_DB_SCHEMA_VERSION in SleuthkitCase.java */ #define TSK_SCHEMA_VER 8 -#define TSK_SCHEMA_MINOR_VER 5 +#define TSK_SCHEMA_MINOR_VER 6 /** * Values for the type column in the tsk_objects table. diff --git a/tsk/fs/ext2fs.c b/tsk/fs/ext2fs.c index b547605622583e1ee701df20fcbab882ccc86bd2..f36a193d86221b4ae3b3e96db87bac50f20b1d22 100755 --- a/tsk/fs/ext2fs.c +++ b/tsk/fs/ext2fs.c @@ -1412,14 +1412,26 @@ ext2fs_make_data_run_extent(TSK_FS_INFO * fs_info, TSK_FS_ATTR * fs_attr, } data_run->offset = tsk_getu32(fs_info->endian, extent->ee_block); - data_run->addr = - (((uint32_t) tsk_getu16(fs_info->endian, + + // Check if the extent is initialized or uninitialized + if (tsk_getu16(fs_info->endian, extent->ee_len) <= EXT2_MAX_INIT_EXTENT_LENGTH) { + // Extent is initalized - process normally + data_run->addr = + (((uint32_t)tsk_getu16(fs_info->endian, extent->ee_start_hi)) << 16) | tsk_getu32(fs_info->endian, - extent->ee_start_lo); - data_run->len = tsk_getu16(fs_info->endian, extent->ee_len); + extent->ee_start_lo); + data_run->len = tsk_getu16(fs_info->endian, extent->ee_len); + } + else { + // Extent is uninitialized - make a sparse run + data_run->len = tsk_getu16(fs_info->endian, extent->ee_len) - EXT2_MAX_INIT_EXTENT_LENGTH; + data_run->addr = 0; + data_run->flags = TSK_FS_ATTR_RUN_FLAG_SPARSE; + } // save the run if (tsk_fs_attr_add_run(fs_info, fs_attr, data_run)) { + tsk_fs_attr_run_free(data_run); return 1; } @@ -1585,6 +1597,50 @@ ext2fs_extent_tree_index_count(TSK_FS_INFO * fs_info, return count; } +/** \internal +* If the file length is longer than what is in the attr runs, add a sparse +* data run to cover the rest of the file. +* +* @return 0 if successful or 1 on error. +*/ +static uint8_t +ext2fs_handle_implicit_sparse_data_run(TSK_FS_INFO * fs_info, TSK_FS_ATTR * fs_attr) { + TSK_FS_FILE *fs_file = fs_attr->fs_file; + + if (fs_file == NULL) { + return 1; + } + + TSK_DADDR_T end_of_runs; + TSK_DADDR_T total_file_blocks = roundup(fs_file->meta->size, fs_info->block_size) / fs_info->block_size; + + if (fs_attr->nrd.run_end) { + end_of_runs = fs_attr->nrd.run_end->offset + fs_attr->nrd.run_end->len; + } + else { + end_of_runs = 0; + } + + if (end_of_runs < total_file_blocks) { + // Make sparse run. + TSK_FS_ATTR_RUN *data_run; + data_run = tsk_fs_attr_run_alloc(); + if (data_run == NULL) { + return 1; + } + data_run->offset = end_of_runs; + data_run->addr = 0; + data_run->len = total_file_blocks - end_of_runs; + data_run->flags = TSK_FS_ATTR_RUN_FLAG_SPARSE; + + // Save the run. + if (tsk_fs_attr_add_run(fs_info, fs_attr, data_run)) { + + return 1; + } + } + return 0; +} /** * \internal @@ -1652,6 +1708,17 @@ ext4_load_attrs_extents(TSK_FS_FILE *fs_file) } if (num_entries == 0) { + if (fs_meta->size == 0) { + // Empty file + fs_meta->attr_state = TSK_FS_META_ATTR_STUDIED; + return 0; + } + + // The entire file is sparse + if (ext2fs_handle_implicit_sparse_data_run(fs_info, fs_attr)) { + return 1; + } + fs_meta->attr_state = TSK_FS_META_ATTR_STUDIED; return 0; } @@ -1723,6 +1790,11 @@ ext4_load_attrs_extents(TSK_FS_FILE *fs_file) } } } + + // There may be implicit sparse blocks at the end of the file + if (ext2fs_handle_implicit_sparse_data_run(fs_info, fs_attr)) { + return 1; + } fs_meta->attr_state = TSK_FS_META_ATTR_STUDIED; diff --git a/tsk/fs/fs_io.c b/tsk/fs/fs_io.c index ec1a15326839f8616e0f0cc409f35286dcb4ca29..acfb99b3fc37b018fdea13510fde5c45b1d31e81 100755 --- a/tsk/fs/fs_io.c +++ b/tsk/fs/fs_io.c @@ -248,7 +248,8 @@ tsk_fs_read_block_decrypt(TSK_FS_INFO * a_fs, TSK_DADDR_T a_addr, char *a_buf, if ((a_fs->flags & TSK_FS_INFO_FLAG_ENCRYPTED) && ret_len > 0 && a_fs->decrypt_block) { - for (TSK_DADDR_T i = 0; i < a_len / a_fs->block_size; i++) { + TSK_DADDR_T i; + for (i = 0; i < a_len / a_fs->block_size; i++) { a_fs->decrypt_block(a_fs, crypto_id + i, a_buf + (a_fs->block_size * i)); } diff --git a/tsk/fs/tsk_ext2fs.h b/tsk/fs/tsk_ext2fs.h index b937a8e43c0a6d9927c83a9cfc308e3b8d0df851..382a9a5312f323046ca256c45484e3895e379a73 100644 --- a/tsk/fs/tsk_ext2fs.h +++ b/tsk/fs/tsk_ext2fs.h @@ -365,7 +365,9 @@ extern "C" { uint8_t eh_generation[4]; /* u32 */ } ext2fs_extent_header; -/* MODE */ +#define EXT2_MAX_INIT_EXTENT_LENGTH 0x8000 /* Maximum length of an initialized extent */ + +/* MODE - Note that values are in octal format */ #define EXT2_IN_FMT 0170000 #define EXT2_IN_SOCK 0140000 #define EXT2_IN_LNK 0120000