4
\$\begingroup\$

Can you please try my algorithm and give comments or feedback about it?

package md52;

import java.io.*; //input outputs

import static java.lang.Math.*; //for math purposes

/**
 *
 * JesseePogi
 */

public class Md52 {

    public static String input;

    public static void main(String[] args) {

        //start timer (for algo speed testing)

        long start = System.currentTimeMillis();

        //input  

        BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));

        try
        {
        System.out.print("Enter the text here: ");
            input = bf.readLine();
        }
        catch(IOException err)
        {
            System.out.println("Read Error!");
        }

        //initialize digest   

        int h0 = 0x67452301;
        int h1 = 0xefcdab89;
        int h2 = 0x98badcfe;
        int h3 = 0x10325476;

        //Initialize hash for chunk

        int a = h0;
        int b = h1;
        int c = h2;
        int d = h3;
        int f = 0, g = 0;

        //initialize shift rotation

        int r[] = {7,12,17,22,7,12,17,22,7,12,17,22,7,12,17,22,
                   5, 9,14,20,5, 9,14,20,5, 9,14,20,5, 9,14,20,
                   4,11,16,23,4,11,16,23,4,11,16,23,4,11,16,23,
                   6,10,15,21,6,10,15,21,6,10,15,21,6,10,15,21};

        //initialize constant k

        int k[] = { 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
                    0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
                    0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
                    0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
                    0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
                    0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
                    0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
                    0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
                    0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
                    0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
                    0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
                    0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
                    0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
                    0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
                    0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
                    0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391};

        //long formula for k (didn't use because of unwanted results when casting as int)

        /*
        double k[] = new double[64];
        for (int i = 0; i < 64; i++)
            {
                k[i] = floor(abs(sin(i+1)) * pow(2,32));
                System.out.println(k[i]);
            }
        */

        //store original input

        String origInput = input;

        //leftrotate13 the original input (by character)

        for(int i = 0; i < 13; ++i)
        { 
            origInput = origInput.substring(1,origInput.length()) +""+ origInput.charAt(0);
        }

        //sum all the values of origInput for salting 

        byte[] bytesTemp1 = origInput.getBytes();
        int sum = 0;
        for (int i : bytesTemp1) sum += i;

        //convert to bit (input)

        byte[] bytesTemp = input.getBytes();
        StringBuilder binaryTemp = new StringBuilder();
        for (byte byt : bytesTemp)
        {
            int val = byt;
            for (int i = 0; i < 8; i++)
            {
                binaryTemp.append((val & 128) == 0 ? 0 : 1);
                val <<= 1;
            }
        }

        String origInput_bits = binaryTemp.toString(); //for padding purposes
        if (origInput_bits.length() < 64)
        {
            origInput_bits = origInput_bits + "1";
            for (int i = origInput_bits.length(); i<64; i++)
            {
                origInput_bits = origInput_bits + "0";
            }
        }

        //padding 1 and 0s'

        binaryTemp.append("1");
        for(int i = binaryTemp.length(); i%512!=448; i++)
        {
            binaryTemp.append("0");
        }

        //pad additional 64bits to get 512bits (from end to end until it reach the middle part)

        String pad1_address0 = origInput_bits.substring(0,8);
        String pad2_addressEnd = origInput_bits.substring(origInput_bits.length()-8,origInput_bits.length());
        String pad3_address1 = origInput_bits.substring(8,16);
        String pad4_addressEnd1 = origInput_bits.substring(origInput_bits.length()-16,origInput_bits.length()-8);
        String pad5_address2 = origInput_bits.substring(16,24);
        String pad6_addressEnd2 = origInput_bits.substring(origInput_bits.length()-24,origInput_bits.length()-16);
        String pad7_address3 = origInput_bits.substring(24,32);
        String pad8_addressEnd3 = origInput_bits.substring(origInput_bits.length()-32,origInput_bits.length()-24);
        String origInput_bits64 = pad1_address0+""+pad2_addressEnd+""+pad3_address1+""+pad4_addressEnd1+""+pad5_address2+""+pad6_addressEnd2+""+pad7_address3+""+pad8_addressEnd3;

        binaryTemp.append(origInput_bits64);

        //sixteen 32bit chunks in string wTemp[]  

        String wTemp[] = new String[16];
        int x = 0;
        for (int i = 0; i < 16; i++)
        {
            wTemp[i] = binaryTemp.substring(x,x+=32);
            wTemp[i] = wTemp[i].toString();
        }

        //string wTemp[] to byte[] data        

        byte[] data1 = new byte[64];
        int y = 0;
        int count = 0;
        for(int i = 0; i < 16; ++i)
        {
            while (count < 64)
            {
                if(i<=3)
                {
                    if(i>=0)
                    {
                        data1[count]= (byte) Integer.parseInt(wTemp[i].substring(y,y+=8),2);
                        if (y==32){y = 0; ++count; break;}
                    }
                }
                if(i<=7)
                {
                    if(i>=4)
                    {
                        data1[count]= (byte) Integer.parseInt(wTemp[i].substring(y,y+=8),2);
                        if (y==32){y = 0; ++count; break;}
                    }
                }
                if(i<=11)
                {
                    if(i>=8)
                    {
                        data1[count]= (byte) Integer.parseInt(wTemp[i].substring(y,y+=8),2);
                        if (y==32){y = 0; ++count; break;}
                    }
                }
                if(i<=15)
                {
                    if(i>=12)
                    {
                        data1[count]= (byte) Integer.parseInt(wTemp[i].substring(y,y+=8),2);
                        if (y==32){y = 0; ++count; break;}
                    }
                }
                ++count;
            }
        }

        /*
        data1[0] = (byte) Integer.parseInt(wTemp[0].substring(0,8), 2);
        data1[1] = (byte) Integer.parseInt(wTemp[0].substring(8,16), 2);
        data1[2] = (byte) Integer.parseInt(wTemp[0].substring(16,24), 2);
        data1[3] = (byte) Integer.parseInt(wTemp[0].substring(24,32), 2);

        data1[4] = (byte) Integer.parseInt(wTemp[1].substring(0,8), 2);
        data1[5] = (byte) Integer.parseInt(wTemp[1].substring(8,16), 2);
        data1[6] = (byte) Integer.parseInt(wTemp[1].substring(16,24), 2);
        data1[7] = (byte) Integer.parseInt(wTemp[1].substring(24,32), 2);

        data1[8] = (byte) Integer.parseInt(wTemp[2].substring(0,8), 2);
        data1[9] = (byte) Integer.parseInt(wTemp[2].substring(8,16), 2);
        data1[10] = (byte) Integer.parseInt(wTemp[2].substring(16,24), 2);
        data1[11] = (byte) Integer.parseInt(wTemp[2].substring(24,32), 2);

        data1[12] = (byte) Integer.parseInt(wTemp[3].substring(0,8), 2);
        data1[13] = (byte) Integer.parseInt(wTemp[3].substring(8,16), 2);
        data1[14] = (byte) Integer.parseInt(wTemp[3].substring(16,24), 2);
        data1[15] = (byte) Integer.parseInt(wTemp[3].substring(24,32), 2);

        data1[16] = (byte) Integer.parseInt(wTemp[4].substring(0,8), 2);
        data1[17] = (byte) Integer.parseInt(wTemp[4].substring(8,16), 2);
        data1[18] = (byte) Integer.parseInt(wTemp[4].substring(16,24), 2);
        data1[19] = (byte) Integer.parseInt(wTemp[4].substring(24,32), 2);

        data1[20] = (byte) Integer.parseInt(wTemp[5].substring(0,8), 2);
        data1[21] = (byte) Integer.parseInt(wTemp[5].substring(8,16), 2);
        data1[22] = (byte) Integer.parseInt(wTemp[5].substring(16,24), 2);
        data1[23] = (byte) Integer.parseInt(wTemp[5].substring(24,32), 2);

        data1[24] = (byte) Integer.parseInt(wTemp[6].substring(0,8), 2);
        data1[25] = (byte) Integer.parseInt(wTemp[6].substring(8,16), 2);
        data1[26] = (byte) Integer.parseInt(wTemp[6].substring(16,24), 2);
        data1[27] = (byte) Integer.parseInt(wTemp[6].substring(24,32), 2);

        data1[28] = (byte) Integer.parseInt(wTemp[7].substring(0,8), 2);
        data1[29] = (byte) Integer.parseInt(wTemp[7].substring(8,16), 2);
        data1[30] = (byte) Integer.parseInt(wTemp[7].substring(16,24), 2);
        data1[31] = (byte) Integer.parseInt(wTemp[7].substring(24,32), 2);

        data1[32] = (byte) Integer.parseInt(wTemp[8].substring(0,8), 2);
        data1[33] = (byte) Integer.parseInt(wTemp[8].substring(8,16), 2);
        data1[34] = (byte) Integer.parseInt(wTemp[8].substring(16,24), 2);
        data1[35] = (byte) Integer.parseInt(wTemp[8].substring(24,32), 2);

        data1[36] = (byte) Integer.parseInt(wTemp[9].substring(0,8), 2);
        data1[37] = (byte) Integer.parseInt(wTemp[9].substring(8,16), 2);
        data1[38] = (byte) Integer.parseInt(wTemp[9].substring(16,24), 2);
        data1[39] = (byte) Integer.parseInt(wTemp[9].substring(24,32), 2);

        data1[40] = (byte) Integer.parseInt(wTemp[10].substring(0,8), 2);
        data1[41] = (byte) Integer.parseInt(wTemp[10].substring(8,16), 2);
        data1[42] = (byte) Integer.parseInt(wTemp[10].substring(16,24), 2);
        data1[43] = (byte) Integer.parseInt(wTemp[10].substring(24,32), 2);

        data1[44] = (byte) Integer.parseInt(wTemp[11].substring(0,8), 2);
        data1[45] = (byte) Integer.parseInt(wTemp[11].substring(8,16), 2);
        data1[46] = (byte) Integer.parseInt(wTemp[11].substring(16,24), 2);
        data1[47] = (byte) Integer.parseInt(wTemp[11].substring(24,32), 2);

        data1[48] = (byte) Integer.parseInt(wTemp[12].substring(0,8), 2);
        data1[49] = (byte) Integer.parseInt(wTemp[12].substring(8,16), 2);
        data1[50] = (byte) Integer.parseInt(wTemp[12].substring(16,24), 2);
        data1[51] = (byte) Integer.parseInt(wTemp[12].substring(24,32), 2);

        data1[52] = (byte) Integer.parseInt(wTemp[13].substring(0,8), 2);
        data1[53] = (byte) Integer.parseInt(wTemp[13].substring(8,16), 2);
        data1[54] = (byte) Integer.parseInt(wTemp[13].substring(16,24), 2);
        data1[55] = (byte) Integer.parseInt(wTemp[13].substring(24,32), 2);

        data1[56] = (byte) Integer.parseInt(wTemp[14].substring(0,8), 2);
        data1[57] = (byte) Integer.parseInt(wTemp[14].substring(8,16), 2);
        data1[58] = (byte) Integer.parseInt(wTemp[14].substring(16,24), 2);
        data1[59] = (byte) Integer.parseInt(wTemp[14].substring(24,32), 2);

        data1[60] = (byte) Integer.parseInt(wTemp[15].substring(0,8), 2);
        data1[61] = (byte) Integer.parseInt(wTemp[15].substring(8,16), 2);
        data1[62] = (byte) Integer.parseInt(wTemp[15].substring(16,24), 2);
        data1[63] = (byte) Integer.parseInt(wTemp[15].substring(24,32), 2);
        */

        //byte[] data to real int w[] (concatenation)  

        int[] w = new int[16];
        int count2 = 0;
        for(int i = 0; i < 16; ++i)
        {
            w[i] = (((int)data1[count2++])) | (((int)data1[count2++]) << 8) | (((int)data1[count2++]) << 16) | (((int)data1[count2++]) << 24);
        }

        //main loop

        for(int i = 0; i <= 63; i++)
        {
            if (i <= 15)
            {
                if (i >= 0)
                {
                    f = (b & c) | ((~b) & d);
                    g = i;
                }
            }
            if (i <= 31)
            {
                if (i >= 16)
                {
                    f = (d & b) | ((~d) & c);
                    g = (5*i + 1) % 16;
                }
            }
            if (i <= 47)
            {
                if (i >= 32)
                {
                    f = (b ^ c ^ d);
                    g = (3*i + 5) % 16;
                }
            }
            if (i <= 63)
            {
                if (i >= 48)
                {
                    f = c ^ (b | (~d));
                    g = (7*i) % 16;
                }
            }
            int temp = d;
            d = c;
            c = b;
            b = b + Integer.rotateLeft((a + f + k[i] + w[g]), r[i]);
            a = temp;

        }

        //Add this chunk's hash to result so far

        h0 = h0 + a;
        h1 = h1 + b;
        h2 = h2 + c;
        h3 = h3 + d + sum; //sum is salted

        //Show the final result 

        System.out.println("Hash Code: "+Integer.toHexString(h0)+Integer.toHexString(h1)+Integer.toHexString(h2)+Integer.toHexString(h3));

        //end timer  

        long end = System.currentTimeMillis();
        long diff = end - start;
        System.out.println("\nAlgorithm Speed (ms): " + diff);
}
}
\$\endgroup\$
1
  • 6
    \$\begingroup\$ What is the purpose of this? Should this be an implementation of md5? Or is it something else? \$\endgroup\$
    – tb-
    Mar 24, 2013 at 23:42

