Is this Java code “write once, run everywhere”?
The checkFileHash method will calculate a hash for the file and check if the correctHash matches with the calculated hash. If the hashes match, the file is identical to what was expected.
boolean checkFileHash(String fileName, String correctHash) {
...
File file = new File(fileName);
MessageDigest md = MessageDigest.getInstance("SHA");
FileInputStream fis = new FileInputStream(file);
byte[] dataBytes = new byte[1024];
int nread = 0;
while ((nread = fis.read(dataBytes)) != -1) {
md.update(dataBytes, 0, nread);
}
byte[] mdbytes = md.digest();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < mdbytes.length; i++) {
sb.append(Integer.toString((mdbytes[i] & 0xff) + 0x100, 16).substring(1));
}
fis.close();
System.out.println("\nHash is " + sb.toString());
return sb.toString().equals(correctHash);
Well this does compile, run and produce a file hash, compare it against the correct one and returns the result.
If the correctHash was calculated earlier on a same OS, hashes will even match. But if the corrrectHash was calculated in a different OS with a different default character encoding, the hashes do not match.
You need to explicitly specify that UTF-8 encoding is used when reading the file — which also should be saved UTF-8 encoded. And when calculating the expected correctHash the UTF-8 encoding should also be used. And when the hash for the file is calculated when file is inspected in this method:
boolean checkFileHash(String fileName, String correctHash) {
...
// Use SHA for hashing, does not need to be secure.
MessageDigest md = MessageDigest.getInstance("SHA");
// Use buffered reader since we need to read explicitly using UTF-8.
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(fileName), "UTF-8"));
// Read the lines from the line to a String.
String line = null;
StringBuilder sb = new StringBuilder();
while ((line = br.readLine()) != null) {
sb.append(line);
}
br.close();
// Calculate the SHA digest (hash) from the string
byte [] mdbytes = md.digest(sb.toString().getBytes("UTF-8"));
// Convert the hash into a String.
StringBuilder hsb = new StringBuilder();
for (int i = 0; i < mdbytes.length; i++) {
hsb.append(Integer.toString((mdbytes[i] & 0xff) + 0x100, 16).substring(1));
}
String calculatedHash = hsb.toString();
System.out.println("\nHash is " + calculatedHash.toString());
// Check if the hash matches with the expected correct one.
boolean matches = calculatedHash.equals(correctHash);
if (!matches) {
System.out.println("Correct has is: " + correctHash);
}
return matches;
Using a platform independent programming language does not guarantee platform independent code.
Obviously UTF-8 specifically is not required, but using a same encoding everywhere.
Once I used (on a macOS) a Java app with file open dialog, that was hardcoded to show directory C:\ by default. Sooooo platform independent…