Reputation: 98
I can run the same maven build 5 times in a row on a group of jar/war files, without any changes to any of them, and yet I get a different MD5 hash on each of the jar/war files each time. I would expect the java compiler to produce the same hash each time. Are there any files that would be affecting the hash that I could exclude to give me the same hash each time? Or is it just that the compiler doesn't compile the same code in the same way each time?
Hash is being generated with the following code:
public static String getHash(File file) throws FileNotFoundException, IOException {
if(file == null || !file.isFile()) {
return "";
}
FileInputStream in = null;
try {
in = new FileInputStream(file);
byte [] bytes = toByteArray(in);
return getHash(bytes);
} catch(Exception e) {
Logging.log("Unable to get MD5 hash for file: " + ile.getName());
} finally {
StreamUtils.close(in);
}
return "";
}
public static String getHash(byte[] bytes) {
MessageDigest digest = getMessageDigest();
byte[] hash = digest.digest(bytes);
StringBuilder builder = new StringBuilder();
for (int val : hash) {
builder.append(Integer.toHexString(val & 0xff));
}
return builder.toString();
}
private static MessageDigest getMessageDigest() {
try {
return MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
Upvotes: 2
Views: 2768
Reputation: 31
Try this code, it scans through Each files in the jar and generates an MD5 signature
It is not well optimized though
import java.io.IOException;
import java.io.InputStream;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
public class MD5forjar {
public static String getMD5forjar(String fileName) throws IOException, NoSuchAlgorithmException {
ZipFile zipFile = new ZipFile(fileName);
Enumeration<? extends ZipEntry> entries = zipFile.entries();
MessageDigest sha = MessageDigest.getInstance("md5");
Map<String, String> fileMap = new HashMap<String, String>();
while (entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
System.out.println(entry.getName());
InputStream stream = zipFile.getInputStream(entry);
DigestInputStream dig = new DigestInputStream(stream, sha);
byte[] buffer = new byte[4096];
int count = 0;
while (dig.read(buffer) > -1) {
count++;
}
MessageDigest digest = dig.getMessageDigest();
dig.close();
byte[] md5 = digest.digest();
StringBuilder sb = new StringBuilder();
for (byte b : md5) {
sb.append(String.format("%02X", b));
}
String checkSum = sb.toString();
fileMap.put(entry.getName(), checkSum);
}
SortedSet<String> sorted = new TreeSet<String>(fileMap.keySet());
StringBuffer buff = new StringBuffer();
for (String key : sorted) {
System.out.println(key);
if (!key.endsWith("pom.properties"))
buff.append(fileMap.get(key));
}
MessageDigest md = MessageDigest.getInstance("md5");
md.update(buff.toString().getBytes());
byte[] digest = md.digest();
StringBuffer sb = new StringBuffer();
for (byte b : digest) {
sb.append(String.format("%02x", b & 0xff));
}
return sb.toString();
}
}
Upvotes: 1
Reputation: 691943
A jar or war file is a zip file. A zip file contains zip entries. And zip entries contain metadata about files like their creation and modification time.
You should pass the content every file of the produced jar/war file to your hash, always in the same order.
Upvotes: 5