2 Answers 2

7
\$\begingroup\$

A few notes:


There is no need to comment import statements. Although I want to say thank you, I've never actually seen anyone do that before. But really, don't do it.


Commented-out code is dead code. Dead code should be removed. If you are afraid of deleting code, you probably don't know about source control management. Look into learning how to work with SCM tools such as git.


Variable names should be meaningful and reveal the semantics in order to make the code read like a story or at least a manual. Names like a, b, c, … are meaningless and only make understanding (and therefore maintaining) the code harder.


Your code contains many magic numbers, i.e. numbers that appear in the code without obviously revealing their meaning. Convert them into constants to improve both readability and maintainability.


Avoid enumerating variable names such as byteTemp and then byteTemp1. Again, variable names should represent semantics. They should not represent their type either (we will know that by reading their declaration).

Ask yourself: If you only saw the name byteTemp, what would you really know about it? Maybe that it (probably) has to do with bytes, but you would know nothing about what this variable represents in the context.


The common Java standard is camelCase, not snake_case. So variables should be named someVariable, not some_variable.


Your method is (way, way) too long. Break every individual piece into its own method. Maybe even break it down into separate classes if necessary. A good method does one thing, yours does dozens of things and makes it pretty much impossible to keep track of what is going on as there is no abstraction supporting this.


