Sleuth Kit Java Bindings (JNI) 4.14.0
Java bindings for using The Sleuth Kit
Loading...
Searching...
No Matches
HashUtility.java
Go to the documentation of this file.
1/*
2 * Sleuth Kit Data Model
3 *
4 * Copyright 2011-2020 Basis Technology Corp.
5 * Contact: carrier <at> sleuthkit <dot> org
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19package org.sleuthkit.datamodel;
20
21import java.io.IOException;
22import java.security.MessageDigest;
23import java.security.NoSuchAlgorithmException;
24import java.util.ArrayList;
25import java.util.Collection;
26import java.util.List;
27import java.util.logging.Level;
28import java.util.logging.Logger;
29import java.util.Map;
30import java.util.HashMap;
31import java.util.Arrays;
32
36public class HashUtility {
37
38 private final static int BUFFER_SIZE = 16 * 1024;
39
50 static public List<HashResult> calculateHashes(Content content, Collection<HashType> hashTypes) throws TskCoreException {
51 Map<HashType, MessageDigest> digests = new HashMap<>();
52
53 for (HashType type : hashTypes) {
54 try {
55 digests.put(type, MessageDigest.getInstance(type.getName()));
56 } catch (NoSuchAlgorithmException ex) {
57 throw new TskCoreException("No algorithm found matching name " + type.getName(), ex);
58 }
59 }
60
61 // Read in byte size chunks and update the hash value with the data.
62 byte[] data = new byte[BUFFER_SIZE];
63 int totalChunks = (int) Math.ceil((double) content.getSize() / (double) BUFFER_SIZE);
64 int read;
65 for (long i = 0; i < totalChunks; i++) {
66 try {
67 read = content.read(data, i * BUFFER_SIZE, BUFFER_SIZE);
68 } catch (TskCoreException ex) {
69 throw new TskCoreException("Error reading data at address " + i * BUFFER_SIZE + " from content with ID: " + content.getId(), ex);
70 }
71
72 // Check for EOF
73 if (read == -1) {
74 break;
75 }
76
77 // Only update with the read bytes.
78 if (read == BUFFER_SIZE) {
79 for (HashType type : hashTypes) {
80 digests.get(type).update(data);
81 }
82 } else {
83 byte[] subData = Arrays.copyOfRange(data, 0, read);
84 for (HashType type : hashTypes) {
85 digests.get(type).update(subData);
86 }
87 }
88 }
89
90 List<HashResult> results = new ArrayList<>();
91 for (HashType type : hashTypes) {
92 byte hashData[] = digests.get(type).digest();
93 StringBuilder sb = new StringBuilder();
94 for (byte b : hashData) {
95 sb.append(String.format("%02x", b));
96 }
97 results.add(new HashResult(type, sb.toString()));
98 }
99 return results;
100 }
101
109 public static boolean isValidMd5Hash(String md5Hash) {
110 return md5Hash.matches("^[A-Fa-f0-9]{32}$");
111 }
112
120 public static boolean isValidSha1Hash(String sha1Hash) {
121 return sha1Hash.matches("^[A-Fa-f0-9]{40}$");
122 }
123
131 public static boolean isValidSha256Hash(String sha256Hash) {
132 return sha256Hash.matches("^[A-Fa-f0-9]{64}$");
133 }
134
144 public static boolean isNoDataMd5(String md5) {
145 return md5.toLowerCase().equals("d41d8cd98f00b204e9800998ecf8427e"); //NON-NLS
146 }
147
151 public static class HashResult {
152
153 private final HashType type;
154 private final String value;
155
156 public HashResult(HashType type, String value) {
157 this.type = type;
158 this.value = value;
159 }
160
161 public HashType getType() {
162 return type;
163 }
164
165 public String getValue() {
166 return value;
167 }
168 }
169
173 public enum HashType {
174 MD5("MD5"),
175 SHA256("SHA-256");
176
177 private final String name; // This should be the string expected by MessageDigest
178
179 HashType(String name) {
180 this.name = name;
181 }
182
183 String getName() {
184 return name;
185 }
186 }
187
200 @Deprecated
201 static public String calculateMd5(AbstractFile file) throws IOException {
202 Logger logger = Logger.getLogger(HashUtility.class.getName());
203 String md5Hash = calculateMd5Hash(file);
204 try {
205 file.getSleuthkitCase().setMd5Hash(file, md5Hash);
206 } catch (TskCoreException ex) {
207 logger.log(Level.WARNING, "Error updating content's md5 in database", ex); //NON-NLS
208 }
209 return md5Hash;
210 }
211
223 @Deprecated
224 static public String calculateMd5Hash(Content content) throws IOException {
225 try {
226 List<HashResult> results = calculateHashes(content, Arrays.asList(HashType.MD5));
227 return results.stream()
228 .filter(result -> result.getType().equals(HashType.MD5))
229 .findFirst().get().getValue();
230
231 } catch (TskCoreException ex) {
232 // Wrap in an IOException to retain the current method signature
233 throw new IOException(ex);
234 }
235 }
236}
static String calculateMd5Hash(Content content)
static boolean isValidMd5Hash(String md5Hash)
static boolean isNoDataMd5(String md5)
static boolean isValidSha256Hash(String sha256Hash)
static boolean isValidSha1Hash(String sha1Hash)
static String calculateMd5(AbstractFile file)
static List< HashResult > calculateHashes(Content content, Collection< HashType > hashTypes)

Copyright © 2011-2024 Brian Carrier. (carrier -at- sleuthkit -dot- org)
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.