title: Java MD5 implementation hashes strings to incorrect values
body: <p>I looked at multiple websites to find what the MD5 algorithm is. Then I used what I learned to write a method in Java that can compute the MD5 hash of a given input. I tried changing certain parts of the code that I thought was incorrect but I still couldn't get the correct hash values for some of the Strings I tried. Here is my code:</p>
  
  <pre><code>    import java.security.MessageDigest;
      import java.security.NoSuchAlgorithmException;
  
      class MD5 {
      public static void main(String[] args) throws NoSuchAlgorithmException {
          String[] msgs = new String[] { "", "md5", "MD5", "Java",
                  "MessageDigest5", "1234", "123abc", "0123456789abcdef" };
          String[] strings = new String[msgs.length + args.length];
          System.arraycopy(msgs, 0, strings, 0, msgs.length);
          for (int i = msgs.length; i &lt; strings.length; ++i)
              strings[i] = args[i - msgs.length];
          for (String s : strings) {
              System.out.print("MD5(\"" + s + "\") = ");
              byte[] md5 = md5(s.getBytes());
              byte[] java = MessageDigest.getInstance("MD5").digest(s.getBytes());
              StringBuilder sbmd5 = new StringBuilder();
              StringBuilder sbjava = new StringBuilder();
              for (int i = 0; i &lt; 16; ++i) {
                  sbmd5.append(String.format("%02x", md5[i] &amp; 0xff));
                  sbjava.append(String.format("%02x", java[i] &amp; 0xff));
              }
              System.out.print("Java(" + sbjava.toString() + ") MD5(");
              System.out.print(sbmd5.toString() + ")");
              System.out.println();
          }
      }
  
      public static byte[] md5(byte[] data) {
          if (data == null)
              throw new NullPointerException();
          byte[] padding = new byte[] { (byte) 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
          int[] SHIFT = new int[] { 7, 12, 17, 22, 5, 9, 14, 20, 4, 11, 16, 23,
                  6, 10, 15, 21 };
          int[] TABLE = new int[64];
          for (int i = 0; i &lt; 64; ++i)
              TABLE[i] = (int) (long) ((1L &lt;&lt; 32) * Math.abs(Math.sin(i + 1)));
          int A = 0x67452301; // 01234567
          int B = 0xefcdab89; // 89abcdef
          int C = 0x98badcfe; // fedcba98
          int D = 0x10325476; // 76543210
          // int A = 0x01234567;
          // int B = 0x89abcdef;
          // int C = 0xfedcba98;
          // int D = 0x76543210;
          byte[] msg = new byte[data.length + 64 - (data.length % 64)];
          System.arraycopy(data, 0, msg, 0, data.length);
          int padPos = 0;
          for (int i = data.length; i &lt; msg.length; ++i)
              msg[i] = padding[padPos++];
          for (int i = 0; i &lt; msg.length &gt;&gt;&gt; 6; ++i) {
              int[] words = new int[16];
              int msgStart = i &lt;&lt; 6;
              for (int j = 0; j &lt; 16; ++j) {
                  int k = j &lt;&lt; 2;
                  int begin = msgStart + k;
                  words[j] = msg[begin] + (msg[begin + 1] &lt;&lt; 8)
                          + (msg[begin + 2] &lt;&lt; 16) + (msg[begin + 3] &lt;&lt; 24);
              }
              int a0 = A;
              int b0 = B;
              int c0 = C;
              int d0 = D;
              for (int j = 0; j &lt; 64; ++j) {
                  int j16 = j &gt;&gt;&gt; 4;
                  int F;
                  int index;
                  switch (j16) {
                  case 0:
                      F = (b0 &amp; c0) | (~b0 &amp; d0);
                      // F = d0 ^ (b0 &amp; (c0 ^ d0));
                      index = j;
                      break;
                  case 1:
                      F = (b0 &amp; d0) | (c0 &amp; ~d0);
                      // F = c0 ^ (d0 &amp; (b0 ^ c0));
                      index = ((j * 5) + 1) &amp; 15;
                      break;
                  case 2:
                      F = b0 ^ c0 ^ d0;
                      index = ((j * 3) + 5) &amp; 15;
                      break;
                  default:
                      F = c0 ^ (b0 | ~d0);
                      index = (j * 7) &amp; 15;
                      break;
                  }
                  int rotateValue = A + F + words[index] + TABLE[j];
                  int rotateDistance = SHIFT[(j16 &lt;&lt; 2) | (j &amp; 3)];
                  int temp = B
                          + ((rotateValue &lt;&lt; rotateDistance) | (rotateValue &gt;&gt;&gt; (32 - rotateDistance)));
                  A = D;
                  D = C;
                  C = B;
                  B = temp;
              }
              A += a0;
              B += b0;
              C += c0;
              D += d0;
          }
          byte[] result = new byte[16];
          int index = 0;
          for (int i = 0; i &lt; 4; ++i) {
              int n = i == 0 ? A : (i == 1 ? B : (i == 2 ? C : D));
              for (int j = 0; j &lt; 4; ++j) {
                  result[index++] = (byte) n;
                  n &gt;&gt;&gt;= 8;
              }
          }
          return result;
      }
  }
  </code></pre>
  
  <p>I don't know what's wrong with it but here is the output. I hashed the same set of strings in both my implementation and java.security.MessageDigest to compare the hashes.</p>
  
  <pre><code>MD5("") = Java(d41d8cd98f00b204e9800998ecf8427e) MD5(6195f07125a3dab6a14e8e929a0ac5bf)
  MD5("md5") = Java(1bc29b36f623ba82aaf6724fd3b16718) MD5(f382be5a669dd9ce3095a4aa2e55ff18)
  MD5("MD5") = Java(7f138a09169b250e9dcb378140907378) MD5(af2ade546a995a239c94f5776393bfdd)
  MD5("Java") = Java(d52387880e1ea22817a72d3759213819) MD5(f512715d4bc0728fd50994d6583d6370)
  MD5("MessageDigest5") = Java(c39f3b584476f0fd9303fe2cba34a1de) MD5(85e2d27519fbf97c3f988e9ccb9564a6)
  MD5("1234") = Java(81dc9bdb52d04dc20036dbd8313ed055) MD5(51e22a66d259c84c920d11f3b1048263)
  MD5("123abc") = Java(a906449d5769fa7361d7ecc6aa3f6d28) MD5(e1254819f3127907cb3e95b3fa3b2e68)
  MD5("0123456789abcdef") = Java(4032af8d61035123906e58e067140cc5) MD5(28fcda2be1f449185c73222e3a6e5ca4)
  </code></pre>