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