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);
}
}
-
6\$\begingroup\$ What is the purpose of this? Should this be an implementation of md5? Or is it something else? \$\endgroup\$tb-– tb-2013年03月24日 23:42:51 +00:00Commented Mar 24, 2013 at 23:42
2 Answers 2
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.
-
\$\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– 200_success2014年06月23日 04:53:03 +00:00Commented 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– Ingo Bürk2014年06月23日 05:18:45 +00:00Commented 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\$CodesInChaos– CodesInChaos2014年08月07日 17:08:11 +00:00Commented 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\$CodesInChaos– CodesInChaos2014年08月07日 17:10:45 +00:00Commented Aug 7, 2014 at 17:10
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.
-
2\$\begingroup\$ There should never have been any Strings in the first place; MD5 should work on byte arrays. \$\endgroup\$200_success– 200_success2013年11月26日 05:18:36 +00:00Commented Nov 26, 2013 at 5:18
-
\$\begingroup\$ Or maybe on UTF-8 encoded strings in NFC. But then consistently. \$\endgroup\$Roland Illig– Roland Illig2013年11月26日 21:14:26 +00:00Commented Nov 26, 2013 at 21:14