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 '13 at 23:42
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\$ – 200_success Jun 23 '14 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 '14 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\$ – CodesInChaos Aug 7 '14 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\$ – CodesInChaos Aug 7 '14 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\$ – 200_success Nov 26 '13 at 5:18
  • \$\begingroup\$ Or maybe on UTF-8 encoded strings in NFC. But then consistently. \$\endgroup\$ – Roland Illig Nov 26 '13 at 21:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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