Instead of printing the result, your method (which won't be a main method anyway) should return the result. Leave it up to the caller to decide what they want to do with the result.

\$\endgroup\$
4
  • \$\begingroup\$ I doubt that there's much that can be done about the magic numbers. They aren't supposed to make logical sense. It's just how the algorithm works. \$\endgroup\$ Jun 23, 2014 at 4:53
  • \$\begingroup\$ Maybe, but it'd still be good to have constants for them because it makes code more maintainable. \$\endgroup\$
    – Ingo Bürk
    Jun 23, 2014 at 5:18
  • \$\begingroup\$ Variables within cryptographic primitives often have no intuitive meaning. An implementation should use the names used in the specification which may well be a,... \$\endgroup\$ Aug 7, 2014 at 17:08
  • \$\begingroup\$ Concerning magic numbers the only thing I'd do is turn h0...h3, r, k into static fields instead of including them in the main method. There is little else you can do with these. \$\endgroup\$ Aug 7, 2014 at 17:10
2
\$\begingroup\$

One thing is that you should always specify an encoding when calling String.getBytes, since otherwise the result depends too much on the execution environment. I didn't look through the rest of the code, though.

\$\endgroup\$
2
  • 2
    \$\begingroup\$ There should never have been any Strings in the first place; MD5 should work on byte arrays. \$\endgroup\$ Nov 26, 2013 at 5:18
  • \$\begingroup\$ Or maybe on UTF-8 encoded strings in NFC. But then consistently. \$\endgroup\$ Nov 26, 2013 at 21:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.