1

Reading in a file and then hashing it using SHA-256 I found a tutorial which showed two separate ways to do it.

When comparing the file that I hashed (Which was a PDF) against both methods, they did not match up. I am following the code properly, not understanding why it isn't matching up.

Here is my result:

Hex format: b050692edb134da209adf76347f6c5e49db8734edeaa44876606ec8e5559ab4e
Hex format: b050692edb134da29adf76347f6c5e49db8734edeaa4487666ec8e5559ab4e

It looks like it is lopping off the two zeros in the middle, I just don't understand why

Java Code

import java.io.FileInputStream;
import java.security.MessageDigest;

public class SHAHash{
   public static void main(String[] args)throws Exception{
      MessageDigest md = MessageDigest.getInstance("SHA-256");
      FileInputStream fis = new FileInputStream("myfile");

      byte[] dataBytes = new byte[1024];
      int nread = 0;
      while((nread = fis.read(dataBytes))!= -1){
         md.update(dataBytes, 0, nread);
      };

      byte[] mdbytes = md.digest();

      StringBuffer sb1 = new StringBuffer();
      for(int i = 0; i < mdbytes.length; i++){
        sb1.append(Integer.toString((mdbytes[i] & 0xFF) + 0x100, 16).substring(1));
      }
      System.out.println("Hex format: " + sb1.toString());

      StringBuffer sb2 = new StringBuffer();
      for(int i = 0; i < mdbytes.length; i++){
         sb2.append(Integer.toHexString(0xFF & mdbytes[i]));
      }
      System.out.println("Hex format: " + sb2.toString());
   }
}
Community
  • 1
  • 1
mcnichol
  • 175
  • 2
  • 14

2 Answers2

2

Instead of StringBuffer you should be using StringBuilder (the methods aren't synchronized and you aren't using multiple threads, it's like the difference between a Vector and an ArrayList). Also, you need to preserve leading 0(s). You could correct your second loop with something like String.format(String, Object...). Putting that together like,

StringBuilder sb2 = new StringBuilder();
for (int i = 0; i < mdbytes.length; i++) {
    sb2.append(String.format("%02x", 0xFF & mdbytes[i]));
}
System.out.println("Hex format: " + sb2.toString());
Elliott Frisch
  • 198,278
  • 20
  • 158
  • 249
  • That's what I'm talking about. Thanks for that explanation that makes sense. Let me make the changes and I will accept your answer. – mcnichol Nov 14 '15 at 20:09
  • This worked, you were right about the formatting of the hex. I suppose had I iterated through each hex value the answer would have popped right int front of me. – mcnichol Nov 14 '15 at 20:39
  • @milk You might also want to read [this answer](http://stackoverflow.com/questions/332079/in-java-how-do-i-convert-a-byte-array-to-a-string-of-hex-digits-while-keeping-l/2197650#2197650) and [this answer](http://stackoverflow.com/a/9855338/2970947). **Or** just use [Apache Commons Codec](https://commons.apache.org/proper/commons-codec/) [`Hex`](https://commons.apache.org/proper/commons-codec/apidocs/org/apache/commons/codec/binary/Hex.html). – Elliott Frisch Nov 14 '15 at 20:50
0

The difference between both is that the first adds 0x100 and then only takes a substring.

That way the toString call in the first loop always returns a string with a leading 1 followed by the actual value. That way the zero is preserved.

The second loop produces wrong output because the zero digit gets lost.

Jimmy T.
  • 4,033
  • 2
  • 22
  • 38
  • I see, that makes a lot of sense. I didn't fully understand why he had done that. Your explanation really clarified that. Thank you. I did what @ElliotFrisch suggested by using the string formatter. I suppose as an integer being parsed, I'm not sure why I expected the leading zero to remain. – mcnichol Nov 14 '15 at 20:42